Mercurial > hg > sonic-visualiser
comparison audioio/AudioCallbackPlaySource.cpp @ 32:e3b32dc5180b
* 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
author | Chris Cannam |
---|---|
date | Thu, 21 Sep 2006 11:17:19 +0000 |
parents | 37af203dbd15 |
children | fbd7a497fd89 |
comparison
equal
deleted
inserted
replaced
31:37af203dbd15 | 32:e3b32dc5180b |
---|---|
18 #include "AudioGenerator.h" | 18 #include "AudioGenerator.h" |
19 | 19 |
20 #include "data/model/Model.h" | 20 #include "data/model/Model.h" |
21 #include "view/ViewManager.h" | 21 #include "view/ViewManager.h" |
22 #include "base/PlayParameterRepository.h" | 22 #include "base/PlayParameterRepository.h" |
23 #include "base/Preferences.h" | |
23 #include "data/model/DenseTimeValueModel.h" | 24 #include "data/model/DenseTimeValueModel.h" |
24 #include "data/model/SparseOneDimensionalModel.h" | 25 #include "data/model/SparseOneDimensionalModel.h" |
25 #include "PhaseVocoderTimeStretcher.h" | 26 #include "PhaseVocoderTimeStretcher.h" |
26 | 27 |
27 #include <iostream> | 28 #include <iostream> |
51 m_lastModelEndFrame(0), | 52 m_lastModelEndFrame(0), |
52 m_outputLeft(0.0), | 53 m_outputLeft(0.0), |
53 m_outputRight(0.0), | 54 m_outputRight(0.0), |
54 m_timeStretcher(0), | 55 m_timeStretcher(0), |
55 m_fillThread(0), | 56 m_fillThread(0), |
56 m_converter(0) | 57 m_converter(0), |
58 m_crapConverter(0), | |
59 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) | |
57 { | 60 { |
58 m_viewManager->setAudioPlaySource(this); | 61 m_viewManager->setAudioPlaySource(this); |
59 | 62 |
60 connect(m_viewManager, SIGNAL(selectionChanged()), | 63 connect(m_viewManager, SIGNAL(selectionChanged()), |
61 this, SLOT(selectionChanged())); | 64 this, SLOT(selectionChanged())); |
65 this, SLOT(playSelectionModeChanged())); | 68 this, SLOT(playSelectionModeChanged())); |
66 | 69 |
67 connect(PlayParameterRepository::getInstance(), | 70 connect(PlayParameterRepository::getInstance(), |
68 SIGNAL(playParametersChanged(PlayParameters *)), | 71 SIGNAL(playParametersChanged(PlayParameters *)), |
69 this, SLOT(playParametersChanged(PlayParameters *))); | 72 this, SLOT(playParametersChanged(PlayParameters *))); |
73 | |
74 connect(Preferences::getInstance(), | |
75 SIGNAL(propertyChanged(PropertyContainer::PropertyName)), | |
76 this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); | |
70 } | 77 } |
71 | 78 |
72 AudioCallbackPlaySource::~AudioCallbackPlaySource() | 79 AudioCallbackPlaySource::~AudioCallbackPlaySource() |
73 { | 80 { |
74 m_exiting = true; | 81 m_exiting = true; |
166 } | 173 } |
167 | 174 |
168 if (buffersChanged || srChanged) { | 175 if (buffersChanged || srChanged) { |
169 if (m_converter) { | 176 if (m_converter) { |
170 src_delete(m_converter); | 177 src_delete(m_converter); |
178 src_delete(m_crapConverter); | |
171 m_converter = 0; | 179 m_converter = 0; |
180 m_crapConverter = 0; | |
172 } | 181 } |
173 } | 182 } |
174 | 183 |
175 m_mutex.unlock(); | 184 m_mutex.unlock(); |
176 | 185 |
200 m_models.erase(model); | 209 m_models.erase(model); |
201 | 210 |
202 if (m_models.empty()) { | 211 if (m_models.empty()) { |
203 if (m_converter) { | 212 if (m_converter) { |
204 src_delete(m_converter); | 213 src_delete(m_converter); |
214 src_delete(m_crapConverter); | |
205 m_converter = 0; | 215 m_converter = 0; |
216 m_crapConverter = 0; | |
206 } | 217 } |
207 m_sourceSampleRate = 0; | 218 m_sourceSampleRate = 0; |
208 } | 219 } |
209 | 220 |
210 size_t lastEnd = 0; | 221 size_t lastEnd = 0; |
230 | 241 |
231 m_models.clear(); | 242 m_models.clear(); |
232 | 243 |
233 if (m_converter) { | 244 if (m_converter) { |
234 src_delete(m_converter); | 245 src_delete(m_converter); |
246 src_delete(m_crapConverter); | |
235 m_converter = 0; | 247 m_converter = 0; |
248 m_crapConverter = 0; | |
236 } | 249 } |
237 | 250 |
238 m_lastModelEndFrame = 0; | 251 m_lastModelEndFrame = 0; |
239 | 252 |
240 m_sourceSampleRate = 0; | 253 m_sourceSampleRate = 0; |
320 RingBuffer<float> *rb = getReadRingBuffer(c); | 333 RingBuffer<float> *rb = getReadRingBuffer(c); |
321 if (rb) rb->reset(); | 334 if (rb) rb->reset(); |
322 } | 335 } |
323 } | 336 } |
324 if (m_converter) src_reset(m_converter); | 337 if (m_converter) src_reset(m_converter); |
338 if (m_crapConverter) src_reset(m_crapConverter); | |
325 } else { | 339 } else { |
326 if (m_converter) src_reset(m_converter); | 340 if (m_converter) src_reset(m_converter); |
341 if (m_crapConverter) src_reset(m_crapConverter); | |
327 m_readBufferFill = m_writeBufferFill = startFrame; | 342 m_readBufferFill = m_writeBufferFill = startFrame; |
328 } | 343 } |
329 m_mutex.unlock(); | 344 m_mutex.unlock(); |
330 | 345 |
331 m_audioGenerator->reset(); | 346 m_audioGenerator->reset(); |
369 | 384 |
370 void | 385 void |
371 AudioCallbackPlaySource::playParametersChanged(PlayParameters *params) | 386 AudioCallbackPlaySource::playParametersChanged(PlayParameters *params) |
372 { | 387 { |
373 clearRingBuffers(); | 388 clearRingBuffers(); |
389 } | |
390 | |
391 void | |
392 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n) | |
393 { | |
394 if (n == "Resample Quality") { | |
395 setResampleQuality(Preferences::getInstance()->getResampleQuality()); | |
396 } | |
374 } | 397 } |
375 | 398 |
376 void | 399 void |
377 AudioCallbackPlaySource::setTargetBlockSize(size_t size) | 400 AudioCallbackPlaySource::setTargetBlockSize(size_t size) |
378 { | 401 { |
536 | 559 |
537 void | 560 void |
538 AudioCallbackPlaySource::setTargetSampleRate(size_t sr) | 561 AudioCallbackPlaySource::setTargetSampleRate(size_t sr) |
539 { | 562 { |
540 m_targetSampleRate = sr; | 563 m_targetSampleRate = sr; |
564 initialiseConverter(); | |
565 } | |
566 | |
567 void | |
568 AudioCallbackPlaySource::initialiseConverter() | |
569 { | |
570 m_mutex.lock(); | |
571 | |
572 if (m_converter) { | |
573 src_delete(m_converter); | |
574 src_delete(m_crapConverter); | |
575 m_converter = 0; | |
576 m_crapConverter = 0; | |
577 } | |
541 | 578 |
542 if (getSourceSampleRate() != getTargetSampleRate()) { | 579 if (getSourceSampleRate() != getTargetSampleRate()) { |
543 | 580 |
544 int err = 0; | 581 int err = 0; |
545 m_converter = src_new(SRC_SINC_BEST_QUALITY, | 582 |
583 m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY : | |
584 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY : | |
585 m_resampleQuality == 0 ? SRC_SINC_FASTEST : | |
586 SRC_SINC_MEDIUM_QUALITY, | |
546 getTargetChannelCount(), &err); | 587 getTargetChannelCount(), &err); |
547 if (!m_converter) { | 588 |
589 if (m_converter) { | |
590 m_crapConverter = src_new(SRC_LINEAR, | |
591 getTargetChannelCount(), | |
592 &err); | |
593 } | |
594 | |
595 if (!m_converter || !m_crapConverter) { | |
548 std::cerr | 596 std::cerr |
549 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " | 597 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " |
550 << src_strerror(err) << std::endl; | 598 << src_strerror(err) << std::endl; |
599 | |
600 if (m_converter) { | |
601 src_delete(m_converter); | |
602 m_converter = 0; | |
603 } | |
604 | |
605 if (m_crapConverter) { | |
606 src_delete(m_crapConverter); | |
607 m_crapConverter = 0; | |
608 } | |
609 | |
610 m_mutex.unlock(); | |
551 | 611 |
552 emit sampleRateMismatch(getSourceSampleRate(), | 612 emit sampleRateMismatch(getSourceSampleRate(), |
553 getTargetSampleRate(), | 613 getTargetSampleRate(), |
554 false); | 614 false); |
555 } else { | 615 } else { |
556 | 616 |
617 m_mutex.unlock(); | |
618 | |
557 emit sampleRateMismatch(getSourceSampleRate(), | 619 emit sampleRateMismatch(getSourceSampleRate(), |
558 getTargetSampleRate(), | 620 getTargetSampleRate(), |
559 true); | 621 true); |
560 } | 622 } |
561 } | 623 } else { |
624 m_mutex.unlock(); | |
625 } | |
626 } | |
627 | |
628 void | |
629 AudioCallbackPlaySource::setResampleQuality(int q) | |
630 { | |
631 if (q == m_resampleQuality) return; | |
632 m_resampleQuality = q; | |
633 | |
634 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
635 std::cerr << "AudioCallbackPlaySource::setResampleQuality: setting to " | |
636 << m_resampleQuality << std::endl; | |
637 #endif | |
638 | |
639 initialiseConverter(); | |
562 } | 640 } |
563 | 641 |
564 size_t | 642 size_t |
565 AudioCallbackPlaySource::getTargetSampleRate() const | 643 AudioCallbackPlaySource::getTargetSampleRate() const |
566 { | 644 { |
892 data.input_frames = got; | 970 data.input_frames = got; |
893 data.output_frames = work; | 971 data.output_frames = work; |
894 data.src_ratio = ratio; | 972 data.src_ratio = ratio; |
895 data.end_of_input = 0; | 973 data.end_of_input = 0; |
896 | 974 |
897 int err = src_process(m_converter, &data); | 975 int err = 0; |
898 // size_t toCopy = size_t(work * ratio + 0.1); | 976 |
977 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { | |
978 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
979 std::cerr << "Using crappy converter" << std::endl; | |
980 #endif | |
981 src_process(m_crapConverter, &data); | |
982 } else { | |
983 src_process(m_converter, &data); | |
984 } | |
985 | |
899 size_t toCopy = size_t(got * ratio + 0.1); | 986 size_t toCopy = size_t(got * ratio + 0.1); |
900 | 987 |
901 if (err) { | 988 if (err) { |
902 std::cerr | 989 std::cerr |
903 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " | 990 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " |