speex+portaudioを使ったechoアプリを書いてみた
Posted on 10月 18, 2008
Filed Under speex, portaudio |
マイク → speexエンコーダ → speexデコーダ → スピーカー
だけの。
speexエンコーダ、speexデコーダ無しだと問題ないところ、ありにすると、
なんか高音のノイズが入るのはなぜ?
speex-devのMLに質問中。。。
コードはこんな
C++:
-
#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;
-
}
Comments
2 Responses to “speex+portaudioを使ったechoアプリを書いてみた”
Leave a Reply
Franchement GG meme nous on sais pas pourquoi sa bipos
Salut,
Je sais aps si tu comprendras ce message mais au pire google trad le fera a peu pres bien.
Si sa bip c’est a cause de l’offset multiplexé.
En effet ton encoder_state ne correspond pas a la valeur de l’offset sur la stack.
Et ton decode chie dans le paté.
Coradialement