Mercurial > hg > svapp
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; |