/* * WaveReader.cs * Copyright (c) 2009 kbinani * * This file is part of Boare.Lib.Media. * * Boare.Lib.Media is free software; you can redistribute it and/or * modify it under the terms of the BSD License. * * Boare.Lib.Media is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ using System; using System.IO; using System.Runtime.InteropServices; namespace Boare.Lib.Media { public class WaveReader : IDisposable{ private int m_channel; private int m_byte_per_sample; private bool m_opened; private FileStream m_stream; private int m_total_samples; public WaveReader() { m_opened = false; } public WaveReader( string file ) { Open( file ); } public void Dispose() { Close(); } public bool Open( string file ) { if ( m_opened ) { m_stream.Close(); } m_stream = new FileStream( file, FileMode.Open ); // RIFF byte[] buf = new byte[4]; m_stream.Read( buf, 0, 4 ); if ( buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' ) { m_stream.Close(); return false; } // ファイルサイズ - 8最後に記入 m_stream.Read( buf, 0, 4 ); // WAVE m_stream.Read( buf, 0, 4 ); if ( buf[0] != 'W' || buf[1] != 'A' || buf[2] != 'V' || buf[3] != 'E' ) { m_stream.Close(); return false; } // fmt m_stream.Read( buf, 0, 4 ); if ( buf[0] != 'f' || buf[1] != 'm' || buf[2] != 't' || buf[3] != ' ' ) { m_stream.Close(); return false; } // fmt チャンクのサイズ m_stream.Read( buf, 0, 4 ); // format ID m_stream.Read( buf, 0, 2 ); // チャンネル数 m_stream.Read( buf, 0, 2 ); m_channel = buf[1] << 8 | buf[0]; // サンプリングレート m_stream.Read( buf, 0, 4 ); // データ速度 m_stream.Read( buf, 0, 4 ); // ブロックサイズ m_stream.Read( buf, 0, 2 ); // サンプルあたりのビット数 m_stream.Read( buf, 0, 2 ); int bit_per_sample = buf[1] << 8 | buf[0]; m_byte_per_sample = bit_per_sample / 8; // 拡張部分 m_stream.Read( buf, 0, 2 ); // data m_stream.Read( buf, 0, 4 ); if ( buf[0] != 'd' || buf[1] != 'a' || buf[2] != 't' || buf[3] != 'a' ) { m_stream.Close(); return false; } // size of data chunk m_stream.Read( buf, 0, 4 ); int size = BitConverter.ToInt32( buf, 0 ); m_total_samples = size / (m_channel * m_byte_per_sample); m_opened = true; return true; } public int TotalSamples { get { return m_total_samples; } } public void Read( int start, int length, out float[] left, out float[] right ) { left = new float[length]; right = new float[length]; if ( !m_opened ) { return; } int loc = 0x2e + m_byte_per_sample * m_channel * start; m_stream.Seek( loc, SeekOrigin.Begin ); if ( m_byte_per_sample == 2 ) { if ( m_channel == 2 ) { byte[] buf = new byte[4]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 4 ); if ( ret < 4 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } short l = (short)(buf[0] | buf[1] << 8); short r = (short)(buf[2] | buf[3] << 8); left[i] = l / 32768.0f; right[i] = r / 32768.0f; } } else { byte[] buf = new byte[2]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 2 ); if ( ret < 2 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } short l = (short)(buf[0] | buf[1] << 8); left[i] = l / 32768.0f; right[i] = left[i]; } } } else { if ( m_channel == 2 ) { byte[] buf = new byte[2]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 2 ); if ( ret < 2 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } left[i] = (buf[0] - 64.0f) / 64.0f; right[i] = (buf[1] - 64.0f) / 64.0f; } } else { byte[] buf = new byte[1]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 1 ); if ( ret < 1 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } left[i] = (buf[0] - 64.0f) / 64.0f; right[i] = left[i]; } } } } public unsafe void Read( int start, int length, out IntPtr ptr_left, out IntPtr ptr_right ) { ptr_left = Marshal.AllocHGlobal( sizeof( float ) * length ); ptr_right = Marshal.AllocHGlobal( sizeof( float ) * length ); float* left = (float*)ptr_left.ToPointer(); float* right = (float*)ptr_right.ToPointer(); if ( !m_opened ) { return; } int loc = 0x2e + m_byte_per_sample * m_channel * start; m_stream.Seek( loc, SeekOrigin.Begin ); if ( m_byte_per_sample == 2 ) { if ( m_channel == 2 ) { byte[] buf = new byte[4]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 4 ); if ( ret < 4 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } short l = (short)(buf[0] | buf[1] << 8); short r = (short)(buf[2] | buf[3] << 8); left[i] = l / 32768.0f; right[i] = r / 32768.0f; } } else { byte[] buf = new byte[2]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 2 ); if ( ret < 2 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } short l = (short)(buf[0] | buf[1] << 8); left[i] = l / 32768.0f; right[i] = left[i]; } } } else { if ( m_channel == 2 ) { byte[] buf = new byte[2]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 2 ); if ( ret < 2 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } left[i] = (buf[0] - 64.0f) / 64.0f; right[i] = (buf[1] - 64.0f) / 64.0f; } } else { byte[] buf = new byte[1]; for ( int i = 0; i < length; i++ ) { int ret = m_stream.Read( buf, 0, 1 ); if ( ret < 1 ) { for ( int j = i; j < length; j++ ) { left[j] = 0.0f; right[j] = 0.0f; } break; } left[i] = (buf[0] - 64.0f) / 64.0f; right[i] = left[i]; } } } } public void Close() { m_opened = false; if ( m_stream != null ) { m_stream.Close(); } } ~WaveReader() { Close(); } } }