PortAudioでのマイク入力をSpeexでエンコード/デコードしてそのまま鳴らす
この例だとNSpeexが負荷の高いノイズフィルタとしか扱えてないのだけど、検証コードとしては十分。
NSpeexエンコーダのポイントとしては、
- 16bit MONO
- サンプルレート: NB=8KHz, WD=16KHz, UWD=32KHz
- フレームサイズ: NB=160, WD=320, UWD=640
- NSpeex.SpeexEncoder.Encode()の第3引数(inCount)は配列サイズではなくフレームバッファの数を指定する
- PortAudioのFramesPerBufferを1280、NSpeexEncoderでBandMode.Wide(FrameSize=320)に指定している場合は、inCount=4を指定する
class Program { private const double SampleRate = 16000.0; private const int FramesPerBuffer = 320; private short[] paBuffer = new short[FramesPerBuffer]; private byte[] spxBuffer = new byte[FramesPerBuffer]; private SpeexEncoder encorder = new SpeexEncoder(BandMode.Wide); private SpeexDecoder decoder = new SpeexDecoder(BandMode.Wide); private PaStreamCallbackDelegate callback; public Program() { callback = new PaStreamCallbackDelegate(HandleCallback); } public void Run() { Pa_Initialize(); var outputDevice = Pa_GetDefaultInputDevice(); var inputDeviceInfo = (PaDeviceInfo)Marshal.PtrToStructure( Pa_GetDeviceInfo(inputDevice), typeof(PaDeviceInfo)); var outputDevice = Pa_GetDefaultOutputDevice(); var outputDeviceInfo = (PaDeviceInfo)Marshal.PtrToStructure( Pa_GetDeviceInfo(outputDevice), typeof(PaDeviceInfo)); var inParams = new PaStreamParameters() { channelCount = 1, device = inputDevice, sampleFormat = PaSampleFormat.Float32, suggestedLatency = inputDeviceInfo.defaultLowInputLatency, }; var outParams = new PaStreamParameters() { channelCount = 1, device = outputDevice, sampleFormat = PaSampleFormat.Float32, suggestedLatency = outputDeviceInfo.defaultLowInputLatency, }; var stream = IntPtr.Zero; Pa_OpenStream( out stream, ref inParams, ref outParams, SampleRate, FramesPerBuffer, PaStreamFlags.NoFlag, callback, IntPtr.Zero); Pa_StartStream(stream); System.Threading.Thread.Sleep(30000); Pa_StopStream(stream); Pa_Terminate(); } public PaStreamCallbackResult HandleCallback( IntPtr input, IntPtr output, uint frameCount, ref PaStreamCallbackTimeInfo timeInfo, PaStreamCallbackFlags statusFlags, IntPtr userData) { try { // encode Marshal.Copy(input, paBuffer, 0, FramesPerBuffer); var encSize = encorder.Encode(paBuffer, 0, 1, spxBuffer, 0, FramesPerBuffer); // decode var decSize = decoder.Decode(spxBuffer, 0, encSize, paBuffer, 0, false); Marshal.Copy(paBuffer, 0, output, decSize); // decSize = FramesPerBuffer になるはず } catch (Exception e) { Console.WriteLine(e.ToString()); } return PaStreamCallbackResult.paContinue; } // P/Invoke関係のコードは省略 }