# HG changeset patch # User Chris Cannam # Date 1158837439 0 # Node ID e3b32dc5180b283448ee95620ccf070ddaf3fb6a # Parent 37af203dbd151f0f9ce78a23383fa63c04e41fb3 * Make resampler quality configurable * Fall back to linear resampling when playing very fast * Switch off transient detection in time stretcher when playing very very fast diff -r 37af203dbd15 -r e3b32dc5180b audioio/AudioCallbackPlaySource.cpp --- a/audioio/AudioCallbackPlaySource.cpp Thu Sep 21 09:43:41 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Thu Sep 21 11:17:19 2006 +0000 @@ -20,6 +20,7 @@ #include "data/model/Model.h" #include "view/ViewManager.h" #include "base/PlayParameterRepository.h" +#include "base/Preferences.h" #include "data/model/DenseTimeValueModel.h" #include "data/model/SparseOneDimensionalModel.h" #include "PhaseVocoderTimeStretcher.h" @@ -53,7 +54,9 @@ m_outputRight(0.0), m_timeStretcher(0), m_fillThread(0), - m_converter(0) + m_converter(0), + m_crapConverter(0), + m_resampleQuality(Preferences::getInstance()->getResampleQuality()) { m_viewManager->setAudioPlaySource(this); @@ -67,6 +70,10 @@ connect(PlayParameterRepository::getInstance(), SIGNAL(playParametersChanged(PlayParameters *)), this, SLOT(playParametersChanged(PlayParameters *))); + + connect(Preferences::getInstance(), + SIGNAL(propertyChanged(PropertyContainer::PropertyName)), + this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); } AudioCallbackPlaySource::~AudioCallbackPlaySource() @@ -168,7 +175,9 @@ if (buffersChanged || srChanged) { if (m_converter) { src_delete(m_converter); + src_delete(m_crapConverter); m_converter = 0; + m_crapConverter = 0; } } @@ -202,7 +211,9 @@ if (m_models.empty()) { if (m_converter) { src_delete(m_converter); + src_delete(m_crapConverter); m_converter = 0; + m_crapConverter = 0; } m_sourceSampleRate = 0; } @@ -232,7 +243,9 @@ if (m_converter) { src_delete(m_converter); + src_delete(m_crapConverter); m_converter = 0; + m_crapConverter = 0; } m_lastModelEndFrame = 0; @@ -322,8 +335,10 @@ } } if (m_converter) src_reset(m_converter); + if (m_crapConverter) src_reset(m_crapConverter); } else { if (m_converter) src_reset(m_converter); + if (m_crapConverter) src_reset(m_crapConverter); m_readBufferFill = m_writeBufferFill = startFrame; } m_mutex.unlock(); @@ -374,6 +389,14 @@ } void +AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n) +{ + if (n == "Resample Quality") { + setResampleQuality(Preferences::getInstance()->getResampleQuality()); + } +} + +void AudioCallbackPlaySource::setTargetBlockSize(size_t size) { // std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; @@ -538,29 +561,84 @@ AudioCallbackPlaySource::setTargetSampleRate(size_t sr) { m_targetSampleRate = sr; + initialiseConverter(); +} + +void +AudioCallbackPlaySource::initialiseConverter() +{ + m_mutex.lock(); + + if (m_converter) { + src_delete(m_converter); + src_delete(m_crapConverter); + m_converter = 0; + m_crapConverter = 0; + } if (getSourceSampleRate() != getTargetSampleRate()) { int err = 0; - m_converter = src_new(SRC_SINC_BEST_QUALITY, + + m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY : + m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY : + m_resampleQuality == 0 ? SRC_SINC_FASTEST : + SRC_SINC_MEDIUM_QUALITY, getTargetChannelCount(), &err); - if (!m_converter) { + + if (m_converter) { + m_crapConverter = src_new(SRC_LINEAR, + getTargetChannelCount(), + &err); + } + + if (!m_converter || !m_crapConverter) { std::cerr << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " << src_strerror(err) << std::endl; + if (m_converter) { + src_delete(m_converter); + m_converter = 0; + } + + if (m_crapConverter) { + src_delete(m_crapConverter); + m_crapConverter = 0; + } + + m_mutex.unlock(); + emit sampleRateMismatch(getSourceSampleRate(), getTargetSampleRate(), false); } else { + m_mutex.unlock(); + emit sampleRateMismatch(getSourceSampleRate(), getTargetSampleRate(), true); } + } else { + m_mutex.unlock(); } } +void +AudioCallbackPlaySource::setResampleQuality(int q) +{ + if (q == m_resampleQuality) return; + m_resampleQuality = q; + +#ifdef DEBUG_AUDIO_PLAY_SOURCE + std::cerr << "AudioCallbackPlaySource::setResampleQuality: setting to " + << m_resampleQuality << std::endl; +#endif + + initialiseConverter(); +} + size_t AudioCallbackPlaySource::getTargetSampleRate() const { @@ -894,8 +972,17 @@ data.src_ratio = ratio; data.end_of_input = 0; - int err = src_process(m_converter, &data); -// size_t toCopy = size_t(work * ratio + 0.1); + int err = 0; + + if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { +#ifdef DEBUG_AUDIO_PLAY_SOURCE + std::cerr << "Using crappy converter" << std::endl; +#endif + src_process(m_crapConverter, &data); + } else { + src_process(m_converter, &data); + } + size_t toCopy = size_t(got * ratio + 0.1); if (err) { diff -r 37af203dbd15 -r e3b32dc5180b audioio/AudioCallbackPlaySource.h --- a/audioio/AudioCallbackPlaySource.h Thu Sep 21 09:43:41 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.h Thu Sep 21 11:17:19 2006 +0000 @@ -18,6 +18,7 @@ #include "base/RingBuffer.h" #include "base/AudioPlaySource.h" +#include "base/PropertyContainer.h" #include "base/Scavenger.h" #include @@ -177,8 +178,20 @@ */ size_t getSourceSamples(size_t count, float **buffer); + /** + * Set the time stretcher factor (i.e. playback speed). Also + * specify whether the time stretcher will be variable rate + * (sharpening transients), and whether time stretching will be + * carried out on data mixed down to mono for speed. + */ void setTimeStretch(float factor, bool sharpen, bool mono); + /** + * Set the resampler quality, 0 - 2 where 0 is fastest and 2 is + * highest quality. + */ + void setResampleQuality(int q); + signals: void modelReplaced(); @@ -191,6 +204,7 @@ void playLoopModeChanged(); void playSelectionModeChanged(); void playParametersChanged(PlayParameters *); + void preferenceChanged(PropertyContainer::PropertyName); protected: ViewManager *m_viewManager; @@ -274,6 +288,9 @@ QWaitCondition m_condition; AudioCallbackPlaySourceFillThread *m_fillThread; SRC_STATE *m_converter; + SRC_STATE *m_crapConverter; // for use when playing very fast + int m_resampleQuality; + void initialiseConverter(); }; #endif diff -r 37af203dbd15 -r e3b32dc5180b audioio/PhaseVocoderTimeStretcher.cpp --- a/audioio/PhaseVocoderTimeStretcher.cpp Thu Sep 21 09:43:41 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.cpp Thu Sep 21 11:17:19 2006 +0000 @@ -38,7 +38,6 @@ m_mutex(new QMutex()) { initialise(); - } PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher() @@ -144,7 +143,7 @@ } else { m_n1 = 256; } - if (m_sharpen) { + if (shouldSharpen()) { m_wlen = 2048; } m_n2 = lrintf(m_n1 * m_ratio); @@ -158,7 +157,7 @@ } else { m_n2 = 256; } - if (m_sharpen) { + if (shouldSharpen()) { if (m_wlen < 2048) m_wlen = 2048; } m_n1 = lrintf(m_n2 / m_ratio); @@ -318,11 +317,12 @@ writable = std::min(writable, samples - consumed); if (writable == 0) { - //!!! then what? I don't think this should happen, but +#ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER std::cerr << "WARNING: PhaseVocoderTimeStretcher::putInput: writable == 0 (inbuf has " << m_inbuf[0]->getReadSpace() << " samples available for reading, space for " << m_inbuf[0]->getWriteSpace() << " more)" << std::endl; +#endif if (m_inbuf[0]->getReadSpace() < m_wlen || m_outbuf[0]->getWriteSpace() < m_n2) { - std::cerr << "Outbuf has space for " << m_outbuf[0]->getWriteSpace() << " (n2 = " << m_n2 << "), won't be able to process" << std::endl; + std::cerr << "WARNING: PhaseVocoderTimeStretcher::putInput: Inbuf has " << m_inbuf[0]->getReadSpace() << ", outbuf has space for " << m_outbuf[0]->getWriteSpace() << " (n2 = " << m_n2 << ", wlen = " << m_wlen << "), won't be able to process" << std::endl; break; } } else { @@ -354,7 +354,7 @@ } bool transient = false; - if (m_sharpen) transient = isTransient(); + if (shouldSharpen()) transient = isTransient(); size_t n2 = m_n2; @@ -380,9 +380,11 @@ n2 = lrintf(idealSquashy / squashyCount); +#ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER if (n2 != m_n2) { std::cerr << m_n2 << " -> " << n2 << std::endl; } +#endif } for (size_t c = 0; c < m_channels; ++c) { diff -r 37af203dbd15 -r e3b32dc5180b audioio/PhaseVocoderTimeStretcher.h --- a/audioio/PhaseVocoderTimeStretcher.h Thu Sep 21 09:43:41 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.h Thu Sep 21 11:17:19 2006 +0000 @@ -143,6 +143,10 @@ void calculateParameters(); void cleanup(); + bool shouldSharpen() { + return m_sharpen && (m_ratio > 0.25); + } + size_t m_sampleRate; size_t m_channels; size_t m_maxOutputBlockSize; diff -r 37af203dbd15 -r e3b32dc5180b main/PreferencesDialog.cpp --- a/main/PreferencesDialog.cpp Thu Sep 21 09:43:41 2006 +0000 +++ b/main/PreferencesDialog.cpp Thu Sep 21 11:17:19 2006 +0000 @@ -94,6 +94,20 @@ connect(frequency, SIGNAL(valueChanged(double)), this, SLOT(tuningFrequencyChanged(double))); + QComboBox *resampleQuality = new QComboBox; + + int rsq = prefs->getPropertyRangeAndValue("Resample Quality", &min, &max); + m_resampleQuality = rsq; + + for (i = min; i <= max; ++i) { + resampleQuality->addItem(prefs->getPropertyValueLabel("Resample Quality", i)); + } + + resampleQuality->setCurrentIndex(rsq); + + connect(resampleQuality, SIGNAL(currentIndexChanged(int)), + this, SLOT(resampleQualityChanged(int))); + int row = 0; subgrid->addWidget(new QLabel(tr("%1:").arg(prefs->getPropertyLabel @@ -106,6 +120,11 @@ row, 0); subgrid->addWidget(frequency, row++, 1, 1, 2); + subgrid->addWidget(new QLabel(tr("%1:").arg(prefs->getPropertyLabel + ("Resample Quality"))), + row, 0); + subgrid->addWidget(resampleQuality, row++, 1, 1, 2); + subgrid->addWidget(new QLabel(prefs->getPropertyLabel ("Smooth Spectrogram")), row, 0, 1, 2); @@ -168,6 +187,13 @@ } void +PreferencesDialog::resampleQualityChanged(int q) +{ + m_resampleQuality = q; + m_applyButton->setEnabled(true); +} + +void PreferencesDialog::okClicked() { applyClicked(); @@ -183,6 +209,7 @@ prefs->setPropertyBoxLayout(Preferences::PropertyBoxLayout (m_propertyLayout)); prefs->setTuningFrequency(m_tuningFrequency); + prefs->setResampleQuality(m_resampleQuality); m_applyButton->setEnabled(false); } diff -r 37af203dbd15 -r e3b32dc5180b main/PreferencesDialog.h --- a/main/PreferencesDialog.h Thu Sep 21 09:43:41 2006 +0000 +++ b/main/PreferencesDialog.h Thu Sep 21 11:17:19 2006 +0000 @@ -36,6 +36,7 @@ void smoothSpectrogramChanged(int state); void propertyLayoutChanged(int layout); void tuningFrequencyChanged(double freq); + void resampleQualityChanged(int quality); void okClicked(); void applyClicked(); @@ -49,6 +50,7 @@ bool m_smoothSpectrogram; int m_propertyLayout; float m_tuningFrequency; + int m_resampleQuality; }; #endif