保存は読み込みと違い、WAVEファイルの構造を理解していれば非常に簡単です。
保存しようとしているWAVEデータは正常であるという仮定が成り立つのでチェックの必要も無く、
基本的にはガンガン書き込んでいくだけです。
■WAVEファイルの構造(PCM形式)
factチャンクは必要ないので、factチャンク無しで保存します。
| アドレス | データ |
| 0 | "RIFF" |
| +4 | (ファイルのバイト数)-8 |
| +8 | "WAVE" |
| +12 | "fmt " |
| +16 | フォーマット情報(PCMWAVEFORMAT構造体)のバイト数 |
| +20 | フォーマット情報(PCMWAVEFORMAT構造体) |
| +36 | "data" |
| +40 | 波形データのバイト数 |
| +44 〜 | 波形データ |
■WAVEデータをファイルに保存する関数
PCM形式のWAVEデータをファイルに保存する関数を作ります。
関数の名前:SaveWaveFile
char *lpFileName:ファイルの名前を指すポインタ
WAVEFORMATEX *lpwfe:データが格納されているWAVEFORMATEX構造体を指すポインタ
WAVEHDR *lpwhdr:データが格納されているWAVEHDR構造体を指すポインタ
戻り値:0(成功) or 負値(失敗)
int SaveWaveFile(char *lpFileName,WAVEFORMATEX *lpwfe,WAVEHDR *lpwhdr)
{
……
}
■ファイルオープン
新しいファイルを書き込み属性で作成します。
上書きはしません。
HANDLE fh=CreateFile(lpFileName,GENERIC_WRITE,0,NULL,
CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(fh==INVALID_HANDLE_VALUE){
MessageBox(NULL,"同名のファイルが既に存在します",lpFileName,MB_OK);
return -1;
}
■WAVEデータの書き込み
ファイルの先頭から4〜7バイトに書き込む (ファイルのバイト数)-8 ですが、
ファイルのバイト数は 波形データのバイト数+44 で計算できます。
44 は波形データ以外にファイルに書き込むバイト数です(ファイルの構造参照)。
フォーマット情報はPCMWAVEFORMAT構造体で保存しなければいけませんが、
WAVEFORMATEX構造体の最後のメンバを書き込まないように
PCMWAVEFORMAT構造体のサイズである 16 バイトだけ書き込めば同じ事です。
波形データのバイト数は WAVEFORMATEX構造体のdwBufferLengthメンバ が、
波形データの先頭を指すポインタは WAVEFORMATEX構造体のlpDataメンバ が保持しています。
DWORD dwWriteSize;
WriteFile(fh,"RIFF",4,&dwWriteSize,NULL);
DWORD size=(lpwhdr->dwBufferLength + 44)-8;
WriteFile(fh,&size,4,&dwWriteSize,NULL);
WriteFile(fh,"WAVE",4,&dwWriteSize,NULL);
WriteFile(fh,"fmt ",4,&dwWriteSize,NULL);
size=16;
WriteFile(fh,&size,4,&dwWriteSize,NULL);
WriteFile(fh,lpwfe,size,&dwWriteSize,NULL);
WriteFile(fh,"data",4,&dwWriteSize,NULL);
WriteFile(fh,&lpwhdr->dwBufferLength,4,&dwWriteSize,NULL);
WriteFile(fh,lpwhdr->lpData,lpwhdr->dwBufferLength,&dwWriteSize,NULL);
■ファイルクローズ
書き込みが終了したのでファイルをクローズして関数を終了します。
CloseHandle(fh);
return 0;
関数の処理はこれだけです。
非常に簡潔だったでしょ?
■WAVEデータを作成して保存する
SaveWaveFile関数を使ってWAVEデータをファイルに保存してみましょう。
WAVEデータは作成するだけで再生したりしないので、waveOut○○関数の実行は必要ありません。
#include<windows.h>
#include"WaveFileIO.h"
// winmm.lib をリンクする
#pragma comment(lib,"winmm")
#define SRATE 8000 //標本化周波数(1秒間のサンプル数)
#define F 400 //周波数(1秒間の波形数)
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
WAVEFORMATEX wfe;
static WAVEHDR whdr;
static LPBYTE lpWave;
int i,len;
switch(uMsg){
case WM_CREATE:
wfe.wFormatTag=WAVE_FORMAT_PCM;
wfe.nChannels=1; //モノラル
wfe.wBitsPerSample=8; //量子化ビット数
wfe.nBlockAlign=wfe.nChannels * wfe.wBitsPerSample/8;
wfe.nSamplesPerSec=SRATE; //標本化周波数
wfe.nAvgBytesPerSec=wfe.nSamplesPerSec * wfe.nBlockAlign;
lpWave=(LPBYTE)calloc(wfe.nAvgBytesPerSec,2); //2秒分
len=SRATE/F; //波長
for(i=0;i<SRATE*2;i++){ //波形データ作成
if(i%len < len/2) lpWave[i]=128+64;
else lpWave[i]=128-64;
}
whdr.lpData=(LPSTR)lpWave;
whdr.dwBufferLength=wfe.nAvgBytesPerSec * 2;
whdr.dwFlags=WHDR_BEGINLOOP | WHDR_ENDLOOP;
whdr.dwLoops=1;
SaveWaveFile("myWaveFile.wav",&wfe,&whdr);
return 0;
case WM_DESTROY:
free(lpWave);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
■WaveFileIO.h
WaveFileIO.h はWAVEファイルを読み書きする関数を集めたヘッダーです。
ソースファイルが適切な場所に存在すれば、WaveFileIO.h をインクルードするだけで
WAVEファイルの読み込み、WAVEデータのファイル保存、の両方が行えるようになります。
// LoadWaveFile.cpp int LoadWaveFile(char *lpFileName,WAVEFORMATEX *lpwfe,WAVEHDR *lpwhdr); void CloseWaveFile(HWAVEOUT hWaveOut,WAVEHDR *lpwhdr); // SaveWaveFile.cpp int SaveWaveFile(char *lpFileName,WAVEFORMATEX *lpwfe,WAVEHDR *lpwhdr);
★☆ ダウンロード ☆★