Декомпилляция звукового файла формата Wave и получение звуковых данных
01.01.2007
Интересно, есть ли технология преобразования Wave-формата в обычный набор звуковых данных? К примеру, мне необходимо удалить заголовок и механизм (метод) сжатия, которые могут компилироваться и сохраняться вместе с Wave-файлами.
У меня есть программа под D1/D2, которая читает WAV-файлы и вытаскивает исходные данные, но она не может их восстанавить, используя зашитый алгоритм сжатия.
unit LinearSystem; interface {============== Тип, описывающий формат WAV ==================} type WAVHeader = record nChannels: Word; nBitsPerSample: LongInt; nSamplesPerSec: LongInt; nAvgBytesPerSec: LongInt; RIFFSize: LongInt; fmtSize: LongInt; formatTag: Word; nBlockAlign: LongInt; DataSize: LongInt; end; {============== Поток данных сэмпла ========================} const MaxN = 300; { максимальное значение величины сэмпла } type SampleIndex = 0..MaxN + 3; type DataStream = array[SampleIndex] of Real; var N: SampleIndex; {============== Переменные сопровождения ======================} type Observation = record Name: string[40]; {Имя данного сопровождения} yyy: DataStream; {Массив указателей на данные} WAV: WAVHeader; {Спецификация WAV для сопровождения} Last: SampleIndex; {Последний доступный индекс yyy} MinO, MaxO: Real; {Диапазон значений yyy} end; var K0R, K1R, K2R, K3R: Observation; K0B, K1B, K2B, K3B: Observation; {================== Переменные имени файла ===================} var StandardDatabase: string[80]; BaseFileName: string[80]; StandardOutput: string[80]; StandardInput: string[80]; {=============== Объявления процедур ==================} procedure ReadWAVFile(var Ki, Kj: Observation); procedure WriteWAVFile(var Ki, Kj: Observation); procedure ScaleData(var Kk: Observation); procedure InitAllSignals; procedure InitLinearSystem; implementation {$R *.DFM} uses VarGraph, SysUtils; {================== Стандартный формат WAV-файла ===================} const MaxDataSize: LongInt = (MaxN + 1) * 2 * 2; const MaxRIFFSize: LongInt = (MaxN + 1) * 2 * 2 + 36; const StandardWAV: WAVHeader = ( nChannels: Word(2); nBitsPerSample: LongInt(16); nSamplesPerSec: LongInt(8000); nAvgBytesPerSec: LongInt(32000); RIFFSize: LongInt((MaxN + 1) * 2 * 2 + 36); fmtSize: LongInt(16); formatTag: Word(1); nBlockAlign: LongInt(4); DataSize: LongInt((MaxN + 1) * 2 * 2) ); {================== Сканирование переменных сопровождения ===================} procedure ScaleData(var Kk: Observation); var I: SampleIndex; begin {Инициализация переменных сканирования} Kk.MaxO := Kk.yyy[0]; Kk.MinO := Kk.yyy[0]; {Сканирование для получения максимального и минимального значения} for I := 1 to Kk.Last do begin if Kk.MaxO < Kk.yyy[I] then Kk.MaxO := Kk.yyy[I]; if Kk.MinO > Kk.yyy[I] then Kk.MinO := Kk.yyy[I]; end; end; { ScaleData } procedure ScaleAllData; begin ScaleData(K0R); ScaleData(K0B); ScaleData(K1R); ScaleData(K1B); ScaleData(K2R); ScaleData(K2B); ScaleData(K3R); ScaleData(K3B); end; {ScaleAllData} {================== Считывание/запись WAV-данных ===================} var InFile, OutFile: file of Byte; type Tag = (F0, T1, M1); type FudgeNum = record case X: Tag of F0: (chrs: array[0..3] of Byte); T1: (lint: LongInt); M1: (up, dn: Integer); end; var ChunkSize: FudgeNum; procedure WriteChunkName(Name: string); var i: Integer; MM: Byte; begin for i := 1 to 4 do begin MM := ord(Name[i]); write(OutFile, MM); end; end; {WriteChunkName} procedure WriteChunkSize(LL: Longint); var I: integer; begin ChunkSize.x := T1; ChunkSize.lint := LL; ChunkSize.x := F0; for I := 0 to 3 do Write(OutFile, ChunkSize.chrs[I]); end; procedure WriteChunkWord(WW: Word); var I: integer; begin ChunkSize.x := T1; ChunkSize.up := WW; ChunkSize.x := M1; for I := 0 to 1 do Write(OutFile, ChunkSize.chrs[I]); end; {WriteChunkWord} procedure WriteOneDataBlock(var Ki, Kj: Observation); var I: Integer; begin ChunkSize.x := M1; with Ki.WAV do begin case nChannels of 1: if nBitsPerSample = 16 then begin {1..2 Помещаем в буфер одноканальный 16-битный сэмпл} ChunkSize.up := trunc(Ki.yyy[N] + 0.5); if N < MaxN then ChunkSize.dn := trunc(Ki.yyy[N + 1] + 0.5); N := N + 2; end else begin {1..4 Помещаем в буфер одноканальный 8-битный сэмпл} for I := 0 to 3 do ChunkSize.chrs[I] := trunc(Ki.yyy[N + I] + 0.5); N := N + 4; end; 2: if nBitsPerSample = 16 then begin {2 Двухканальный 16-битный сэмпл} ChunkSize.dn := trunc(Ki.yyy[N] + 0.5); ChunkSize.up := trunc(Kj.yyy[N] + 0.5); N := N + 1; end else begin {4 Двухканальный 8-битный сэмпл} ChunkSize.chrs[1] := trunc(Ki.yyy[N] + 0.5); ChunkSize.chrs[3] := trunc(Ki.yyy[N + 1] + 0.5); ChunkSize.chrs[0] := trunc(Kj.yyy[N] + 0.5); ChunkSize.chrs[2] := trunc(Kj.yyy[N + 1] + 0.5); N := N + 2; end; end; {with WAV do begin..} end; {четырехбайтовая переменная "ChunkSize" теперь заполнена} ChunkSize.x := T1; WriteChunkSize(ChunkSize.lint); {помещаем 4 байта данных} end; {WriteOneDataBlock} procedure WriteWAVFile(var Ki, Kj: Observation); var MM: Byte; I: Integer; OK: Boolean; begin {Приготовления для записи файла данных} AssignFile(OutFile, StandardOutput); { Файл, выбранный в диалоговом окне } ReWrite(OutFile); with Ki.WAV do begin DataSize := nChannels * (nBitsPerSample div 8) * (Ki.Last + 1); RIFFSize := DataSize + 36; fmtSize := 16; end; {Записываем ChunkName "RIFF"} WriteChunkName('RIFF'); {Записываем ChunkSize} WriteChunkSize(Ki.WAV.RIFFSize); {Записываем ChunkName "WAVE"} WriteChunkName('WAVE'); {Записываем tag "fmt_"} WriteChunkName('fmt '); {Записываем ChunkSize} Ki.WAV.fmtSize := 16; {должно быть 16-18} WriteChunkSize(Ki.WAV.fmtSize); {Записываем formatTag, nChannels} WriteChunkWord(Ki.WAV.formatTag); WriteChunkWord(Ki.WAV.nChannels); {Записываем nSamplesPerSec} WriteChunkSize(Ki.WAV.nSamplesPerSec); {Записываем nAvgBytesPerSec} WriteChunkSize(Ki.WAV.nAvgBytesPerSec); {Записываем nBlockAlign, nBitsPerSample} WriteChunkWord(Ki.WAV.nBlockAlign); WriteChunkWord(Ki.WAV.nBitsPerSample); {Записываем метку блока данных "data"} WriteChunkName('data'); {Записываем DataSize} WriteChunkSize(Ki.WAV.DataSize); N := 0; {первая запись-позиция} while N <= Ki.Last do WriteOneDataBlock(Ki, Kj); {помещаем 4 байта и увеличиваем счетчик N} {Освобождаем буфер файла} CloseFile(OutFile); end; {WriteWAVFile} procedure InitSpecs; begin end; { InitSpecs } procedure InitSignals(var Kk: Observation); var J: Integer; begin for J := 0 to MaxN do Kk.yyy[J] := 0.0; Kk.MinO := 0.0; Kk.MaxO := 0.0; Kk.Last := MaxN; end; {InitSignals} procedure InitAllSignals; begin InitSignals(K0R); InitSignals(K0B); InitSignals(K1R); InitSignals(K1B); InitSignals(K2R); InitSignals(K2B); InitSignals(K3R); InitSignals(K3B); end; {InitAllSignals} var ChunkName: string[4]; procedure ReadChunkName; var I: integer; MM: Byte; begin ChunkName[0] := chr(4); for I := 1 to 4 do begin Read(InFile, MM); ChunkName[I] := chr(MM); end; end; {ReadChunkName} procedure ReadChunkSize; var I: integer; MM: Byte; begin ChunkSize.x := F0; ChunkSize.lint := 0; for I := 0 to 3 do begin Read(InFile, MM); ChunkSize.chrs[I] := MM; end; ChunkSize.x := T1; end; {ReadChunkSize} procedure ReadOneDataBlock(var Ki, Kj: Observation); var I: Integer; begin if N <= MaxN then begin ReadChunkSize; {получаем 4 байта данных} ChunkSize.x := M1; with Ki.WAV do case nChannels of 1: if nBitsPerSample = 16 then begin {1..2 Помещаем в буфер одноканальный 16-битный сэмпл} Ki.yyy[N] := 1.0 * ChunkSize.up; if N < MaxN then Ki.yyy[N + 1] := 1.0 * ChunkSize.dn; N := N + 2; end else begin {1..4 Помещаем в буфер одноканальный 8-битный сэмпл} for I := 0 to 3 do Ki.yyy[N + I] := 1.0 * ChunkSize.chrs[I]; N := N + 4; end; 2: if nBitsPerSample = 16 then begin {2 Двухканальный 16-битный сэмпл} Ki.yyy[N] := 1.0 * ChunkSize.dn; Kj.yyy[N] := 1.0 * ChunkSize.up; N := N + 1; end else begin {4 Двухканальный 8-битный сэмпл} Ki.yyy[N] := 1.0 * ChunkSize.chrs[1]; Ki.yyy[N + 1] := 1.0 * ChunkSize.chrs[3]; Kj.yyy[N] := 1.0 * ChunkSize.chrs[0]; Kj.yyy[N + 1] := 1.0 * ChunkSize.chrs[2]; N := N + 2; end; end; if N <= MaxN then begin {LastN := N;} Ki.Last := N; if Ki.WAV.nChannels = 2 then Kj.Last := N; end else begin {LastN := MaxN;} Ki.Last := MaxN; if Ki.WAV.nChannels = 2 then Kj.Last := MaxN; end; end; end; {ReadOneDataBlock} procedure ReadWAVFile(var Ki, Kj: Observation); var MM: Byte; I: Integer; OK: Boolean; NoDataYet: Boolean; DataYet: Boolean; nDataBytes: LongInt; begin if FileExists(StandardInput) then with Ki.WAV do begin { Вызов диалога открытия файла } OK := True; {если не изменится где-нибудь ниже} {Приготовления для чтения файла данных} AssignFile(InFile, StandardInput); { Файл, выбранный в диалоговом окне } Reset(InFile); {Считываем ChunkName "RIFF"} ReadChunkName; if ChunkName <> 'RIFF' then OK := False; {Считываем ChunkSize} ReadChunkSize; RIFFSize := ChunkSize.lint; {должно быть 18,678} {Считываем ChunkName "WAVE"} ReadChunkName; if ChunkName <> 'WAVE' then OK := False; {Считываем ChunkName "fmt_"} ReadChunkName; if ChunkName <> 'fmt ' then OK := False; {Считываем ChunkSize} ReadChunkSize; fmtSize := ChunkSize.lint; {должно быть 18} {Считываем formatTag, nChannels} ReadChunkSize; ChunkSize.x := M1; formatTag := ChunkSize.up; nChannels := ChunkSize.dn; {Считываем nSamplesPerSec} ReadChunkSize; nSamplesPerSec := ChunkSize.lint; {Считываем nAvgBytesPerSec} ReadChunkSize; nAvgBytesPerSec := ChunkSize.lint; {Считываем nBlockAlign} ChunkSize.x := F0; ChunkSize.lint := 0; for I := 0 to 3 do begin Read(InFile, MM); ChunkSize.chrs[I] := MM; end; ChunkSize.x := M1; nBlockAlign := ChunkSize.up; {Считываем nBitsPerSample} nBitsPerSample := ChunkSize.dn; for I := 17 to fmtSize do Read(InFile, MM); NoDataYet := True; while NoDataYet do begin {Считываем метку блока данных "data"} ReadChunkName; {Считываем DataSize} ReadChunkSize; DataSize := ChunkSize.lint; if ChunkName <> 'data' then begin for I := 1 to DataSize do {пропуск данных, не относящихся к набору звуковых данных} Read(InFile, MM); end else NoDataYet := False; end; nDataBytes := DataSize; {Наконец, начинаем считывать данные для байтов nDataBytes} if nDataBytes > 0 then DataYet := True; N := 0; {чтение с первой позиции} while DataYet do begin ReadOneDataBlock(Ki, Kj); {получаем 4 байта} nDataBytes := nDataBytes - 4; if nDataBytes <= 4 then DataYet := False; end; ScaleData(Ki); if Ki.WAV.nChannels = 2 then begin Kj.WAV := Ki.WAV; ScaleData(Kj); end; {Освобождаем буфер файла} CloseFile(InFile); end else begin InitSpecs; {файл не существует} InitSignals(Ki); {обнуляем массив "Ki"} InitSignals(Kj); {обнуляем массив "Kj"} end; end; { ReadWAVFile } {================= Операции с набором данных ====================} const MaxNumberOfDataBaseItems = 360; type SignalDirectoryIndex = 0..MaxNumberOfDataBaseItems; var DataBaseFile: file of Observation; LastDataBaseItem: LongInt; {Номер текущего элемента набора данных} ItemNameS: array[SignalDirectoryIndex] of string[40]; procedure GetDatabaseItem(Kk: Observation; N: LongInt); begin if N <= LastDataBaseItem then begin Seek(DataBaseFile, N); Read(DataBaseFile, Kk); end else InitSignals(Kk); end; {GetDatabaseItem} procedure PutDatabaseItem(Kk: Observation; N: LongInt); begin if N < MaxNumberOfDataBaseItems then if N <= LastDataBaseItem then begin Seek(DataBaseFile, N); Write(DataBaseFile, Kk); LastDataBaseItem := LastDataBaseItem + 1; end else while LastDataBaseItem <= N do begin Seek(DataBaseFile, LastDataBaseItem); Write(DataBaseFile, Kk); LastDataBaseItem := LastDataBaseItem + 1; end else ReportError(1); {Попытка чтения MaxNumberOfDataBaseItems} end; {PutDatabaseItem} procedure InitDataBase; begin LastDataBaseItem := 0; if FileExists(StandardDataBase) then begin Assign(DataBaseFile, StandardDataBase); Reset(DataBaseFile); while not EOF(DataBaseFile) do begin GetDataBaseItem(K0R, LastDataBaseItem); ItemNameS[LastDataBaseItem] := K0R.Name; LastDataBaseItem := LastDataBaseItem + 1; end; if EOF(DataBaseFile) then if LastDataBaseItem > 0 then LastDataBaseItem := LastDataBaseItem - 1; end; end; {InitDataBase} function FindDataBaseName(Nstg: string): LongInt; var ThisOne: LongInt; begin ThisOne := 0; FindDataBaseName := -1; while ThisOne < LastDataBaseItem do begin if Nstg = ItemNameS[ThisOne] then begin FindDataBaseName := ThisOne; Exit; end; ThisOne := ThisOne + 1; end; end; {FindDataBaseName} {======================= Инициализация модуля ========================} procedure InitLinearSystem; begin BaseFileName := '\PROGRA~1\SIGNAL~1\'; StandardOutput := BaseFileName + 'K0.wav'; StandardInput := BaseFileName + 'K0.wav'; StandardDataBase := BaseFileName + 'Radar.sdb'; InitAllSignals; InitDataBase; ReadWAVFile(K0R, K0B); ScaleAllData; end; {InitLinearSystem} begin {инициализируемый модулем код} InitLinearSystem; end. {Unit LinearSystem}
Взято с https://delphiworld.narod.ru