Mercurial > hg > svapp
diff audioio/AudioGenerator.cpp @ 11:8dc0ae8fccdd
* Add LED button
* Add note model playback (currently assuming that value == MIDI pitch)
* Reorganise PlayParameters and move repository from ViewManager to new
PlayParameterRepository class
author | Chris Cannam |
---|---|
date | Wed, 15 Feb 2006 17:58:35 +0000 |
parents | b6dc944128da |
children | 89bb89894ad6 |
line wrap: on
line diff
--- a/audioio/AudioGenerator.cpp Thu Feb 09 18:01:52 2006 +0000 +++ b/audioio/AudioGenerator.cpp Wed Feb 15 17:58:35 2006 +0000 @@ -11,7 +11,9 @@ #include "base/ViewManager.h" #include "base/PlayParameters.h" +#include "base/PlayParameterRepository.h" +#include "model/NoteModel.h" #include "model/DenseTimeValueModel.h" #include "model/SparseOneDimensionalModel.h" @@ -58,15 +60,45 @@ SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>(model); - if (!sodm) return false; // nothing else to initialise + if (sodm) { + QString pluginId = QString("dssi:%1:sample_player"). + arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); + RealTimePluginInstance *plugin = loadPlugin(pluginId, "cowbell"); + if (plugin) { + QMutexLocker locker(&m_mutex); + m_synthMap[sodm] = plugin; + return true; + } else { + return false; + } + } + NoteModel *nm = dynamic_cast<NoteModel *>(model); + if (nm) { + QString pluginId = QString("dssi:%1:sample_player"). + arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); + RealTimePluginInstance *plugin = loadPlugin(pluginId, "piano"); + if (plugin) { + QMutexLocker locker(&m_mutex); + m_synthMap[nm] = plugin; + return true; + } else { + return false; + } + } + + + return false; +} + +RealTimePluginInstance * +AudioGenerator::loadPlugin(QString pluginId, QString program) +{ // QString pluginId = "dssi:/usr/lib/dssi/dssi-vst.so:FEARkILLERrev1.dll"; // QString pluginId = "dssi:/usr/lib/dssi/hexter.so:hexter"; // QString pluginId = "dssi:/usr/lib/dssi/sineshaper.so:sineshaper"; // QString pluginId = "dssi:/usr/local/lib/dssi/xsynth-dssi.so:Xsynth"; // QString pluginId = "dssi:/usr/local/lib/dssi/trivial_synth.so:TS"; - QString pluginId = QString("dssi:%1:sample_player"). - arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); RealTimePluginFactory *factory = RealTimePluginFactory::instanceFor(pluginId); @@ -80,24 +112,24 @@ (pluginId, 0, 0, m_sourceSampleRate, m_pluginBlockSize, m_targetChannelCount); if (instance) { - QMutexLocker locker(&m_mutex); - m_synthMap[sodm] = instance; for (unsigned int i = 0; i < instance->getParameterCount(); ++i) { instance->setParameterValue(i, instance->getParameterDefault(i)); } - QString program = instance->getProgram(0, 0); + QString defaultProgram = instance->getProgram(0, 0); + if (defaultProgram != "") { + std::cerr << "first selecting default program " << defaultProgram.toLocal8Bit().data() << std::endl; + instance->selectProgram(defaultProgram); + } if (program != "") { - std::cerr << "selecting program " << program.toLocal8Bit().data() << std::endl; + std::cerr << "now selecting desired program " << program.toLocal8Bit().data() << std::endl; instance->selectProgram(program); } - instance->selectProgram("cowbell"); //!!! instance->setIdealChannelCount(m_targetChannelCount); // reset! } else { std::cerr << "Failed to instantiate plugin" << std::endl; - return false; } - return true; + return instance; } void @@ -169,7 +201,8 @@ QMutexLocker locker(&m_mutex); - PlayParameters *parameters = m_viewManager->getPlayParameters(model); + PlayParameters *parameters = + PlayParameterRepository::instance()->getPlayParameters(model); if (!parameters) return frameCount; bool playing = !parameters->isPlayMuted(); @@ -191,6 +224,12 @@ buffer, gain, pan, fadeIn, fadeOut); } + NoteModel *nm = dynamic_cast<NoteModel *>(model); + if (nm) { + return mixNoteModel(nm, startFrame, frameCount, + buffer, gain, pan, fadeIn, fadeOut); + } + return frameCount; } @@ -246,7 +285,7 @@ return got; } - + size_t AudioGenerator::mixSparseOneDimensionalModel(SparseOneDimensionalModel *sodm, size_t startFrame, size_t frames, @@ -377,3 +416,137 @@ return got; } + +//!!! mucho duplication with above -- refactor +size_t +AudioGenerator::mixNoteModel(NoteModel *nm, + size_t startFrame, size_t frames, + float **buffer, float gain, float pan, + size_t /* fadeIn */, + size_t /* fadeOut */) +{ + RealTimePluginInstance *plugin = m_synthMap[nm]; + if (!plugin) return 0; + + size_t latency = plugin->getLatency(); + size_t blocks = frames / m_pluginBlockSize; + + //!!! hang on -- the fact that the audio callback play source's + //buffer is a multiple of the plugin's buffer size doesn't mean + //that we always get called for a multiple of it here (because it + //also depends on the JACK block size). how should we ensure that + //all models write the same amount in to the mix, and that we + //always have a multiple of the plugin buffer size? I guess this + //class has to be queryable for the plugin buffer size & the + //callback play source has to use that as a multiple for all the + //calls to mixModel + + size_t got = blocks * m_pluginBlockSize; + +#ifdef DEBUG_AUDIO_GENERATOR + std::cout << "mixModel [note]: frames " << frames + << ", blocks " << blocks << std::endl; +#endif + + snd_seq_event_t onEv; + onEv.type = SND_SEQ_EVENT_NOTEON; + onEv.data.note.channel = 0; + onEv.data.note.note = 64; + onEv.data.note.velocity = 127; + + snd_seq_event_t offEv; + offEv.type = SND_SEQ_EVENT_NOTEOFF; + offEv.data.note.channel = 0; + offEv.data.note.velocity = 0; + + NoteOffSet ¬eOffs = m_noteOffs[nm]; + + for (size_t i = 0; i < blocks; ++i) { + + size_t reqStart = startFrame + i * m_pluginBlockSize; + + NoteModel::PointList points = + nm->getPoints(reqStart + latency, + reqStart + latency + m_pluginBlockSize); + + RealTime blockTime = RealTime::frame2RealTime + (startFrame + i * m_pluginBlockSize, m_sourceSampleRate); + + for (NoteModel::PointList::iterator pli = + points.begin(); pli != points.end(); ++pli) { + + size_t pliFrame = pli->frame; + + if (pliFrame >= latency) pliFrame -= latency; + + if (pliFrame < reqStart || + pliFrame >= reqStart + m_pluginBlockSize) continue; + + while (noteOffs.begin() != noteOffs.end() && + noteOffs.begin()->frame <= pliFrame) { + + RealTime eventTime = RealTime::frame2RealTime + (noteOffs.begin()->frame, m_sourceSampleRate); + + offEv.data.note.note = noteOffs.begin()->pitch; + +#ifdef DEBUG_AUDIO_GENERATOR + std::cerr << "mixModel [note]: sending note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl; +#endif + + plugin->sendEvent(eventTime, &offEv); + noteOffs.erase(noteOffs.begin()); + } + + RealTime eventTime = RealTime::frame2RealTime + (pliFrame, m_sourceSampleRate); + + onEv.data.note.note = lrintf(pli->value); + + plugin->sendEvent(eventTime, &onEv); + +#ifdef DEBUG_AUDIO_GENERATOR + std::cout << "mixModel [note]: point at frame " << pliFrame << ", block start " << (startFrame + i * m_pluginBlockSize) << ", resulting time " << eventTime << std::endl; +#endif + + size_t duration = pli->duration; + NoteOff noff; + noff.pitch = onEv.data.note.note; + noff.frame = pliFrame + duration; + noteOffs.insert(noff); + } + + while (noteOffs.begin() != noteOffs.end() && + noteOffs.begin()->frame <= + startFrame + i * m_pluginBlockSize + m_pluginBlockSize) { + + RealTime eventTime = RealTime::frame2RealTime + (noteOffs.begin()->frame, m_sourceSampleRate); + + offEv.data.note.note = noteOffs.begin()->pitch; + +#ifdef DEBUG_AUDIO_GENERATOR + std::cerr << "mixModel [note]: sending leftover note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl; +#endif + + plugin->sendEvent(eventTime, &offEv); + noteOffs.erase(noteOffs.begin()); + } + + plugin->run(blockTime); + float **outs = plugin->getAudioOutputBuffers(); + + for (size_t c = 0; c < m_targetChannelCount && c < plugin->getAudioOutputCount(); ++c) { +#ifdef DEBUG_AUDIO_GENERATOR + std::cout << "mixModel [note]: adding " << m_pluginBlockSize << " samples from plugin output " << c << std::endl; +#endif + + for (size_t j = 0; j < m_pluginBlockSize; ++j) { + buffer[c][i * m_pluginBlockSize + j] += gain * outs[c][j]; + } + } + } + + return got; +} +