マイク → speexエンコーダ → speexデコーダ → スピーカー
だけの。
speexエンコーダ、speexデコーダ無しだと問題ないところ、ありにすると、
なんか高音のノイズが入るのはなぜ?
speex-devのMLに質問中。。。
コードはこんな
#include "stdafx.h"
#include <queue>
#include <iostream>
#include <portaudio .h> #include <speex /speex.h>
#include </speex><speex /speex_callbacks.h>
#define USE_SPEEX
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (256)
#define NUM_SECONDS (10)
//#define NUM_CHANNELS (2)
#define NUM_CHANNELS (1) // try mono first
/* #define DITHER_FLAG (paDitherOff) */
#define DITHER_FLAG (0) /**/
/* Select sample format. */
#define PA_SAMPLE_TYPE paFloat32
typedef float SAMPLE;
#define SAMPLE_SILENCE (0.0f)
#define PRINTF_S_FORMAT "%.8f"
typedef struct {
int frameIndex; /* Index into sample array. */
int maxFrameIndex;
std::queue
<sample> qu_microphone;
std::queue<char> qu_speex;
std::queue
<sample> qu_speaker;
} paTestData;
// speex globals
SpeexBits encoder_bits;
SpeexBits decoder_bits;
void *encoder_state;
void *decoder_state;
unsigned int speex_frame_size; // 320 or 640 or ..
unsigned int speex_packet_size = 74; // 74 or something
/* This routine will be called by the PortAudio engine when audio is needed.
** It may be called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int echo( const void *inputBuffer,
void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData
)
{
paTestData *data = (paTestData*)userData;
const SAMPLE *rptr = (const SAMPLE*)inputBuffer;
SAMPLE *wptr = (SAMPLE*)outputBuffer;
#ifdef USE_SPEEX
std::queue</sample> <sample>& qu_microphone = data->qu_microphone;
std::queue<char>& qu_speex = data->qu_speex;
std::queue
<sample>& qu_speaker = data->qu_speaker;
#else
std::queue</sample> <sample>& qu_microphone = data->qu_microphone;
//std::queue<char>& qu_speex = data->qu_speex;
std::queue
<sample>& qu_speaker = data->qu_microphone; // point at the same queue, to feed the speaker what we got from the microphone
#endif
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
if( framesLeft < framesPerBuffer ) {
framesToCalc = framesLeft;
finished = paComplete;
}
else {
framesToCalc = framesPerBuffer;
finished = paContinue;
}
// process input from mic
if( rptr == 0 ) {
}
else {
for( i=0; i<framesToCalc; i++ ) {
qu_microphone.push( *rptr++ );
if ( NUM_CHANNELS == 2 ) {
qu_microphone.push( *rptr++ );
}
}
}
#ifdef USE_SPEEX
// speex encoder
while ( qu_microphone.size() > speex_frame_size ) {
float input[1000];
char encoded[1000];
for ( unsigned int i=0; i<speex_frame_size ; i++ ) {
input[i] = qu_microphone.front(); qu_microphone.pop();
}
speex_bits_reset( &encoder_bits );
speex_encode( encoder_state, input, &encoder_bits );
speex_packet_size = speex_bits_write( &encoder_bits, encoded, 1000 );
for ( unsigned int i=0; i<speex_packet_size; i++ ) {
qu_speex.push( encoded[i] );
}
}
// speex decoder
while ( qu_speex.size() >= speex_packet_size ) {
float output[1000];
char encoded[1000];
int nbBytes = speex_packet_size;
for ( int i=0; i<nbbytes ; i++ ) {
encoded[i] = qu_speex.front(); qu_speex.pop();
}
speex_bits_read_from( &decoder_bits, encoded, nbBytes );
speex_decode( decoder_state, &decoder_bits, output );
for ( unsigned int i=0; i<speex_frame_size; i++ ) {
qu_speaker.push( output[i] );
}
}
#endif
// pop to speaker
for( i=0; i<framesToCalc; i++ ) {
if ( qu_speaker.size() > 0 ) {
*wptr++ = qu_speaker.front(); qu_speaker.pop();
}
else {
*wptr++ = SAMPLE_SILENCE;
}
if( NUM_CHANNELS == 2 ) {
if ( qu_speaker.size() > 0 ) {
*wptr++ = qu_speaker.front(); qu_speaker.pop();
}
else {
*wptr++ = SAMPLE_SILENCE;
}
}
}
data->frameIndex += framesToCalc;
return finished;
}
/*******************************************************************/
int main(void)
{
PaStreamParameters inputParameters,
outputParameters;
PaStream* stream;
PaError err = paNoError;
int totalFrames;
std::cout < < "patest_record.c";
paTestData data;
data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
data.frameIndex = 0;
int numSamples = totalFrames * NUM_CHANNELS;
int numBytes = numSamples * sizeof(SAMPLE);
int tmp;
// encoder
encoder_state = speex_encoder_init( speex_lib_get_mode(SPEEX_MODEID_UWB) );
tmp=0;
speex_encoder_ctl(encoder_state, SPEEX_SET_VBR, &tmp);
tmp=8;
speex_encoder_ctl(encoder_state, SPEEX_SET_QUALITY, &tmp); // 8: 27,800[bps]
tmp=3;
speex_encoder_ctl(encoder_state, SPEEX_SET_COMPLEXITY, &tmp);
// 320[samples] = 20ms? according to http://www.speex.org/docs/manual/speex-manual/node7.html
speex_encoder_ctl( encoder_state, SPEEX_GET_FRAME_SIZE, &speex_frame_size );
speex_bits_init( &encoder_bits );
// decoder
decoder_state = speex_decoder_init( speex_lib_get_mode(SPEEX_MODEID_UWB) );
SpeexCallback callback;
callback.callback_id = SPEEX_INBAND_CHAR;
callback.func = speex_std_char_handler;
callback.data = stderr;
speex_decoder_ctl(decoder_state, SPEEX_SET_HANDLER, &callback);
tmp=1;
speex_decoder_ctl(decoder_state, SPEEX_SET_ENH, &tmp);
speex_bits_init( &decoder_bits );
err = Pa_Initialize();
if( err != paNoError ) goto done;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = NUM_CHANNELS; /* stereo input */
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = 0;
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
if (outputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default output device.\n");
goto done;
}
outputParameters.channelCount = NUM_CHANNELS; /* stereo output */
outputParameters.sampleFormat = PA_SAMPLE_TYPE;
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
outputParameters.hostApiSpecificStreamInfo = 0;
/* start echo ----------------------------- */
err = Pa_OpenStream(
&stream,
&inputParameters,
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
echo,
&data );
if( err != paNoError ) goto done;
err = Pa_StartStream( stream );
if( err != paNoError ) goto done;
printf("Now recording!!\n"); fflush(stdout);
while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
{
Pa_Sleep(1000);
printf("index = %d\n", data.frameIndex ); fflush(stdout);
}
if( err < 0 ) goto done;
err = Pa_CloseStream( stream );
if( err != paNoError ) goto done;
done:
// destruct speex
speex_encoder_destroy( encoder_state );
speex_bits_destroy( &encoder_bits );
speex_decoder_destroy( decoder_state );
speex_bits_destroy( &decoder_bits );
Pa_Terminate();
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
err = 1; /* Always return 0 or 1, but no other return codes. */
}
return err;
}
</speex_frame_size>