comparison audioio/AudioCallbackPlaySource.cpp @ 62:ae2627ac7db2

* Add support for Rubber Band timestretcher
author Chris Cannam
date Mon, 26 Nov 2007 13:33:44 +0000
parents 7b71da2d0631
children 9fc4b256c283 22bf057ea151
comparison
equal deleted inserted replaced
61:215b8b1b0308 62:ae2627ac7db2
23 #include "base/Preferences.h" 23 #include "base/Preferences.h"
24 #include "data/model/DenseTimeValueModel.h" 24 #include "data/model/DenseTimeValueModel.h"
25 #include "data/model/WaveFileModel.h" 25 #include "data/model/WaveFileModel.h"
26 #include "data/model/SparseOneDimensionalModel.h" 26 #include "data/model/SparseOneDimensionalModel.h"
27 #include "plugin/RealTimePluginInstance.h" 27 #include "plugin/RealTimePluginInstance.h"
28
29 #ifdef HAVE_RUBBERBAND
30 #include <rubberband/RubberBandStretcher.h>
31 using namespace RubberBand;
32 #else
28 #include "PhaseVocoderTimeStretcher.h" 33 #include "PhaseVocoderTimeStretcher.h"
34 #endif
29 35
30 #include <iostream> 36 #include <iostream>
31 #include <cassert> 37 #include <cassert>
32 38
33 //#define DEBUG_AUDIO_PLAY_SOURCE 1 39 //#define DEBUG_AUDIO_PLAY_SOURCE 1
101 107
102 delete m_audioGenerator; 108 delete m_audioGenerator;
103 109
104 m_bufferScavenger.scavenge(true); 110 m_bufferScavenger.scavenge(true);
105 m_pluginScavenger.scavenge(true); 111 m_pluginScavenger.scavenge(true);
112 #ifndef HAVE_RUBBERBAND
106 m_timeStretcherScavenger.scavenge(true); 113 m_timeStretcherScavenger.scavenge(true);
114 #endif
107 } 115 }
108 116
109 void 117 void
110 AudioCallbackPlaySource::addModel(Model *model) 118 AudioCallbackPlaySource::addModel(Model *model)
111 { 119 {
495 } 503 }
496 504
497 size_t latency = m_playLatency; 505 size_t latency = m_playLatency;
498 if (resample) latency = size_t(m_playLatency * ratio + 0.1); 506 if (resample) latency = size_t(m_playLatency * ratio + 0.1);
499 507
508 #ifdef HAVE_RUBBERBAND
509 if (m_timeStretcher) {
510 latency += m_timeStretcher->getLatency();
511 }
512 #else
500 PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher; 513 PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher;
501 if (timeStretcher) { 514 if (timeStretcher) {
502 latency += timeStretcher->getProcessingLatency(); 515 latency += timeStretcher->getProcessingLatency();
503 } 516 }
517 #endif
504 518
505 latency += readSpace; 519 latency += readSpace;
506 size_t bufferedFrame = m_readBufferFill; 520 size_t bufferedFrame = m_readBufferFill;
507 521
508 bool looping = m_viewManager->getPlayLoopMode(); 522 bool looping = m_viewManager->getPlayLoopMode();
744 } 758 }
745 759
746 void 760 void
747 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) 761 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono)
748 { 762 {
763 #ifdef HAVE_RUBBERBAND
764 if (m_timeStretcher) {
765 m_timeStretchRatioMutex.lock();
766 m_timeStretcher->setTimeRatio(factor);
767 m_timeStretchRatioMutex.unlock();
768 return;
769 } else {
770 RubberBandStretcher *stretcher = new RubberBandStretcher
771 (getTargetSampleRate(),
772 getTargetChannelCount(),
773 RubberBandStretcher::OptionProcessRealTime,
774 factor);
775 m_timeStretcher = stretcher;
776 return;
777 }
778 #else
749 // Avoid locks -- create, assign, mark old one for scavenging 779 // Avoid locks -- create, assign, mark old one for scavenging
750 // later (as a call to getSourceSamples may still be using it) 780 // later (as a call to getSourceSamples may still be using it)
751 781
752 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher; 782 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher;
753 783
784 } 814 }
785 815
786 if (existingStretcher) { 816 if (existingStretcher) {
787 m_timeStretcherScavenger.claim(existingStretcher); 817 m_timeStretcherScavenger.claim(existingStretcher);
788 } 818 }
819 #endif
789 } 820 }
790 821
791 size_t 822 size_t
792 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) 823 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
793 { 824 {
827 } 858 }
828 } 859 }
829 860
830 if (count == 0) return 0; 861 if (count == 0) return 0;
831 862
863 #ifdef HAVE_RUBBERBAND
864 RubberBandStretcher *ts = m_timeStretcher;
865 float ratio = ts ? ts->getTimeRatio() : 1.f;
866 #else
832 PhaseVocoderTimeStretcher *ts = m_timeStretcher; 867 PhaseVocoderTimeStretcher *ts = m_timeStretcher;
833 868 float ratio = ts ? ts->getRatio() : 1.f;
834 if (!ts || ts->getRatio() == 1) { 869 #endif
870
871 if (!ts || ratio == 1.f) {
835 872
836 size_t got = 0; 873 size_t got = 0;
837 874
838 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { 875 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
839 876
864 901
865 m_condition.wakeAll(); 902 m_condition.wakeAll();
866 return got; 903 return got;
867 } 904 }
868 905
869 float ratio = ts->getRatio();
870
871 // std::cout << "ratio = " << ratio << std::endl;
872
873 size_t channels = getTargetChannelCount(); 906 size_t channels = getTargetChannelCount();
907
908 #ifdef HAVE_RUBBERBAND
909 bool mix = false;
910 #else
874 bool mix = (channels > 1 && ts->getChannelCount() == 1); 911 bool mix = (channels > 1 && ts->getChannelCount() == 1);
912 #endif
875 913
876 size_t available; 914 size_t available;
877 915
878 int warned = 0; 916 int warned = 0;
879 917
883 // output is approx output / ratio, but we can't predict it 921 // output is approx output / ratio, but we can't predict it
884 // exactly, for an adaptive timestretcher. The stretcher will 922 // exactly, for an adaptive timestretcher. The stretcher will
885 // need some additional buffer space. See the time stretcher code 923 // need some additional buffer space. See the time stretcher code
886 // and comments. 924 // and comments.
887 925
926 #ifdef HAVE_RUBBERBAND
927 m_timeStretchRatioMutex.lock();
928 while ((available = ts->available()) < count) {
929 #else
888 while ((available = ts->getAvailableOutputSamples()) < count) { 930 while ((available = ts->getAvailableOutputSamples()) < count) {
931 #endif
889 932
890 size_t reqd = lrintf((count - available) / ratio); 933 size_t reqd = lrintf((count - available) / ratio);
934 #ifdef HAVE_RUBBERBAND
935 reqd = std::max(reqd, ts->getSamplesRequired());
936 #else
891 reqd = std::max(reqd, ts->getRequiredInputSamples()); 937 reqd = std::max(reqd, ts->getRequiredInputSamples());
938 #endif
892 if (reqd == 0) reqd = 1; 939 if (reqd == 0) reqd = 1;
893 940
894 float *ib[channels]; 941 float *ib[channels];
895 942
896 size_t got = reqd; 943 size_t got = reqd;
921 if (got < reqd) { 968 if (got < reqd) {
922 std::cerr << "WARNING: Read underrun in playback (" 969 std::cerr << "WARNING: Read underrun in playback ("
923 << got << " < " << reqd << ")" << std::endl; 970 << got << " < " << reqd << ")" << std::endl;
924 } 971 }
925 972
973 #ifdef HAVE_RUBBERBAND
974 ts->process(ib, got, false);
975 #else
926 ts->putInput(ib, got); 976 ts->putInput(ib, got);
977 #endif
927 978
928 for (size_t c = 0; c < channels; ++c) { 979 for (size_t c = 0; c < channels; ++c) {
929 delete[] ib[c]; 980 delete[] ib[c];
930 } 981 }
931 982
932 if (got == 0) break; 983 if (got == 0) break;
933 984
985 #ifdef HAVE_RUBBERBAND
986 if (ts->available() == available) {
987 #else
934 if (ts->getAvailableOutputSamples() == available) { 988 if (ts->getAvailableOutputSamples() == available) {
989 #endif
935 std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl; 990 std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl;
936 if (++warned == 5) break; 991 if (++warned == 5) break;
937 } 992 }
938 } 993 }
939 994
995 #ifdef HAVE_RUBBERBAND
996 ts->retrieve(buffer, count);
997 m_timeStretchRatioMutex.unlock();
998 #else
940 ts->getOutput(buffer, count); 999 ts->getOutput(buffer, count);
1000 #endif
941 1001
942 if (mix) { 1002 if (mix) {
943 for (size_t c = 1; c < channels; ++c) { 1003 for (size_t c = 1; c < channels; ++c) {
944 for (size_t i = 0; i < count; ++i) { 1004 for (size_t i = 0; i < count; ++i) {
945 buffer[c][i] = buffer[0][i] / channels; 1005 buffer[c][i] = buffer[0][i] / channels;
1122 data.src_ratio = ratio; 1182 data.src_ratio = ratio;
1123 data.end_of_input = 0; 1183 data.end_of_input = 0;
1124 1184
1125 int err = 0; 1185 int err = 0;
1126 1186
1187 #ifdef HAVE_RUBBERBAND
1188 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
1189 #else
1127 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { 1190 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) {
1191 #endif
1128 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1192 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1129 std::cout << "Using crappy converter" << std::endl; 1193 std::cout << "Using crappy converter" << std::endl;
1130 #endif 1194 #endif
1131 err = src_process(m_crapConverter, &data); 1195 err = src_process(m_crapConverter, &data);
1132 } else { 1196 } else {
1447 while (!s.m_exiting) { 1511 while (!s.m_exiting) {
1448 1512
1449 s.unifyRingBuffers(); 1513 s.unifyRingBuffers();
1450 s.m_bufferScavenger.scavenge(); 1514 s.m_bufferScavenger.scavenge();
1451 s.m_pluginScavenger.scavenge(); 1515 s.m_pluginScavenger.scavenge();
1516 #ifndef HAVE_RUBBERBAND
1452 s.m_timeStretcherScavenger.scavenge(); 1517 s.m_timeStretcherScavenger.scavenge();
1518 #endif
1453 1519
1454 if (work && s.m_playing && s.getSourceSampleRate()) { 1520 if (work && s.m_playing && s.getSourceSampleRate()) {
1455 1521
1456 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1522 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1457 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl; 1523 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl;