void Resampler::initialize() { if(dstSamplesPerSec_ == srcSamplesPerSec_){ convertTypeFunc_ = getConvTypeFunc( dstNumChannels_, dstBytesPerSample_, srcNumChannels_, srcBytesPerSample_); }else{ if(resamplerChannels_ != srcNumChannels_){ destroyResampler(); } if(NULL == resampler_){ resampler_ = speex_resampler_init(srcNumChannels_, srcSamplesPerSec_, dstSamplesPerSec_, SPEEX_RESAMPLER_QUALITY_DEFAULT, NULL); }else{ speex_resampler_set_rate(resampler_, srcSamplesPerSec_, dstSamplesPerSec_); speex_resampler_reset_mem(resampler_); } resampleRate_ = static_cast<f32>(dstSamplesPerSec_)/srcSamplesPerSec_; convertTypeFunc_ = getConvTypeFunc( dstNumChannels_, dstBytesPerSample_, srcNumChannels_, dstBytesPerSample_); } }
void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels) { if (mPlaybackRateTimeline.HasSimpleValue()) { mPlaybackRate = mPlaybackRateTimeline.GetValue(); } else { mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition()); } // Make sure the playback rate and the doppler shift are something // our resampler can work with. if (ComputeFinalOutSampleRate(aStream->SampleRate()) == 0) { mPlaybackRate = 1.0; mDopplerShift = 1.0; } uint32_t currentOutSampleRate, currentInSampleRate; if (ShouldResample(aStream->SampleRate())) { SpeexResamplerState* resampler = Resampler(aStream, aChannels); speex_resampler_get_rate(resampler, ¤tInSampleRate, ¤tOutSampleRate); uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate()); if (currentOutSampleRate != finalSampleRate) { speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate); } } }
static block_t *Resample (filter_t *filter, block_t *in) { SpeexResamplerState *st = (SpeexResamplerState *)filter->p_sys; const size_t framesize = filter->fmt_out.audio.i_bytes_per_frame; const unsigned irate = filter->fmt_in.audio.i_rate; const unsigned orate = filter->fmt_out.audio.i_rate; spx_uint32_t ilen = in->i_nb_samples; spx_uint32_t olen = ((ilen + 2) * orate * UINT64_C(11)) / (irate * UINT64_C(10)); block_t *out = block_Alloc (olen * framesize); if (unlikely(out == NULL)) goto error; speex_resampler_set_rate (st, irate, orate); int err; if (filter->fmt_in.audio.i_format == VLC_CODEC_FL32) err = speex_resampler_process_interleaved_float (st, (float *)in->p_buffer, &ilen, (float *)out->p_buffer, &olen); else err = speex_resampler_process_interleaved_int (st, (int16_t *)in->p_buffer, &ilen, (int16_t *)out->p_buffer, &olen); if (err != 0) { msg_Err (filter, "cannot resample: %s", speex_resampler_strerror (err)); block_Release (out); out = NULL; goto error; } if (ilen < in->i_nb_samples) msg_Err (filter, "lost %"PRIu32" of %u input frames", in->i_nb_samples - ilen, in->i_nb_samples); out->i_buffer = olen * framesize; out->i_nb_samples = olen; out->i_pts = in->i_pts; out->i_length = olen * CLOCK_FREQ / filter->fmt_out.audio.i_rate; error: block_Release (in); return out; }
void Mixer::MixChannel(Channel& channel, uint8* data, int length) { // Do not mix channel if channel is a sound and sound is disabled if (channel.group == MIXER_GROUP_SOUND && !gConfigSound.sound_enabled) { return; } if (channel.source && channel.source->Length() > 0 && !channel.done) { AudioFormat streamformat = channel.source->Format(); int loaded = 0; SDL_AudioCVT cvt; cvt.len_ratio = 1; do { int samplesize = format.channels * format.BytesPerSample(); int samples = length / samplesize; int samplesloaded = loaded / samplesize; double rate = 1; if (format.format == AUDIO_S16SYS) { rate = channel.rate; } int samplestoread = (int)((samples - samplesloaded) * rate); int lengthloaded = 0; if (channel.offset < channel.source->Length()) { bool mustconvert = false; if (MustConvert(*channel.source)) { if (SDL_BuildAudioCVT(&cvt, streamformat.format, streamformat.channels, streamformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { break; } mustconvert = true; } const uint8* datastream = 0; int toread = (int)(samplestoread / cvt.len_ratio) * samplesize; int readfromstream = (channel.source->GetSome(channel.offset, &datastream, toread)); if (readfromstream == 0) { break; } uint8* dataconverted = 0; const uint8* tomix = 0; if (mustconvert) { // tofix: there seems to be an issue with converting audio using SDL_ConvertAudio in the callback vs preconverted, can cause pops and static depending on sample rate and channels if (Convert(cvt, datastream, readfromstream, &dataconverted)) { tomix = dataconverted; lengthloaded = cvt.len_cvt; } else { break; } } else { tomix = datastream; lengthloaded = readfromstream; } bool effectbufferloaded = false; if (rate != 1 && format.format == AUDIO_S16SYS) { int in_len = (int)((double)lengthloaded / samplesize); int out_len = samples; if (!channel.resampler) { channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); } if (readfromstream == toread) { // use buffer lengths for conversion ratio so that it fits exactly speex_resampler_set_rate(channel.resampler, in_len, samples - samplesloaded); } else { // reached end of stream so we cant use buffer length as resampling ratio speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / rate))); } speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); effectbufferloaded = true; tomix = effectbuffer; lengthloaded = (out_len * samplesize); } if (channel.pan != 0.5f && format.channels == 2) { if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } switch (format.format) { case AUDIO_S16SYS: EffectPanS16(channel, (sint16*)effectbuffer, lengthloaded / samplesize); break; case AUDIO_U8: EffectPanU8(channel, (uint8*)effectbuffer, lengthloaded / samplesize); break; } } int mixlength = lengthloaded; if (loaded + mixlength > length) { mixlength = length - loaded; } float volumeadjust = volume; volumeadjust *= (gConfigSound.master_volume / 100.0f); switch (channel.group) { case MIXER_GROUP_SOUND: volumeadjust *= (gConfigSound.sound_volume / 100.0f); // Cap sound volume on title screen so music is more audible if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) { volumeadjust = Math::Min(volumeadjust, 0.75f); } break; case MIXER_GROUP_RIDE_MUSIC: volumeadjust *= (gConfigSound.ride_music_volume / 100.0f); break; } int startvolume = (int)(channel.oldvolume * volumeadjust); int endvolume = (int)(channel.volume * volumeadjust); if (channel.stopping) { endvolume = 0; } int mixvolume = (int)(channel.volume * volumeadjust); if (startvolume != endvolume) { // fade between volume levels to smooth out sound and minimize clicks from sudden volume changes if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } mixvolume = SDL_MIX_MAXVOLUME; // set to max since we are adjusting the volume ourselves int fadelength = mixlength / format.BytesPerSample(); switch (format.format) { case AUDIO_S16SYS: EffectFadeS16((sint16*)effectbuffer, fadelength, startvolume, endvolume); break; case AUDIO_U8: EffectFadeU8((uint8*)effectbuffer, fadelength, startvolume, endvolume); break; } } SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, mixvolume); if (dataconverted) { delete[] dataconverted; } channel.offset += readfromstream; } loaded += lengthloaded; if (channel.loop != 0 && channel.offset >= channel.source->Length()) { if (channel.loop != -1) { channel.loop--; } channel.offset = 0; } } while(loaded < length && channel.loop != 0 && !channel.stopping); channel.oldvolume = channel.volume; channel.oldvolume_l = channel.volume_l; channel.oldvolume_r = channel.volume_r; if (channel.loop == 0 && channel.offset >= channel.source->Length()) { channel.done = true; } } }
static int resample(unsigned char *input, int /*input_avail*/, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate) { int *psrc = (int*)input; int *pdest = (int*)output; int i = 0, j = 0; #ifdef USE_SPEEX spx_uint32_t in_len, out_len; if(Resample == RESAMPLER_SPEEX) { if(spx_state == NULL) { spx_state = speex_resampler_init(2, oldsamplerate, newsamplerate, ResampleQuality, &error); if(spx_state == NULL) { memset(output, 0, output_needed); return 0; } } speex_resampler_set_rate(spx_state, oldsamplerate, newsamplerate); in_len = input_avail / 4; out_len = output_needed / 4; if ((error = speex_resampler_process_interleaved_int(spx_state, (const spx_int16_t *)input, &in_len, (spx_int16_t *)output, &out_len))) { memset(output, 0, output_needed); return input_avail; // number of bytes consumed } return in_len * 4; } #endif #ifdef USE_SRC if(Resample == RESAMPLER_SRC) { // the high quality resampler needs more input than the samplerate ratio would indicate to work properly if (input_avail > output_needed * 3 / 2) input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time if (_src_len < input_avail*2 && input_avail > 0) { if(_src) free(_src); _src_len = input_avail*2; _src = malloc(_src_len); } if (_dest_len < output_needed*2 && output_needed > 0) { if(_dest) free(_dest); _dest_len = output_needed*2; _dest = malloc(_dest_len); } memset(_src,0,_src_len); memset(_dest,0,_dest_len); if(src_state == NULL) { src_state = src_new (ResampleQuality, 2, &error); if(src_state == NULL) { memset(output, 0, output_needed); return 0; } } src_short_to_float_array ((short *) input, _src, input_avail/2); src_data.end_of_input = 0; src_data.data_in = _src; src_data.input_frames = input_avail/4; src_data.src_ratio = (float) newsamplerate / oldsamplerate; src_data.data_out = _dest; src_data.output_frames = output_needed/4; if ((error = src_process (src_state, &src_data))) { memset(output, 0, output_needed); return input_avail; // number of bytes consumed } src_float_to_short_array (_dest, (short *) output, output_needed/2); return src_data.input_frames_used * 4; } #endif // RESAMPLE == TRIVIAL if (newsamplerate >= oldsamplerate) { int sldf = oldsamplerate; int const2 = 2*sldf; int dldf = newsamplerate; int const1 = const2 - 2*dldf; int criteria = const2 - dldf; for (i = 0; i < output_needed/4; i++) { pdest[i] = psrc[j]; if(criteria >= 0) { ++j; criteria += const1; } else criteria += const2; } return j * 4; //number of bytes consumed } // newsamplerate < oldsamplerate, this only happens when speed_factor > 1 for (i = 0; i < output_needed/4; i++) { j = i * oldsamplerate / newsamplerate; pdest[i] = psrc[j]; } return j * 4; //number of bytes consumed }
void Mixer::MixChannel(Channel& channel, uint8* data, int length) { if (channel.stream) { if (!channel.resampler) { channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); } AudioFormat channelformat = *channel.stream->Format(); int loaded = 0; SDL_AudioCVT cvt; cvt.len_ratio = 1; do { int samplesize = format.channels * format.BytesPerSample(); int samples = length / samplesize; int samplesloaded = loaded / samplesize; int samplestoread = (int)ceil((samples - samplesloaded) * channel.rate); int lengthloaded = 0; if (channel.offset < channel.stream->Length()) { bool mustconvert = false; if (MustConvert(*channel.stream)) { if (SDL_BuildAudioCVT(&cvt, channelformat.format, channelformat.channels, channelformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) { break; } mustconvert = true; } const uint8* datastream = 0; int readfromstream = (channel.stream->GetSome(channel.offset, &datastream, (int)(((samplestoread) * samplesize) / cvt.len_ratio)) / channelformat.BytesPerSample()) * channelformat.BytesPerSample(); if (readfromstream == 0) { break; } int volume = channel.volume; uint8* dataconverted = 0; const uint8* tomix = 0; if (mustconvert) { if (Convert(cvt, datastream, readfromstream, &dataconverted)) { tomix = dataconverted; lengthloaded = (cvt.len_cvt / samplesize) * samplesize; } else { break; } } else { tomix = datastream; lengthloaded = readfromstream; } bool effectbufferloaded = false; if (channel.rate != 1 && format.format == AUDIO_S16SYS) { int in_len = (int)(ceil((double)lengthloaded / samplesize)); int out_len = samples + 20; // needs some extra, otherwise resampler sometimes doesn't process all the input samples speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / channel.rate))); speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); effectbufferloaded = true; tomix = effectbuffer; lengthloaded = (out_len * samplesize); } if (channel.pan != 0.5f && format.channels == 2) { if (!effectbufferloaded) { memcpy(effectbuffer, tomix, lengthloaded); effectbufferloaded = true; tomix = effectbuffer; } switch (format.format) { case AUDIO_S16SYS: EffectPanS16(channel, (sint16*)effectbuffer, lengthloaded / samplesize); break; case AUDIO_U8: EffectPanU8(channel, (uint8*)effectbuffer, lengthloaded / samplesize); break; } } int mixlength = lengthloaded; if (loaded + mixlength > length) { mixlength = length - loaded; } SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, volume); if (dataconverted) { delete[] dataconverted; } channel.offset += readfromstream; } loaded += lengthloaded; if (channel.loop != 0 && channel.offset >= channel.stream->Length()) { if (channel.loop != -1) { channel.loop--; } channel.offset = 0; } } while(loaded < length && channel.loop != 0); } }
int main(int argc, char **argv) { CALLGRIND_STOP_INSTRUMENTATION; CALLGRIND_ZERO_STATS; QCoreApplication a(argc, argv); QFile f((argc >= 2) ? argv[1] : "wb_male.wav"); if (! f.open(QIODevice::ReadOnly)) { qFatal("Failed to open file!"); } f.seek(36 + 8); QFile o("output.raw"); if (!(RUNNING_ON_VALGRIND)) if (! o.open(QIODevice::WriteOnly)) qFatal("Failed to open output!"); QFile vf((argc >= 3) ? argv[2] : "verify.raw"); if (! vf.open(QIODevice::ReadOnly)) { qWarning("Failed to open validate file!"); } QDataStream out(&o); QDataStream verify(&vf); const int iFrameSize = 320; QVector<QByteArray> v; while (1) { QByteArray qba = f.read(iFrameSize * 2); if (qba.size() != iFrameSize * 2) break; v.append(qba); } int nframes = v.size(); qWarning("Ready to process %d frames of %d samples", nframes, iFrameSize); QVector<short *> qvInShort; QVector<float *> qvIn; QVector<float *> qvDirect; QVector<float *> qvInterpolate; QVector<float *> qvInterpolateMC; QVector<short *> qvInterpolateShort; QVector<float *> qv8; QVector<float *> qv96; const float sfraq1 = tfreq1 / 16000.0f; float fOutSize1 = iFrameSize * sfraq1; int iOutSize1 = lroundf(fOutSize1); const float sfraq2 = tfreq2 / 16000.0f; float fOutSize2 = iFrameSize * sfraq2; int iOutSize2 = lroundf(fOutSize2); int iOutSize8 = iFrameSize / 2; int iOutSize96 = iFrameSize * 6; if (RUNNING_ON_VALGRIND) nframes = qMin(nframes, 10); QVector<float> fInput(nframes * iFrameSize); QVector<float> fDirect(nframes * iOutSize1); QVector<float> fInterpolate(nframes * iOutSize2); QVector<float> fInterpolateMC(nframes * iOutSize2); QVector<short> sInterpolate(nframes * iOutSize2); QVector<float> f96(nframes * iOutSize96); QVector<float> f8(nframes *iOutSize8); for (int i=0;i<nframes;i++) { short *s = reinterpret_cast<short *>(v[i].data()); float *f = fInput.data() + i * iFrameSize; for (int j=0;j<iFrameSize;j++) f[j]=s[j]+20; qvInShort.append(s); qvIn.append(f); qvDirect.append(fDirect.data() + i * iOutSize1); qvInterpolate.append(fInterpolate.data() + i * iOutSize2); qvInterpolateMC.append(fInterpolateMC.data() + i * iOutSize2); qvInterpolateShort.append(sInterpolate.data() + i * iOutSize2); qv8.append(f8.data() + i * iOutSize8); qv96.append(f96.data() + i * iOutSize96); } int err; SpeexResamplerState *srs1 = speex_resampler_init(1, 16000, lroundf(tfreq1), qual, &err); SpeexResamplerState *srs2 = speex_resampler_init(1, 16000, lroundf(tfreq2), qual, &err); SpeexResamplerState *srs2i = speex_resampler_init(1, 16000, lroundf(tfreq2), qual, &err); SpeexResamplerState *srss = speex_resampler_init(3, 16000, lroundf(tfreq2), qual, &err); SpeexResamplerState *srsto96 = speex_resampler_init(1, 16000, 96000, 5, &err); SpeexResamplerState *srs8to96 = speex_resampler_init(1, 8000, 96000, qual, &err); SpeexResamplerState *srs96to8 = speex_resampler_init(1, 96000, 8000, qual, &err); #ifdef Q_OS_WIN if (!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS)) qWarning("Application: Failed to set priority!"); #endif int len; spx_uint32_t inlen; spx_uint32_t outlen; Timer t; quint64 e; if (! RUNNING_ON_VALGRIND) { #ifndef Q_OS_WIN struct sched_param sp; sp.sched_priority = sched_get_priority_max(SCHED_FIFO); cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(1, &cpuset); if (sched_setscheduler(getpid(), SCHED_FIFO, &sp) != 0) qWarning("No realtime."); if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) qWarning("No mlock."); if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) qWarning("No affinity"); sched_yield(); #endif for (int i=0;i<nframes;++i) { inlen = iFrameSize; outlen = iOutSize96; speex_resampler_process_float(srsto96, 0, qvIn[i], &inlen, qv96[i], &outlen); } QVector<unsigned long long> qvTimes; QPair<unsigned long long, unsigned long long> ci; for (int j=0;j<loops;j++) { t.restart(); for (int i=0;i<nframes;i++) { inlen = iFrameSize; outlen = iOutSize1; speex_resampler_process_float(srs1, 0, qvIn[i], &inlen, qvDirect[i], &outlen); } e = t.elapsed(); qvTimes.append(e); } ci = confint(qvTimes); qWarning("Direct: %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count(), qvTimes.count()); qvTimes.clear(); for (int j=0;j<loops;j++) { t.restart(); for (int i=0;i<nframes;i++) { inlen = iFrameSize; outlen = iOutSize2; speex_resampler_process_float(srs2, 0, qvIn[i], &inlen, qvInterpolate[i], &outlen); } e = t.elapsed(); qvTimes.append(e); } ci = confint(qvTimes); qWarning("Interpolate: %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count()); qvTimes.clear(); for (int j=0;j<loops;j++) { t.restart(); for (int i=0;i<nframes;i++) { inlen = iOutSize96; outlen = iOutSize8; speex_resampler_process_float(srs96to8, 0, qv96[i], &inlen, qv8[i], &outlen); } e = t.elapsed(); qvTimes.append(e); } ci = confint(qvTimes); qWarning("96 => 8: %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count()); qvTimes.clear(); t.restart(); for (int j=0;j<loops;j++) { t.restart(); for (int i=0;i<nframes;i++) { inlen = iOutSize8; outlen = iOutSize96; speex_resampler_process_float(srs8to96, 0, qv8[i], &inlen, qv96[i], &outlen); } e = t.elapsed(); qvTimes.append(e); } ci = confint(qvTimes); qWarning("8 => 96: %8llu +/- %3llu usec (%d)", ci.first, ci.second, qvTimes.count()); speex_resampler_reset_mem(srs1); speex_resampler_reset_mem(srs2); } t.restart(); CALLGRIND_START_INSTRUMENTATION; for (int i=0;i<nframes;i++) { inlen = iFrameSize; outlen = iOutSize1; speex_resampler_process_float(srs1, 0, qvIn[i], &inlen, qvDirect[i], &outlen); inlen = iFrameSize; outlen = iOutSize2; speex_resampler_process_float(srs2, 0, qvIn[i], &inlen, qvInterpolate[i], &outlen); inlen = iFrameSize; outlen = iOutSize2; speex_resampler_process_int(srs2i, 0, qvInShort[i], &inlen, qvInterpolateShort[i], &outlen); inlen = iFrameSize / 4; outlen = iOutSize2 / 4; speex_resampler_process_interleaved_float(srss, qvIn[i], &inlen, qvInterpolateMC[i], &outlen); } e = t.elapsed(); #ifdef Q_OS_WIN if (!SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS)) qWarning("Application: Failed to reset priority!"); #endif const int freq[10] = { 22050, 32000, 11025, 16000, 48000, 41000, 8000, 96000, 11025, 1600 }; QVector<float> fMagic; for (int f=0;f<10;f++) { float fbuff[32767]; speex_resampler_set_rate(srs1, 16000, freq[f]); for (int q = 0;q < 10;q++) { speex_resampler_set_quality(srs1, (3*q) % 7); inlen = iFrameSize; outlen = 32767; speex_resampler_process_float(srs1, 0, qvIn[(f*10+q) % nframes], &inlen, fbuff, &outlen); for (int j=0;j<outlen;j++) fMagic.append(fbuff[j]); } inlen = iFrameSize; outlen = 32767; speex_resampler_process_float(srs1, 0, NULL, &inlen, fbuff, &outlen); for (int j=0;j<outlen;j++) fMagic.append(fbuff[j]); } // Cropped magic test for (int f=0;f<10;f++) { float fbuff[32767]; speex_resampler_set_rate(srs1, 16000, freq[f]); for (int q = 0;q < 10;q++) { speex_resampler_set_quality(srs1, (3*q) % 7); inlen = iFrameSize; outlen = 16; speex_resampler_process_float(srs1, 0, qvIn[(f*10+q) % nframes], &inlen, fbuff, &outlen); for (int j=0;j<outlen;j++) fMagic.append(fbuff[j]); } inlen = iFrameSize; outlen = 32767; speex_resampler_process_float(srs1, 0, NULL, &inlen, fbuff, &outlen); for (int j=0;j<outlen;j++) fMagic.append(fbuff[j]); } CALLGRIND_STOP_INSTRUMENTATION; qWarning("Used %llu usec", e); qWarning("%.2f times realtime", (20000ULL * nframes) / (e * 1.0)); if (! RUNNING_ON_VALGRIND) { QVector<float> vDirect; QVector<float> vInterpolate; QVector<short> vsInterpolate; QVector<float> vMagic; QVector<float> vInterpolateMC; out << fDirect << fInterpolate << sInterpolate << fMagic << fInterpolateMC; if (vf.isOpen()) { verify >> vDirect >> vInterpolate >> vsInterpolate >> vMagic >> vInterpolateMC; double rmsd = veccomp(vDirect, fDirect, "SRS1"); double rmsi = veccomp(vInterpolate, fInterpolate, "SRS2"); veccomp(vsInterpolate, sInterpolate, "SRS2i"); veccomp(vMagic, fMagic, "Magic"); veccomp(vInterpolateMC, fInterpolateMC, "MC"); qWarning("Direct: %g", rmsd); qWarning("Interp: %g", rmsi); } else {
void RtpAudioStream::decode() { if (rtp_packets_.size() < 1) return; // gtk/rtp_player.c:decode_rtp_stream // XXX This is more messy than it should be. gsize resample_buff_len = 0x1000; SAMPLE *resample_buff = (SAMPLE *) g_malloc(resample_buff_len); spx_uint32_t cur_in_rate = 0, visual_out_rate = 0; char *write_buff = NULL; qint64 write_bytes = 0; unsigned channels = 0; unsigned sample_rate = 0; int last_sequence = 0; double rtp_time_prev = 0.0; double arrive_time_prev = 0.0; double pack_period = 0.0; double start_time = 0.0; double start_rtp_time = 0.0; guint32 start_timestamp = 0; size_t decoded_bytes_prev = 0; for (int cur_packet = 0; cur_packet < rtp_packets_.size(); cur_packet++) { SAMPLE *decode_buff = NULL; // XXX The GTK+ UI updates a progress bar here. rtp_packet_t *rtp_packet = rtp_packets_[cur_packet]; stop_rel_time_ = start_rel_time_ + rtp_packet->arrive_offset; speex_resampler_get_rate(visual_resampler_, &cur_in_rate, &visual_out_rate); QString payload_name; if (rtp_packet->info->info_payload_type_str) { payload_name = rtp_packet->info->info_payload_type_str; } else { payload_name = try_val_to_str_ext(rtp_packet->info->info_payload_type, &rtp_payload_type_short_vals_ext); } if (!payload_name.isEmpty()) { payload_names_ << payload_name; } if (cur_packet < 1) { // First packet start_timestamp = rtp_packet->info->info_timestamp; start_rtp_time = 0; rtp_time_prev = 0; last_sequence = rtp_packet->info->info_seq_num - 1; } size_t decoded_bytes = decode_rtp_packet(rtp_packet, &decode_buff, decoders_hash_, &channels, &sample_rate); if (decoded_bytes == 0 || sample_rate == 0) { // We didn't decode anything. Clean up and prep for the next packet. last_sequence = rtp_packet->info->info_seq_num; g_free(decode_buff); continue; } if (audio_out_rate_ == 0) { // First non-zero wins audio_out_rate_ = sample_rate; RTP_STREAM_DEBUG("Audio sample rate is %u", audio_out_rate_); // Prepend silence to match our sibling streams. tempfile_->seek(0); int prepend_samples = (start_rel_time_ - global_start_rel_time_) * audio_out_rate_; if (prepend_samples > 0) { writeSilence(prepend_samples); } } if (rtp_packet->info->info_seq_num != last_sequence+1) { out_of_seq_timestamps_.append(stop_rel_time_); } last_sequence = rtp_packet->info->info_seq_num; double rtp_time = (double)(rtp_packet->info->info_timestamp-start_timestamp)/sample_rate - start_rtp_time; double arrive_time; if (timing_mode_ == RtpTimestamp) { arrive_time = rtp_time; } else { arrive_time = rtp_packet->arrive_offset - start_time; } double diff = qAbs(arrive_time - rtp_time); if (diff*1000 > jitter_buffer_size_ && timing_mode_ != Uninterrupted) { // rtp_player.c:628 jitter_drop_timestamps_.append(stop_rel_time_); RTP_STREAM_DEBUG("Packet drop by jitter buffer exceeded %f > %d", diff*1000, jitter_buffer_size_); /* if there was a silence period (more than two packetization period) resync the source */ if ((rtp_time - rtp_time_prev) > pack_period*2) { int silence_samples; RTP_STREAM_DEBUG("Resync..."); silence_samples = (int)((arrive_time - arrive_time_prev)*sample_rate - decoded_bytes_prev / sample_bytes_); /* Fix for bug 4119/5902: don't insert too many silence frames. * XXX - is there a better thing to do here? */ silence_samples = qMin(silence_samples, max_silence_samples_); writeSilence(silence_samples); silence_timestamps_.append(stop_rel_time_); decoded_bytes_prev = 0; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */ /* XXX: if timestamps (RTP) are missing/ignored try use packet arrive time only (see also "rtp_time") */ start_timestamp = rtp_packet->info->info_timestamp; start_rtp_time = 0; start_time = rtp_packet->arrive_offset; rtp_time_prev = 0; } } else { // rtp_player.c:664 /* Add silence if it is necessary */ int silence_samples; if (timing_mode_ == Uninterrupted) { silence_samples = 0; } else { silence_samples = (int)((rtp_time - rtp_time_prev)*sample_rate - decoded_bytes_prev / sample_bytes_); } if (silence_samples != 0) { wrong_timestamp_timestamps_.append(stop_rel_time_); } if (silence_samples > 0) { /* Fix for bug 4119/5902: don't insert too many silence frames. * XXX - is there a better thing to do here? */ silence_samples = qMin(silence_samples, max_silence_samples_); writeSilence(silence_samples); silence_timestamps_.append(stop_rel_time_); } // XXX rtp_player.c:696 adds audio here. rtp_time_prev = rtp_time; pack_period = (double) decoded_bytes / sample_bytes_ / sample_rate; decoded_bytes_prev = decoded_bytes; arrive_time_prev = arrive_time; } // Write samples to our file. write_buff = (char *) decode_buff; write_bytes = decoded_bytes; if (audio_out_rate_ != sample_rate) { // Resample the audio to match our previous output rate. if (!audio_resampler_) { audio_resampler_ = speex_resampler_init(1, sample_rate, audio_out_rate_, 10, NULL); speex_resampler_skip_zeros(audio_resampler_); RTP_STREAM_DEBUG("Started resampling from %u to (out) %u Hz.", sample_rate, audio_out_rate_); } else { spx_uint32_t audio_out_rate; speex_resampler_get_rate(audio_resampler_, &cur_in_rate, &audio_out_rate); // Adjust rates if needed. if (sample_rate != cur_in_rate) { speex_resampler_set_rate(audio_resampler_, sample_rate, audio_out_rate); speex_resampler_set_rate(visual_resampler_, sample_rate, visual_out_rate); RTP_STREAM_DEBUG("Changed input rate from %u to %u Hz. Out is %u.", cur_in_rate, sample_rate, audio_out_rate_); } } spx_uint32_t in_len = (spx_uint32_t)rtp_packet->info->info_payload_len; spx_uint32_t out_len = (audio_out_rate_ * (spx_uint32_t)rtp_packet->info->info_payload_len / sample_rate) + (audio_out_rate_ % sample_rate != 0); if (out_len * sample_bytes_ > resample_buff_len) { while ((out_len * sample_bytes_ > resample_buff_len)) resample_buff_len *= 2; resample_buff = (SAMPLE *) g_realloc(resample_buff, resample_buff_len); } speex_resampler_process_int(audio_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); write_buff = (char *) decode_buff; write_bytes = out_len * sample_bytes_; } // Write the decoded, possibly-resampled audio to our temp file. tempfile_->write(write_buff, write_bytes); // Collect our visual samples. spx_uint32_t in_len = (spx_uint32_t)rtp_packet->info->info_payload_len; spx_uint32_t out_len = (visual_out_rate * in_len / sample_rate) + (visual_out_rate % sample_rate != 0); if (out_len * sample_bytes_ > resample_buff_len) { while ((out_len * sample_bytes_ > resample_buff_len)) resample_buff_len *= 2; resample_buff = (SAMPLE *) g_realloc(resample_buff, resample_buff_len); } speex_resampler_process_int(visual_resampler_, 0, decode_buff, &in_len, resample_buff, &out_len); for (unsigned i = 0; i < out_len; i++) { packet_timestamps_[stop_rel_time_ + (double) i / visual_out_rate] = rtp_packet->frame_num; if (qAbs(resample_buff[i]) > max_sample_val_) max_sample_val_ = qAbs(resample_buff[i]); visual_samples_.append(resample_buff[i]); } // Finally, write the resampled audio to our temp file and clean up. g_free(decode_buff); } g_free(resample_buff); }
/** * * @param aqi * @param sampleRate * @param sampleSizeInBits * @param channels * @param buffer * @param length the length of <tt>buffer</tt> in bytes */ static void AudioQualityImprovement_resampleInPlay (AudioQualityImprovement *aqi, double sampleRate, unsigned long sampleSizeInBits, int channels, void *buffer, unsigned long length) { spx_uint32_t playSize; spx_uint32_t playCapacity; spx_uint32_t playLength;; spx_int16_t *play; if (sampleRate == aqi->sampleRate) playSize = length; else if (length * aqi->sampleRate == aqi->frameSize * sampleRate) { if (aqi->resampler) { speex_resampler_set_rate( aqi->resampler, (spx_uint32_t) sampleRate, (spx_uint32_t) (aqi->sampleRate)); playSize = aqi->frameSize; } else { aqi->resampler = speex_resampler_init( channels, (spx_uint32_t) sampleRate, (spx_uint32_t) (aqi->sampleRate), SPEEX_RESAMPLER_QUALITY_VOIP, NULL); if (aqi->resampler) playSize = aqi->frameSize; else { aqi->playIsDelaying = JNI_TRUE; aqi->playLength = 0; return; } } } else { /* * The specified buffer neither is in the format of the audio capture * nor can be resampled to it. */ aqi->playIsDelaying = JNI_TRUE; aqi->playLength = 0; return; } /* Ensure that play exists and is large enough. */ playCapacity = ((1 + aqi->playDelay) + 1) * (aqi->frameSize / sizeof(spx_int16_t)); playLength = playSize / sizeof(spx_int16_t); if (playCapacity < playLength) playCapacity = playLength; if (!(aqi->play) || (aqi->playCapacity < playCapacity)) { spx_int16_t *newPlay; newPlay = realloc(aqi->play, playCapacity * sizeof(spx_int16_t)); if (newPlay) { if (!(aqi->play)) { aqi->playIsDelaying = JNI_TRUE; aqi->playLength = 0; } aqi->play = newPlay; aqi->playCapacity = playCapacity; } else { aqi->playIsDelaying = JNI_TRUE; aqi->playLength = 0; return; } } /* Ensure that there is room for buffer in play. */ if (aqi->playLength + playLength > aqi->playCapacity) { aqi->playIsDelaying = JNI_TRUE; aqi->playLength = 0; /* * We don't have enough room in play for buffer which means that we'll * have to throw some samples away. But it'll effectively mean that * we'll enlarge the drift which will disrupt the echo cancellation. So * it seems the least of two evils to just reset the echo cancellation. */ speex_echo_state_reset(aqi->echo); } /* Place buffer in play. */ play = aqi->play + aqi->playLength; if (length == aqi->frameSize) memcpy(play, buffer, playSize); else { unsigned long sampleSizeInBytes = sampleSizeInBits / 8; spx_uint32_t bufferSampleCount = length / sampleSizeInBytes; speex_resampler_process_interleaved_int( aqi->resampler, buffer, &bufferSampleCount, play, &playLength); } aqi->playLength += playLength; /* Take into account the latency. */ if (aqi->playIsDelaying == JNI_TRUE) AudioQualityImprovement_updatePlayIsDelaying(aqi); }