2009-06-25 07:16:22 -07:00
|
|
|
|
/*
|
|
|
|
|
* 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();
|
|
|
|
|
}
|
2009-07-29 10:03:20 -07:00
|
|
|
|
m_stream = new FileStream( file, FileMode.Open, FileAccess.Read );
|
2009-06-25 07:16:22 -07:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-29 10:03:20 -07:00
|
|
|
|
public void Read( long start, int length, out double[] left, out double[] right ) {
|
|
|
|
|
left = new double[length];
|
|
|
|
|
right = new double[length];
|
|
|
|
|
if ( !m_opened ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
long 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 Read( long start, int length, out float[] left, out float[] right ) {
|
2009-06-25 07:16:22 -07:00
|
|
|
|
left = new float[length];
|
|
|
|
|
right = new float[length];
|
|
|
|
|
if ( !m_opened ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-07-29 10:03:20 -07:00
|
|
|
|
long loc = 0x2e + m_byte_per_sample * m_channel * start;
|
2009-06-25 07:16:22 -07:00
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-29 10:03:20 -07:00
|
|
|
|
public unsafe void Read( long start, int length, out IntPtr ptr_left, out IntPtr ptr_right ) {
|
2009-06-25 07:16:22 -07:00
|
|
|
|
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;
|
|
|
|
|
}
|
2009-07-29 10:03:20 -07:00
|
|
|
|
long loc = 0x2e + m_byte_per_sample * m_channel * start;
|
2009-06-25 07:16:22 -07:00
|
|
|
|
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();
|
2009-07-29 10:03:20 -07:00
|
|
|
|
m_stream = null;
|
2009-06-25 07:16:22 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~WaveReader() {
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|