解交错 24 位音频缓冲区以用于 ASIO 输出

问题描述 投票:0回答:1

我正在使用 ASIO 组件(在 Delphi 7 中),当它将左/右通道解交错到 2 个独立的 ASIO 缓冲区时,该组件仅支持 16 位和 32 位输出。一些 ASIO 驱动程序仅支持 24 位输出,因此我想为此位深度添加解交错功能,但所需的按位逻辑超出了我的范围。 以下是 DeInterleave32 和 DeInterleave16 函数。 有人可以帮忙创建一个 DeInterleave24 函数吗?

PBufferInfoArray 基本上是一个指针数组。

type
  TBuffer32 = array[0..0] of LongWord;
  PBuffer32 = ^TBuffer32;

  TBuffer16 = array[0..0] of SmallInt;
  PBuffer16 = ^TBuffer16;

procedure Deinterleave32(InputBuffer : PBuffer32; OutputBuffer : PBufferInfoArray; Samples, BufferIndex : LongWord);
var
  i, j : LongWord;
  Dest : array[0..1] of PBuffer32;
begin
  for i := 0 to 1 do // always 2 channels
    Dest[i] := OutputBuffer[i].buffers[BufferIndex];
  i := 0;
  while i < Samples do
  begin
    j := i shl 1;
    Dest[0][i] := InputBuffer[j];
    Dest[1][i] := InputBuffer[j+1];
    Inc(i);
  end;
end;

procedure Deinterleave16(InputBuffer : PBuffer16; OutputBuffer : PBufferInfoArray; Samples, BufferIndex : LongWord);
var
  i, j : LongWord;
  Dest : array[0..1] of PBuffer16;
begin
  for i := 0 to 1 do // always 2 channels
    Dest[i] := OutputBuffer[i].buffers[BufferIndex];
  for i := 0 to Samples - 1 do
    for j := 0 to 1 do
      Dest[j][i] := InputBuffer[i*2 + j];
end;

如果您能提供帮助,我们将不胜感激。

delphi audio asio 24-bit
1个回答
0
投票

我掌握的信息很少。缺少某些类型以及有关数据布局的任何信息。因此,我给自己一些自由。

  1. 我从头开始重写了两个旧程序,这次使用指针而不是数组索引。这提高了性能,因为每次指针变量访问都是 1 次内存读取,而每次数组变量访问都是 2 次(一次用于数组变量本身,一次用于索引变量)。新程序的速度是旧程序的两倍以上(时间嵌入在源代码片段中)。

  2. 24位缓冲区需要被写入,所以我也重写了你的两个旧缓冲区结构。为了一致性、更细粒度的子元素访问和性能原因。

新的 16 位和 32 位程序具有与旧程序相同的签名。也就是说,他们仍然期望旧的缓冲区类型。请注意,这不是问题,因为新类型与旧类型具有相同的内存占用量。出于显而易见的原因,新的 24 位过程确实使用了新的 24 位类型。

所有新类型和过程都带有下划线前缀 (

_
),以将它们与旧代码区分开来。

我无法访问

PBufferInfoArray
,所以我通过分析你的旧程序收集了它的结构。这就是我得出的结论,它必须看起来像这样:

type
  PBufferInfoArray = ^TBufferInfoArray;
  TBufferInfoArray = array [0..1] of record
    buffers: array [0..0] of Pointer;
  end;

这是所有新内容:

type
  _PBuffer32 = ^_TBuffer32;
  _TBuffer32 = packed record // SizeOf(_TBuffer32) = 4
    case Integer of
      0: (d: Cardinal);
      1: (w0, w1: Word);
      2: (b0, b1, b2, b3: Byte);
  end;

  _PBuffer24 = ^_TBuffer24;
  _TBuffer24 = packed record // SizeOf(_TBuffer24) = 3
    case Integer of
      0: (w0: Word; w1: Byte); // !
      1: (b0, b1, b2: Byte);
  end;

  _PBuffer16 = ^_TBuffer16;
  _TBuffer16 = packed record // SizeOf(_TBuffer16) = 2
    case Integer of
      0: (w: Word);
      1: (b0, b1: Byte);
  end;

// ~105.16 ms (67108864 SAMPLES)
procedure _Deinterleave32(InputBuffer: PBuffer32; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord);
var
  psrc, esrc: _PBuffer32;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples);

  pdst0 := OutputBuffer[0].buffers[BufferIndex];
  pdst1 := OutputBuffer[1].buffers[BufferIndex];

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    pdst0.d := psrc.d;
    Inc(psrc);
    pdst1.d := psrc.d;
    Inc(psrc);

    Inc(pdst0);
    Inc(pdst1);
  end;
end;

// ~124.44 ms (67108864 SAMPLES)
procedure _Deinterleave24(InputBuffer: _PBuffer24; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord);
var
  psrc, esrc: _PBuffer24;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples);

  pdst0 := OutputBuffer[0].buffers[BufferIndex];
  pdst1 := OutputBuffer[1].buffers[BufferIndex];

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    pdst0.w0 := psrc.w0;
    pdst0.w1 := psrc.w1;
    Inc(psrc);
    pdst1.w0 := psrc.w0;
    pdst1.w1 := psrc.w1;
    Inc(psrc);

    Inc(pdst0);
    Inc(pdst1);
  end;
end;

// ~91.31 ms (67108864 SAMPLES)
procedure _Deinterleave16(InputBuffer: PBuffer16; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord);
var
  psrc, esrc: _PBuffer16;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples);

  pdst0 := OutputBuffer[0].buffers[BufferIndex];
  pdst1 := OutputBuffer[1].buffers[BufferIndex];

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    pdst0.d := psrc.w;
    Inc(psrc);
    pdst1.d := psrc.w;
    Inc(psrc);

    Inc(pdst0);
    Inc(pdst1);
  end;
end;

以下是您未更改的旧程序(带有时间安排):

// ~232.12 ms (67108864 SAMPLES)
procedure Deinterleave32(InputBuffer : PBuffer32; OutputBuffer : PBufferInfoArray; Samples, BufferIndex : LongWord);
var
  i, j : LongWord;
  Dest : array[0..1] of PBuffer32;
begin
  for i := 0 to 1 do // always 2 channels
    Dest[i] := OutputBuffer[i].buffers[BufferIndex];
  i := 0;
  while i < Samples do
  begin
    j := i shl 1;
    Dest[0][i] := InputBuffer[j];
    Dest[1][i] := InputBuffer[j+1];
    Inc(i);
  end;
end;

// ~264.79 ms (67108864 SAMPLES)
procedure Deinterleave16(InputBuffer : PBuffer16; OutputBuffer : PBufferInfoArray; Samples, BufferIndex : LongWord);
var
  i, j : LongWord;
  Dest : array[0..1] of PBuffer16;
begin
  for i := 0 to 1 do // always 2 channels
    Dest[i] := OutputBuffer[i].buffers[BufferIndex];
  for i := 0 to Samples - 1 do
    for j := 0 to 1 do
      Dest[j][i] := InputBuffer[i*2 + j];
end;

奖励:这是您的旧程序,但进行了一些清理:

// ~220.23 ms (67108864 SAMPLES)
procedure Deinterleave32_clean(InputBuffer: PBuffer32; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord);
var
  i   : LongWord;
  Dest: array[0..1] of PBuffer32;
begin
  Dest[0] := OutputBuffer[0].buffers[BufferIndex];
  Dest[1] := OutputBuffer[1].buffers[BufferIndex];

  for i := 0 to (Samples - 1) do
  begin
    Dest[0][i] := InputBuffer[i*2];
    Dest[1][i] := InputBuffer[i*2 + 1];
  end;
end;

// ~143.78 ms (67108864 SAMPLES)
procedure Deinterleave16_clean(InputBuffer: PBuffer16; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord);
var
  i   : LongWord;
  Dest: array [0..1] of PBuffer16;
begin
  Dest[0] := OutputBuffer[0].buffers[BufferIndex];
  Dest[1] := OutputBuffer[1].buffers[BufferIndex];

  for i := 0 to (Samples - 1) do
  begin
    Dest[0][i] := InputBuffer[i*2];
    Dest[1][i] := InputBuffer[i*2 + 1];
  end;
end;
© www.soinside.com 2019 - 2024. All rights reserved.