音ファイル(拡張子: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分析した結果も画面に表示したい
- バンドパスフィルタをかけた結果を画面に表示したい
などお困り事があれば計測機器ソフト屋である弊社にお任せ下さい。
なお、上記プログラムにてご指摘などがある際は、お問合せフォームよりご連絡下さると大変助かります。