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)