diff audio/AudioCallbackPlaySource.cpp @ 548:baa11365ebdd bqaudioio

Merge from branch bqresample
author Chris Cannam
date Wed, 07 Dec 2016 11:51:42 +0000
parents c4391f6c7484
children c732251237b1
line wrap: on
line diff
--- a/audio/AudioCallbackPlaySource.cpp	Wed Dec 07 11:50:54 2016 +0000
+++ b/audio/AudioCallbackPlaySource.cpp	Wed Dec 07 11:51:42 2016 +0000
@@ -23,6 +23,7 @@
 #include "base/Preferences.h"
 #include "data/model/DenseTimeValueModel.h"
 #include "data/model/WaveFileModel.h"
+#include "data/model/ReadOnlyWaveFileModel.h"
 #include "data/model/SparseOneDimensionalModel.h"
 #include "plugin/RealTimePluginInstance.h"
 
@@ -77,9 +78,7 @@
     m_stretcherInputs(0),
     m_stretcherInputSizes(0),
     m_fillThread(0),
-    m_converter(0),
-    m_crapConverter(0),
-    m_resampleQuality(Preferences::getInstance()->getResampleQuality())
+    m_resampler(0)
 {
     m_viewManager->setAudioPlaySource(this);
 
@@ -161,8 +160,8 @@
     bool buffersChanged = false, srChanged = false;
 
     int modelChannels = 1;
-    DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
-    if (dtvm) modelChannels = dtvm->getChannelCount();
+    ReadOnlyWaveFileModel *rowfm = qobject_cast<ReadOnlyWaveFileModel *>(model);
+    if (rowfm) modelChannels = rowfm->getChannelCount();
     if (modelChannels > m_sourceChannelCount) {
 	m_sourceChannelCount = modelChannels;
     }
@@ -178,24 +177,26 @@
 
     } else if (model->getSampleRate() != m_sourceSampleRate) {
 
-        // If this is a dense time-value model and we have no other, we
-        // can just switch to this model's sample rate
+        // If this is a read-only wave file model and we have no
+        // other, we can just switch to this model's sample rate
 
-        if (dtvm) {
+        if (rowfm) {
 
             bool conflicting = false;
 
             for (std::set<Model *>::const_iterator i = m_models.begin();
                  i != m_models.end(); ++i) {
-                // Only wave file models can be considered conflicting --
-                // writable wave file models are derived and we shouldn't
-                // take their rates into account.  Also, don't give any
-                // particular weight to a file that's already playing at
-                // the wrong rate anyway
-                WaveFileModel *wfm = dynamic_cast<WaveFileModel *>(*i);
-                if (wfm && wfm != dtvm &&
-                    wfm->getSampleRate() != model->getSampleRate() &&
-                    wfm->getSampleRate() == m_sourceSampleRate) {
+                // Only read-only wave file models should be
+                // considered conflicting -- writable wave file models
+                // are derived and we shouldn't take their rates into
+                // account.  Also, don't give any particular weight to
+                // a file that's already playing at the wrong rate
+                // anyway
+                ReadOnlyWaveFileModel *other =
+                    qobject_cast<ReadOnlyWaveFileModel *>(*i);
+                if (other && other != rowfm &&
+                    other->getSampleRate() != model->getSampleRate() &&
+                    other->getSampleRate() == m_sourceSampleRate) {
                     SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl;
                     conflicting = true;
                     break;
@@ -229,11 +230,12 @@
     }
 
     if (buffersChanged || srChanged) {
-	if (m_converter) {
-	    src_delete(m_converter);
-            src_delete(m_crapConverter);
-	    m_converter = 0;
-            m_crapConverter = 0;
+	if (m_resampler) {
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+            cerr << "AudioCallbackPlaySource::addModel: Buffers or sample rate changed, deleting existing resampler" << endl;
+#endif
+            delete m_resampler;
+	    m_resampler = 0;
 	}
     }
 
@@ -241,6 +243,8 @@
 
     m_mutex.unlock();
 
+    initialiseResampler();
+    
     m_audioGenerator->setTargetChannelCount(getTargetChannelCount());
 
     if (!m_fillThread) {
@@ -297,11 +301,12 @@
     m_models.erase(model);
 
     if (m_models.empty()) {
-	if (m_converter) {
-	    src_delete(m_converter);
-            src_delete(m_crapConverter);
-	    m_converter = 0;
-            m_crapConverter = 0;
+	if (m_resampler) {
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+            cerr << "AudioCallbackPlaySource::removeModel: No models left, deleting resampler" << endl;
+#endif
+	    delete m_resampler;
+	    m_resampler = 0;
 	}
 	m_sourceSampleRate = 0;
     }
@@ -339,11 +344,12 @@
 
     m_models.clear();
 
-    if (m_converter) {
-	src_delete(m_converter);
-        src_delete(m_crapConverter);
-	m_converter = 0;
-        m_crapConverter = 0;
+    if (m_resampler) {
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+        cerr << "AudioCallbackPlaySource::clearModels: Deleting resampler" << endl;
+#endif
+	delete m_resampler;
+	m_resampler = 0;
     }
 
     m_lastModelEndFrame = 0;
@@ -407,6 +413,8 @@
 void
 AudioCallbackPlaySource::play(sv_frame_t startFrame)
 {
+    if (!m_target) return;
+    
     if (!m_sourceSampleRate) {
         cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl;
         return;
@@ -464,8 +472,9 @@
             if (rb) rb->reset();
         }
     }
-    if (m_converter) src_reset(m_converter);
-    if (m_crapConverter) src_reset(m_crapConverter);
+    if (m_resampler) {
+        m_resampler->reset();
+    }
 
     m_mutex.unlock();
 
@@ -551,9 +560,6 @@
 void
 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n)
 {
-    if (n == "Resample Quality") {
-        setResampleQuality(Preferences::getInstance()->getResampleQuality());
-    }
 }
 
 void
@@ -941,7 +947,7 @@
     bool first = (m_targetSampleRate == 0);
 
     m_targetSampleRate = sr;
-    initialiseConverter();
+    initialiseResampler();
 
     if (first && (m_stretchRatio != 1.f)) {
         // couldn't create a stretcher before because we had no sample
@@ -951,81 +957,37 @@
 }
 
 void
-AudioCallbackPlaySource::initialiseConverter()
+AudioCallbackPlaySource::initialiseResampler()
 {
     m_mutex.lock();
 
-    if (m_converter) {
-        src_delete(m_converter);
-        src_delete(m_crapConverter);
-        m_converter = 0;
-        m_crapConverter = 0;
+#ifdef DEBUG_AUDIO_PLAY_SOURCE
+    cerr << "AudioCallbackPlaySource::initialiseResampler(): from "
+         << getSourceSampleRate() << " to " << getTargetSampleRate() << endl;
+#endif
+    
+    if (m_resampler) {
+        delete m_resampler;
+        m_resampler = 0;
     }
 
     if (getSourceSampleRate() != getTargetSampleRate()) {
 
-	int err = 0;
+        m_resampler = new breakfastquay::Resampler
+            (breakfastquay::Resampler::FastestTolerable,
+             getTargetChannelCount());
 
-	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);
+        m_mutex.unlock();
 
-        if (m_converter) {
-            m_crapConverter = src_new(SRC_LINEAR,
-                                      getTargetChannelCount(),
-                                      &err);
-        }
-
-	if (!m_converter || !m_crapConverter) {
-	    cerr
-		<< "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: "
-		<< src_strerror(err) << 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);
-        }
+        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
-    SVDEBUG << "AudioCallbackPlaySource::setResampleQuality: setting to "
-              << m_resampleQuality << endl;
-#endif
-
-    initialiseConverter();
-}
-
-void
 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a)
 {
     RealTimePluginInstance *plugin = dynamic_cast<RealTimePluginInstance *>(a);
@@ -1393,6 +1355,9 @@
         return false;
     }
 
+    // space is now the number of samples that can be written on each
+    // channel's write ringbuffer
+    
     sv_frame_t f = m_writeBufferFill;
 	
     bool readWriteEqual = (m_readBuffers == m_writeBuffers);
@@ -1430,15 +1395,11 @@
 
     sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize();
 
-    if (resample && !m_converter) {
-	static bool warned = false;
-	if (!warned) {
-	    cerr << "WARNING: sample rates differ, but no converter available!" << endl;
-	    warned = true;
-	}
+    if (resample && !m_resampler) {
+        throw std::logic_error("Sample rates differ, but no resampler available!");
     }
 
-    if (resample && m_converter) {
+    if (resample && m_resampler) {
 
 	double ratio =
 	    double(getTargetSampleRate()) / double(getSourceSampleRate());
@@ -1490,7 +1451,10 @@
 		intlv[channels * i + c] = sample;
 	    }
 	}
-		
+
+        sv_frame_t toCopy = m_resampler->resampleInterleaved
+            (intlv, srcout, got, ratio, false);
+        
 	SRC_DATA data;
 	data.data_in = intlv;
 	data.data_out = srcout;
@@ -1499,16 +1463,7 @@
 	data.src_ratio = ratio;
 	data.end_of_input = 0;
 	
-	int err = 0;
-
-        if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
-#ifdef DEBUG_AUDIO_PLAY_SOURCE
-            cout << "Using crappy converter" << endl;
-#endif
-            err = src_process(m_crapConverter, &data);
-        } else {
-            err = src_process(m_converter, &data);
-        }
+	int err = src_process(m_converter, &data);
 
 	sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1);