Декомпилляция звукового файла формата Wave и получение звуковых данных
ИМХО - это аббревиатура.
Истинное Мнение Хр#н Оспоришь.
Интересно, есть ли технология преобразования 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 dobeginif 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: fileof Byte;
type
Tag = (F0, T1, M1);
type
FudgeNum = recordcase 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;
beginfor i := 1 to 4 dobegin
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 dobegincase nChannels of
1: if nBitsPerSample = 16 thenbegin{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;
endelsebegin{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 thenbegin{2 Двухканальный 16-битный сэмпл}
ChunkSize.dn := trunc(Ki.yyy[N] + 0.5);
ChunkSize.up := trunc(Kj.yyy[N] + 0.5);
N := N + 1;
endelsebegin{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 dobegin
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;
beginend; { InitSpecs }procedure InitSignals(var Kk: Observation);
var
J: Integer;
beginfor 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 dobeginRead(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 dobeginRead(InFile, MM);
ChunkSize.chrs[I] := MM;
end;
ChunkSize.x := T1;
end; {ReadChunkSize}procedure ReadOneDataBlock(var Ki, Kj: Observation);
var
I: Integer;
beginif N <= MaxN thenbegin
ReadChunkSize; {получаем 4 байта данных}
ChunkSize.x := M1;
with Ki.WAV docase nChannels of
1: if nBitsPerSample = 16 thenbegin{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;
endelsebegin{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 thenbegin{2 Двухканальный 16-битный сэмпл}
Ki.yyy[N] := 1.0 * ChunkSize.dn;
Kj.yyy[N] := 1.0 * ChunkSize.up;
N := N + 1;
endelsebegin{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 thenbegin{LastN := N;}
Ki.Last := N;
if Ki.WAV.nChannels = 2 then
Kj.Last := N;
endelsebegin{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;
beginif FileExists(StandardInput) thenwith Ki.WAV dobegin{ Вызов диалога открытия файла }
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 dobeginRead(InFile, MM);
ChunkSize.chrs[I] := MM;
end;
ChunkSize.x := M1;
nBlockAlign := ChunkSize.up;
{Считываем nBitsPerSample}
nBitsPerSample := ChunkSize.dn;
for I := 17 to fmtSize doRead(InFile, MM);
NoDataYet := True;
while NoDataYet dobegin{Считываем метку блока данных "data"}
ReadChunkName;
{Считываем DataSize}
ReadChunkSize;
DataSize := ChunkSize.lint;
if ChunkName <> 'data' thenbeginfor I := 1 to DataSize do{пропуск данных, не относящихся к набору звуковых данных}Read(InFile, MM);
endelse
NoDataYet := False;
end;
nDataBytes := DataSize;
{Наконец, начинаем считывать данные для байтов nDataBytes}if nDataBytes > 0 then
DataYet := True;
N := 0; {чтение с первой позиции}while DataYet dobegin
ReadOneDataBlock(Ki, Kj); {получаем 4 байта}
nDataBytes := nDataBytes - 4;
if nDataBytes <= 4 then
DataYet := False;
end;
ScaleData(Ki);
if Ki.WAV.nChannels = 2 thenbegin
Kj.WAV := Ki.WAV;
ScaleData(Kj);
end;
{Освобождаем буфер файла}
CloseFile(InFile);
endelsebegin
InitSpecs; {файл не существует}
InitSignals(Ki); {обнуляем массив "Ki"}
InitSignals(Kj); {обнуляем массив "Kj"}end;
end; { ReadWAVFile }{================= Операции с набором данных ====================}const
MaxNumberOfDataBaseItems = 360;
type
SignalDirectoryIndex = 0..MaxNumberOfDataBaseItems;
var
DataBaseFile: fileof Observation;
LastDataBaseItem: LongInt; {Номер текущего элемента набора данных}
ItemNameS: array[SignalDirectoryIndex] ofstring[40];
procedure GetDatabaseItem(Kk: Observation; N: LongInt);
beginif N <= LastDataBaseItem thenbegin
Seek(DataBaseFile, N);
Read(DataBaseFile, Kk);
endelse
InitSignals(Kk);
end; {GetDatabaseItem}procedure PutDatabaseItem(Kk: Observation; N: LongInt);
beginif N < MaxNumberOfDataBaseItems thenif N <= LastDataBaseItem thenbegin
Seek(DataBaseFile, N);
Write(DataBaseFile, Kk);
LastDataBaseItem := LastDataBaseItem + 1;
endelsewhile LastDataBaseItem <= N dobegin
Seek(DataBaseFile, LastDataBaseItem);
Write(DataBaseFile, Kk);
LastDataBaseItem := LastDataBaseItem + 1;
endelse
ReportError(1); {Попытка чтения MaxNumberOfDataBaseItems}end; {PutDatabaseItem}procedure InitDataBase;
begin
LastDataBaseItem := 0;
if FileExists(StandardDataBase) thenbegin
Assign(DataBaseFile, StandardDataBase);
Reset(DataBaseFile);
whilenot EOF(DataBaseFile) dobegin
GetDataBaseItem(K0R, LastDataBaseItem);
ItemNameS[LastDataBaseItem] := K0R.Name;
LastDataBaseItem := LastDataBaseItem + 1;
end;
if EOF(DataBaseFile) thenif 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 dobeginif Nstg = ItemNameS[ThisOne] thenbegin
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}
Программный код, предоставленный вам, является модулем Delphi, предназначенным для работы с файлами формата WAV и чтения/записи данных из них. Вот подробное описание различных процедур, функций и переменных:
Структура заголовка WAV
Рекорд типа WAVHeader определяет структуру заголовка файла WAV, включая поля, такие как nChannels, nBitsPerSample, nSamplesPerSec, nAvgBytesPerSec и другие.
Процедура ReadWAVFile
Эта процедура читает файл WAV из указанного входного файла (StandardInput) и пополняет структуру наблюдения (Ki и/или Kj) аудиоданными. Она также рассчитывает различные значения, такие как DataSize и Last.
Процедура WriteWAVFile
Эта процедура записывает файл WAV в указанный выходной файл (StandardOutput) с использованием аудиоданных из структуры наблюдения (Ki и/или Kj). Она генерирует необходимую информацию заголовка, включая chunk RIFF, fmt и data.
Процедура ScaleData
Эта процедура масштабирует аудиоданные в структуре наблюдения (Kk) путем расчета минимальных и максимальных значений данных.
Процедура ReadOneDataBlock
Эта процедура читает блок аудиоданных из файла WAV и пополняет структуру наблюдения (Ki и/или Kj) данными. Она обрабатывает случаи, когда файл имеет несколько каналов (например, стерео).
Процедура GetDatabaseItem
Эта процедура получает структуру наблюдения (Kk) из файла базы данных (DataBaseFile) по указанному индексу (N). Если индекс выходит за пределы диапазона, она инициализирует структуру наблюдения с дефолтными значениями.
Процедура PutDatabaseItem
Эта процедура записывает структуру наблюдения (Kk) в файл базы данных (DataBaseFile) по указанному индексу (N). Если индекс превышает текущий последний элемент, она добавляет новые элементы в конец файла.
InitDataBase
Эта процедура инициализирует файл базы данных, прочитав все доступные записи из файла и пополнив массив структур наблюдения (ItemNameS).
FindDataBaseName
Функция поиска ищет структуру наблюдения в файле базы данных по имени и возвращает ее индекс, если найдена. Если не найдена, она возвращает -1.
InitLinearSystem
Эта процедура инициализирует различные глобальные переменные, включая путь основного каталога, стандартные входной и выходной файлы и стандартный файл базы данных. Она также вызывает другие инициализационные процедуры для настройки линейной системы.
В целом, этот код appears to be a part of a larger audio processing or analysis application that uses WAV files as its data format.
Декомпилляция звукового файла формата Wave и получение звуковых данных.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.