Как получить уровень громкости в текущей выборке? Delphi 7 - PullRequest
1 голос
/ 06 ноября 2019

В Delphi 7 я запускаю этот код с библиотекой NewAC Audio. У меня короткий WAV-файл, 44,100 кГц, моно, 16 бит.

unit Main;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ACS_Classes, ACS_DXAudio, ACS_Wave, ACS_Misc, ACS_Types, StdCtrls;

type
  TForm1 = class(TForm)
    AudioProcessor1: TAudioProcessor;
    WaveIn1: TWaveIn;
    DXAudioOut1: TDXAudioOut;
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    Button2: TButton;
    procedure AudioProcessor1GetData(
      Sender: TComponent;
      var Buffer: Pointer;
      var NBlockBytes: Cardinal);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure DXAudioOut1Done(Sender: TComponent);
    procedure AudioProcessor1Init(Sender: TComponent; var TotalSize: Int64);
    procedure AudioProcessor1Flush(Sender: TComponent);
  end;

var Form1: TForm1;
implementation
{$R *.dfm}

procedure TForm1.AudioProcessor1GetData(Sender: TComponent;
  var Buffer: Pointer; var NBlockBytes: Cardinal);
var Tmp : Integer;
 i : Integer;
 list1: TStringList;
 list2: TStringList;
 b1, b2, b3, b4:byte;
 si1, si2, si3, si4: ShortInt;
 mono: Boolean;
 values: array of word;
begin
  list1 := TStringList.Create;
  list2 := TStringList.Create;
  AudioProcessor1.Input.GetData(Buffer, NBlockBytes);
  if Buffer = nil then
    Exit;
  mono := false;
  case AudioProcessor1.Input.BitsPerSample of
    16 :
    begin
      B16 := Buffer;
      setlength(values, NBlockBytes div 2);
      for i := 0 to (NBlockBytes div 4) - 1 do
      begin
        Tmp := B16[i*2];
        move(B16[i*2], b1, 1); // copy left channel
        move(B16[i*2+1], b2, 1); // copy right channel
        move(B16[i*2+2], b3, 1); // copy left channel
        move(B16[i*2+3], b4, 1); // copy right channel
        si1 := b1;
        si2 := b2;
        si3 := b3;
        si4 := b4;
        list1.add(''+inttostr(si1));
        list2.add(''+inttostr(si2));
        list1.add(''+inttostr(si3));
        list2.add(''+inttostr(si4));
        B16[i*2] := B16[i*2 + 1];
        B16[i*2 + 1] := Tmp;
      end;
    end;
  end;
list1.free;
list2.free;

end;

procedure TForm1.AudioProcessor1Init(Sender: TComponent; var TotalSize: Int64);
begin
  TAudioProcessor(Sender).Input.Init;
  TotalSize := TAudioProcessor(Sender).Input.Size
end;

procedure TForm1.AudioProcessor1Flush(Sender: TComponent);
begin
  TAudioProcessor(Sender).Input.Flush;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    Button1.Enabled := False;
    WaveIn1.FileName := OpenDialog1.FileName;
    DXAudioOut1.Run;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DXAudioOut1.Stop;
end;    

procedure TForm1.DXAudioOut1Done(Sender: TComponent);
begin
  Button1.Enabled := True;
end;

end.

Когда я открываю файл в программном обеспечении для редактирования, я вижу амплитуду звука и вижу, что начальные значения равны 0. Но когда я запускаю эту программу и добавляю si1, si2, si3и si4 для просмотра (в этом порядке находятся переменные в watch), поэтому у меня есть эти значения в первой итерации:

80,124,104,32.

Я ожидал, что эти значения должны быть 0, потому что таммолчание в начале.

Во-первых, вы можете объяснить, почему они не равны нулю?

Во-вторых, я не уверен, что эти значения действительно представляют. Я знаю, что si1 и si2 - первый образец. Но действительно ли это уровень громкости? Как исправить программу, чтобы она распознала тишину в начале?

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

The part

Эта часть не обработана (поскольку я обработал только несколько циклов первого цикла):

tested file

Я провел несколько тестов с файлом «silence plus», усилениями и увидел первые 8 значений циклов.

enter image description here

Еще один тестсо словом вместо байта:

B16 := Buffer;
...
move(B16[i*2], w1, 2);
move(B16[i*2+1], w2, 2);

word

Похоже, что биты нужно поменять местами. Я думал, что в Windows XP у меня есть порядок байтов. Поэтому я напишу свопер.

1 Ответ

1 голос
/ 07 ноября 2019

Основными проблемами моего кода были:

1) Чтение 1 байта выборки вместо 2 байтов выборки.

2) Образец подписан, а не без знака. Поэтому, когда я пытался прочитать два байта слова, я получаю неправильные числа (см. Последнюю таблицу, о которой идет речь).

3) Я также пытался использовать два байта подкачки SmallInt, но это приводило к сумасшедшим числам, таким как-25345, -1281, 26624, -19968 ... Это потому, что в моей системе я использую Little endian (Windows XP). Нет необходимости менять его в Windows.

Таким образом, решение было скопировать 16 бит в SmallInt, без обмена.

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ACS_Classes, ACS_DXAudio, ACS_Wave, ACS_Misc, ACS_Types, StdCtrls;

type
  TForm1 = class(TForm)
    AudioProcessor1: TAudioProcessor;
    WaveIn1: TWaveIn;
    DXAudioOut1: TDXAudioOut;
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    Button2: TButton;
    procedure AudioProcessor1GetData(
      Sender: TComponent;
      var Buffer: Pointer;
      var NBlockBytes: Cardinal);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure DXAudioOut1Done(Sender: TComponent);
    procedure AudioProcessor1Init(Sender: TComponent; var TotalSize: Int64);
    procedure AudioProcessor1Flush(Sender: TComponent);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.AudioProcessor1GetData(Sender: TComponent;
   var Buffer: Pointer; var NBlockBytes: Cardinal);
var
 B16 : PBuffer16;
 i, end_  : Integer;
 si1, si2: SmallInt;
begin
  AudioProcessor1.Input.GetData(Buffer, NBlockBytes);
  if Buffer = nil then
    Exit;
  case AudioProcessor1.Input.BitsPerSample of
    16 :
    begin
      B16 := Buffer;
      end_ := (NBlockBytes div 2) - 1;
      for i := 0 to end_ do
      begin
        move(B16[i*2], si1, 2);
        move(B16[i*2+1], si2, 2);
      end;
    end;
  end;
end;

procedure TForm1.AudioProcessor1Init(Sender: TComponent; var TotalSize: Int64);
begin
  TAudioProcessor(Sender).Input.Init;
  TotalSize := TAudioProcessor(Sender).Input.Size
end;    

procedure TForm1.AudioProcessor1Flush(Sender: TComponent);
begin
  TAudioProcessor(Sender).Input.Flush;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    Button1.Enabled := False;
    WaveIn1.FileName := OpenDialog1.FileName;
    DXAudioOut1.Run;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DXAudioOut1.Stop;
end;

procedure TForm1.DXAudioOut1Done(Sender: TComponent);
begin
  Button1.Enabled := True;
end;

конец.

Вот значения:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...