ホーム > カテゴリ > フォーマット変換 >

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