プログラミングメモ →目次

PCMデータをwaveファイルにの保存(VC++)

mmio関数群を利用して、録音したデータやプログラムで作った音声データをwaveファイルに保存する手順についてのメモです。mmio関数群を利用する為に、winmm.libをリンクして、mmsystem.hをインクルードする必要があります。データをwaveファイルに保存するために、下記の処理が必要です。

1.WAVEFORMATEX構造体を設定します。音声データを準備します。

2.ファイルオープン。WINMMAPI HMMIO WINAPI mmioOpen(LPSTR pszFileName, LPMMIOINFO pmmioinfo, DWORD fdwOpen)というAPI関数を呼び出して、保存先のwaveファイルを開きます。

3.各情報チャンクの書き込み。WINMMAPI FOURCC WINAPI mmioStringToFOURCC(LPCSTR sz, UINT uFlags)関数を使って、各情報を「チャンク」に保存します。下記の三つのチャンクに必要な情報を保存しなければいけません。RIFFチャンクで、WAV形式のデータファイルであることを設定します。フォーマットチャンクは、音声制御情報(WAVEFORMATEX)を保存します。データチャンクは、音声データの塊りを保存します。例:Dドライブに「file1.wav」というファイルに長さの10秒の音階の「ラ=440Hz」を保存します。

    WAVEFORMATEX wf;
    wf.nChannels       = 1;
    wf.wFormatTag      = WAVE_FORMAT_PCM;
    wf.wBitsPerSample  = 8;
    wf.nBlockAlign     = wf.nChannels * wf.wBitsPerSample / 8;
    wf.nSamplesPerSec  = 32000;
    wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
    DWORD dwRecordSecond = 10;

    LPSTR lpData = (LPSTR)HeapAlloc(GetProcessHeap(), 0, 
                                    wf.nAvgBytesPerSec * dwRecordSecond);
    if (lpData)
    {
        double pi_2_f_deltaT_left = 8.0 * atan(1.0) * 440.0 / 32000.0;

        for (int i = 0; i < (int)(wf.nAvgBytesPerSec * dwRecordSecond); i ++)
        {
            double dblY1 = 127 * sin(pi_2_f_deltaT_left * i);
            BYTE byt = (BYTE)dblY1;
            byt += (BYTE)127;
            lpData[i] = byt;
        }

        DWORD dwSize = wf.nAvgBytesPerSec * dwRecordSecond;

        HMMIO    hmmio;
        MMCKINFO mmckRif;
        MMCKINFO mmckDat;
        MMCKINFO mmckFmt;
        hmmio = mmioOpen(TEXT("d:\\file1.wav"), NULL, MMIO_CREATE | MMIO_WRITE);
        mmckRif.fccType = mmioStringToFOURCC(TEXT("WAVE"), 0);
        mmioCreateChunk(hmmio, &mmckRif, MMIO_CREATERIFF);
        mmckFmt.ckid = mmioStringToFOURCC(TEXT("fmt "), 0);
        mmioCreateChunk(hmmio, &mmckFmt, 0);
        mmioWrite(hmmio, (char *)&wf, sizeof(WAVEFORMATEX));
        mmioAscend(hmmio, &mmckFmt, 0);

        mmckDat.ckid = mmioStringToFOURCC(TEXT("data"), 0);
        mmioCreateChunk(hmmio, &mmckDat, 0);
        mmioWrite(hmmio, (char *)lpData, dwSize);
        mmioAscend(hmmio, &mmckDat, 0);
        
        mmioAscend(hmmio, &mmckRif, 0);
        mmioClose(hmmio, 0);
        HeapFree(GetProcessHeap(), 0, lpData);
    }