maaash.jp

what I create

speex+portaudioを使ったechoアプリを書いてみた

マイク → speexエンコーダ → speexデコーダ → スピーカー
だけの。
speexエンコーダ、speexデコーダ無しだと問題ないところ、ありにすると、
なんか高音のノイズが入るのはなぜ?

speex-devのMLに質問中。。。

コードはこんな
[cpp]

include “stdafx.h”

include

include

include #include

include

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
qu_microphone;
std::queue qu_speex;
std::queue
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 & qu_microphone = data->qu_microphone;
std::queue& qu_speex = data->qu_speex;
std::queue
& qu_speaker = data->qu_speaker;

else

std::queue & qu_microphone = data->qu_microphone;
//std::queue& qu_speex = data->qu_speex;
std::queue
& 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;
}

[/cpp]</speex_frame_size>

Comments