00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "AudioGenerator.h"
00017
00018 #include "base/TempDirectory.h"
00019 #include "base/PlayParameters.h"
00020 #include "base/PlayParameterRepository.h"
00021 #include "base/Pitch.h"
00022 #include "base/Exceptions.h"
00023
00024 #include "data/model/NoteModel.h"
00025 #include "data/model/DenseTimeValueModel.h"
00026 #include "data/model/SparseOneDimensionalModel.h"
00027
00028 #include "plugin/RealTimePluginFactory.h"
00029 #include "plugin/RealTimePluginInstance.h"
00030 #include "plugin/PluginIdentifier.h"
00031 #include "plugin/PluginXml.h"
00032 #include "plugin/api/alsa/seq_event.h"
00033
00034 #include <iostream>
00035 #include <math.h>
00036
00037 #include <QDir>
00038 #include <QFile>
00039
00040 const size_t
00041 AudioGenerator::m_pluginBlockSize = 2048;
00042
00043 QString
00044 AudioGenerator::m_sampleDir = "";
00045
00046
00047
00048 AudioGenerator::AudioGenerator() :
00049 m_sourceSampleRate(0),
00050 m_targetChannelCount(1),
00051 m_soloing(false)
00052 {
00053 connect(PlayParameterRepository::getInstance(),
00054 SIGNAL(playPluginIdChanged(const Model *, QString)),
00055 this,
00056 SLOT(playPluginIdChanged(const Model *, QString)));
00057
00058 connect(PlayParameterRepository::getInstance(),
00059 SIGNAL(playPluginConfigurationChanged(const Model *, QString)),
00060 this,
00061 SLOT(playPluginConfigurationChanged(const Model *, QString)));
00062 }
00063
00064 AudioGenerator::~AudioGenerator()
00065 {
00066 }
00067
00068 bool
00069 AudioGenerator::canPlay(const Model *model)
00070 {
00071 if (dynamic_cast<const DenseTimeValueModel *>(model) ||
00072 dynamic_cast<const SparseOneDimensionalModel *>(model) ||
00073 dynamic_cast<const NoteModel *>(model)) {
00074 return true;
00075 } else {
00076 return false;
00077 }
00078 }
00079
00080 bool
00081 AudioGenerator::addModel(Model *model)
00082 {
00083 if (m_sourceSampleRate == 0) {
00084
00085 m_sourceSampleRate = model->getSampleRate();
00086
00087 } else {
00088
00089 DenseTimeValueModel *dtvm =
00090 dynamic_cast<DenseTimeValueModel *>(model);
00091
00092 if (dtvm) {
00093 m_sourceSampleRate = model->getSampleRate();
00094 return true;
00095 }
00096 }
00097
00098 RealTimePluginInstance *plugin = loadPluginFor(model);
00099 if (plugin) {
00100 QMutexLocker locker(&m_mutex);
00101 m_synthMap[model] = plugin;
00102 return true;
00103 }
00104
00105 return false;
00106 }
00107
00108 void
00109 AudioGenerator::playPluginIdChanged(const Model *model, QString)
00110 {
00111 if (m_synthMap.find(model) == m_synthMap.end()) return;
00112
00113 RealTimePluginInstance *plugin = loadPluginFor(model);
00114 if (plugin) {
00115 QMutexLocker locker(&m_mutex);
00116 delete m_synthMap[model];
00117 m_synthMap[model] = plugin;
00118 }
00119 }
00120
00121 void
00122 AudioGenerator::playPluginConfigurationChanged(const Model *model,
00123 QString configurationXml)
00124 {
00125
00126
00127 if (m_synthMap.find(model) == m_synthMap.end()) {
00128 std::cerr << "AudioGenerator::playPluginConfigurationChanged: We don't know about this plugin" << std::endl;
00129 return;
00130 }
00131
00132 RealTimePluginInstance *plugin = m_synthMap[model];
00133 if (plugin) {
00134 PluginXml(plugin).setParametersFromXml(configurationXml);
00135 }
00136 }
00137
00138 QString
00139 AudioGenerator::getDefaultPlayPluginId(const Model *model)
00140 {
00141 const SparseOneDimensionalModel *sodm =
00142 dynamic_cast<const SparseOneDimensionalModel *>(model);
00143 if (sodm) {
00144 return QString("dssi:%1:sample_player").
00145 arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME);
00146 }
00147
00148 const NoteModel *nm = dynamic_cast<const NoteModel *>(model);
00149 if (nm) {
00150 return QString("dssi:%1:sample_player").
00151 arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME);
00152 }
00153
00154 return "";
00155 }
00156
00157 QString
00158 AudioGenerator::getDefaultPlayPluginConfiguration(const Model *model)
00159 {
00160 QString program = "";
00161
00162 const SparseOneDimensionalModel *sodm =
00163 dynamic_cast<const SparseOneDimensionalModel *>(model);
00164 if (sodm) {
00165 program = "tap";
00166 }
00167
00168 const NoteModel *nm = dynamic_cast<const NoteModel *>(model);
00169 if (nm) {
00170 program = "piano";
00171 }
00172
00173 if (program == "") return "";
00174
00175 return
00176 QString("<plugin configuration=\"%1\" program=\"%2\"/>")
00177 .arg(XmlExportable::encodeEntities
00178 (QString("sampledir=%1")
00179 .arg(PluginXml::encodeConfigurationChars(getSampleDir()))))
00180 .arg(XmlExportable::encodeEntities(program));
00181 }
00182
00183 QString
00184 AudioGenerator::getSampleDir()
00185 {
00186 if (m_sampleDir != "") return m_sampleDir;
00187
00188 try {
00189 m_sampleDir = TempDirectory::getInstance()->getSubDirectoryPath("samples");
00190 } catch (DirectoryCreationFailed f) {
00191 std::cerr << "WARNING: AudioGenerator::getSampleDir: Failed to create "
00192 << "temporary sample directory" << std::endl;
00193 m_sampleDir = "";
00194 return "";
00195 }
00196
00197 QDir sampleResourceDir(":/samples", "*.wav");
00198
00199 for (unsigned int i = 0; i < sampleResourceDir.count(); ++i) {
00200
00201 QString fileName(sampleResourceDir[i]);
00202 QFile file(sampleResourceDir.filePath(fileName));
00203
00204 if (!file.copy(QDir(m_sampleDir).filePath(fileName))) {
00205 std::cerr << "WARNING: AudioGenerator::getSampleDir: "
00206 << "Unable to copy " << fileName.toStdString()
00207 << " into temporary directory \""
00208 << m_sampleDir.toStdString() << "\"" << std::endl;
00209 }
00210 }
00211
00212 return m_sampleDir;
00213 }
00214
00215 void
00216 AudioGenerator::setSampleDir(RealTimePluginInstance *plugin)
00217 {
00218 plugin->configure("sampledir", getSampleDir().toStdString());
00219 }
00220
00221 RealTimePluginInstance *
00222 AudioGenerator::loadPluginFor(const Model *model)
00223 {
00224 QString pluginId, configurationXml;
00225
00226 PlayParameters *parameters =
00227 PlayParameterRepository::getInstance()->getPlayParameters(model);
00228 if (parameters) {
00229 pluginId = parameters->getPlayPluginId();
00230 configurationXml = parameters->getPlayPluginConfiguration();
00231 }
00232
00233 if (pluginId == "") {
00234 pluginId = getDefaultPlayPluginId(model);
00235 configurationXml = getDefaultPlayPluginConfiguration(model);
00236 }
00237
00238 if (pluginId == "") return 0;
00239
00240 RealTimePluginInstance *plugin = loadPlugin(pluginId, "");
00241 if (!plugin) return 0;
00242
00243 if (configurationXml != "") {
00244 PluginXml(plugin).setParametersFromXml(configurationXml);
00245 }
00246
00247 if (parameters) {
00248 parameters->setPlayPluginId(pluginId);
00249 parameters->setPlayPluginConfiguration(configurationXml);
00250 }
00251
00252 return plugin;
00253 }
00254
00255 RealTimePluginInstance *
00256 AudioGenerator::loadPlugin(QString pluginId, QString program)
00257 {
00258 RealTimePluginFactory *factory =
00259 RealTimePluginFactory::instanceFor(pluginId);
00260
00261 if (!factory) {
00262 std::cerr << "Failed to get plugin factory" << std::endl;
00263 return false;
00264 }
00265
00266 RealTimePluginInstance *instance =
00267 factory->instantiatePlugin
00268 (pluginId, 0, 0, m_sourceSampleRate, m_pluginBlockSize, m_targetChannelCount);
00269
00270 if (!instance) {
00271 std::cerr << "Failed to instantiate plugin " << pluginId.toStdString() << std::endl;
00272 return 0;
00273 }
00274
00275 setSampleDir(instance);
00276
00277 for (unsigned int i = 0; i < instance->getParameterCount(); ++i) {
00278 instance->setParameterValue(i, instance->getParameterDefault(i));
00279 }
00280 std::string defaultProgram = instance->getProgram(0, 0);
00281 if (defaultProgram != "") {
00282
00283 instance->selectProgram(defaultProgram);
00284 }
00285 if (program != "") {
00286
00287 instance->selectProgram(program.toStdString());
00288 }
00289 instance->setIdealChannelCount(m_targetChannelCount);
00290
00291 return instance;
00292 }
00293
00294 void
00295 AudioGenerator::removeModel(Model *model)
00296 {
00297 SparseOneDimensionalModel *sodm =
00298 dynamic_cast<SparseOneDimensionalModel *>(model);
00299 if (!sodm) return;
00300
00301 QMutexLocker locker(&m_mutex);
00302
00303 if (m_synthMap.find(sodm) == m_synthMap.end()) return;
00304
00305 RealTimePluginInstance *instance = m_synthMap[sodm];
00306 m_synthMap.erase(sodm);
00307 delete instance;
00308 }
00309
00310 void
00311 AudioGenerator::clearModels()
00312 {
00313 QMutexLocker locker(&m_mutex);
00314 while (!m_synthMap.empty()) {
00315 RealTimePluginInstance *instance = m_synthMap.begin()->second;
00316 m_synthMap.erase(m_synthMap.begin());
00317 delete instance;
00318 }
00319 }
00320
00321 void
00322 AudioGenerator::reset()
00323 {
00324 QMutexLocker locker(&m_mutex);
00325 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
00326 if (i->second) {
00327 i->second->silence();
00328 i->second->discardEvents();
00329 }
00330 }
00331
00332 m_noteOffs.clear();
00333 }
00334
00335 void
00336 AudioGenerator::setTargetChannelCount(size_t targetChannelCount)
00337 {
00338 if (m_targetChannelCount == targetChannelCount) return;
00339
00340
00341
00342 QMutexLocker locker(&m_mutex);
00343 m_targetChannelCount = targetChannelCount;
00344
00345 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
00346 if (i->second) i->second->setIdealChannelCount(targetChannelCount);
00347 }
00348 }
00349
00350 size_t
00351 AudioGenerator::getBlockSize() const
00352 {
00353 return m_pluginBlockSize;
00354 }
00355
00356 void
00357 AudioGenerator::setSoloModelSet(std::set<Model *> s)
00358 {
00359 QMutexLocker locker(&m_mutex);
00360
00361 m_soloModelSet = s;
00362 m_soloing = true;
00363 }
00364
00365 void
00366 AudioGenerator::clearSoloModelSet()
00367 {
00368 QMutexLocker locker(&m_mutex);
00369
00370 m_soloModelSet.clear();
00371 m_soloing = false;
00372 }
00373
00374 size_t
00375 AudioGenerator::mixModel(Model *model, size_t startFrame, size_t frameCount,
00376 float **buffer, size_t fadeIn, size_t fadeOut)
00377 {
00378 if (m_sourceSampleRate == 0) {
00379 std::cerr << "WARNING: AudioGenerator::mixModel: No base source sample rate available" << std::endl;
00380 return frameCount;
00381 }
00382
00383 QMutexLocker locker(&m_mutex);
00384
00385 PlayParameters *parameters =
00386 PlayParameterRepository::getInstance()->getPlayParameters(model);
00387 if (!parameters) return frameCount;
00388
00389 bool playing = !parameters->isPlayMuted();
00390 if (!playing) {
00391 #ifdef DEBUG_AUDIO_GENERATOR
00392 std::cout << "AudioGenerator::mixModel(" << model << "): muted" << std::endl;
00393 #endif
00394 return frameCount;
00395 }
00396
00397 if (m_soloing) {
00398 if (m_soloModelSet.find(model) == m_soloModelSet.end()) {
00399 #ifdef DEBUG_AUDIO_GENERATOR
00400 std::cout << "AudioGenerator::mixModel(" << model << "): not one of the solo'd models" << std::endl;
00401 #endif
00402 return frameCount;
00403 }
00404 }
00405
00406 float gain = parameters->getPlayGain();
00407 float pan = parameters->getPlayPan();
00408
00409 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
00410 if (dtvm) {
00411 return mixDenseTimeValueModel(dtvm, startFrame, frameCount,
00412 buffer, gain, pan, fadeIn, fadeOut);
00413 }
00414
00415 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
00416 (model);
00417 if (sodm) {
00418 return mixSparseOneDimensionalModel(sodm, startFrame, frameCount,
00419 buffer, gain, pan, fadeIn, fadeOut);
00420 }
00421
00422 NoteModel *nm = dynamic_cast<NoteModel *>(model);
00423 if (nm) {
00424 return mixNoteModel(nm, startFrame, frameCount,
00425 buffer, gain, pan, fadeIn, fadeOut);
00426 }
00427
00428 return frameCount;
00429 }
00430
00431 size_t
00432 AudioGenerator::mixDenseTimeValueModel(DenseTimeValueModel *dtvm,
00433 size_t startFrame, size_t frames,
00434 float **buffer, float gain, float pan,
00435 size_t fadeIn, size_t fadeOut)
00436 {
00437 static float **channelBuffer = 0;
00438 static size_t channelBufSiz = 0;
00439 static size_t channelBufCount = 0;
00440
00441 size_t totalFrames = frames + fadeIn/2 + fadeOut/2;
00442
00443 size_t modelChannels = dtvm->getChannelCount();
00444
00445 if (channelBufSiz < totalFrames || channelBufCount < modelChannels) {
00446
00447 for (size_t c = 0; c < channelBufCount; ++c) {
00448 delete[] channelBuffer[c];
00449 }
00450
00451 delete[] channelBuffer;
00452 channelBuffer = new float *[modelChannels];
00453
00454 for (size_t c = 0; c < modelChannels; ++c) {
00455 channelBuffer[c] = new float[totalFrames];
00456 }
00457
00458 channelBufCount = modelChannels;
00459 channelBufSiz = totalFrames;
00460 }
00461
00462 size_t got = 0;
00463
00464 if (startFrame >= fadeIn/2) {
00465 got = dtvm->getData(0, modelChannels - 1,
00466 startFrame - fadeIn/2,
00467 frames + fadeOut/2 + fadeIn/2,
00468 channelBuffer);
00469 } else {
00470 size_t missing = fadeIn/2 - startFrame;
00471
00472 for (size_t c = 0; c < modelChannels; ++c) {
00473 channelBuffer[c] += missing;
00474 }
00475
00476 got = dtvm->getData(0, modelChannels - 1,
00477 startFrame,
00478 frames + fadeOut/2,
00479 channelBuffer);
00480
00481 for (size_t c = 0; c < modelChannels; ++c) {
00482 channelBuffer[c] -= missing;
00483 }
00484
00485 got += missing;
00486 }
00487
00488 for (size_t c = 0; c < m_targetChannelCount; ++c) {
00489
00490 size_t sourceChannel = (c % modelChannels);
00491
00492
00493
00494 float channelGain = gain;
00495 if (pan != 0.0) {
00496 if (c == 0) {
00497 if (pan > 0.0) channelGain *= 1.0 - pan;
00498 } else {
00499 if (pan < 0.0) channelGain *= pan + 1.0;
00500 }
00501 }
00502
00503 for (size_t i = 0; i < fadeIn/2; ++i) {
00504 float *back = buffer[c];
00505 back -= fadeIn/2;
00506 back[i] += (channelGain * channelBuffer[sourceChannel][i] * i) / fadeIn;
00507 }
00508
00509 for (size_t i = 0; i < frames + fadeOut/2; ++i) {
00510 float mult = channelGain;
00511 if (i < fadeIn/2) {
00512 mult = (mult * i) / fadeIn;
00513 }
00514 if (i > frames - fadeOut/2) {
00515 mult = (mult * ((frames + fadeOut/2) - i)) / fadeOut;
00516 }
00517 float val = channelBuffer[sourceChannel][i];
00518 if (i >= got) val = 0.f;
00519 buffer[c][i] += mult * val;
00520 }
00521 }
00522
00523 return got;
00524 }
00525
00526 size_t
00527 AudioGenerator::mixSparseOneDimensionalModel(SparseOneDimensionalModel *sodm,
00528 size_t startFrame, size_t frames,
00529 float **buffer, float gain, float pan,
00530 size_t ,
00531 size_t )
00532 {
00533 RealTimePluginInstance *plugin = m_synthMap[sodm];
00534 if (!plugin) return 0;
00535
00536 size_t latency = plugin->getLatency();
00537 size_t blocks = frames / m_pluginBlockSize;
00538
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 size_t got = blocks * m_pluginBlockSize;
00550
00551 #ifdef DEBUG_AUDIO_GENERATOR
00552 std::cout << "mixModel [sparse]: frames " << frames
00553 << ", blocks " << blocks << std::endl;
00554 #endif
00555
00556 snd_seq_event_t onEv;
00557 onEv.type = SND_SEQ_EVENT_NOTEON;
00558 onEv.data.note.channel = 0;
00559 onEv.data.note.note = 64;
00560 onEv.data.note.velocity = 100;
00561
00562 snd_seq_event_t offEv;
00563 offEv.type = SND_SEQ_EVENT_NOTEOFF;
00564 offEv.data.note.channel = 0;
00565 offEv.data.note.velocity = 0;
00566
00567 NoteOffSet ¬eOffs = m_noteOffs[sodm];
00568
00569 for (size_t i = 0; i < blocks; ++i) {
00570
00571 size_t reqStart = startFrame + i * m_pluginBlockSize;
00572
00573 SparseOneDimensionalModel::PointList points =
00574 sodm->getPoints(reqStart + latency,
00575 reqStart + latency + m_pluginBlockSize);
00576
00577 Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime
00578 (startFrame + i * m_pluginBlockSize, m_sourceSampleRate);
00579
00580 for (SparseOneDimensionalModel::PointList::iterator pli =
00581 points.begin(); pli != points.end(); ++pli) {
00582
00583 size_t pliFrame = pli->frame;
00584
00585 if (pliFrame >= latency) pliFrame -= latency;
00586
00587 if (pliFrame < reqStart ||
00588 pliFrame >= reqStart + m_pluginBlockSize) continue;
00589
00590 while (noteOffs.begin() != noteOffs.end() &&
00591 noteOffs.begin()->frame <= pliFrame) {
00592
00593 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00594 (noteOffs.begin()->frame, m_sourceSampleRate);
00595
00596 offEv.data.note.note = noteOffs.begin()->pitch;
00597
00598 #ifdef DEBUG_AUDIO_GENERATOR
00599 std::cerr << "mixModel [sparse]: sending note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl;
00600 #endif
00601
00602 plugin->sendEvent(eventTime, &offEv);
00603 noteOffs.erase(noteOffs.begin());
00604 }
00605
00606 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00607 (pliFrame, m_sourceSampleRate);
00608
00609 plugin->sendEvent(eventTime, &onEv);
00610
00611 #ifdef DEBUG_AUDIO_GENERATOR
00612 std::cout << "mixModel [sparse]: point at frame " << pliFrame << ", block start " << (startFrame + i * m_pluginBlockSize) << ", resulting time " << eventTime << std::endl;
00613 #endif
00614
00615 size_t duration = 7000;
00616 NoteOff noff;
00617 noff.pitch = onEv.data.note.note;
00618 noff.frame = pliFrame + duration;
00619 noteOffs.insert(noff);
00620 }
00621
00622 while (noteOffs.begin() != noteOffs.end() &&
00623 noteOffs.begin()->frame <=
00624 startFrame + i * m_pluginBlockSize + m_pluginBlockSize) {
00625
00626 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00627 (noteOffs.begin()->frame, m_sourceSampleRate);
00628
00629 offEv.data.note.note = noteOffs.begin()->pitch;
00630
00631 #ifdef DEBUG_AUDIO_GENERATOR
00632 std::cerr << "mixModel [sparse]: sending leftover note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl;
00633 #endif
00634
00635 plugin->sendEvent(eventTime, &offEv);
00636 noteOffs.erase(noteOffs.begin());
00637 }
00638
00639 plugin->run(blockTime);
00640 float **outs = plugin->getAudioOutputBuffers();
00641
00642 for (size_t c = 0; c < m_targetChannelCount; ++c) {
00643 #ifdef DEBUG_AUDIO_GENERATOR
00644 std::cout << "mixModel [sparse]: adding " << m_pluginBlockSize << " samples from plugin output " << c << std::endl;
00645 #endif
00646
00647 size_t sourceChannel = (c % plugin->getAudioOutputCount());
00648
00649 float channelGain = gain;
00650 if (pan != 0.0) {
00651 if (c == 0) {
00652 if (pan > 0.0) channelGain *= 1.0 - pan;
00653 } else {
00654 if (pan < 0.0) channelGain *= pan + 1.0;
00655 }
00656 }
00657
00658 for (size_t j = 0; j < m_pluginBlockSize; ++j) {
00659 buffer[c][i * m_pluginBlockSize + j] +=
00660 channelGain * outs[sourceChannel][j];
00661 }
00662 }
00663 }
00664
00665 return got;
00666 }
00667
00668
00670 size_t
00671 AudioGenerator::mixNoteModel(NoteModel *nm,
00672 size_t startFrame, size_t frames,
00673 float **buffer, float gain, float pan,
00674 size_t ,
00675 size_t )
00676 {
00677 RealTimePluginInstance *plugin = m_synthMap[nm];
00678 if (!plugin) return 0;
00679
00680 size_t latency = plugin->getLatency();
00681 size_t blocks = frames / m_pluginBlockSize;
00682
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 size_t got = blocks * m_pluginBlockSize;
00694
00695 #ifdef DEBUG_AUDIO_GENERATOR
00696 std::cout << "mixModel [note]: frames " << frames
00697 << ", blocks " << blocks << std::endl;
00698 #endif
00699
00700 snd_seq_event_t onEv;
00701 onEv.type = SND_SEQ_EVENT_NOTEON;
00702 onEv.data.note.channel = 0;
00703 onEv.data.note.note = 64;
00704 onEv.data.note.velocity = 100;
00705
00706 snd_seq_event_t offEv;
00707 offEv.type = SND_SEQ_EVENT_NOTEOFF;
00708 offEv.data.note.channel = 0;
00709 offEv.data.note.velocity = 0;
00710
00711 NoteOffSet ¬eOffs = m_noteOffs[nm];
00712
00713 for (size_t i = 0; i < blocks; ++i) {
00714
00715 size_t reqStart = startFrame + i * m_pluginBlockSize;
00716
00717 NoteModel::PointList points =
00718 nm->getPoints(reqStart + latency,
00719 reqStart + latency + m_pluginBlockSize);
00720
00721 Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime
00722 (startFrame + i * m_pluginBlockSize, m_sourceSampleRate);
00723
00724 for (NoteModel::PointList::iterator pli =
00725 points.begin(); pli != points.end(); ++pli) {
00726
00727 size_t pliFrame = pli->frame;
00728
00729 if (pliFrame >= latency) pliFrame -= latency;
00730
00731 if (pliFrame < reqStart ||
00732 pliFrame >= reqStart + m_pluginBlockSize) continue;
00733
00734 while (noteOffs.begin() != noteOffs.end() &&
00735 noteOffs.begin()->frame <= pliFrame) {
00736
00737 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00738 (noteOffs.begin()->frame, m_sourceSampleRate);
00739
00740 offEv.data.note.note = noteOffs.begin()->pitch;
00741
00742 #ifdef DEBUG_AUDIO_GENERATOR
00743 std::cerr << "mixModel [note]: sending note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl;
00744 #endif
00745
00746 plugin->sendEvent(eventTime, &offEv);
00747 noteOffs.erase(noteOffs.begin());
00748 }
00749
00750 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00751 (pliFrame, m_sourceSampleRate);
00752
00753 if (nm->getScaleUnits() == "Hz") {
00754 onEv.data.note.note = Pitch::getPitchForFrequency(pli->value);
00755 } else {
00756 onEv.data.note.note = lrintf(pli->value);
00757 }
00758
00759 if (pli->level > 0.f && pli->level <= 1.f) {
00760 onEv.data.note.velocity = lrintf(pli->level * 127);
00761 } else {
00762 onEv.data.note.velocity = 100;
00763 }
00764
00765 plugin->sendEvent(eventTime, &onEv);
00766
00767 #ifdef DEBUG_AUDIO_GENERATOR
00768 std::cout << "mixModel [note]: point at frame " << pliFrame << ", block start " << (startFrame + i * m_pluginBlockSize) << ", resulting time " << eventTime << std::endl;
00769 #endif
00770
00771 size_t duration = pli->duration;
00772 if (duration == 0 || duration == 1) {
00773 duration = m_sourceSampleRate / 20;
00774 }
00775 NoteOff noff;
00776 noff.pitch = onEv.data.note.note;
00777 noff.frame = pliFrame + duration;
00778 noteOffs.insert(noff);
00779 }
00780
00781 while (noteOffs.begin() != noteOffs.end() &&
00782 noteOffs.begin()->frame <=
00783 startFrame + i * m_pluginBlockSize + m_pluginBlockSize) {
00784
00785 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
00786 (noteOffs.begin()->frame, m_sourceSampleRate);
00787
00788 offEv.data.note.note = noteOffs.begin()->pitch;
00789
00790 #ifdef DEBUG_AUDIO_GENERATOR
00791 std::cerr << "mixModel [note]: sending leftover note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl;
00792 #endif
00793
00794 plugin->sendEvent(eventTime, &offEv);
00795 noteOffs.erase(noteOffs.begin());
00796 }
00797
00798 plugin->run(blockTime);
00799 float **outs = plugin->getAudioOutputBuffers();
00800
00801 for (size_t c = 0; c < m_targetChannelCount; ++c) {
00802 #ifdef DEBUG_AUDIO_GENERATOR
00803 std::cout << "mixModel [note]: adding " << m_pluginBlockSize << " samples from plugin output " << c << std::endl;
00804 #endif
00805
00806 size_t sourceChannel = (c % plugin->getAudioOutputCount());
00807
00808 float channelGain = gain;
00809 if (pan != 0.0) {
00810 if (c == 0) {
00811 if (pan > 0.0) channelGain *= 1.0 - pan;
00812 } else {
00813 if (pan < 0.0) channelGain *= pan + 1.0;
00814 }
00815 }
00816
00817 for (size_t j = 0; j < m_pluginBlockSize; ++j) {
00818 buffer[c][i * m_pluginBlockSize + j] +=
00819 channelGain * outs[sourceChannel][j];
00820 }
00821 }
00822 }
00823
00824 return got;
00825 }
00826