ステレオ
チャンネルごとに異なる音声
これまでは、常にひとつのチャンネルに対して音声の入出力を行いました
つまり、「1 サンプル=振幅ビット数」という関係のモノラル音声です
スピーカーがいくつあっても、全てのスピーカーから同じ音声が出力されます
ところが、通常 PC の音声はステレオをサポートしています
ステレオは、2 つの音声出力先を持っているということになります
これを利用すれば、左右のスピーカーに、同時に異なる音声を出力することができます
それこそ、低レベル API を使いこなすことができれば
異なるモノラル音声ファイルを左右のスピーカーに分け、同時に再生するなんてこともできます
瞬間に出力するデバイスが 2 つになるということは、単純に記憶容量も倍になります
つまり、1 サンプルに使う記憶領域が倍になると考えれば良いのです
例えば、8 ビット振幅の場合は 1 サンプルに 16 ビット必要ということになります
この場合 下位 8 ビットに左、上位 8 ビットに右の音声が入ります
16 ビット振幅ならば、下位 16 ビットに左、上位 16 ビットに右の音声が入るということです
この性質を上手く利用することで、プログラムで機械的に生成した音声でも
左から右に流れるような音や、左右交互に音を鳴らすという事ができます
ゲームなど、臨場感や演出が問われるプログラムでは、こういったことも重要です
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")
#define SRATE 11025
LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
static HWAVEOUT hWave;
static BYTE *bWave;
DWORD dwCount , dwWaveL = 0 , dwWaveR = 0;
WAVEFORMATEX wfe;
WAVEHDR whdr;
switch (msg) {
case WM_DESTROY:
waveOutReset(hWave);
waveOutUnprepareHeader(hWave , &whdr , sizeof(WAVEHDR));
free(bWave);
waveOutClose(hWave);
PostQuitMessage(0);
return 0;
case WM_CREATE:
bWave = malloc(SRATE * 2);
for (dwCount = 0 ; dwCount < SRATE * 2 ; dwCount++) {
if (dwWaveL > 256) dwWaveL = 0;
*(bWave + dwCount++) = dwWaveL;
dwWaveL += 10;
if (dwWaveR > 256) dwWaveR = 0;
*(bWave + dwCount) = dwWaveR;
dwWaveR += 20;
}
wfe.wFormatTag = WAVE_FORMAT_PCM;
wfe.nChannels = 2;
wfe.nSamplesPerSec = SRATE;
wfe.nAvgBytesPerSec = SRATE;
wfe.wBitsPerSample = 8;
wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;
waveOutOpen(&hWave ,
WAVE_MAPPER , &wfe , 0 , 0 , CALLBACK_NULL);
whdr.lpData = bWave;
whdr.dwBufferLength = SRATE * 2;
whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
whdr.dwLoops = 5;
waveOutPrepareHeader(hWave , &whdr , sizeof(WAVEHDR));
waveOutWrite(hWave , &whdr , sizeof(WAVEHDR));
return 0;
}
return DefWindowProc(hWnd , msg , wp , lp);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow) {
HWND hWnd;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = TEXT("KITTY");
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return 1;
hWnd = CreateWindow(
TEXT("KITTY") , TITLE ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , hInstance , NULL
);
if (hWnd == NULL) return 1;
while (GetMessage(&msg , NULL , 0 , 0 )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
このプログラムを実行すると、左のスピーカに低いノコギリ波を
右のスピーカに左の音をオクターブ上げた高い音を 5 秒間だけ出力します
双方とも 440 Hz よりもやや低い音になっています
スピーカの左右のバランスを調節して、片方だけ鳴らすようにすればよく聞こえます