diff audioio/AudioGenerator.cpp @ 308:289d65722123 tonioni

More work on mixing and file i/o for sample stuff
author Chris Cannam
date Tue, 07 Jan 2014 15:50:04 +0000
parents 6eb15c3aee0a
children 71050ffd0141
line wrap: on
line diff
--- a/audioio/AudioGenerator.cpp	Tue Jan 07 13:10:35 2014 +0000
+++ b/audioio/AudioGenerator.cpp	Tue Jan 07 15:50:04 2014 +0000
@@ -145,9 +145,9 @@
     if (mixer) {
         QMutexLocker locker(&m_mutex);
         m_clipMixerMap[model] = mixer;
-        return true;
     }
 }
+
 /*!!!
 void
 AudioGenerator::playPluginConfigurationChanged(const Playable *playable,
@@ -196,78 +196,31 @@
         sampleId = parameters->getPlaySampleId();
     }
 
-    std::cerr << "AudioGenerator::loadPluginFor(" << model << "): sample id = " << sampleId << std::endl;
+    std::cerr << "AudioGenerator::makeClipMixerFor(" << model << "): sample id = " << sampleId << std::endl;
 
     if (sampleId == "") {
-        SVDEBUG << "AudioGenerator::loadPluginFor(" << model << "): no sample, skipping" << endl;
+        SVDEBUG << "AudioGenerator::makeClipMixerFor(" << model << "): no sample, skipping" << endl;
         return 0;
     }
 
+    ClipMixer *mixer = new ClipMixer(m_targetChannelCount,
+                                     m_sourceSampleRate,
+                                     m_processingBlockSize);
 
+    float clipF0 = Pitch::getFrequencyForPitch(60, 0, 440.0f); // required
 
+    QString clipPath = QString("%1/%2.wav").arg(m_sampleDir).arg(sampleId);
 
-
-
-    RealTimePluginInstance *plugin = loadPlugin(pluginId, "");
-    if (!plugin) return 0;
-
-    std::cerr << "AudioGenerator::loadPluginFor(" << model << "): loaded plugin "
-              << plugin << std::endl;
-
-    if (configurationXml != "") {
-        PluginXml(plugin).setParametersFromXml(configurationXml);
-        setSampleDir(plugin);
-    }
-
-    configurationXml = PluginXml(plugin).toXmlString();
-
-    if (parameters) {
-        parameters->setPlaySampleId(pluginId);
-        parameters->setPlayPluginConfiguration(configurationXml);
-    }
-
-    return plugin;
-}
-
-RealTimePluginInstance *
-AudioGenerator::loadPlugin(QString pluginId, QString program)
-{
-    RealTimePluginFactory *factory =
-	RealTimePluginFactory::instanceFor(pluginId);
-    
-    if (!factory) {
-	cerr << "Failed to get plugin factory" << endl;
-	return 0;
-    }
-	
-    RealTimePluginInstance *instance =
-	factory->instantiatePlugin
-	(pluginId, 0, 0, m_sourceSampleRate, m_processingBlockSize, m_targetChannelCount);
-
-    if (!instance) {
-	cerr << "Failed to instantiate plugin " << pluginId << endl;
+    if (!mixer->loadClipData(clipPath, clipF0)) {
+        delete mixer;
         return 0;
     }
 
-    setSampleDir(instance);
+    std::cerr << "AudioGenerator::makeClipMixerFor(" << model << "): loaded clip " << sampleId << std::endl;
 
-    for (unsigned int i = 0; i < instance->getParameterCount(); ++i) {
-        instance->setParameterValue(i, instance->getParameterDefault(i));
-    }
-    std::string defaultProgram = instance->getProgram(0, 0);
-    if (defaultProgram != "") {
-        cerr << "first selecting default program " << defaultProgram << endl;
-        instance->selectProgram(defaultProgram);
-    }
-    if (program != "") {
-        cerr << "now selecting desired program " << program << endl;
-        instance->selectProgram(program.toStdString());
-    }
-    instance->setIdealChannelCount(m_targetChannelCount); // reset!
+    return mixer;
+}
 
-    return instance;
-}
-*/
 void
 AudioGenerator::removeModel(Model *model)
 {
@@ -277,38 +230,35 @@
 
     QMutexLocker locker(&m_mutex);
 
-    if (m_synthMap.find(sodm) == m_synthMap.end()) return;
+    if (m_clipMixerMap.find(sodm) == m_clipMixerMap.end()) return;
 
-//!!!    RealTimePluginInstance *instance = m_synthMap[sodm];
-//    m_synthMap.erase(sodm);
-    delete instance;
+    ClipMixer *mixer = m_clipMixerMap[sodm];
+    m_clipMixerMap.erase(sodm);
+    delete mixer;
 }
 
 void
 AudioGenerator::clearModels()
 {
     QMutexLocker locker(&m_mutex);
-/*!!!
-    while (!m_synthMap.empty()) {
-	RealTimePluginInstance *instance = m_synthMap.begin()->second;
-	m_synthMap.erase(m_synthMap.begin());
-	delete instance;
+
+    while (!m_clipMixerMap.empty()) {
+        ClipMixer *mixer = m_clipMixerMap.begin()->second;
+	m_clipMixerMap.erase(m_clipMixerMap.begin());
+	delete mixer;
     }
-*/
 }    
 
 void
 AudioGenerator::reset()
 {
     QMutexLocker locker(&m_mutex);
-/*!!!
-    for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
+
+    for (ClipMixerMap::iterator i = m_clipMixerMap.begin(); i != m_clipMixerMap.end(); ++i) {
 	if (i->second) {
-	    i->second->silence();
-	    i->second->discardEvents();
+	    i->second->reset();
 	}
     }
-*/
 
     m_noteOffs.clear();
 }
@@ -323,11 +273,9 @@
     QMutexLocker locker(&m_mutex);
     m_targetChannelCount = targetChannelCount;
 
-/*!!!
-    for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
-	if (i->second) i->second->setIdealChannelCount(targetChannelCount);
+    for (ClipMixerMap::iterator i = m_clipMixerMap.begin(); i != m_clipMixerMap.end(); ++i) {
+	if (i->second) i->second->setChannelCount(targetChannelCount);
     }
-*/
 }
 
 size_t
@@ -515,10 +463,9 @@
                                       size_t /* fadeIn */,
                                       size_t /* fadeOut */)
 {
-    RealTimePluginInstance *plugin = m_synthMap[model];
-    if (!plugin) return 0;
+    ClipMixer *clipMixer = m_clipMixerMap[model];
+    if (!clipMixer) return 0;
 
-    size_t latency = plugin->getLatency();
     size_t blocks = frames / m_processingBlockSize;
     
     //!!! hang on -- the fact that the audio callback play source's
@@ -538,17 +485,13 @@
 	      << ", blocks " << blocks << endl;
 #endif
 
-    snd_seq_event_t onEv;
-    onEv.type = SND_SEQ_EVENT_NOTEON;
-    onEv.data.note.channel = 0;
+    ClipMixer::NoteStart on;
+    ClipMixer::NoteEnd off;
 
-    snd_seq_event_t offEv;
-    offEv.type = SND_SEQ_EVENT_NOTEOFF;
-    offEv.data.note.channel = 0;
-    offEv.data.note.velocity = 0;
-    
     NoteOffSet &noteOffs = m_noteOffs[model];
 
+    float **bufferIndexes = new float *[m_targetChannelCount];
+
     for (size_t i = 0; i < blocks; ++i) {
 
 	size_t reqStart = startFrame + i * m_processingBlockSize;
@@ -556,105 +499,77 @@
         NoteList notes;
         NoteExportable *exportable = dynamic_cast<NoteExportable *>(model);
         if (exportable) {
-            notes = exportable->getNotes(reqStart + latency,
-                                         reqStart + latency + m_processingBlockSize);
+            notes = exportable->getNotes(reqStart,
+                                         reqStart + m_processingBlockSize);
         }
 
-        Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime
-	    (startFrame + i * m_processingBlockSize, m_sourceSampleRate);
+        std::vector<ClipMixer::NoteStart> starts;
+        std::vector<ClipMixer::NoteEnd> ends;
 
 	for (NoteList::const_iterator ni = notes.begin();
              ni != notes.end(); ++ni) {
 
 	    size_t noteFrame = ni->start;
 
-	    if (noteFrame >= latency) noteFrame -= latency;
-
 	    if (noteFrame < reqStart ||
 		noteFrame >= reqStart + m_processingBlockSize) continue;
 
 	    while (noteOffs.begin() != noteOffs.end() &&
 		   noteOffs.begin()->frame <= noteFrame) {
 
-                Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
-		    (noteOffs.begin()->frame, m_sourceSampleRate);
+                size_t eventFrame = noteOffs.begin()->frame;
+                if (eventFrame < reqStart) eventFrame = reqStart;
 
-		offEv.data.note.note = noteOffs.begin()->pitch;
+                off.frameOffset = eventFrame - reqStart;
+                off.frequency = noteOffs.begin()->frequency;
 
 #ifdef DEBUG_AUDIO_GENERATOR
-		cerr << "mixModel [synthetic]: sending note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << " pitch " << noteOffs.begin()->pitch << endl;
+		cerr << "mixModel [synthetic]: adding note-off at frame " << eventFrame << " frame offset " << off.frameOffset << " frequency " << off.frequency << endl;
 #endif
 
-		plugin->sendEvent(eventTime, &offEv);
+                ends.push_back(off);
 		noteOffs.erase(noteOffs.begin());
 	    }
 
-            Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
-		(noteFrame, m_sourceSampleRate);
-	    
-            if (ni->isMidiPitchQuantized) {
-                onEv.data.note.note = ni->midiPitch;
-            } else {
-#ifdef DEBUG_AUDIO_GENERATOR
-                cerr << "mixModel [synthetic]: non-pitch-quantized notes are not supported [yet], quantizing" << endl;
-#endif
-                onEv.data.note.note = Pitch::getPitchForFrequency(ni->frequency);
-            }
-
-            onEv.data.note.velocity = ni->velocity;
-
-	    plugin->sendEvent(eventTime, &onEv);
+            on.frameOffset = noteFrame - reqStart;
+            on.frequency = ni->getFrequency();
+            on.level = float(ni->velocity) / 127.0;
+            on.pan = pan;
 
 #ifdef DEBUG_AUDIO_GENERATOR
-	    cout << "mixModel [synthetic]: note at frame " << noteFrame << ", block start " << (startFrame + i * m_processingBlockSize) << ", resulting time " << eventTime << endl;
+	    cout << "mixModel [synthetic]: adding note at frame " << noteFrame << ", frame offset " << on.frameOffset << " frequency " << on.frequency << endl;
 #endif
 	    
+            starts.push_back(on);
 	    noteOffs.insert
-                (NoteOff(onEv.data.note.note, noteFrame + ni->duration));
+                (NoteOff(on.frequency, noteFrame + ni->duration));
 	}
 
 	while (noteOffs.begin() != noteOffs.end() &&
-	       noteOffs.begin()->frame <=
-	       startFrame + i * m_processingBlockSize + m_processingBlockSize) {
+	       noteOffs.begin()->frame <= reqStart + m_processingBlockSize) {
 
-            Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
-		(noteOffs.begin()->frame, m_sourceSampleRate);
+            size_t eventFrame = noteOffs.begin()->frame;
+            if (eventFrame < reqStart) eventFrame = reqStart;
 
-	    offEv.data.note.note = noteOffs.begin()->pitch;
+            off.frameOffset = eventFrame - reqStart;
+            off.frequency = noteOffs.begin()->frequency;
 
 #ifdef DEBUG_AUDIO_GENERATOR
-            cerr << "mixModel [synthetic]: sending leftover note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << " pitch " << noteOffs.begin()->pitch << endl;
+            cerr << "mixModel [synthetic]: adding leftover note-off at frame " << eventFrame << " frame offset " << off.frameOffset << " frequency " << off.frequency << endl;
 #endif
 
-	    plugin->sendEvent(eventTime, &offEv);
-	    noteOffs.erase(noteOffs.begin());
+            ends.push_back(off);
+            noteOffs.erase(noteOffs.begin());
 	}
-	
-	plugin->run(blockTime);
-	float **outs = plugin->getAudioOutputBuffers();
 
 	for (size_t c = 0; c < m_targetChannelCount; ++c) {
-#ifdef DEBUG_AUDIO_GENERATOR
-	    cout << "mixModel [synthetic]: adding " << m_processingBlockSize << " samples from plugin output " << c << endl;
-#endif
+            bufferIndexes[c] = buffer[c] + i * m_processingBlockSize;
+        }
 
-	    size_t sourceChannel = (c % plugin->getAudioOutputCount());
+        clipMixer->mix(bufferIndexes, gain, starts, ends);
+    }
 
-	    float channelGain = gain;
-	    if (pan != 0.0) {
-		if (c == 0) {
-		    if (pan > 0.0) channelGain *= 1.0 - pan;
-		} else {
-		    if (pan < 0.0) channelGain *= pan + 1.0;
-		}
-	    }
-
-	    for (size_t j = 0; j < m_processingBlockSize; ++j) {
-		buffer[c][i * m_processingBlockSize + j] +=
-		    channelGain * outs[sourceChannel][j];
-	    }
-	}
-    }
+    delete[] bufferIndexes;
 
     return got;
 }