From e326245ae87c5d259c8e3cedb1e057b1842487c7 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Mon, 2 May 2011 03:05:28 +0000 Subject: More fixes, improvements to ladspa and dssi processing, control responsiveness. --- muse2/ChangeLog | 8 +++++++ muse2/muse/audio.h | 1 + muse2/muse/dssihost.cpp | 64 +++++++++++++++++++++++++++++++++++++------------ muse2/muse/plugin.cpp | 37 ++++++++++++++++++++-------- 4 files changed, 85 insertions(+), 25 deletions(-) (limited to 'muse2') diff --git a/muse2/ChangeLog b/muse2/ChangeLog index a2248523..9bd18d89 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,11 @@ +01.05.2011: + - More fixes, improvements to ladspa and dssi processing, control responsiveness, of 25.04.2011. (Tim) + Timestamp control ring buffer items with linear Audio::curFrame() instead of circular Audio::timestamp(). + Added Audio::curSyncFrame(), used it in process routines to subtract from timestamp. + All effect/synth generic/native gui controls should be quick now. + - Dssi synths respond to Audio track controller graphs now. + Still TODO: Make Audio track controllers full-speed (like the controls), they are still once per period. + Do same for midi->ladspa controller code. 28.04.2011: - More separation of Alsa and Jack midi processing. Possible fix for crash report by Geoff B. (p4.0.22 Tim) Added MidiDevice::handleStop(), ::handleSeek(). Split processing among MidiSeq::processStop, ::processSeek diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h index 1eb03bbc..940dd2a5 100644 --- a/muse2/muse/audio.h +++ b/muse2/muse/audio.h @@ -283,6 +283,7 @@ class Audio { int timestamp() const; void processMidi(); unsigned curFrame() const; + unsigned curSyncFrame() const { return syncFrame; } void recordStop(); bool freewheel() const { return _freewheel; } void setFreewheel(bool val); diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp index adfda659..e5ccd628 100644 --- a/muse2/muse/dssihost.cpp +++ b/muse2/muse/dssihost.cpp @@ -353,11 +353,10 @@ static void scanDSSILib(QFileInfo& fi) // ddskrjo removed const for argument // That way we cover all bases - effect plugins and synths. // Non-synths will show up in the ladspa effect dialog, while synths will show up here... // There should be nothing left out... - if(descr->run_synth || + if(descr->run_synth || descr->run_synth_adding || descr->run_multiple_synths || descr->run_multiple_synths_adding) - { const QString label(descr->LADSPA_Plugin->Label); @@ -404,13 +403,13 @@ static void scanDSSILib(QFileInfo& fi) // ddskrjo removed const for argument synthis.push_back(s); } - else - { + //else + //{ // NOTE: Just a test //QFileInfo ffi(fi); //plugins.add(&ffi, LADSPA_Descriptor_Function(NULL), descr->LADSPA_Plugin, false); //plugins.add(&ffi, descr, false); - } + //} } } dlclose(handle); @@ -1407,7 +1406,10 @@ void DssiSynthIF::setParameter(unsigned long n, float v) // Time-stamp the event. This does a possibly slightly slow call to gettimeofday via timestamp(). // timestamp() is more or less an estimate of the current frame. (This is exactly how ALSA events // are treated when they arrive in our ALSA driver.) - ce.frame = audio->timestamp(); + //ce.frame = audio->timestamp(); + // p4.0.23 timestamp() is circular, which is making it impossible to deal with 'modulo' events which + // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead: + ce.frame = audio->curFrame(); if(_controlFifo.put(ce)) { fprintf(stderr, "DssiSynthIF::setParameter: fifo overflow: in control number:%lu\n", n); @@ -2315,8 +2317,9 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns //nevents = 0; - unsigned long endPos = pos + n; + //unsigned long endPos = pos + n; int frameOffset = audio->getFrameOffset(); + unsigned long syncFrame = audio->curSyncFrame(); // All ports must be connected to something! unsigned long nop, k; @@ -2369,6 +2372,17 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns if(fixedsize > n) fixedsize = n; + // Process automation control values now. + // TODO: This needs to be respect frame resolution. Put this inside the sample loop below. + for(unsigned long k = 0; k < synth->_controlInPorts; ++k) + { + if(automation && synti && synti->automationType() != AUTO_OFF && id() != -1) + { + if(controls[k].enCtrl && controls[k].en2Ctrl ) + controls[k].val = synti->pluginCtrlVal(genACnum(id(), k)); + } + } + while(sample < n) { //unsigned long nsamp = n; @@ -2377,22 +2391,32 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns bool found = false; unsigned long frame = 0; unsigned long index = 0; + unsigned long evframe; // Get all control ring buffer items valid for this time period... //for(int m = 0; m < cbsz; ++m) while(!_controlFifo.isEmpty()) { //ControlValue v = _controlFifo.get(); ControlEvent v = _controlFifo.peek(); - //printf("DssiSynthIF::getData control idx:%d frame:%d val:%f\n", v.idx, v.frame, v.value); // REMOVE Tim. + // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio. + // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame. + //evframe = (pos + frameOffset > v.frame + n) ? 0 : v.frame - pos - frameOffset + n; + evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n; + + //printf("DssiSynthIF::getData ctrl dssi:%d idx:%lu frame:%lu val:%f unique:%d evframe:%lu\n", + // synth->_isDssiVst, v.idx, v.frame, v.value, v.unique, evframe); // REMOVE Tim. // Process only items in this time period. Make sure to process all // subsequent items which have the same frame. //if(v.frame >= (endPos + frameOffset) || (found && v.frame != frame)) //if(v.frame < sample || v.frame >= (sample + nsamp) || (found && v.frame != frame)) //if(v.frame < sample || v.frame >= (endPos + frameOffset) || (found && v.frame != frame)) - if(v.frame < sample || v.frame >= (endPos + frameOffset) + //if(v.frame < startPos || v.frame >= (endPos + frameOffset) + //if(evframe < sample || evframe >= n + //if(evframe < sample || evframe >= (n + frameOffset) + if(evframe >= n //|| (found && v.frame != frame) //|| (!usefixedrate && found && !v.unique && v.frame != frame) - || (found && !v.unique && v.frame != frame) + || (found && !v.unique && evframe != frame) // dssi-vst needs them serialized and accounted for, no matter what. This works with fixed rate // because nsamp is constant. But with packets, we need to guarantee at least one-frame spacing. // Although we likely won't be using packets with dssi-vst, so it's OK for now. @@ -2404,7 +2428,8 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns if(v.idx >= synth->_controlInPorts) // Sanity check. break; found = true; - frame = v.frame; + //frame = v.frame; + frame = evframe; index = v.idx; // Set the ladspa control port value. controls[v.idx].val = v.value; @@ -2417,8 +2442,8 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns if(sample + nsamp >= n) // Safety check. nsamp = n - sample; - //printf("DssiSynthIF::getData n:%d frame:%d sample:%d nsamp:%d pos:%d fOffset:%d loopcount:%d\n", - // n, frame, sample, nsamp, pos, frameOffset, loopcount); // REMOVE Tim. + //printf("DssiSynthIF::getData n:%d frame:%lu sample:%lu nsamp:%lu pos:%d fOffset:%d syncFrame:%lu loopcount:%d\n", + // n, frame, sample, nsamp, pos, frameOffset, syncFrame, loopcount); // REMOVE Tim. // TODO: TESTING: Don't allow zero-length runs. This could/should be checked in the control loop instead. // Note this means it is still possible to get stuck in the top loop (at least for a while). @@ -2607,6 +2632,12 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns snd_seq_event_t* ev = events; synth->dssi->run_multiple_synths(1, &handle, nsamp, &ev, &nevents); } + //else + //if(synth->dssi->LADSPA_Plugin->run) + //{ + // // Just a test, worked OK. + // synth->dssi->LADSPA_Plugin->run(handle, nsamp); + //} sample += nsamp; loopcount++; // REMOVE Tim. @@ -2982,7 +3013,7 @@ int DssiSynthIF::oscControl(unsigned long port, float value) //LADSPA_Data value = argv[1]->f; #ifdef DSSI_DEBUG - printf("DssiSynthIF::oscControl received oscControl port:%lu val:%f\n", port, value); + printf("DssiSynthIF::oscControl received oscControl port:%lu val:%f\n", port, value); #endif //int controlPorts = synth->_controlInPorts; @@ -3051,7 +3082,10 @@ int DssiSynthIF::oscControl(unsigned long port, float value) // Time-stamp the event. This does a possibly slightly slow call to gettimeofday via timestamp(). // timestamp() is more or less an estimate of the current frame. (This is exactly how ALSA events // are treated when they arrive in our ALSA driver.) - ce.frame = audio->timestamp(); + //ce.frame = audio->timestamp(); + // p4.0.23 timestamp() is circular, which is making it impossible to deal with 'modulo' events which + // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead: + ce.frame = audio->curFrame(); if(_controlFifo.put(ce)) { fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\n", cport); diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 78ade353..bd33fb15 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -1825,7 +1825,10 @@ void PluginI::setParam(unsigned long i, float val) // Time-stamp the event. This does a possibly slightly slow call to gettimeofday via timestamp(). // timestamp() is more or less an estimate of the current frame. (This is exactly how ALSA events // are treated when they arrive in our ALSA driver.) - ce.frame = audio->timestamp(); + //ce.frame = audio->timestamp(); + // p4.0.23 timestamp() is circular, which is making it impossible to deal with 'modulo' events which + // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead: + ce.frame = audio->curFrame(); if(_controlFifo.put(ce)) { fprintf(stderr, "PluginI::setParameter: fifo overflow: in control number:%lu\n", i); @@ -2538,7 +2541,8 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** //} //unsigned endPos = pos + n; - unsigned long frameOffset = audio->getFrameOffset(); + //unsigned long frameOffset = audio->getFrameOffset(); + unsigned long syncFrame = audio->curSyncFrame(); unsigned long sample = 0; int loopcount = 0; // REMOVE Tim. @@ -2577,23 +2581,30 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** bool found = false; unsigned long frame = 0; unsigned long index = 0; + unsigned long evframe; // Get all control ring buffer items valid for this time period... //for(int m = 0; m < cbsz; ++m) while(!_controlFifo.isEmpty()) { //ControlValue v = _controlFifo.get(); ControlEvent v = _controlFifo.peek(); - //printf("PluginI::apply control idx:%lu frame:%lu val:%f\n", v.idx, v.frame, v.value); // REMOVE Tim. + // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio. + // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame. + //evframe = (pos + frameOffset > v.frame + n) ? 0 : v.frame - pos - frameOffset + n; + evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n; // Process only items in this time period. Make sure to process all // subsequent items which have the same frame. + //printf("PluginI::apply control idx:%lu frame:%lu val:%f unique:%d evframe:%lu\n", + // v.idx, v.frame, v.value, v.unique, evframe); // REMOVE Tim. //if(v.frame >= (endPos + frameOffset) || (found && v.frame != frame)) //if(v.frame < sample || v.frame >= (sample + nsamp) || (found && v.frame != frame)) //if(v.frame < sample || v.frame >= (endPos + frameOffset) || (found && v.frame != frame)) //if(v.frame < sample || v.frame >= (endPos + frameOffset) - if(v.frame < sample || v.frame >= frameOffset + //if(v.frame < sample || v.frame >= frameOffset + if(evframe >= n //|| (found && v.frame != frame) //|| (!usefixedrate && found && !v.unique && v.frame != frame) - || (found && !v.unique && v.frame != frame) + || (found && !v.unique && evframe != frame) // dssi-vst needs them serialized and accounted for, no matter what. This works with fixed rate // because nsamp is constant. But with packets, we need to guarantee at least one-frame spacing. // Although we likely won't be using packets with dssi-vst, so it's OK for now. @@ -2606,12 +2617,14 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** if(v.idx >= _plugin->_controlInPorts) break; found = true; - frame = v.frame; + //frame = v.frame; + frame = evframe; index = v.idx; // Set the ladspa control port value. //controls[v.idx].val = v.value; controls[v.idx].tmpVal = v.value; + /* // Need to update the automation value, otherwise it overwrites later with the last automation value. if(_track && _id != -1) { @@ -2637,6 +2650,7 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** // enableController(k, false); //_track->recordAutomation(id, v.value); } + */ } // Now update the actual values from the temporary values... @@ -2650,8 +2664,8 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** if(sample + nsamp >= n) // Safety check. nsamp = n - sample; - //printf("PluginI::apply ports:%lu n:%lu frame:%lu sample:%lu nsamp:%lu fOffset:%lu loopcount:%d\n", - // ports, n, frame, sample, nsamp, frameOffset, loopcount); // REMOVE Tim. + //printf("PluginI::apply ports:%lu n:%lu frame:%lu sample:%lu nsamp:%lu syncFrame:%lu loopcount:%d\n", + // ports, n, frame, sample, nsamp, syncFrame, loopcount); // REMOVE Tim. // TODO: TESTING: Don't allow zero-length runs. This could/should be checked in the control loop instead. // Note this means it is still possible to get stuck in the top loop (at least for a while). @@ -2829,7 +2843,7 @@ int PluginI::oscControl(unsigned long port, float value) //LADSPA_Data value = argv[1]->f; #ifdef PLUGIN_DEBUGIN - printf("PluginI::oscControl received oscControl port:%lu val:%f\n", port, value); + printf("PluginI::oscControl received oscControl port:%lu val:%f\n", port, value); #endif //int controlPorts = synth->_controller; @@ -2892,7 +2906,10 @@ int PluginI::oscControl(unsigned long port, float value) // Time-stamp the event. This does a possibly slightly slow call to gettimeofday via timestamp(). // timestamp() is more or less an estimate of the current frame. (This is exactly how ALSA events // are treated when they arrive in our ALSA driver.) - ce.frame = audio->timestamp(); + //ce.frame = audio->timestamp(); + // p4.0.23 timestamp() is circular, which is making it impossible to deal with 'modulo' events which + // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead: + ce.frame = audio->curFrame(); if(_controlFifo.put(ce)) { fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%lu\n", cport); -- cgit v1.2.3