Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Получение данных из WAV


Автор: Black_Joker 13.4.2006, 19:32
Здравствуйте.

Мне надо получить данные из wav.
Делаю следующее...

В итоге получаю несколько нулевых значений.
Подскажите где ошиПка.

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  MaxN = 300; { максимальное значение величины сэмпла }
  MaxDataSize: LongInt = (MaxN + 1) * 2 * 2;
  MaxRIFFSize: LongInt = (MaxN + 1) * 2 * 2 + 36;


type
 WAVHeader = record
  nChannels: Word;
  nBitsPerSample: LongInt;
  nSamplesPerSec: LongInt;
  nAvgBytesPerSec: LongInt;
  RIFFSize: LongInt;
  fmtSize: LongInt;
  formatTag: Word;
  nBlockAlign: LongInt;
  DataSize: LongInt;
 end;

 SampleIndex = 0..MaxN + 3;
 DataStream = array[SampleIndex] of Real;

 Observation = record
  Name: string[40]; {Имя данного сопровождения}
  yyy: DataStream; {Массив указателей на данные}
  WAV: WAVHeader; {Спецификация WAV для сопровождения}
  Last: SampleIndex; {Последний доступный индекс yyy}
  MinO, MaxO: Real; {Диапазон значений yyy}
 end;



 Tag = (F0, T1, M1);

 FudgeNum = record
  case X: Tag of
       F0: (chrs: array[0..3] of Byte);
       T1: (lint: LongInt);
       M1: (up, dn: Integer);
 end;

var
  Form1: TForm1;
  N: SampleIndex;
  Ki, Kj: Observation;

  StandardDatabase: string[80];
  BaseFileName: string[80];
  StandardOutput: string[80];
  StandardInput: string[80];

  InFile: file of Byte;
  FFile: TextFile;
  ChunkSize: FudgeNum;
  ChunkName: string[4];

implementation
{$R *.dfm}

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 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 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 TForm1.Button1Click(Sender: TObject); //procedure ReadWAVFile(var Ki, Kj: Observation);
var
  MM: Byte;
  I: Integer;
  OK: Boolean;
  NoDataYet: Boolean;
  DataYet: Boolean;
  nDataBytes: LongInt;
begin
 IF not OpenDialog1.Execute then abort;
   with Ki.WAV do
    begin { Вызов диалога открытия файла }
      OK := True; {если не изменится где-нибудь ниже}
      {Приготовления для чтения файла данных}
      AssignFile(InFile, OpenDialog1.FileName); { Файл, выбранный в диалоговом окне }
      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 {пропуск данных, не относящихся к набору звуковых данных}
          for I := 1 to DataSize do Read(InFile, MM)
        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;

AssignFile(FFile, 'c:\wav.txt'); rewrite(FFile);

 for i:= 0 to high(ki.yyy) do writeln(ffile, varToStr(ki.yyy[i])+'   '+varToStr(kj.yyy[i]));
CloseFile(FFile);
end; { ReadWAVFile - Батон 1}


end.

Автор: Alexeis 14.4.2006, 09:15
Black_Joker, вы невнимательно читали мою статью, там было описано, что байты в словах в файле записываются в обратном порядке, вначале младшие затем старшие, т.о. указанный код
Код

  for I := 0 to 3 do    
  begin
    Read(InFile, MM); ChunkSize.chrs[I]:= MM;
  end;

читает совсем не то что надо. У меня описан рабочий пример чтения Wav файлов. Не обижайтесь на критику но код написан кошмарно нерационально, а поэтому сложно!

Предположение о том что ChunkSize = 18 совсем неверно (часто это значение равно 16)

Если вам не нравятся потоки, то воспользуйтесь нетипизированными файлами, это куда проще и понятней

Автор: Black_Joker 14.4.2006, 12:29
Применил пример из статьи.
Порадовался, что так много сторочек в Мемо1.

А как получить данные, так и не понял.
Как работать с TMemoryStream???
К примеру, мне нужно вывести данные в текстовый файл. Один столбик - левый канал, другой столбик - правый (если есть). Как это сделать?

Автор: Alexeis 14.4.2006, 14:07
Цитата(Black_Joker @ 14.4.2006, 11:29 Найти цитируемый пост)
Порадовался, что так много сторочек в Мемо1

Так это было для того чтобы еще раз посмотреть внутреннюю структуру Wav - в реальной программе их надо удалять smile
(в смысле код вывода этих строчек)

Из memoryStream данные получить легко
Код

Strm.seek(0, soFromBegining);
// 16 бит стерео
for i := 1 to Strm.Size div 4
do
   Begin
      Strm.readBuffer(W1, 2);
      Strm.readBuffer(W2, 2);
      Memo.Lines.Add('Left-' + IntToStr(W1) + '   ' +
                                'Right-' + IntToStr(W2))
   end;

Автор: Black_Joker 25.4.2006, 17:43
Не пойму как вывести данные в поле Мемо?
делаю следующее...
получаю только данные строк 
Memo1.Lines.Add('SampleCount: ' + IntToStr(SampleCount));
...
Memo1.Lines.Add('Bits: ' + IntToStr(BitsPerSample));

звук однокональный, 16 бит.
Как переделать для 8 бит?



Код

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls;

type
  TWaveHeader = record
    idRiff: array[0..3] of char;
    RiffLen: longint;
    idWave: array[0..3] of char;
    idFmt: array[0..3] of char;
    InfoLen: longint;
    WaveType: smallint;
    Ch: smallint;
    Freq: longint;
    BytesPerSec: longint;
    align: smallint;
    Bits: smallint;
  end;
  TDataHeader = record
    idData: array[0..3] of char;
    DataLen: longint;
  end;
type
  TForm1 = class(TForm)
    OpenDialog1: TOpenDialog;
    Memo1: TMemo;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure ReadWaveHeader(Stream: TStream; var SampleCount, SamplesPerSec: integer;
                                          var BitsPerSample, Channeles: smallint);
var
i, W1: integer;
  WaveHeader: TWaveHeader;
  DataHeader: TDataHeader;
begin
  Stream.Read(WaveHeader, sizeof(TWaveHeader));
  with WaveHeader do
  begin
    if idRiff <> 'RIFF' then raise EReadError.Create('Wrong idRIFF');
    if idWave <> 'WAVE' then raise EReadError.Create('Wrong idWAVE');
    if idFmt <> 'fmt ' then  raise EReadError.Create('Wrong idFmt');
    if WaveType <> 1 then   raise EReadError.Create('Unknown format');
    Channeles:= Ch;  SamplesPerSec:= Freq;  BitsPerSample:= Bits;
    Stream.Seek(InfoLen - 16, soFromCurrent);
  end;
  Stream.Read(DataHeader, sizeof(TDataHeader));
  if DataHeader.idData = 'fact' then
  begin
    Stream.Seek(4, soFromCurrent);
    Stream.Read(DataHeader, sizeof(TDataHeader));
  end;
  with DataHeader do
  begin
    if idData <> 'data' then raise EReadError.Create('Wrong idData');
    SampleCount:= DataLen div (Channeles * BitsPerSample div 8)
  end;

  //считывание данных
for i := SampleCount to Stream.Size div 4 do
 Begin
  Strm.readBuffer(W1, 2);
  Form1.Memo1.Lines.Add(IntToStr(W1));
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Memo1.Clear;
 OpenDialog1.Filter := 'Wave files|*.wav';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  F: TFileStream;
  W1, i: integer;
  SampleCount, SamplesPerSec: integer;
  BitsPerSample, Channeles: smallint;
begin
  // Вызов OpenDialog1:
  if not OpenDialog1.Execute then Exit;
  try
    // Открытие файла:
    F:= TFileStream.Create(OpenDialog1.FileName, fmOpenRead);
    // Чтение заголовка:
    ReadWaveHeader(F, SampleCount, SamplesPerSec, BitsPerSample, Channeles);
    F.Free;
    //Memo1.Clear;
    // Заполнение Memo информацией о файле:
    Memo1.Lines.Add('SampleCount: ' + IntToStr(SampleCount));
    Memo1.Lines.Add(Format('Length: %5.3f sec', [SampleCount / SamplesPerSec]));
    Memo1.Lines.Add('Channeles: ' + IntToStr(Channeles));
    Memo1.Lines.Add('Freq: ' + IntToStr(SamplesPerSec));
    Memo1.Lines.Add('Bits: ' + IntToStr(BitsPerSample));
  except
    raise Exception.Create('Problems with file reading');
  end;
end;

end.
 

Автор: Alexeis 26.4.2006, 09:11
Код

var
  b : Byte;
  s : SmallInt;
  i  : integer;
  Strm2 : TMemoryStream;

Begin
  Strm.seek(0, soFromBeginning);
  Strm2 := TMemoryStream.Create;
  Strm2.seek(0, soFromBeginning);

  // 16 бит моно
  for i := 1 to Strm.Size  div 2  //делим на 2 (размер фрейма)
  do                                         //равен 1 байту
     Begin
        Strm.readBuffer(s, 2);

        b := word(s) shr 8;          //для 16 бит в 8 бит
        Strm2.WriteBuffer(b, 1);
        Memo.Lines.Add(IntToStr(b));
     end;
   

Автор: Black_Joker 26.4.2006, 09:28
Понятно. Спасибо.
А что у меня в проге не правильно?
Почему не выводит данные? 

Автор: Alexeis 26.4.2006, 09:53
Black_Joker, я ошибся 
не b := word(s) div 2; 
а b := word(s) shr 8;
 

Автор: Alexeis 26.4.2006, 10:24
Код

  Stream.Read(DataHeader, sizeof(TDataHeader));    
  if DataHeader.idData = 'fact' then    
  begin    
    Stream.Seek(4, soFromCurrent);    
    Stream.Read(DataHeader, sizeof(TDataHeader));    
  end;

Зачем нужен сдвиг на 4 байта после чтения,
Кроме того если размер чанка fact больше 8 байт то остальные данные запишутся в пространство занятое любыми другими данными т.е. неизбежно приведет к ошибке! 

Автор: Black_Joker 26.4.2006, 21:09
признаю свою безмерную тупость и т.д. ... smile  smile  smile 

Нельзя ли довести до ума мою прогу и выложить вновь. 

Автор: Alexeis 27.4.2006, 10:42
Black_Joker, чтоб исправить программу надо знать источник файлов, какой програмой создаются и какие чанки содержаться, потому что данная програма привязана к какому-то типу wav.

Пример универсальной программы для чтения я приводил... 

Автор: Black_Joker 27.4.2006, 13:33
Я Ваш, пример и использую.
Данные о файле выдает исправно, а сами данные выдавать отказывается. Об ошибках не сообщает. Просто молчит... smile  smile  

Автор: Alexeis 27.4.2006, 14:49
Black_Joker, Что возвращенный поток в себе ничего не содержит?

Добавлено @ 14:58 
Вот прикол размер данных проверил, а содержимое нет - и вправду там пусто! 

Автор: Alexeis 27.4.2006, 15:31
Я ошибся там совсем не пусто просто в начале тишина
Вот Проект целиком посмотрите...
http://alexei-s1.narod.ru/Wav.rar 

Автор: Black_Joker 27.4.2006, 20:02
Спасибо. Посмотрю. 


Большое спасибо.

Не совсем понятно по поводу рисования.

for i:= 1 to r.Data.Size div 4 do
 Begin
  r.Data.readBuffer(W1, 2);
  r.Data.readBuffer(W2, 2);
  Form1.Canvas.LineTo(round(100+2000/r.Data.Size*i), round(200+W1/100));
   end;

Считывается пара переменных, а почему используется только первая?
Такая "форма сигнала" нормальная? - речь записанная с микофона.

вывод:
Код

IF r.wChannels = 2 THEN
  for i:= 1 to r.Data.Size div 4 do
   Begin
      r.Data.readBuffer(W1, 2);
      r.Data.readBuffer(W2, 2);
      Form1.Canvas.LineTo(round(100+2000/r.Data.Size*i), round(200+W1/100));
writeln(ff, 'Left: ' + IntToStr(W1) + '   ' + 'Right: ' + IntToStr(W2)); //вывод цифр в файл
   end
                   ELSE
     for i:= 1 to r.Data.Size div 4 do
   Begin
      r.Data.readBuffer(W1, 2);
//      r.Data.readBuffer(W2, 2);
      Form1.Canvas.LineTo(round(100+2000/r.Data.Size*i), round(200+W1/100));
writeln(ff, IntToStr(W1)); //вывод цифр в файл
   end;
  

Автор: Black_Joker 3.5.2006, 11:32
for i:= 1 to r.Data.Size div 4 do
почему именно div 4 ? 

Автор: Alexeis 3.5.2006, 11:50
Я читаю данные фреймами. 1 фрейм 2 - канала по 2 байта в сэмпле каждого канала. 
2х2=4 байта. 
Таким образом r.Data.Size div 4 дает нам именно число фреймов в блоке данных размером r.Data.Size.

Для других данных размер фрейма будет другим...

Добавлено @ 11:52 
Размер фрейма можно вычислить по формуле
FrSize := Round(wBitsPerSample / 8) * wChannels;  

Автор: Black_Joker 3.5.2006, 20:23
Понятно. Большое спасибо.
а можно пояснить по поводу вопроса от 27.4.2006, 17:02  

Автор: Alexeis 4.5.2006, 10:15
Цитата(Black_Joker @  3.5.2006,  19:23 Найти цитируемый пост)
а можно пояснить по поводу вопроса от 27.4.2006, 17:02  

Sorry не заметил поста.
Цитата

Считывается пара переменных, а почему используется только первая?

Это был только пример кода демонстрирующий, что поток данных не пустой. А выводился только левый канал. Данный код ни в коем случае нельзя использовать в качестве образца! Он писался только чтоб отобразить именно этот фрагмет. А результат у вас получился плохой, только потому что моя методика слишком простая. Помните?  частота дискретизации (в нашем случае частота пикелей) должна в два раза превышать частоту сигнала, иначе на изображении будут видны биения (они как раз и видны у вас, у меня их просто невидно, так как трек длиннее и сжатие графика выше).  

Автор: Black_Joker 4.5.2006, 12:05
Понятно. "Рисовать звук" мне не надо. Мне надо только получить данные.
Надеюсь, на это пример способен?
А то я уже собрался к начальнику идти... Очень не хрочется лохонуться. 

Автор: Alexeis 4.5.2006, 12:14
Если использовать в точности пример поста 27.4.2006, 17:02 
то нет, там неправельно определен размер фрейма, а потому читается только половина файла, если заменить div 4, на div 2, то будет верно. 

Автор: Black_Joker 5.5.2006, 08:53
Не понял?
Если 1 канала, то используем div 4, а если 1 канал используем div 2.
Это я сделал.

Чтоеще надо поправить? 

Автор: Alexeis 5.5.2006, 09:46
Цитата(Black_Joker @  5.5.2006,  07:53 Найти цитируемый пост)
Чтоеще надо поправить? 

Все больше ничего smile , я просто уточнил, так как в посте от  27.4.2006, 17:02  - на один канал указано  div 4,
 

Автор: Black_Joker 5.5.2006, 21:30
Огромное спасибо за терпение и отзывчивость.

Кто бы еще подсказал. как из этих данных частоту("ноты") выцепить... smile  

Автор: Black_Joker 8.5.2006, 20:00
Подскажите, пожалуйста, чем обоснован выбор именно SmallInt, а не Integer?

мне нужно из одного звука "вычесть" второй.
Считываю данные - W1 и W2 (массивы. звук одноканальный).
Пишу
W[i]:= abs(W1[i] - W2[i]);
И получаю несколько отрицательных значений.
Задал тип данных Integer. Все значения положительные, но очень большие - 9-и значные.

Это нормально? 

Автор: Alexeis 11.5.2006, 09:16
Цитата(Black_Joker @  8.5.2006,  19:00 Найти цитируемый пост)
Подскажите, пожалуйста, чем обоснован выбор именно SmallInt,

По документации 16 битные выборки записываются ввиде 2-х байтовых целых чисел со знаком, в делфи - такому типу соответствует
smallint.
Считывать нужно именно smallInt, а операции можно производить и с  integer

Цитата(Black_Joker @  8.5.2006,  19:00 Найти цитируемый пост)
Задал тип данных Integer.
 - где задан integer?

Цитата(Black_Joker @  8.5.2006,  19:00 Найти цитируемый пост)
Все значения положительные, но очень большие - 9-и значные.
 - вероятно произошло переполнение переменной..

Цитата(Black_Joker @  5.5.2006,  20:30 Найти цитируемый пост)
Кто бы еще подсказал. как из этих данных частоту("ноты") выцепить... 


Преобразование фурье - дает амплитуду каждой частоты в обработанном фрагменте.
 

Автор: Black_Joker 11.5.2006, 09:32
Массивы W, W1, W2 сперва были заданы типом СмолИнт. - при вычсислении
W[i]:= abs(W1[i] - W2[i]);
В массиве W[i] появлялись отрицательные значения.
Задал дял массивов Интеджер - значеия в массива W - все положительные, но 9 значные.

Вы предлагаете, использовать W1, W2 - СмолИнт, а W - Интеджер?
 

Автор: Alexeis 11.5.2006, 09:49
Цитата(Black_Joker @  11.5.2006,  08:32 Найти цитируемый пост)
 при вычсислении
W[i]:= abs(W1[i] - W2[i]);
В массиве W[i] появлялись отрицательные значения.


А что до сих пор не было отрицательных? Если данные 16 ти разрядные то волна должна переходить от плюса к минусу за период колебания.

W точно должен быть integer ведь -32000 - (-32000) = -64000 - а это уже не поместится в smallInt
 

Автор: Black_Joker 17.5.2006, 10:20
Подскажите, пожалуйста

Считал 2 звука (в DataStrim: TStream) - 1-й поменьше - W1
2-й побольше - W2.

1. Что будет если из W2 отнять W1? Такое вобще возможно?

2.
Во 2-м звуке может содержаться первый (может несколько раз или ни одного раза)

Предполагается, что первый звук входит (если входит) без изменений во второй. Можно ли его найти (только средствами работы с DataStrim)? Как? 

Автор: Alexeis 17.5.2006, 13:45
Black_Joker, Разность это тоже что и сумма с перевернутым сигналом.
Для того чтобы определить насколько один сигнал похож на другой необходимо провести операцию свертки.
В качестве ядра свертки будет выступать первый сигнал. Свертка будет производится по второму сигналу. В результате мы получим масив длины равной разности втророго и первого, по значениям этого сигнала можно определить где именно появились повторения и насколько близки фрагмент второго и первый сигнал. Если они абсалютно подобны, то сигнал (массив) будет содержать несколько острых пиков, по числу появлений первого сигнала во втором. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)