ASIOやVSTなどの規格ではオーディオデータは各チャンネルごとに分かれて配列として格納する(LLLLRRRRのような構造)のだが、従来のマルチメディア入出力では左右チャンネルのデータがストライプ状に並んでおり(LRLRLRLRLRのような構造)、ASIO以外で入力したオーディオデータにVSTエフェクトをかけようと思った場合、一旦データを並び替えなければいけなくなる。
普段 Delphi を使ってコーディングしている私は MiniHost で有名な TobyBear で配布されているコンポーネントを使おうと思ったのだが、それ用のコンバートルーチンは標準で用意されていなかったので DASIOConvert.pas の処理を参考にステレオ用のコンバート処理を書いてみた。
const
MinSmall : Single = 1/$8000;
MaxSmall : Single = $7FFF;
procedure ToInt16LSB_x87_forDS_2ch(target1: psingle; target2: psingle; frames: longint; source: pointer );
asm
push ebx
mov ebx, source
fld MinSmall //for speed
@Start:
fild [ebx].word
fmul st(0),st(1)
fstp [eax].single;
add ebx, 2
fild [ebx].word
fmul st(0),st(1)
fstp [edx].single;
add ebx, 2
add eax, 4
add edx, 4
loop @Start
ffree st(0)
pop ebx
end;
procedure FromInt16LSB_x87_forDS_2ch(source1: psingle; source2: psingle; frames: longint; target: pointer );
asm
push ebx
mov ebx, target
fld MaxSmall // move to register for speed
@Start: // Samplecount already in ecx!
fld [eax].single;
fmul st(0),st(1)
fistp word ptr [ebx]
add ebx, 2
fld [edx].single;
fmul st(0),st(1)
fistp word ptr [ebx]
add ebx, 2
add eax, 4
add edx, 4
loop @start
ffree st(0) // free after loop has finished
pop ebx
end;
引数を増やすしかなく ebx を退避させないといけなくなったのは残念なところだけど、2回呼ぶよりはマシなんじゃないかなと思うので(速度テストはしてない)、取り合えずこれで行く事に。
誰かの参考になれば幸い。