マイク → 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>