lipsync/trunk/Boare.Lib.Media/WaveReader.cs

284 lines
10 KiB
C#

/*
* 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();
}
}
}