WAVEファイルを作成する(C++)
テキストボックスに「ドレミファソラシド」を入力してその結果をWAVEファイルとして保存する事ができるサンプルプログラムです。正直、音は悪いですがWAVEファイルフォーマットの勉強として少しは参考になるかと思います。
サンプルの画面
サンプルプログラムの実行画面です。
[Wave.cpp]
//-------------------------------------------------------------------------------------- // ■ミニミニWAVEコンパイラー // // //-------------------------------------------------------------------------------------- //このサンプル自体は波形を作りません。既存の波形データを結合してWAVEファイルを作成します。 //また、結合方法はmmio系APIを使用したほうがいいのですが楽(?)なのでCreateFile()APIを使用しました。 //※WAVEファイルを結合する際は同じ形式でないと結合できませんので注意して下さい。 // 今回結合している波データは「PCM,8,000 kHz, 8 ビット, モノラル形式」です。 #include <windows.h> #include <mmreg.h> //ダイアログリソース #define IDD_DIALOG 101 #define IDB_DO 1000 #define IDB_RE 1001 #define IDB_MI 1002 #define IDB_FA 1003 #define IDB_SO 1004 #define IDB_RA 1005 #define IDB_SI 1006 #define IDB_BREAK 1007 #define IDB_WRITE 1008 #define IDB_CLAER 1009 #define IDE_EDIT 1011 //WAVEリソースとID併用 #define DO 10 //ド #define RE 11 //レ #define MI 12 //ミ #define FA 13 //ファ #define SO 14 //ソ #define RA 15 //ラ #define SI 16 //シ #define _BREAK 17 //休符 //RIFFチャンク(8bytes) typedef struct { BYTE _RIFF[4]; //マジック "RIFF" DWORD dwSize; //このチャンクのサイズ(RIFF+WAVE+DATAチャンクのサイズ) }TRIFFCHANKU; //WAVEチャンク(28bytes) typedef struct { BYTE _WAVE[8]; //マジック "WAVEfmt " DWORD dwSize; //このチャンクのサイズ 今回のサンプルでは常に16 WAVEFORMAT _Format; //フォーマット情報 WORD wBitsPerSample; //サンプル数 今回は8bit }TWAVECHANKU; //DATAチャンク(8bytes) typedef struct { BYTE _DATA[4]; //マジック "data" DWORD dwSize; //このチャンクのサイズ(波形データのサイズ) }TDATACHANKU; //WAVEヘッダー typedef struct { TRIFFCHANKU RIFFCHANKU; //RIFFチャンク TWAVECHANKU WAVECHANKU; //WAVEチャンク TDATACHANKU DATACHANKU; //DATAチャンク }TWAVEHEADER; //サンプルで使用するWAVEフォーマット(PCM)----------- //+ RIFFチャンク // - WAVEfmtチャンク // - DATAチャンク // これ以後波形データが続く // //------------------------------------------------ //※今回は書きこみだけなので関係ないですが途中にfact/LISTチャンクなどが入る場合もあります。 // また、WAVEfmtチャンクが16バイトではなく18バイトの場合もあります。 BYTE DataCode[10000]; //演奏データ とりあえず10kまで int CodeCount; //波形データ保持用グローバルポインタ変数 BYTE *DO_BUFFER; BYTE *RE_BUFFER; BYTE *MI_BUFFER; BYTE *FA_BUFFER; BYTE *SO_BUFFER; BYTE *RA_BUFFER; BYTE *SI_BUFFER; BYTE *BREAK_BUFFER; //コールバックプロシージャ LRESULT CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); /////////////////////////////////////////////////////////////////////////////// // // WinMain // int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HRSRC hRsrc =NULL; HGLOBAL hGlobal=NULL; LPVOID lpVoid =NULL; //リソースから波形データの取得(面倒なのでエラー処理は行わない) //ド hRsrc=FindResource(hInstance,MAKEINTRESOURCE(DO),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); DO_BUFFER=(BYTE *)malloc(4000); //4000は波形データリソースのサイズ(WAVEファイルから波形データの部分のみ取り出したデータファイルです。res.zipファイルの内容と比較して下さい。) MoveMemory(DO_BUFFER,lpVoid,4000); //レ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(RE),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); RE_BUFFER=(BYTE *)malloc(4000); MoveMemory(RE_BUFFER,lpVoid,4000); //ミ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(MI),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); MI_BUFFER=(BYTE *)malloc(4000); MoveMemory(MI_BUFFER,lpVoid,4000); //ファ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(FA),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); FA_BUFFER=(BYTE *)malloc(4000); MoveMemory(FA_BUFFER,lpVoid,4000); //ソ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(SO),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); SO_BUFFER=(BYTE *)malloc(4000); MoveMemory(SO_BUFFER,lpVoid,4000); //ラ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(RA),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); RA_BUFFER=(BYTE *)malloc(4000); MoveMemory(RA_BUFFER,lpVoid,4000); //シ hRsrc=FindResource(hInstance,MAKEINTRESOURCE(SI),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); SI_BUFFER=(BYTE *)malloc(4000); MoveMemory(SI_BUFFER,lpVoid,4000); //休符 hRsrc=FindResource(hInstance,MAKEINTRESOURCE(_BREAK),"WAVE"); hGlobal=LoadResource(hInstance,hRsrc); lpVoid=LockResource(hGlobal); BREAK_BUFFER=(BYTE *)malloc(4000); MoveMemory(BREAK_BUFFER,lpVoid,4000); //ウインドウ始動 DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), 0, (DLGPROC)DialogProc); //メモリ解放 free(DO_BUFFER);free(RE_BUFFER);free(MI_BUFFER);free(FA_BUFFER); free(SO_BUFFER);free(RA_BUFFER);free(SI_BUFFER);free(BREAK_BUFFER); return (0); } /////////////////////////////////////////////////////////////////////////////// // // DialogProc // LRESULT CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { int _size,i; CHAR *buffer; HANDLE hFile; //ファイルポインタ DWORD Work; //単なるワークエリア DWORD _FileSize; //ファイル全体のサイズ DWORD _DataSize; //波形データのサイズ TWAVEHEADER WAVEHEADER;//waveヘッダー switch (uMsg) { case WM_INITDIALOG: SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,NULL); return false; case WM_COMMAND: switch (LOWORD(wParam)) { //ユーザーが指定した音符データの取得-----> case IDB_DO: //10kまで if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sド",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=DO; CodeCount++; break; case IDB_RE: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sレ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); DataCode[CodeCount]=RE; CodeCount++; free(buffer); break; case IDB_MI: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sミ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=MI; CodeCount++; break; case IDB_FA: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sファ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=FA; CodeCount++; break; case IDB_SO: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sソ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=SO; CodeCount++; break; case IDB_RA: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sラ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=RA; CodeCount++; break; case IDB_SI: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%sシ",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=SI; CodeCount++; break; case IDB_BREAK: if (CodeCount>10000) { MessageBox(0,"これ以上音符データを書き込めせん。","エラー",MB_OK); break;} buffer=(CHAR*)malloc(10000); ZeroMemory(buffer,10000); _size= SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXTLENGTH ,0,0)+1; if (_size!=1) SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_GETTEXT,_size,(LPARAM)buffer); wsprintf(buffer,"%s-",buffer); SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,(LPARAM)buffer); free(buffer); DataCode[CodeCount]=_BREAK; CodeCount++; break; //WAVEファイル生成-----> case IDB_WRITE: /* if (CodeCount==0) { MessageBox(0,"音符データが入力されていません。","エラー",MB_OK); break; } */ hFile = CreateFile("Test.wav", GENERIC_WRITE, 0,NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL); if (hFile!=NULL) { ZeroMemory(&WAVEHEADER,44); //44byteジャンプ SetFilePointer(hFile,44,NULL,FILE_BEGIN); //波形データの書きこみ-----> if (CodeCount!=0) { buffer=(char *)malloc(4000*CodeCount); //<-メモリが確保できているか確認したほうが良いでしょう。 for (i=0;i<CodeCount;i++) { switch (DataCode[i]) { case DO: MoveMemory(buffer,DO_BUFFER,4000);buffer=buffer+4000; break; case RE: MoveMemory(buffer,RE_BUFFER,4000);buffer=buffer+4000; break; case MI: MoveMemory(buffer,MI_BUFFER,4000);buffer=buffer+4000; break; case FA: MoveMemory(buffer,FA_BUFFER,4000);buffer=buffer+4000; break; case SO: MoveMemory(buffer,SO_BUFFER,4000);buffer=buffer+4000; break; case RA: MoveMemory(buffer,RA_BUFFER,4000);buffer=buffer+4000; break; case SI: MoveMemory(buffer,SI_BUFFER,4000);buffer=buffer+4000; break; case _BREAK: MoveMemory(buffer,BREAK_BUFFER,4000);buffer=buffer+4000; break; } } //ポインタをベースアドレスへ戻す buffer=buffer-(4000*CodeCount); WriteFile(hFile,buffer,4000*CodeCount,&Work,NULL); free(buffer); _FileSize= GetFileSize(hFile,NULL); } else _FileSize=44; //波形データのサイズを取得(4000は1つのリソースサイズ) _DataSize=CodeCount*4000; //ファイルポインタを先頭にする SetFilePointer(hFile,0,NULL,FILE_BEGIN); //WAVEヘッダーの書きこみ-----> //RIFFマジック WAVEHEADER.RIFFCHANKU._RIFF[0]=0x52; WAVEHEADER.RIFFCHANKU._RIFF[1]=0x49; WAVEHEADER.RIFFCHANKU._RIFF[2]=0x46; WAVEHEADER.RIFFCHANKU._RIFF[3]=0x46; //このチャンクのサイズ WAVEHEADER.RIFFCHANKU.dwSize=_FileSize; //WAVEマジック WAVEHEADER.WAVECHANKU._WAVE[0] =0x57; WAVEHEADER.WAVECHANKU._WAVE[1] =0x41; WAVEHEADER.WAVECHANKU._WAVE[2] =0x56; WAVEHEADER.WAVECHANKU._WAVE[3] =0x45; WAVEHEADER.WAVECHANKU._WAVE[4] =0x66; WAVEHEADER.WAVECHANKU._WAVE[5] =0x6D; WAVEHEADER.WAVECHANKU._WAVE[6] =0x74; WAVEHEADER.WAVECHANKU._WAVE[7] =0x20; //このチャンクのサイズ WAVEHEADER.WAVECHANKU.dwSize =16; //WAVEフォーマットの種類(PCM) WAVEHEADER.WAVECHANKU._Format.wFormatTag =WAVE_FORMAT_PCM; //モノラル WAVEHEADER.WAVECHANKU._Format.nChannels =1; //毎秒サンプル数 WAVEHEADER.WAVECHANKU._Format.nSamplesPerSec =8000; //毎秒バイト数 WAVEHEADER.WAVECHANKU._Format.nAvgBytesPerSec =8000; //ブロックの境界 WAVEHEADER.WAVECHANKU._Format.nBlockAlign =1; //サンプル数 WAVEHEADER.WAVECHANKU.wBitsPerSample=8; //dataマジック WAVEHEADER.DATACHANKU._DATA[0]=0x64; WAVEHEADER.DATACHANKU._DATA[1]=0x61; WAVEHEADER.DATACHANKU._DATA[2]=0x74; WAVEHEADER.DATACHANKU._DATA[3]=0x61; //このチャンクのサイズ WAVEHEADER.DATACHANKU.dwSize=_DataSize; //書きこむ WriteFile(hFile,&WAVEHEADER,44,&Work,NULL); CloseHandle(hFile); } break; case IDB_CLAER: SendMessage(GetDlgItem(hwnd,IDE_EDIT),WM_SETTEXT,0,NULL); ZeroMemory(DataCode,10000); CodeCount=0; break; case 2: EndDialog(hwnd, 2); break; default: return false; } default: return false; } return true; }
サンプルプログラム一式のダウンロード
create_wave.zip 36.5 KB (37,389 バイト)
注意事項
このサンプルは約15年前に作成した「いにしえ」の産物です。予めご了承下さい。
スポンサーリンク
関連記事
公開日:2015年02月19日
記事NO:00242