音ファイル(拡張子:Wav)をダウンロードする
音ファイルは純音ファイル(正弦波の周波数10kHz)を利用。
音が聞こえない人は耳年齢は60才以上です。以下を再生して聞こえますか?
再生時は音量に気をつけて下さいね。
上の右端スピーカー横にある所をクリックすると音ファイルをダウンロードできます。
上記方法でダウンロード出来ない場合は、下記の “音ファイルダウンロード” リンク上で右クリックして、”名前を付けてリンク先を保存(K)”をクリックしてください。
音ファイルダウンロード
ダウンロード出来たら、次はWavファイルのフォーマットを確認します。プログラム制作時に何をやっているか分からなるので、WAVファイルのデータ構造を知る必要があります。
WAVファイルデータ構造(フォーマット)を確認する
項目 | サイズ (byte) | データ部 |
---|---|---|
チャンク識別子 | 4 | “RIFF”(0x52494646)で固定。 |
チャンク サイズ | 4 | ファイル全体サイズからRIFFとWAVEのバイト数(8Byte)を引いた数 |
フォーマット | 4 | WAVファイルの場合は“WAVE”(0x57415645)で固定。AVIファイルの場合は“AVI”が入る |
サブチャンク①識別子 | 4 | “fmt “(0x666D7420)で固定。 |
サブチャンク①サイズ | 4 | 16 + 拡張パラメータのサイズ。デフォルト値は16 |
音声フォーマット | 2 |
圧縮のフォーマットIDを表す。非圧縮のリニアPCMは1 0x0001:リニアPCM 0x0002:MS ADPCM 0x0005:IBM CSVD 0x0006:A-Law 0x0007:μ-Law 上記以外はこちらを参照 |
チャンネル数 | 2 | モノラルは1、ステレオは2 |
サンプリング周波数 [byte/sec] |
4 | 8kHzの場合は8000、44.1kHzの場合なら44100 44.1kHz 16bitステレオの場合:44100×2×2 =176400 44.1KHz 16bitモノラルの場合:44100×2×1=88200 |
1 秒あたりバイト数の平均 | 4 | サンプリング周波数 * ブロックサイズで求める |
ブロックサイズ | 2 | チャンネル数 * 1サンプルあたりのビット数 / 8で求める。ステレオ16bitなら16bit*2 = 32bit = 4byte |
バイト/サンプル | 2 | サンプルあたりのバイト数 16bitステレオ:4 16bitモノラル:2 8bitモノラル:1 |
拡張パラメータのサイズ | (2) | リニア PCM (音声フォーマットが1) の場合は未使用。 |
拡張パラメータ | (*) | リニア PCM (音声フォーマットが1) の場合は未使用。 |
サブチャンク② 識別子 | 4 | “data” (0x64617461)で固定。 |
サブチャンク② サイズ | 4 | 波形データのバイト数(総ファイルサイズ – 126) |
データ | * | 波形データを格納。リニアPCMの場合は時間順に格納される。ステレオは左→右→左→右…のように格納される。8ビットの場合は符号無し整数 (0 – 255)、16ビットの場合は符号付き整数 (-32768 – 32767) で表わす。 |
Wavファイルの構造をもっと知りたい方はこちら(音ファイル(拡張子:WAVファイル)のデータ構造について)に記載しています。ご参考にどうぞ。
音ファイルを読み込むプログラムを作成する(VB.net)
ここから本題に入ります。以下の順番で作ります。
- プロジェクトを作る
- ヘッダー部を読み込む処理
- フォームを作成してChartオブジェクトを貼る
- データ部を読み込み波形を作る処理
- 音ファイルを取り込んで画面に波形グラフを表示する
プロジェクトを作る
Visual Studioで何か適当なプロジェクトを作ります。ここではVisual Studio 2015を使用しています。Visual BasicのWindowsフォームアプリケーションを選択します。
ヘッダー部を読み込む処理を制作
Imports System.IO Imports System.Text.Encoding Public Class clsHeader ' riffチャンク Public strRiff As String Public intChunkSize As Integer Public strFileFormat As String ' fmtチャンク Public strFmt As String Public intFmtSize As Integer Public shFmtFormat As Short Public shChannel As Short Public intSampleRate As Integer Public intBytePerSec As Integer Public shBlockSize As Short Public shBitPerSample As Short Public PlayTime As Integer Public strWork As String '''''' Wavファイルヘッダー読み込み処理 ''' ''' ''' Public Sub readHeader(ByRef fs As FileStream, ByRef br As BinaryReader) Try ' ====================== ' RIFFヘッダー読み込み ' ====================== strRiff = GetEncoding(20127).GetString(br.ReadBytes(4)) intChunkSize = BitConverter.ToInt32(br.ReadBytes(4), 0) strFileFormat = GetEncoding(20127).GetString(br.ReadBytes(4)) If (strRiff.ToLower() <> "riff") Then MessageBox.Show("riff chunk doesn't exists.") Exit Sub End If If (strFileFormat.ToLower() <> "wave") Then MessageBox.Show("format isn't wave format.") Exit Sub End If ' ====================== ' fmtチャンクの読み込み ' ====================== strFmt = GetEncoding(20127).GetString(br.ReadBytes(4)) If (strFmt.ToLower() <> "fmt ") Then MessageBox.Show("fmt chunk doesn't exists.") Exit Sub End If intFmtSize = BitConverter.ToInt32(br.ReadBytes(4), 0) shFmtFormat = BitConverter.ToInt16(br.ReadBytes(2), 0) shChannel = BitConverter.ToInt16(br.ReadBytes(2), 0) intSampleRate = BitConverter.ToInt32(br.ReadBytes(4), 0) intBytePerSec = BitConverter.ToInt32(br.ReadBytes(4), 0) shBlockSize = BitConverter.ToInt16(br.ReadBytes(2), 0) shBitPerSample = BitConverter.ToInt16(br.ReadBytes(2), 0) ' ================================ ' dataチャンクを見つけるまでループ ' ================================ Dim blnFindD As Boolean = False Dim intWorkSize As Integer = 0 While blnFindD = False ' 拡張部分を考慮して2byteずつ取得 strWork = GetEncoding(20127).GetString(br.ReadBytes(2)) If strWork = "da" Then 'dataチャンクの頭2文字が含まれている事を確認 strWork = GetEncoding(20127).GetString(br.ReadBytes(2)) If strWork = "ta" Then blnFindD = True End If End If End While Catch ex As Exception MessageBox.Show("readHeader:" & ex.ToString()) End Try End Sub End Class
フォームを作成してChartオブジェクトを貼る
チャートライブラリ(System.Windows.Forms.DataVisualization)を参照追加する。
データ部を読み込み波形を作る処理
Imports System.IO Imports System.Windows.Forms.DataVisualization.Charting Public Class Form1 Dim intDataSize As Integer Dim strFilePath As String = "C:\Users\owner\Desktop\wav\sample_2000msec.wav" '''''' フォームロード ''' ''' ''' Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Try Using fs = New FileStream(strFilePath, FileMode.Open, FileAccess.Read, FileShare.Read) Dim br As BinaryReader = New BinaryReader(fs) Dim objHeader As clsHeader = New clsHeader ' wavファイルのヘッダー情報を読み込む objHeader.readHeader(fs, br) ' dataチャンクの読み込み intDataSize = BitConverter.ToInt32(br.ReadBytes(4), 0) ' 波形を格納 Dim waveData As Byte() = br.ReadBytes(intDataSize) convertWaveData(objHeader, waveData) End Using Catch ex As Exception MessageBox.Show("Form1_Load:" & ex.ToString()) End Try End Sub '''''' 波形ファイルを作成する ''' ''' ''' Sub convertWaveData(ByRef objHeader As clsHeader, ByRef waveData As Byte()) Try ' 音声データの取得 Dim intWork As Integer intWork = CInt((intDataSize / objHeader.shChannel) / (objHeader.shBitPerSample / 8)) Dim valuesR(intWork) As Integer intWork = CInt((intDataSize / objHeader.shChannel) / (objHeader.shBitPerSample / 8)) Dim valuesL(intWork) As Integer ' 1標本分の値を取得 Dim frameIndex As Integer = 0 Dim chanelIndex As Integer = 0 Dim data(2) As Byte For i As Integer = 0 To (intDataSize / (objHeader.shBitPerSample / 8)) - 1 Dim work As Integer = 0 Select Case (objHeader.shBitPerSample) Case 8 work = CInt(waveData(frameIndex)) frameIndex = frameIndex + 1 Case 16 Array.Copy(waveData, frameIndex, data, 0, 2) work = CInt(BitConverter.ToInt16(data, 0)) frameIndex = frameIndex + 2 Case Else MessageBox.Show("波形解析できません", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error) End Select If (objHeader.shChannel = 1) Then valuesR(i) = work Else If (chanelIndex = 0) Then chanelIndex = 1 valuesR(i / 2) = work Else chanelIndex = 0 valuesL(i / 2) = work End If End If Next ' 波形描画 Call makeChart(valuesR, objHeader.PlayTime) Catch ex As Exception MessageBox.Show("convertWaveData:" & ex.ToString()) End Try End Sub '''''' 波形描画 ''' ''' ''' 横軸の数値(単位:秒) Private Sub makeChart(ByVal valuesR() As Integer, ByVal intPlayTime As Integer) Try With Chart1 ' 初期化 .Series.Clear() .Titles.Clear() ' 作成 Dim objTitle As Title = New Title("波形ファイル") .Titles.Add(objTitle) Dim objSeries As Series = New Series objSeries.ChartType = SeriesChartType.Line ' グラフタイプ objSeries.Name = "Waveデータ" ' 凡例に表示される文字列を指定 For i As Integer = 0 To valuesR.Length - 1 objSeries.Points.AddXY(i, valuesR(i)) ' データ追加 Next .Series.Add(objSeries) .BackColor = Color.White ' 背景色 .Series(0).Color = Color.Lime ' グラフの色 .ChartAreas(0).AxisX.MajorGrid.Enabled = True .ChartAreas(0).AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dot .ChartAreas(0).AxisX.MajorGrid.LineColor = Color.Green .ChartAreas(0).AxisX.MinorGrid.Enabled = False .ChartAreas(0).AxisY.MajorGrid.Enabled = True .ChartAreas(0).AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dot .ChartAreas(0).AxisY.MajorGrid.LineColor = Color.Green .ChartAreas(0).AxisY.MinorGrid.Enabled = False End With Catch ex As Exception MessageBox.Show("makeChart:" & ex.ToString()) End Try End Sub End Class
音ファイルを取り込んで画面に波形グラフを表示する
後は、実行ボタンを押せば、以下の画像が画面に表示されます。
なお、音ファイル(199msec)をプログラムに読み込ませると以下のグラフが描画されます。
うまく表示できましたでしょうか? もし以下でお困りでしたら
- 集音機からくるデータをリアルタイムで処理したい
- 画像描画までが遅すぎるのでもっと早くしたい
- mp3、aviファイルなどの拡張子も対応したい
- なぜかプログラムが落ちてしまう
- コーデックの部分がよく解らない
- ステレオ時は2つの波形を表示したい
- FFT分析した結果も画面に表示したい
- バンドパスフィルタをかけた結果を画面に表示したい
などお困り事があれば計測機器ソフト屋である弊社にお任せ下さい。
なお、上記プログラムにてご指摘などがある際は、お問合せフォームよりご連絡下さると大変助かります。