void DspRate::CreateBackend() { assert(m_state != State::Passthrough); assert(m_inputRate > 0); assert(m_outputRate > 0); assert(m_channels > 0); if (m_state == State::Variable) { assert(!m_soxrv); auto ioSpec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I); auto qualitySpec = soxr_quality_spec(SOXR_HQ, SOXR_VR); m_soxrv = soxr_create(m_inputRate * 2, m_outputRate, m_channels, nullptr, &ioSpec, &qualitySpec, nullptr); soxr_set_io_ratio(m_soxrv, (double)m_inputRate / m_outputRate, 0); m_variableInputFrames = 0; m_variableOutputFrames = 0; m_variableDelay = 0; } else if (m_state == State::Constant) { assert(m_inputRate != m_outputRate); assert(!m_soxrc); auto ioSpec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I); auto qualitySpec = soxr_quality_spec(SOXR_HQ, 0); m_soxrc = soxr_create(m_inputRate, m_outputRate, m_channels, nullptr, &ioSpec, &qualitySpec, nullptr); } }
VarRateResample::VarRateResample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor) : Resample() { this->SetMethod(useBestMethod); soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR); mHandle = (void *)soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0); }
ConstRateResample::ConstRateResample(const bool useBestMethod, const double dFactor) : Resample() { this->SetMethod(useBestMethod); soxr_quality_spec_t q_spec = soxr_quality_spec("\0\1\4\6"[mMethod], 0); mHandle = (void *)soxr_create(1, dFactor, 1, 0, 0, &q_spec, 0); }
static struct ResampleContext *create(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, double precision, int cheby){ soxr_error_t error; soxr_datatype_t type = format == AV_SAMPLE_FMT_S16P? SOXR_INT16_S : format == AV_SAMPLE_FMT_S16 ? SOXR_INT16_I : format == AV_SAMPLE_FMT_S32P? SOXR_INT32_S : format == AV_SAMPLE_FMT_S32 ? SOXR_INT32_I : format == AV_SAMPLE_FMT_FLTP? SOXR_FLOAT32_S : format == AV_SAMPLE_FMT_FLT ? SOXR_FLOAT32_I : format == AV_SAMPLE_FMT_DBLP? SOXR_FLOAT64_S : format == AV_SAMPLE_FMT_DBL ? SOXR_FLOAT64_I : (soxr_datatype_t)-1; soxr_io_spec_t io_spec = soxr_io_spec(type, type); soxr_quality_spec_t q_spec = soxr_quality_spec((int)((precision-2)/4), (SOXR_HI_PREC_CLOCK|SOXR_ROLLOFF_NONE)*!!cheby); q_spec.precision = linear? 0 : precision; #if !defined SOXR_VERSION /* Deprecated @ March 2013: */ q_spec.bw_pc = cutoff? FFMAX(FFMIN(cutoff,.995),.8)*100 : q_spec.bw_pc; #else q_spec.passband_end = cutoff? FFMAX(FFMIN(cutoff,.995),.8) : q_spec.passband_end; #endif soxr_delete((soxr_t)c); c = (struct ResampleContext *) soxr_create(in_rate, out_rate, 0, &error, &io_spec, &q_spec, 0); if (!c) av_log(NULL, AV_LOG_ERROR, "soxr_create: %s\n", error); return c; }
Resample::Resample(const bool useBestMethod, const double dMinFactor, const double dMaxFactor) { this->SetMethod(useBestMethod); soxr_quality_spec_t q_spec; if (dMinFactor == dMaxFactor) { mbWantConstRateResampling = true; // constant rate resampling q_spec = soxr_quality_spec("\0\1\4\6"[mMethod], 0); } else { mbWantConstRateResampling = false; // variable rate resampling q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR); } mHandle = (void *)soxr_create(1, dMinFactor, 1, 0, 0, &q_spec, 0); }
AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float volume, const float stretchFactor, const glm::vec3 position) { if (soundUrl.isEmpty()) { return NULL; } auto soundCache = DependencyManager::get<SoundCache>(); if (soundCache.isNull()) { return NULL; } SharedSoundPointer sound = soundCache->getSound(QUrl(soundUrl)); if (sound.isNull() || !sound->isReady()) { return NULL; } AudioInjectorOptions options; options.stereo = sound->isStereo(); options.position = position; options.volume = volume; QByteArray samples = sound->getByteArray(); if (stretchFactor == 1.0f) { return playSound(samples, options, NULL); } soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); const int channelCount = sound->isStereo() ? 2 : 1; const int standardRate = AudioConstants::SAMPLE_RATE; const int resampledRate = standardRate * stretchFactor; const int nInputSamples = samples.size() / sizeof(int16_t); const int nOutputSamples = nInputSamples * stretchFactor; QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0'); const int16_t* receivedSamples = reinterpret_cast<const int16_t*>(samples.data()); soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount, receivedSamples, nInputSamples, NULL, reinterpret_cast<int16_t*>(resampled.data()), nOutputSamples, NULL, &spec, &qualitySpec, 0); if (soxError) { qCDebug(audio) << "Unable to resample" << soundUrl << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate; resampled = samples; } return playSound(resampled, options, NULL); }
void BE_ST_InitAudio(void) { g_sdlAudioSubsystemUp = false; g_sdlEmulatedOPLChipReady = false; int inSampleRate = BE_Cross_GetSelectedGameVerSampleRate(); bool doDigitized = (inSampleRate != 0); if (!doDigitized) inSampleRate = OPL_SAMPLE_RATE; if (g_refKeenCfg.sndSubSystem) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { BE_Cross_LogMessage(BE_LOG_MSG_WARNING, "SDL audio system initialization failed,\n%s\n", SDL_GetError()); } else { g_sdlAudioSpec.freq = g_refKeenCfg.sndSampleRate; #ifdef MIXER_SAMPLE_FORMAT_FLOAT g_sdlAudioSpec.format = AUDIO_F32SYS; #elif (defined MIXER_SAMPLE_FORMAT_SINT16) g_sdlAudioSpec.format = AUDIO_S16SYS; #endif g_sdlAudioSpec.channels = 1; // Should be some power-of-two roughly proportional to the sample rate; Using 1024 for 48000Hz. for (g_sdlAudioSpec.samples = 1; g_sdlAudioSpec.samples < g_refKeenCfg.sndSampleRate/64; g_sdlAudioSpec.samples *= 2) { } if (doDigitized) g_sdlAudioSpec.callback = (g_refKeenCfg.sndSampleRate == inSampleRate) ? BEL_ST_Simple_DigiCallBack : BEL_ST_Resampling_DigiCallBack; else g_sdlAudioSpec.callback = ((g_refKeenCfg.sndSampleRate == inSampleRate) || !g_refKeenCfg.oplEmulation) ? BEL_ST_Simple_EmuCallBack : BEL_ST_Resampling_EmuCallBack; g_sdlAudioSpec.userdata = NULL; if (SDL_OpenAudio(&g_sdlAudioSpec, NULL)) { BE_Cross_LogMessage(BE_LOG_MSG_WARNING, "Cannot open SDL audio device,\n%s\n", SDL_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); } else { #ifdef REFKEEN_CONFIG_THREADS g_sdlCallbackMutex = SDL_CreateMutex(); if (!g_sdlCallbackMutex) { BE_Cross_LogMessage(BE_LOG_MSG_ERROR, "Cannot create recursive mutex for SDL audio callback,\n%s\nClosing SDL audio subsystem\n", SDL_GetError()); SDL_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); } else #endif { BE_Cross_LogMessage(BE_LOG_MSG_NORMAL, "Audio subsystem initialized, requested spec: freq %d, format %u, channels %d, samples %u\n", (int)g_sdlAudioSpec.freq, (unsigned int)g_sdlAudioSpec.format, (int)g_sdlAudioSpec.channels, (unsigned int)g_sdlAudioSpec.samples); g_sdlAudioSubsystemUp = true; } } } } // If the audio subsystem is off, let us simulate a byte rate // of 1000Hz (same as SDL_GetTicks() time units) if (!g_sdlAudioSubsystemUp) { g_sdlAudioSpec.freq = doDigitized ? inSampleRate : (NUM_OF_BYTES_FOR_SOUND_CALLBACK_WITH_DISABLED_SUBSYSTEM / sizeof(BE_ST_SndSample_T)); g_sdlAudioSpec.callback = doDigitized ? BEL_ST_Resampling_DigiCallBack : BEL_ST_Resampling_EmuCallBack; return; } if (g_refKeenCfg.oplEmulation) { YM3812Init(1, 3579545, OPL_SAMPLE_RATE); g_sdlEmulatedOPLChipReady = true; } if ((doDigitized || g_sdlEmulatedOPLChipReady) && (g_sdlAudioSpec.freq != inSampleRate)) { // Should allocate this first, for g_sdlSrcData.data_in g_sdlMiscOutNumOfSamples = 2*g_sdlAudioSpec.samples; g_sdlMiscOutSamples = (BE_ST_SndSample_T *)malloc(sizeof(BE_ST_SndSample_T) * g_sdlMiscOutNumOfSamples); if (g_sdlMiscOutSamples == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: Out of memory! (Failed to allocate g_sdlMiscOutSamples.)"); #ifndef REFKEEN_RESAMPLER_NONE if (g_refKeenCfg.useResampler) { #if (!defined REFKEEN_RESAMPLER_LIBRESAMPLE) && (!defined REFKEEN_RESAMPLER_LIBAVCODEC) char errMsg[160]; #endif #if (defined REFKEEN_RESAMPLER_LIBSWRESAMPLE) g_sdlSwrContext = swr_alloc_set_opts( NULL, // allocating a new context AV_CH_LAYOUT_MONO, // out channels layout AV_SAMPLE_FMT_S16, // out format g_sdlAudioSpec.freq, // out rate AV_CH_LAYOUT_MONO, // in channels layout AV_SAMPLE_FMT_S16, // in format inSampleRate, // in rate 0, NULL ); if (g_sdlSwrContext == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: swr_alloc_set_opts failed!"); int error = swr_init(g_sdlSwrContext); if (error != 0) { // av_err2str requires libavutil/libavutil-ffmpeg, so don't convert code to string snprintf(errMsg, sizeof(errMsg), "BE_ST_InitAudio: swr_init failed! Error code: %d", error); BE_ST_ExitWithErrorMsg(errMsg); } #elif (defined REFKEEN_RESAMPLER_LIBAVRESAMPLE) g_sdlAvAudioResampleContext = avresample_alloc_context(); if (g_sdlAvAudioResampleContext == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: avresample_alloc_context failed!"); av_opt_set_int(g_sdlAvAudioResampleContext, "in_channel_layout", AV_CH_LAYOUT_MONO, 0); av_opt_set_int(g_sdlAvAudioResampleContext, "out_channel_layout", AV_CH_LAYOUT_MONO, 0); av_opt_set_int(g_sdlAvAudioResampleContext, "in_sample_rate", inSampleRate, 0); av_opt_set_int(g_sdlAvAudioResampleContext, "out_sample_rate", g_sdlAudioSpec.freq, 0); av_opt_set_int(g_sdlAvAudioResampleContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); av_opt_set_int(g_sdlAvAudioResampleContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); int error = avresample_open(g_sdlAvAudioResampleContext); if (error != 0) { // av_err2str requires libavutil/libavutil-ffmpeg, so don't convert code to string snprintf(errMsg, sizeof(errMsg), "BE_ST_InitAudio: swr_init failed! Error code: %d", error); BE_ST_ExitWithErrorMsg(errMsg); } #elif (defined REFKEEN_RESAMPLER_LIBAVCODEC) avcodec_register_all(); g_sdlAvResampleContext = av_resample_init( g_sdlAudioSpec.freq, // out rate inSampleRate, // in rate 16, // filter length 10, // phase count 0, // linear FIR filter 1.0 // cutoff frequency ); if (g_sdlAvResampleContext == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: av_resample_init failed!"); #elif (defined REFKEEN_RESAMPLER_LIBRESAMPLE) g_sdlResampleFactor = (double)g_sdlAudioSpec.freq/inSampleRate; g_sdlResampleHandle = resample_open(0, g_sdlResampleFactor, g_sdlResampleFactor); if (g_sdlResampleHandle == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: resample_open failed!"); #elif (defined REFKEEN_RESAMPLER_LIBSOXR) soxr_io_spec_t io_spec = soxr_io_spec(SOXR_INT16, SOXR_INT16); soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_LQ, 0); // Default quality spec adds an audible latency for resampling to 8000Hz soxr_error_t error; g_sdlSoxr = soxr_create( inSampleRate, // in rate g_sdlAudioSpec.freq, // out rate 1, // channels &error, &io_spec, &q_spec, NULL // runtime spec ); if (g_sdlSoxr == NULL) { snprintf(errMsg, sizeof(errMsg), "BE_ST_InitAudio: soxr_create failed!\nError: %s", soxr_strerror(error)); BE_ST_ExitWithErrorMsg(errMsg); } #elif (defined REFKEEN_RESAMPLER_LIBSPEEXDSP) int error; g_sdlSpeexResamplerState = speex_resampler_init( 1, // channels inSampleRate, // in rate g_sdlAudioSpec.freq, // out rate 0, // quality in the range 0-10 (10 is higher) &error ); if (g_sdlSpeexResamplerState == NULL) { snprintf(errMsg, sizeof(errMsg), "BE_ST_InitAudio: speex_resampler_init failed! Error code: %d\nError: %s", error, speex_resampler_strerror(error)); BE_ST_ExitWithErrorMsg(errMsg); } #elif (defined REFKEEN_RESAMPLER_LIBSAMPLERATE) int error; g_sdlSrcResampler = src_new(SRC_SINC_FASTEST, 1, &error); if (g_sdlSrcResampler == NULL) { snprintf(errMsg, sizeof(errMsg), "BE_ST_InitAudio: src_new failed!\nError code: %d", error); BE_ST_ExitWithErrorMsg(errMsg); } g_sdlSrcData.data_in = doDigitized ? g_sdlMiscOutSamples : g_sdlALOutSamples; g_sdlSrcData.src_ratio = (double)g_sdlAudioSpec.freq / inSampleRate; #endif } else #endif // REFKEEN_RESAMPLER_NONE { // The sum of all entries should be g_sdlAudioSpec.freq, // "uniformly" distributed over g_sdlALSampleRateConvTable g_sdlSampleRateConvTable = (int *)malloc(sizeof(int) * inSampleRate); if (g_sdlSampleRateConvTable == NULL) BE_ST_ExitWithErrorMsg("BE_ST_InitAudio: Failed to allocate memory for sample rate conversion!"); g_sdlSampleRateConvTableSize = inSampleRate; for (int i = 0; i < inSampleRate; ++i) { // Using uint64_t cause an overflow is possible g_sdlSampleRateConvTable[i] = ((uint64_t)(i+1)*(uint64_t)g_sdlAudioSpec.freq/inSampleRate)-(uint64_t)i*(uint64_t)g_sdlAudioSpec.freq/inSampleRate; } g_sdlSampleRateConvCurrIndex = 0; g_sdlSampleRateConvCounter = 0; } } }
static int Open( vlc_object_t *p_obj, bool b_change_ratio ) { filter_t *p_filter = (filter_t *)p_obj; /* Cannot remix */ if( p_filter->fmt_in.audio.i_channels != p_filter->fmt_out.audio.i_channels ) return VLC_EGENERIC; /* Get SoXR input/output format */ soxr_datatype_t i_itype, i_otype; if( !SoXR_GetFormat( p_filter->fmt_in.audio.i_format, &i_itype ) || !SoXR_GetFormat( p_filter->fmt_out.audio.i_format, &i_otype ) ) return VLC_EGENERIC; filter_sys_t *p_sys = calloc( 1, sizeof( filter_sys_t ) ); if( unlikely( p_sys == NULL ) ) return VLC_ENOMEM; /* Setup SoXR */ int64_t i_vlc_q = var_InheritInteger( p_obj, "soxr-resampler-quality" ); if( i_vlc_q < 0 ) i_vlc_q = 0; else if( i_vlc_q > MAX_SOXR_QUALITY ) i_vlc_q = MAX_SOXR_QUALITY; const unsigned long i_recipe = soxr_resampler_quality_list[i_vlc_q]; const unsigned i_channels = p_filter->fmt_in.audio.i_channels; const double f_ratio = p_filter->fmt_out.audio.i_rate / (double) p_filter->fmt_in.audio.i_rate; p_sys->f_fixed_ratio = f_ratio; soxr_error_t error; /* IO spec */ soxr_io_spec_t io_spec = soxr_io_spec( i_itype, i_otype ); /* Quality spec */ soxr_quality_spec_t q_spec = soxr_quality_spec( i_recipe, 0 ); /* Create SoXR */ p_sys->soxr = soxr_create( 1, f_ratio, i_channels, &error, &io_spec, &q_spec, NULL ); if( error ) { msg_Err( p_filter, "soxr_create failed: %s", soxr_strerror( error ) ); free( p_sys ); return VLC_EGENERIC; } /* Create a 'variable-rate' SoXR if needed: it is slower than the fixed * one, but it will be only used when the input rate is changing (to catch * up a delay). */ if( b_change_ratio ) { q_spec = soxr_quality_spec( SOXR_LQ, SOXR_VR ); p_sys->vr_soxr = soxr_create( 1, f_ratio, i_channels, &error, &io_spec, &q_spec, NULL ); if( error ) { msg_Err( p_filter, "soxr_create failed: %s", soxr_strerror( error ) ); soxr_delete( p_sys->soxr ); free( p_sys ); return VLC_EGENERIC; } soxr_set_io_ratio( p_sys->vr_soxr, 1 / f_ratio, 0 ); } msg_Dbg( p_filter, "Using SoX Resampler with '%s' engine and '%s' quality " "to convert %4.4s/%dHz to %4.4s/%dHz.", soxr_engine( p_sys->soxr ), soxr_resampler_quality_vlctext[i_vlc_q], (const char *)&p_filter->fmt_in.audio.i_format, p_filter->fmt_in.audio.i_rate, (const char *)&p_filter->fmt_out.audio.i_format, p_filter->fmt_out.audio.i_rate ); p_filter->p_sys = p_sys; p_filter->pf_audio_filter = Resample; p_filter->pf_flush = Flush; p_filter->pf_audio_drain = Drain; return VLC_SUCCESS; }
void Resampler::Resample(unsigned int in_channels, unsigned int in_sample_rate, AVSampleFormat in_format, unsigned int in_sample_count, const uint8_t* in_data, unsigned int out_channels, unsigned int out_sample_rate, AVSampleFormat out_format, unsigned int* out_sample_count, const uint8_t** out_data) { Q_ASSERT(in_channels > 0 && out_channels > 0); Q_ASSERT(in_sample_rate > 0 && out_sample_rate > 0); Q_ASSERT(in_channels == out_channels); Q_ASSERT(out_format == AV_SAMPLE_FMT_FLT); if(m_started) { Q_ASSERT(m_out_channels == out_channels); Q_ASSERT(m_out_sample_rate == out_sample_rate); } else { m_started = true; m_in_sample_rate = 0; // trigger creation of new resampler m_out_channels = out_channels; m_out_sample_rate = out_sample_rate; } // prepare output samples unsigned int out_pos = 0; m_out_data.alloc(16 * 1024); // do we need a new resampler? if(in_sample_rate != m_in_sample_rate) { // delete old resampler if(m_soxr != NULL) { // flush resampler for( ; ; ) { size_t out_done; soxr_error_t error = soxr_process(m_soxr, NULL, 0, NULL, m_out_data.data() + out_pos * out_channels * sizeof(float), m_out_data.size() / (out_channels * sizeof(float)) - out_pos, &out_done); if(error != NULL) { Logger::LogError("[Resampler::Resample] " + QObject::tr("Error: Flushing resampler failed! Reason: %s").arg(soxr_strerror(error))); throw SoxrException(); } out_pos += out_done; if(out_pos < m_out_data.size() / (out_channels * sizeof(float))) break; m_out_data.realloc(m_out_data.size() * 2); } soxr_delete(m_soxr); m_soxr = NULL; } m_in_sample_rate = in_sample_rate; // do we really need a resampler? if(m_in_sample_rate != m_out_sample_rate) { Logger::LogInfo("[Resampler::Resampler] " + QObject::tr("Resampling from %1 to %2.").arg(m_in_sample_rate).arg(m_out_sample_rate)); soxr_error_t error; soxr_quality_spec_t quality = soxr_quality_spec(SOXR_MQ, 0); m_soxr = soxr_create((double) m_in_sample_rate, (double) m_out_sample_rate, out_channels, &error, NULL, &quality, NULL); if(m_soxr == NULL || error != NULL) { m_in_sample_rate = 0; Logger::LogError("[Resampler::Resampler] " + QObject::tr("Error: Can't create resampler! Reason: %s").arg(soxr_strerror(error))); throw SoxrException(); } } else { Logger::LogInfo("[Resampler::Resampler] " + QObject::tr("Resampling not needed.")); } } // prepare input samples uint8_t *in_data_float; unsigned int in_pos = 0; if(in_format == AV_SAMPLE_FMT_FLT) { in_data_float = (uint8_t*) in_data; } else if(in_format == AV_SAMPLE_FMT_S16) { m_in_data.alloc(in_sample_count * out_channels * sizeof(float)); SampleCopy(in_sample_count * out_channels, (const int16_t*) in_data, 1, (float*) m_in_data.data(), 1); in_data_float = (uint8_t*) m_in_data.data(); } else { Q_ASSERT(false); // unsupported input format return; } // no resampling needed? if(m_in_sample_rate == m_out_sample_rate) { if(out_pos == 0) { *out_sample_count = in_sample_count; *out_data = in_data_float; } else { m_out_data.realloc((out_pos + in_sample_count) * out_channels * sizeof(float)); memcpy(m_out_data.data() + out_pos * out_channels * sizeof(float), in_data_float, in_sample_count * out_channels * sizeof(float)); *out_sample_count = out_pos + in_sample_count; *out_data = m_out_data.data(); } return; } // resample for( ; ; ) { size_t in_done, out_done; soxr_error_t error = soxr_process(m_soxr, in_data_float + in_pos * out_channels * sizeof(float), in_sample_count - in_pos, &in_done, m_out_data.data() + out_pos * out_channels * sizeof(float), m_out_data.size() / (out_channels * sizeof(float)) - out_pos, &out_done); if(error != NULL) { Logger::LogError("[Resampler::Resample] " + QObject::tr("Error: Resampling failed!")); throw SoxrException(); } in_pos += in_done; out_pos += out_done; if(in_pos == in_sample_count) break; m_out_data.realloc(m_out_data.size() * 2); } *out_sample_count = out_pos; *out_data = m_out_data.data(); }
int main(int n, char const * arg[]) { char const * const arg0 = n? --n, *arg++ : "", * engine = ""; double const irate = n? --n, atof(*arg++) : 96000.; double const orate = n? --n, atof(*arg++) : 44100.; unsigned const chans = n? --n, (unsigned)atoi(*arg++) : 1; soxr_datatype_t const itype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0; unsigned const ospec = n? --n, (soxr_datatype_t)atoi(*arg++) : 0; unsigned long const q_recipe= n? --n, strtoul(*arg++, 0, 16) : SOXR_HQ; unsigned long const q_flags = n? --n, strtoul(*arg++, 0, 16) : 0; double const passband_end = n? --n, atof(*arg++) : 0; double const stopband_begin = n? --n, atof(*arg++) : 0; double const phase_response = n? --n, atof(*arg++) : -1; int const use_threads = n? --n, atoi(*arg++) : 1; soxr_datatype_t const otype = ospec & 3; soxr_quality_spec_t q_spec = soxr_quality_spec(q_recipe, q_flags); soxr_io_spec_t io_spec = soxr_io_spec(itype, otype); soxr_runtime_spec_t const runtime_spec = soxr_runtime_spec(!use_threads); /* Allocate resampling input and output buffers in proportion to the input * and output rates: */ #define buf_total_len 15000 /* In samples per channel. */ size_t const osize = soxr_datatype_size(otype) * chans; size_t const isize = soxr_datatype_size(itype) * chans; size_t const olen0= (size_t)(orate * buf_total_len / (irate + orate) + .5); size_t const olen = min(max(olen0, 1), buf_total_len - 1); size_t const ilen = buf_total_len - olen; void * const obuf = malloc(osize * olen); void * const ibuf = malloc(isize * ilen); size_t odone = 0, clips = 0, omax = 0, i; soxr_error_t error; soxr_t soxr; int32_t seed = 0; char const * e = getenv("SOXR_THROUGHPUT_GAIN"); double gain = e? atof(e) : .5; /* Overrides (if given): */ if (passband_end > 0) q_spec.passband_end = passband_end / 100; if (stopband_begin > 0) q_spec.stopband_begin = stopband_begin / 100; if (phase_response >=0) q_spec.phase_response = phase_response; io_spec.flags = ospec & ~7u; /* Create a stream resampler: */ soxr = soxr_create( irate, orate, chans, /* Input rate, output rate, # of channels. */ &error, /* To report any error during creation. */ &io_spec, &q_spec, &runtime_spec); #define ranqd1(x) ((x) = 1664525 * (x) + 1013904223) /* int32_t x */ #define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */ #define RAND (dranqd1(seed) * gain) #define DURATION_MSECS 125 #define NUM_ATTEMPTS 8 if (!error) { /* If all is well, run the resampler: */ engine = soxr_engine(soxr); switch (itype & 3) { case 0: for (i=0;i<ilen*chans; ((float *)ibuf)[i]=(float )RAND, ++i); break; case 1: for (i=0;i<ilen*chans; ((double *)ibuf)[i]=(double )RAND, ++i); break; case 2: for (i=0;i<ilen*chans; ((int32_t *)ibuf)[i]=rint32(65536.*32768*RAND), ++i); break; case 3: for (i=0;i<ilen*chans; ((int16_t *)ibuf)[i]=rint16( 1.*32768*RAND), ++i); break; } /* Resample in blocks: */ for (i=0; i<NUM_ATTEMPTS; ++i) { size_t itotal = 0, ototal = 0; timerStart(DURATION_MSECS); do { size_t const ilen1 = odone < olen? ilen : 0; error = soxr_process(soxr, ibuf, ilen1, NULL, obuf, olen, &odone); itotal += ilen1; ototal += odone; } while (!error && timerRunning()); omax = max(omax, ototal); } } /* Tidy up: */ clips = *soxr_num_clips(soxr); /* Can occur only with integer output. */ soxr_delete(soxr); free(obuf), free(ibuf); /* Diagnostics: */ fprintf(stderr, "%-26s %s; %lu clips; I/O: %s (%-5s) %.2f Ms/s\n", arg0, soxr_strerror(error), (long unsigned)clips, ferror(stdin) || ferror(stdout)? strerror(errno) : "no error", engine, 1e-6 * k / DURATION_MSECS * chans * (double)omax); return !!error; }