AudioGenerator.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
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 //#define DEBUG_AUDIO_GENERATOR 1
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 //    std::cerr << "AudioGenerator::playPluginConfigurationChanged" << std::endl;
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 //        std::cerr << "first selecting default program " << defaultProgram << std::endl;
00283         instance->selectProgram(defaultProgram);
00284     }
00285     if (program != "") {
00286 //        std::cerr << "now selecting desired program " << program.toStdString() << std::endl;
00287         instance->selectProgram(program.toStdString());
00288     }
00289     instance->setIdealChannelCount(m_targetChannelCount); // reset!
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; // nothing to do
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 //    std::cerr << "AudioGenerator::setTargetChannelCount(" << targetChannelCount << ")" << std::endl;
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 //      std::cerr << "mixing channel " << c << " from source channel " << sourceChannel << std::endl;
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 /* fadeIn */,
00531                                              size_t /* fadeOut */)
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     //buffer is a multiple of the plugin's buffer size doesn't mean
00541     //that we always get called for a multiple of it here (because it
00542     //also depends on the JACK block size).  how should we ensure that
00543     //all models write the same amount in to the mix, and that we
00544     //always have a multiple of the plugin buffer size?  I guess this
00545     //class has to be queryable for the plugin buffer size & the
00546     //callback play source has to use that as a multiple for all the
00547     //calls to mixModel
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 &noteOffs = 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; // frames [for now]
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 /* fadeIn */,
00675                              size_t /* fadeOut */)
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     //buffer is a multiple of the plugin's buffer size doesn't mean
00685     //that we always get called for a multiple of it here (because it
00686     //also depends on the JACK block size).  how should we ensure that
00687     //all models write the same amount in to the mix, and that we
00688     //always have a multiple of the plugin buffer size?  I guess this
00689     //class has to be queryable for the plugin buffer size & the
00690     //callback play source has to use that as a multiple for all the
00691     //calls to mixModel
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 &noteOffs = 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 

Generated on Wed Feb 20 15:45:24 2008 for SonicVisualiser by  doxygen 1.5.1