$./flite -t "test" frameIndex: 0 maxFrameIndex: 0 numChannels: 1 numSamples: 7225 sampleRate: 8000 === Now playing back. === Waiting for playback to finish. frameIndex in callback: -2008986336 maxFrameIndex in callback: 32655 numChannels in callback: 152579008 numSamples in callback: 0 sampleRate in callback: 0 Segmentation fault: 11 $./flite -t "test" frameIndex: 0 maxFrameIndex: 0 numChannels: 1 numSamples: 7225 sampleRate: 8000 === Now playing back. === Waiting for playback to finish. frameIndex in callback: -71217888 maxFrameIndex in callback: 32712 numChannels in callback: 232979392 numSamples in callback: 0 sampleRate in callback: 0 Segmentation fault: 11
这是audio.c文件中的相关代码,当我提供命令行参数-t时调用它.在进行了一些调试之后,我在playCallback()函数中标记了分段故障发生的兴趣区域.
static int playCallback( const void *inputBuffer,void *outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo* timeInfo,PaStreamCallbackFlags statusFlags,void *userData ) { cst_wave *data = (cst_wave*)userData; short *rptr = &data->samples[data->frameIndex * data->num_channels]; short *wptr = (short*)outputBuffer; unsigned int i; int finished; unsigned int framesLeft = cst_wave_maxFrameIndex(data) - cst_wave_frameIndex(data); (void) inputBuffer; /* Prevent unused variable warnings. */ (void) timeInfo; (void) statusFlags; (void) userData; printf("frameIndex in callback: %d\n",cst_wave_frameIndex(data)); printf("maxFrameIndex in callback: %d\n",cst_wave_maxFrameIndex(data)); printf("numChannels in callback: %d\n",cst_wave_num_channels(data)); printf("numSamples in callback: %d\n",cst_wave_num_samples(data)); printf("sampleRate in callback: %d\n\n",cst_wave_sample_rate(data)); if( framesLeft < framesPerBuffer ) { /* final buffer... */ for( i=0; i<framesLeft; i++ ) { *wptr++ = *rptr++; /* left */ if( cst_wave_num_channels(data) == 2 ) *wptr++ = *rptr++; /* right */ } for( ; i<framesPerBuffer; i++ ) { *wptr++ = 0; /* left */ if( cst_wave_num_channels(data) == 2) *wptr++ = 0; /* right */ } data->frameIndex += framesLeft; finished = paComplete; } else { for( i=0; i<framesPerBuffer; i++ ) { *wptr++ = *rptr++; /* left */ if( cst_wave_num_channels(data) == 2 ) *wptr++ = *rptr++; /* right */ } cst_wave_set_frameIndex(data,framesPerBuffer); finished = paContinue; } return finished; } int play_wave(cst_wave *w) { PaStream* stream; PaStreamParameters outputParameters; cst_wave_set_frameIndex(w,0); cst_wave_set_maxFrameIndex(w,(cst_wave_num_samples(w) / cst_wave_sample_rate(w)) * cst_wave_num_channels(w) * sizeof(short)); int err = 0; err = Pa_Initialize(); outputParameters.device = Pa_GetDefaultOutputDevice(); if (outputParameters.device == paNoDevice) { fprintf(stderr,"Error: No default output device.\n"); return -5; } printf("frameIndex: %d\n",cst_wave_frameIndex(w)); printf("maxFrameIndex: %d\n",cst_wave_maxFrameIndex(w)); printf("numChannels: %d\n",cst_wave_num_channels(w)); printf("numSamples: %d\n",cst_wave_num_samples(w)); printf("sampleRate: %d\n",cst_wave_sample_rate(w)); outputParameters.channelCount = cst_wave_num_channels(w); outputParameters.sampleFormat = paInt16; outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; puts("=== Now playing back. ==="); err = Pa_OpenStream(&stream,NULL,/* no input */ &outputParameters,cst_wave_sample_rate(w),512,paClipOff,playCallback,&w); if( stream ) { err = Pa_StartStream( stream ); if( err != paNoError ) goto done; puts("Waiting for playback to finish."); while((err = Pa_IsStreamActive(stream)) == 1) Pa_Sleep(100); if( err < 0 ) goto done; err = Pa_CloseStream( stream ); if( err != paNoError ) goto done; puts("Done."); } done: Pa_Terminate(); free(cst_wave_samples(w)); }
因为它是相关的,我还稍微修改cst_wave.h中的cst_wave结构,以便它包含我必须存储的数据,以及添加一些已经存在的#define:
typedef struct cst_wave_struct { const char *type; int frameIndex; int maxFrameIndex; int sample_rate; int num_samples; int num_channels; short *samples; } cst_wave; #define cst_wave_num_samples(w) (w?w->num_samples:0) #define cst_wave_num_channels(w) (w?w->num_channels:0) #define cst_wave_sample_rate(w) (w?w->sample_rate:0) #define cst_wave_samples(w) (w->samples) #define cst_wave_frameIndex(w) (w->frameIndex) #define cst_wave_maxFrameIndex(w) (w->maxFrameIndex) #define cst_wave_set_num_samples(w,s) w->num_samples=s #define cst_wave_set_num_channels(w,s) w->num_channels=s #define cst_wave_set_sample_rate(w,s) w->sample_rate=s #define cst_wave_set_frameIndex(w,s) w->frameIndex=s #define cst_wave_set_maxFrameIndex(w,s) w->maxFrameIndex=s
更新1:
按照@Rohan的建议,现在给我这个输出:
$./bin/flite -t "test" frameIndex: 0 maxFrameIndex: 0 numChannels: 1 numSamples: 7225 sampleRate: 8000 === Now playing back. === Waiting for playback to finish. frameIndex in callback: 0 maxFrameIndex in callback: 0 numChannels in callback: 1 numSamples in callback: 7225 sampleRate in callback: 8000 Done. flite(68929,0x7fff71c0d310) malloc: *** error for object 0x7fd6e2809800: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug Abort trap: 6
为了解决这个问题,我删除了free(cst_wave_samples(w));.现在程序执行正常,没有可见的错误,但我的Mac上仍然没有音频输出.有什么建议么?
解决方法
除了之前提到的以外,您还有以下几个问题,我在下面的代码转储中已经解决了所有这些问题.
>次要:你不会一直使用你自己的cst_wave API.
>次要的:我喜欢把我的时间,如果块总是包含{}.这有一个防止神秘错误的习惯.
>最大帧被设置为零.这是因为在(cst_wave_num_samples(w)/ cst_wave_sample_rate(w))* cst_wave_num_channels(w)* sizeof(short)中,您除以采样率,大于您的采样数.假定整数除法是左关联的并截断,yadda yadda yadda为零.
>最大帧仍然是错误的,因为帧包括所有通道样本.因此,帧的数量对于信道的数量和样本本身的大小是不可知的.允许自己猜测,flite将样本误认为是帧,您的最大帧索引只是cst_wave_num_samples(w).否则它将是cst_wave_num_samples(w)/ cst_wave_num_channels(w).
> PortAudio的文档指出,在流变为无效后,您应该调用Pa_StopStream(流),无论您是否等待,直到它变得如此.
>我简化了回调,并对其进行了更正
>次要:一致使用您的API
> MAJOR:Ehm … cst_wave_set_frameIndex(data,framesPerBuffer);肯定是错的你固定在帧索引512而不是递增!这是因为您打开流时要求每个缓冲区512帧,而不是通过framePerBuffer递增帧索引,您将帧索引设置为framesPerBuffer.你没有这么做,因为你的maxFrameIndex是0,所以你退出.我修改它,以便帧索引增加 – 当然你的API.
这是代码,我采取了文件和清洁的自由,直到它接近我的优雅标准.请享用!
#include <stdio.h> #include <string.h> /** * Audio play callback. * * Follows the PaStreamCallback signature,wherein: * * @param input and * @param output are either arrays of interleaved samples or; if * non-interleaved samples were requested using the * paNonInterleaved sample format flag,an array of buffer * pointers,one non-interleaved buffer for each channel. * @param frameCount The number of sample frames to be processed by the * stream callback. * @param timeInfo Timestamps indicating the ADC capture time of the first * sample in the input buffer,the DAC output time of the * first sample in the output buffer and the time the * callback was invoked. See PaStreamCallbackTimeInfo and * Pa_GetStreamTime() * @param statusFlags Flags indicating whether input and/or output buffers * have been inserted or will be dropped to overcome * underflow or overflow conditions. * @param userData The value of a user supplied pointer passed to * Pa_OpenStream() intended for storing synthesis data * etc. */ static int playCallback(const void* inputBuffer,void* outputBuffer,unsigned long framesPerBuffer,PaStreamCallbackFlags statusFlags,void* userData){ (void) inputBuffer; /* Prevent unused variable warnings. */ (void) timeInfo; (void) statusFlags; (void) userData; /** * Compute current processing state. */ cst_wave* data; short* rptr; short* wptr; unsigned int framesLeft,/* Number of frames of data remaining within the stream ***as a whole*** */ frames,/* Number of frames of data to be written for this buffer. */ framesPad,/* Number of frames of padding required within the final buffer. */ samples,/* Number of samples of data to be written for this buffer. */ samplesPad,/* Number of samples of padding required within the final buffer. */ numBytes,/* Number of bytes of data to be written for this buffer. */ numBytesPad;/* Number of bytes of padding required within the final buffer. */ int finalBuffer;/* Stores whether or not this is the final buffer. */ data = (cst_wave*)userData; rptr = &data->samples[cst_wave_frameIndex (data) * cst_wave_num_channels(data)]; wptr = (short*)outputBuffer; framesLeft = cst_wave_maxFrameIndex(data) - cst_wave_frameIndex(data); finalBuffer = framesLeft <= framesPerBuffer; frames = finalBuffer ? framesLeft : framesPerBuffer; framesPad = framesPerBuffer - frames; samples = frames * cst_wave_num_channels(data); samplesPad = framesPad * cst_wave_num_channels(data); numBytes = samples * sizeof(short); numBytesPad = samplesPad * sizeof(short); /** * Debug code. Comment out in production. */ printf("framesLeft in callback: %u\n",framesLeft); printf("framesPerBuffer in callback: %lu\n",framesPerBuffer); printf("frames in callback: %u\n",frames); printf("frameIndex in callback: %d\n",cst_wave_sample_rate(data)); /** * Output data. We handle the final buffer specially,padding it with zeros. */ memcpy(wptr,rptr,numBytes); wptr += samples; rptr += samples; cst_wave_set_frameIndex(data,cst_wave_frameIndex(data) + frames); memset(wptr,numBytesPad); wptr += samplesPad; rptr += samplesPad; /** * Return a completion or continue code depending on whether this was the * final buffer or not respectively. */ return finalBuffer ? paComplete : paContinue; } /** * Play wave function. * * Plays the given cst_wave data as audio,blocking until this is done. */ int play_wave(cst_wave *w){ PaStream* stream; PaStreamParameters outputParameters; int err; /** * Initialize custom fields in cst_wave struct. */ cst_wave_set_frameIndex(w,(cst_wave_num_samples(w))); // / cst_wave_sample_rate(w) * cst_wave_num_channels(w) * sizeof(short) /** * Initialize Port Audio device and stream parameters. */ err = Pa_Initialize(); outputParameters.device = Pa_GetDefaultOutputDevice(); if (outputParameters.device == paNoDevice){ fprintf(stderr,"Error: No default output device.\n"); return -5; } printf("frameIndex: %d\n",cst_wave_sample_rate(w)); outputParameters.channelCount = cst_wave_num_channels(w); outputParameters.sampleFormat = paInt16; outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; /** * Open the stream for playback. */ puts("=== Now playing back. ==="); err = Pa_OpenStream(&stream,w); if(stream){ /** * Start the stream. */ err = Pa_StartStream(stream); if(err != paNoError){ goto done; } /** * Block while it plays. */ puts("Waiting for playback to finish."); while((err = Pa_IsStreamActive(stream)) == 1){ Pa_Sleep(100); } if(err < 0){ goto done; } /** * Stop and close the stream. Both are necessary. */ Pa_StopStream(stream); err = Pa_CloseStream(stream); if(err != paNoError){ goto done; } puts("Done."); } /** * Terminate and leave. */ done: Pa_Terminate(); return 0; }