int Resample::Process(double factor, float *inBuffer, int inBufferLen, bool lastFlag, int *inBufferUsed, float *outBuffer, int outBufferLen) { size_t idone, odone; if (mbWantConstRateResampling) { soxr_process((soxr_t)mHandle, inBuffer , (size_t)(lastFlag? ~inBufferLen : inBufferLen), &idone, outBuffer, (size_t) outBufferLen, &odone); } else { soxr_set_io_ratio((soxr_t)mHandle, 1/factor, 0); inBufferLen = lastFlag? ~inBufferLen : inBufferLen; soxr_process((soxr_t)mHandle, inBuffer , (size_t)inBufferLen , &idone, outBuffer, (size_t)outBufferLen, &odone); } *inBufferUsed = (int)idone; return (int)odone; }
std::pair<size_t, size_t> Resample::Process(double factor, float *inBuffer, size_t inBufferLen, bool lastFlag, float *outBuffer, size_t outBufferLen) { size_t idone, odone; if (mbWantConstRateResampling) { soxr_process(mHandle.get(), inBuffer , (lastFlag? ~inBufferLen : inBufferLen), &idone, outBuffer, outBufferLen, &odone); } else { soxr_set_io_ratio(mHandle.get(), 1/factor, 0); inBufferLen = lastFlag? ~inBufferLen : inBufferLen; soxr_process(mHandle.get(), inBuffer , inBufferLen , &idone, outBuffer, outBufferLen, &odone); } return { idone, odone }; }
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); } }
void DspRate::Process(DspChunk& chunk) { soxr_t soxr = GetBackend(); if (!soxr || chunk.IsEmpty()) return; if (m_state == State::Variable && !m_inStateTransition && m_variableDelay > 0) { uint64_t inputPosition = llMulDiv(m_variableOutputFrames, m_inputRate, m_outputRate, 0); int64_t adjustedFrames = inputPosition + m_variableDelay - m_variableInputFrames; REFERENCE_TIME adjustTime = m_adjustTime - FramesToTimeLong(adjustedFrames, m_inputRate); double ratio = (double)m_inputRate * 4 / (m_outputRate * (4 + (double)adjustTime / OneSecond)); // TODO: decrease jitter soxr_set_io_ratio(m_soxrv, ratio, m_outputRate / 1000); } DspChunk output = ProcessChunk(soxr, chunk); if (m_state == State::Variable) { m_variableInputFrames += chunk.GetFrameCount(); m_variableOutputFrames += output.GetFrameCount(); // soxr_delay() method is not implemented for variable rate conversion yet, // but the delay stays more or less constant and we can calculate it in a roundabout way. if (m_variableDelay == 0 && m_variableOutputFrames > 0) { uint64_t inputPosition = llMulDiv(m_variableOutputFrames, m_inputRate, m_outputRate, 0); m_variableDelay = m_variableInputFrames - inputPosition; } } FinishStateTransition(output, chunk, false); chunk = std::move(output); }
static block_t * Resample( filter_t *p_filter, block_t *p_in ) { filter_sys_t *p_sys = p_filter->p_sys; const vlc_tick_t i_pts = p_in->i_pts; if( p_sys->vr_soxr ) { /* "audio resampler" with variable ratio: use the fixed resampler when * the ratio is the same than the fixed one, otherwise use the variable * resampler. */ soxr_t soxr; block_t *p_flushed_out = NULL, *p_out = NULL; const double f_ratio = p_filter->fmt_out.audio.i_rate / (double) p_filter->fmt_in.audio.i_rate; const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples, f_ratio ); if( f_ratio != p_sys->f_fixed_ratio ) { /* using variable resampler */ soxr_set_io_ratio( p_sys->vr_soxr, 1 / f_ratio, i_olen ); soxr = p_sys->vr_soxr; } else if( f_ratio == 1.0f ) { /* not using any resampler */ soxr = NULL; p_out = p_in; } else { /* using fixed resampler */ soxr = p_sys->soxr; } /* If the new soxr is different than the last one, flush it */ if( p_sys->last_soxr && soxr != p_sys->last_soxr && p_sys->i_last_olen ) { p_flushed_out = SoXR_Resample( p_filter, p_sys->last_soxr, NULL, p_sys->i_last_olen ); if( soxr ) msg_Dbg( p_filter, "Using '%s' engine", soxr_engine( soxr ) ); } if( soxr ) { assert( !p_out ); p_out = SoXR_Resample( p_filter, soxr, p_in, i_olen ); if( !p_out ) goto error; } if( p_flushed_out ) { /* Prepend the flushed output data to p_out */ const unsigned i_nb_samples = p_flushed_out->i_nb_samples + p_out->i_nb_samples; block_ChainAppend( &p_flushed_out, p_out ); p_out = block_ChainGather( p_flushed_out ); if( !p_out ) goto error; p_out->i_nb_samples = i_nb_samples; } p_out->i_pts = i_pts; return p_out; } else { /* "audio converter" with fixed ratio */ const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples, p_sys->f_fixed_ratio ); block_t *p_out = SoXR_Resample( p_filter, p_sys->soxr, p_in, i_olen ); if( p_out ) p_out->i_pts = i_pts; return p_out; } error: block_Release( p_in ); return NULL; }
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; }