Deinterleave 24 bit audio buffer for ASIO output

I’m using an ASIO component (in Delphi 7) which supports only 16-bit and 32-bit output when it deinterleaves the left/right channels into 2 separate ASIO buffers. Some ASIO drivers only support 24-bit output so I want to add a deinterleaving function for this bit depth, but the bitwise logic required is beyond me. Below are the DeInterleave32 and DeInterleave16 functions. Can someone please help create a DeInterleave24 function.

The PBufferInfoArray is basically an array of pointers.

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;

Most appreciated if you can help.

4

I had very little information to go on. Some types were missing, as well as any information about the layout of the data. I therefore took myself a few liberties.

  1. I rewrote both of your old procedures from scratch, this time using pointers instead of array indices. This improves performance, because every pointer variable access is 1 memory read, and every array variable access is 2 (one for the array variable itself and one for the index variable). The new procedures are over twice as fast as your old ones (Timings are embedded in the source snippets).

  2. The 24 bit buffer needed to be written up, so I rewrote both of your old buffer structures as well. For consistency, more granular sub element access and performance reasons.

The new 16 bit and 32 bit procedures have the same signature as the old ones. That is, they still expect the old buffer types. Note that this is not a problem, because the new types have the same memory footprint as the old ones. The new 24 bit procedure does for obvious reasons use the new 24 bit type.

All the new types and procedures are prefixed with an underscore (_) to differentiate them from your old code.

I didn’t have access to PBufferInfoArray, so I gleaned its structure from analyzing your old procedures. This is what I concluded it had to look like:

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

Here is all the new stuff:

Warning: No argument validation or error checking in these functions!

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;

// ~92.07 ms (67108864 SAMPLES)
function _Deinterleave32(InputBuffer: PBuffer32; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord): Boolean;
var
  psrc, esrc: _PBuffer32;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples * 2); // The InputBuffer is twice as long as the OutputBuffers.

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

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    pdst0.d := psrc.d;
{
    pdst0.b0 := psrc.b0;
    pdst0.b1 := psrc.b1;
    pdst0.b2 := psrc.b2;
    pdst0.b3 := psrc.b3;
}
    Inc(psrc);
    pdst1.d := psrc.d;
{
    pdst1.b0 := psrc.b0;
    pdst1.b1 := psrc.b1;
    pdst1.b2 := psrc.b2;
    pdst1.b3 := psrc.b3;
}
    Inc(psrc);

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

  Result := True;
end;

// ~99.70 ms (67108864 SAMPLES)
function _Deinterleave24(InputBuffer: _PBuffer24; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord): Boolean;
var
  psrc, esrc: _PBuffer24;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples * 2); // The InputBuffer is twice as long as the OutputBuffers.

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

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    // Data shifted 8 bits to the left to keep the volume.
    pdst0.d := (psrc.w0 or (psrc.w1 shl 16)) shl 8;
{
    pdst0.b0 := 0;
    pdst0.b1 := psrc.b0;
    pdst0.b2 := psrc.b1;
    pdst0.b3 := psrc.b2;
}
    Inc(psrc);
    pdst1.d := (psrc.w0 or (psrc.w1 shl 16)) shl 8;
{
    pdst1.b0 := 0;
    pdst1.b1 := psrc.b0;
    pdst1.b2 := psrc.b1;
    pdst1.b3 := psrc.b2;
}
    Inc(psrc);

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

  Result := True;
end;

// ~99.74 ms (67108864 SAMPLES)
function _Deinterleave16(InputBuffer: PBuffer16; OutputBuffer: PBufferInfoArray; Samples, BufferIndex: LongWord): Boolean;
var
  psrc, esrc: _PBuffer16;
  pdst0, pdst1: _PBuffer32;
begin
  psrc := Pointer(InputBuffer);
  esrc := psrc;
  Inc(esrc, Samples * 2); // The InputBuffer is twice as long as the OutputBuffers.

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

  while (NativeInt(psrc) < NativeInt(esrc)) do
  begin
    // Data shifted 16 bits to the left to keep the volume.
    pdst0.d := psrc.w shl 16;
{
    pdst0.b0 := 0;
    pdst0.b1 := 0;
    pdst0.b2 := psrc.b0;
    pdst0.b3 := psrc.b1;
}
    Inc(psrc);
    pdst1.d := psrc.w shl 16;
{
    pdst1.b0 := 0;
    pdst1.b1 := 0;
    pdst1.b2 := psrc.b0;
    pdst1.b3 := psrc.b1;
}
    Inc(psrc);

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

  Result := True;
end;

Here are your old untouched procedures (with timings):

// ~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;

Bonus: Here are your old procedures, but cleaned up a little:

// ~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;

11

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật