Mercurial > hg > svapp
comparison audioio/AudioCallbackPlaySource.cpp @ 235:1fcee2a1c03e sonification
Add queueExampleNote method to AudioCallbackPlaySource, providing a way to add a note to a special model which is mixed in outside of the normal playback flow. Currently mixing & generation happen in the play thread, which doesn't work very well -- buffer pending.
author | Chris Cannam |
---|---|
date | Fri, 24 Jun 2011 16:44:02 +0100 |
parents | 8aace2d9f1c2 |
children | a99de38af73f |
comparison
equal
deleted
inserted
replaced
234:a98f1638c5ec | 235:1fcee2a1c03e |
---|---|
22 #include "base/PlayParameterRepository.h" | 22 #include "base/PlayParameterRepository.h" |
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 "data/model/NoteModel.h" | |
27 #include "plugin/RealTimePluginInstance.h" | 28 #include "plugin/RealTimePluginInstance.h" |
29 #include "base/Debug.h" | |
28 | 30 |
29 #include "AudioCallbackPlayTarget.h" | 31 #include "AudioCallbackPlayTarget.h" |
30 | 32 |
31 #include <rubberband/RubberBandStretcher.h> | 33 #include <rubberband/RubberBandStretcher.h> |
32 using namespace RubberBand; | 34 using namespace RubberBand; |
67 m_outputRight(0.0), | 69 m_outputRight(0.0), |
68 m_auditioningPlugin(0), | 70 m_auditioningPlugin(0), |
69 m_auditioningPluginBypassed(false), | 71 m_auditioningPluginBypassed(false), |
70 m_playStartFrame(0), | 72 m_playStartFrame(0), |
71 m_playStartFramePassed(false), | 73 m_playStartFramePassed(false), |
74 m_exampleNotes(0), | |
75 m_examplePlaybackFrame(0), | |
72 m_timeStretcher(0), | 76 m_timeStretcher(0), |
73 m_monoStretcher(0), | 77 m_monoStretcher(0), |
74 m_stretchRatio(1.0), | 78 m_stretchRatio(1.0), |
75 m_stretcherInputCount(0), | 79 m_stretcherInputCount(0), |
76 m_stretcherInputs(0), | 80 m_stretcherInputs(0), |
113 m_fillThread->wait(); | 117 m_fillThread->wait(); |
114 delete m_fillThread; | 118 delete m_fillThread; |
115 } | 119 } |
116 | 120 |
117 clearModels(); | 121 clearModels(); |
122 | |
123 delete m_exampleNotes; | |
118 | 124 |
119 if (m_readBuffers != m_writeBuffers) { | 125 if (m_readBuffers != m_writeBuffers) { |
120 delete m_readBuffers; | 126 delete m_readBuffers; |
121 } | 127 } |
122 | 128 |
985 | 991 |
986 m_mutex.lock(); | 992 m_mutex.lock(); |
987 m_auditioningPlugin = plugin; | 993 m_auditioningPlugin = plugin; |
988 m_auditioningPluginBypassed = false; | 994 m_auditioningPluginBypassed = false; |
989 m_mutex.unlock(); | 995 m_mutex.unlock(); |
996 } | |
997 | |
998 void | |
999 AudioCallbackPlaySource::queueExampleNote(int midiPitch) | |
1000 { | |
1001 SVDEBUG << "AudioCallbackPlaySource::queueExampleNote " << midiPitch << endl; | |
1002 | |
1003 size_t rate = getTargetSampleRate(); | |
1004 if (!rate) return; | |
1005 | |
1006 Note n(m_examplePlaybackFrame, | |
1007 midiPitch, | |
1008 rate / 2, // half a second | |
1009 0, | |
1010 ""); | |
1011 | |
1012 NoteModel *newNoteModel = 0; | |
1013 | |
1014 if (!m_exampleNotes) { | |
1015 // do this outside mutex -- adding the playable and the model | |
1016 // both call back on us into functions that need to lock | |
1017 newNoteModel = new NoteModel(rate, 1, false); | |
1018 PlayParameterRepository::getInstance()->addPlayable(newNoteModel); | |
1019 m_audioGenerator->addModel(newNoteModel); | |
1020 m_exampleNotes = newNoteModel; | |
1021 } | |
1022 | |
1023 m_mutex.lock(); | |
1024 m_exampleNotes->addPoint(n); | |
1025 m_mutex.unlock(); | |
1026 | |
1027 SVDEBUG << "AudioCallbackPlaySource::queueExampleNote: Added note at frame " | |
1028 << n.frame << endl; | |
990 } | 1029 } |
991 | 1030 |
992 void | 1031 void |
993 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s) | 1032 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s) |
994 { | 1033 { |
1060 | 1099 |
1061 emit activity(tr("Change time-stretch factor to %1").arg(factor)); | 1100 emit activity(tr("Change time-stretch factor to %1").arg(factor)); |
1062 } | 1101 } |
1063 | 1102 |
1064 size_t | 1103 size_t |
1104 AudioCallbackPlaySource::mixExampleModel(size_t count, float **buffer) | |
1105 { | |
1106 SVDEBUG << "AudioCallbackPlaySource::mixExampleModel" << endl; | |
1107 | |
1108 if (!m_exampleNotes || m_exampleNotes->isEmpty()) { | |
1109 return 0; | |
1110 } | |
1111 | |
1112 SVDEBUG << "AudioCallbackPlaySource::mixExampleModel: Model non-empty; m_examplePlaybackFrame is " << m_examplePlaybackFrame << " and count " << count << endl; | |
1113 | |
1114 QMutexLocker locker(&m_mutex); | |
1115 | |
1116 size_t n = 0; | |
1117 | |
1118 n = m_audioGenerator->mixModel(m_exampleNotes, | |
1119 m_examplePlaybackFrame, | |
1120 count, | |
1121 buffer, | |
1122 0, | |
1123 0); | |
1124 | |
1125 m_examplePlaybackFrame += n; | |
1126 | |
1127 // prune notes that have finished | |
1128 while (1) { | |
1129 const NoteModel::PointList &points = m_exampleNotes->getPoints(); | |
1130 if (!points.empty()) { | |
1131 NoteModel::Point p(*points.begin()); | |
1132 if (p.frame + p.duration < m_examplePlaybackFrame) { | |
1133 m_exampleNotes->deletePoint(p); | |
1134 continue; | |
1135 } | |
1136 } | |
1137 break; | |
1138 } | |
1139 | |
1140 SVDEBUG << "AudioCallbackPlaySource::mixExampleModel: done, got " | |
1141 << n << " frames for new m_examplePlaybackFrame of " | |
1142 << m_examplePlaybackFrame << ", " | |
1143 << m_exampleNotes->getPoints().size() << " queued notes remain" | |
1144 << endl; | |
1145 | |
1146 return n; | |
1147 } | |
1148 | |
1149 size_t | |
1065 AudioCallbackPlaySource::getSourceSamples(size_t ucount, float **buffer) | 1150 AudioCallbackPlaySource::getSourceSamples(size_t ucount, float **buffer) |
1066 { | 1151 { |
1067 int count = ucount; | 1152 int count = ucount; |
1068 | 1153 |
1069 if (!m_playing) { | 1154 if (!m_playing) { |
1073 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { | 1158 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { |
1074 for (int i = 0; i < count; ++i) { | 1159 for (int i = 0; i < count; ++i) { |
1075 buffer[ch][i] = 0.0; | 1160 buffer[ch][i] = 0.0; |
1076 } | 1161 } |
1077 } | 1162 } |
1078 return 0; | 1163 return mixExampleModel(ucount, buffer); |
1079 } | 1164 } |
1080 | 1165 |
1081 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1166 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1082 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Playing" << endl; | 1167 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Playing" << endl; |
1083 #endif | 1168 #endif |
1178 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1263 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1179 std::cout << "AudioCallbackPlaySource::getSamples: awakening thread" << std::endl; | 1264 std::cout << "AudioCallbackPlaySource::getSamples: awakening thread" << std::endl; |
1180 #endif | 1265 #endif |
1181 | 1266 |
1182 m_condition.wakeAll(); | 1267 m_condition.wakeAll(); |
1268 | |
1269 (void)mixExampleModel(got, buffer); | |
1183 | 1270 |
1184 return got; | 1271 return got; |
1185 } | 1272 } |
1186 | 1273 |
1187 size_t channels = getTargetChannelCount(); | 1274 size_t channels = getTargetChannelCount(); |
1271 std::cout << "AudioCallbackPlaySource::getSamples [stretched]: awakening thread" << std::endl; | 1358 std::cout << "AudioCallbackPlaySource::getSamples [stretched]: awakening thread" << std::endl; |
1272 #endif | 1359 #endif |
1273 | 1360 |
1274 m_condition.wakeAll(); | 1361 m_condition.wakeAll(); |
1275 | 1362 |
1363 (void)mixExampleModel(count, buffer); | |
1364 | |
1276 return count; | 1365 return count; |
1277 } | 1366 } |
1278 | 1367 |
1279 void | 1368 void |
1280 AudioCallbackPlaySource::applyAuditioningEffect(size_t count, float **buffers) | 1369 AudioCallbackPlaySource::applyAuditioningEffect(size_t count, float **buffers) |