Author Topic: Compare 2 Audiosignals  (Read 113 times)

PMKnecht

  • Posts: 7
Compare 2 Audiosignals
« on: 2 Jan '23 - 14:56 »
Hi,

I got stuck a bit in the following problem and I need an advice. You here in the forum seem to have more knowledge about these things. I would like compare two audio streams in order to check the latency. They do not have a unique PCR which means I have to compare them otherwise. They are also not made by the same encoder so I can not compare the byte stream. I probably have to write an FFT incl. a buffer for both streams and check for similarities. Are there some known algorithms or solutions how to handle this?

I did something like this, but this seem to be not correct:

unit UMainThread;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, SyncObjs, Bass;

const
  BUFFER_SIZE = 4096; // Größe des Puffers für die Sample-Arrays
  SAMPLE_COUNT = 16384; // Anzahl der Samples pro Aufzeichnung

type
  TAutoCorrelation = array[0..SAMPLE_COUNT - 1] of single;

  TStreamSyncThread = class(TThread)
  private
    FStream1, FStream2: HSTREAM; // Handles für die beiden Streams
    FShift: integer; // Versatz zwischen den Streams in Samples
    FLock: TCriticalSection;

    function GetShift: integer;
  protected
    procedure Execute; override;
  public
    constructor Create(Stream1, Stream2: HSTREAM);
    destructor Destroy; override;
    property Shift: integer read GetShift;
  end;

implementation

constructor TStreamSyncThread.Create(Stream1, Stream2: HSTREAM);
begin
  inherited Create(False);
  FStream1 := Stream1;
  FStream2 := Stream2;
  FLock := TCriticalSection.Create;
end;

destructor TStreamSyncThread.Destroy;
begin
  Terminate;
  WaitFor;
  FLock.Leave;
  inherited;
end;

procedure TStreamSyncThread.Execute;
var
  i, j: integer;
  Samples1, Samples2: array[0..BUFFER_SIZE - 1] of single; // Puffer für die Samples
  AutoCorr: TAutoCorrelation; // Array zum Speichern des Autokorrelation-Ergebnisses
  MaxCorr: single; // Maximale Korrelation
  MaxCorrIndex: integer; // Index der maximalen Korrelation

  SampleCount: DWord;
begin
  while not Terminated do
  begin
    SampleCount := BASS_ChannelGetData(FStream1, @Samples1[0],
      BUFFER_SIZE * SizeOf(single) or BASS_DATA_FLOAT) div sizeof(single);
    BASS_ChannelGetData(FStream2, @Samples2[0], BUFFER_SIZE *
      SizeOf(single) or BASS_DATA_FLOAT);

    // Berechne die Autokorrelation der Samples
    for i := 0 to High(AutoCorr) do
    begin
      AutoCorr := 0;
      for j := 0 to SampleCount - 1 do
        AutoCorr := AutoCorr + Samples1[j] * Samples2[(int64(j) + i) mod SampleCount];
    end;

    // Bestimme den Index mit der maximalen Korrelation
    MaxCorr := 0;
    MaxCorrIndex := 0;
    for i := 0 to High(AutoCorr) do
    begin
      if Autocorr > MaxCorr then
      begin
        MaxCorr := Autocorr;
        MaxCorrIndex := i;
      end;
    end;

    FLock.Enter;
    try
      FShift := MaxCorrIndex;
    finally
      FLock.Leave;
    end;
    sleep(1000);
  end;
end;

function TStreamSyncThread.GetShift: integer;
begin
  FLock.Enter;
  try
    Result := FShift;
  finally
    FLock.Leave;
  end;
end;

end.

Cheers
Peter
« Last Edit: 2 Jan '23 - 16:57 by PMKnecht »

Ian @ un4seen

  • Administrator
  • Posts: 24797
Re: Compare 2 Audiosignals
« Reply #1 on: 4 Jan '23 - 14:46 »
If I understand correctly, you know 2 streams contain the same sound but possibly with a time difference, and you want get that time difference? If so, cross-correlation like in your code above seems like the right idea, but perhaps the "mod" here is causing problems?

Code: [Select]
      for j := 0 to SampleCount - 1 do
        AutoCorr := AutoCorr + Samples1[j] * Samples2[(int64(j) + i) mod SampleCount];

You could try this:

Code: [Select]
      for j := 0 to SampleCount - 1 - i do
        AutoCorr := AutoCorr + Samples1[j] * Samples2[j + i];

Note this code is assuming that stream 2 is the delayed one. If stream 1 may be delayed instead then you would need to check that too, eg. swap Samples1 and Samples2 in the loop above.

PMKnecht

  • Posts: 7
Re: Compare 2 Audiosignals
« Reply #2 on: 13 Jan '23 - 12:05 »
Awesome, thanks for your help. I do the modulo, because I+J can be out of the range of the sample.

Regards
Peter