wavファイルを加工する

wavファイルを加工する

wavファイルはWinでよく使われる非圧縮の音声ファイルです。(圧縮もたまにある)
今回はそんな非圧縮wavファイルの加工をします。
とりあえずノーマライズに挑戦します。
手順は以下の通りです。
1,wavファイルを開く
   ↓
2,wavヘッダ読み込み&確認
   ↓
3,pcmデータ読み込み
   ↓
4,最大値探す
   ↓
5,ノーマライズ
   ↓
6,保存

プログラムは以下のようになります。
普通のwavファイルのヘッダは決まりがあります。
それを素直にWAVEHEADER構造体にしています。
pcmデータは16bitしか扱えません。
入力ファイルはtest.wavです。出力はtest2.wavになります。
'ノーマライズ

#console
#include<vcrt71.sbp>

Type WAVEHEADER
    RIFF[3] As Byte'"RIFF"
    bytes As DWord'(ファイルのバイト数)-8
    WAVE[3] As Byte' "WAVE"
    fmt[3] As Byte '"fmt " 
    siz_wf As DWord'PCMWAVEFORMAT構造体のバイト数=常に16
    'PCMWAVEFORMAT構造
    wFormatTag As Word 'pcm=1
    nChannels As  Word 'ch数
    nSamplesPerSec As Dword 'サンプリング周波数
    nAvgBytesPerSec As  DWord
    nBlockAlign As Word
    wBitsPerSample As Word '量子化数
    data[3] As Byte'"data"
    pcmbytes As DWord'波形データのバイト数
End Type 

Dim fp As *FILE
Dim buf[100] As Byte
Dim pcm As *Integer'PCMは16bit決め打ち
Dim read As DWord
Dim wh As WAVEHEADER
Dim max As DWord
Dim n As DWord
Dim dB As Double
Dim gain As Double
fp = fopen("test.wav" , "rb")
If fp = NULL Then
    printf(Ex"入力ファイルを開けません。\n")
    exit(0)
End If

fread(VarPtr(wh) , sizeof(WAVEHEADER) , 1 , fp)

'wavフォーマットかどうか
memcpy(buf , wh.RIFF , 4)
memcpy(VarPtr(buf[4]) , wh.WAVE , 4)
memcpy(VarPtr(buf[8]) , wh.fmt , 4)
If strcmp(buf , "RIFFWAVEfmt ") <>0 Then
    printf("wavフォーマットではありません")
    exit(0)
End If

'フォーマットを表示
printf(Ex"%dch %dHz %dbit\n" , wh.nChannels , _
        wh.nSamplesPerSec , wh.wBitsPerSample)

'データを読み込む
pcm = malloc(wh.pcmbytes)
fread(pcm , 1 , wh.pcmbytes , fp)

fclose(fp)

'ピークサーチ
For n=0 To wh.pcmbytes/2
    If max < pcm[n] Then max = pcm[n]
Next
dB = 20*(log10(max)- log10(32767))


printf(Ex"最大値=%d [%4.4fdB]\n" , max, dB)

If max = 32767 Then
    printf(Ex"ノーマライズの必要はありません。\n")
    exit(0)
End If

'ノーマライズ
printf(Ex"ノーマライズ中...")
gain = 32767 / max
For n=0 To wh.pcmbytes/2
    pcm[n] = pcm[n] * gain
Next
printf(Ex"終了しました。\n保存します。\n")
'保存
fp = fopen("test2.wav" , "wb")
If fp = NULL Then
    printf(Ex"出力ファイルを開けません。\n")
    exit(0)
End If
fwrite(VarPtr(wh) , sizeof(WAVEHEADER) , 1 , fp)
fwrite(pcm , 1 , wh.pcmbytes , fp)
fclose(fp)

printf(Ex"完了!\n")
system("pause")

exit(0)

その他

ピークサーチからノーマライズまでの部分を変えることで、以下のようなことが出来ます。
モノラルのwavファイルで行うと悲劇です。
wh.nChannels = 2のときのみ行うようにしてください。

LR反転するなら
'LR反転
printf(Ex"LR反転中...")
For n=0 To wh.pcmbytes/2 Step 2
    pcm[n+1] = pcm[n] - pcm[n+1] 
    pcm[n] = pcm[n] - pcm[n+1]
    pcm[n+1] = pcm[n+1] + pcm[n]
Next

カラオケモードにするなら
'カラオケ
printf(Ex"カラオケモード変換中...")
For n=0 To wh.pcmbytes/2 Step 2
    pcm[n] = pcm[n] - pcm[n+1]
    pcm[n+1] = pcm[n]
Next

モノラル化(擬似モノラル)するには
'擬似モノラル化
printf(Ex"擬似モノラルに変換中...")
For n=0 To wh.pcmbytes/2 Step 2
    pcm[n] = (pcm[n] + pcm[n+1]) /2
    pcm[n+1] = pcm[n]
Next

正しくモノラル化するには、
'モノラル化
printf(Ex"モノラルに変換中...")
For n=0 To wh.pcmbytes/2 Step 2
    pcm[n/2] = (pcm[n] + pcm[n+1]) /2
Next
'フォーマットを書き換え
wh.nChannels=1
wh.nBlockAlign = wh.wBitsPerSample/8
wh.nAvgBytesPerSec = wh.nSamplesPerSec * wh.nBlockAlign
wh.pcmbytes = wh.pcmbytes / 2
wh.bytes = wh.pcmbytes + 44 -8