summaryrefslogtreecommitdiff
path: root/muse2/muse/dssihost.cpp
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2011-04-25 20:47:28 +0000
committerTim E. Real <termtech@rogers.com>2011-04-25 20:47:28 +0000
commit499ccec21dd2ac636fb019c98a902c351b4ec165 (patch)
tree03b867772f9d4543c2ae0e8ca49f389333ea5ad7 /muse2/muse/dssihost.cpp
parent5974951aeaf0a86b83175e018d5bf35e509f5181 (diff)
Overhaul plugin module and add variable run-length ladspa + dssi processing. Please see ChangeLog.
Diffstat (limited to 'muse2/muse/dssihost.cpp')
-rw-r--r--muse2/muse/dssihost.cpp430
1 files changed, 406 insertions, 24 deletions
diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp
index f2e94dae..b91000be 100644
--- a/muse2/muse/dssihost.cpp
+++ b/muse2/muse/dssihost.cpp
@@ -48,6 +48,7 @@
#include "midiport.h"
#include "stringparam.h"
#include "plugin.h"
+#include "controlfifo.h"
//#include "al/al.h"
//#include "al/xml.h"
#include "xml.h"
@@ -550,8 +551,10 @@ DssiSynth::DssiSynth(QFileInfo& fi, const DSSI_Descriptor* d) : // ddskrjo remov
_inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(descr->Properties);
- // Blacklist vst plugins in-place configurable for now.
- if ((_inports != _outports) || (fi.completeBaseName() == QString("dssi-vst") && !config.vstInPlace))
+ // Hack: Special flag required for example for control processing.
+ _isDssiVst = fi.completeBaseName() == QString("dssi-vst");
+ // Hack: Blacklist vst plugins in-place, configurable for now.
+ if ((_inports != _outports) || (_isDssiVst && !config.vstInPlace))
_inPlaceCapable = false;
}
@@ -677,8 +680,10 @@ SynthIF* DssiSynth::createSIF(SynthI* synti)
}
_inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(descr->Properties);
- // Blacklist vst plugins in-place configurable for now.
- if((_inports != _outports) || (info.completeBaseName() == QString("dssi-vst") && !config.vstInPlace))
+ // Hack: Special flag required for example for control processing.
+ _isDssiVst = info.completeBaseName() == QString("dssi-vst");
+ // Hack: Blacklist vst plugins in-place, configurable for now.
+ if((_inports != _outports) || (_isDssiVst && !config.vstInPlace))
_inPlaceCapable = false;
}
}
@@ -1374,10 +1379,22 @@ void DssiSynthIF::setParameter(unsigned long n, float v)
return;
}
- if(!controls)
- return;
-
- controls[n].val = v;
+ //if(!controls)
+ // return;
+ //controls[n].val = v;
+ // p4.0.21
+ ControlEvent ce;
+ ce.unique = false;
+ ce.idx = n;
+ ce.value = 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();
+ if(_controlFifo.put(ce))
+ {
+ fprintf(stderr, "DssiSynthIF::setParameter: fifo overflow: in control number:%ld\n", n);
+ }
// Notify that changes are to be sent upon heartbeat.
// TODO: No, at least not for now. So far, setParameter is only called during loading of stored params,
@@ -1579,7 +1596,7 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
len += 2;
//snd_seq_event_t* event = &events[nevents];
- event->queue = SND_SEQ_QUEUE_DIRECT;
+ //event->queue = SND_SEQ_QUEUE_DIRECT;
#ifdef DSSI_DEBUG
fprintf(stderr, "DssiSynthIF::processEvent midi event type:%d chn:%d a:%d b:%d\n", e.type(), chn, a, b);
@@ -1592,12 +1609,16 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_NOTEON\n");
#endif
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
if(b)
snd_seq_ev_set_noteon(event, chn, a, b);
else
snd_seq_ev_set_noteoff(event, chn, a, 0);
break;
case ME_NOTEOFF:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_noteoff(event, chn, a, 0);
break;
case ME_PROGRAM:
@@ -1665,6 +1686,8 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
#endif
b &= 0x3fff;
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_pitchbend(event, chn, b);
// Event pointer filled. Return true.
return true;
@@ -1697,7 +1720,7 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
int ctlnum = a;
//switch(midiControllerType(a))
if(midiControllerType(a) != MidiController::Controller7)
- return false;
+ return false; // Event pointer not filled. Return false.
else
{
/*
@@ -1782,6 +1805,8 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
#ifdef DSSI_DEBUG
printf("DssiSynthIF::processEvent non-ladspa filling midi event chn:%d dataA:%d dataB:%d\n", chn, a, b);
#endif
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_controller(event, chn, a, b);
return true;
}
@@ -1867,9 +1892,13 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
}
break;
case ME_PITCHBEND:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_pitchbend(event, chn, a);
break;
case ME_AFTERTOUCH:
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_chanpress(event, chn, a);
break;
case ME_SYSEX:
@@ -1948,6 +1977,8 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
// "DssiSynthIF::processEvent midi event is ME_SYSEX"
// "WARNING: MIDI event of type ? decoded to 367 bytes, discarding"
// That might be ALSA doing that.
+ snd_seq_ev_clear(event);
+ event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_sysex(event, len,
//(unsigned char*)ba.data());
(unsigned char*)ca);
@@ -1964,6 +1995,8 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
return true;
}
+#if 0
+
//---------------------------------------------------------
// getData
//---------------------------------------------------------
@@ -2241,6 +2274,331 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, uns
return i;
}
+#else
+
+//---------------------------------------------------------
+// getData
+//---------------------------------------------------------
+
+//void DssiSynthIF::getData(MidiEventList* el, unsigned pos, int ch, unsigned samples, float** data)
+iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, unsigned pos, int ports, unsigned n, float** buffer)
+{
+ //#ifdef DSSI_DEBUG
+ // fprintf(stderr, "DssiSynthIF::getData elsize:%d pos:%d ports:%d samples:%d processed already?:%d\n", el->size(), pos, ports, n, synti->processed());
+ //#endif
+
+ // Grab the control ring buffer size now.
+ //const int cbsz = _controlFifo.getSize();
+
+ // We may not be using nevents all at once - this will be just the maximum.
+ unsigned long nevents = el->size() + synti->eventFifo.getSize();
+ snd_seq_event_t events[nevents];
+ // No, do this in processEvent.
+ //memset(events, 0, sizeof(events));
+
+ //nevents = 0;
+
+ unsigned endPos = pos + n;
+ int frameOffset = audio->getFrameOffset();
+
+ // All ports must be connected to something!
+ unsigned long nop, k;
+ // First, copy the given input buffers to our local input buffers.
+ //np = portsin > synth->_inports ? synth->_inports : portsin;
+ //for(k = 0; k < np; ++k)
+ // memcpy(audioInBuffers[k], inbuffer[k], sizeof(float) * n);
+ //for(; k < portsin; ++k)
+ // memset(audioInBuffers[k], 0, sizeof(float) * n);
+
+ // Watch our limits.
+ //willyfoobar-2011-02-13
+ //old code//np = ports > synth->_outports ? synth->_outports : ports;
+ nop = ((unsigned long) ports) > synth->_outports ? synth->_outports : ((unsigned long) ports);
+ // TODO Number of inports requested?
+ //nip = ((unsigned long) iports) > synth->_inports ? synth->_inports : ((unsigned long) iports);
+
+ const DSSI_Descriptor* dssi = synth->dssi;
+ const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
+ unsigned sample = 0;
+ int loopcount = 0; // REMOVE Tim.
+
+ // NOTE Tested: Variable run-lengths worked superbly for LADSPA and DSSI synths. But DSSI-VST definitely
+ // does NOT like changing sample run length. It crashes the plugin and Wine (but MusE keeps running!).
+ // Furthermore, it resizes the shared memory (mmap, remap) upon each run length DIFFERENT from the last.
+ // And all of this done through client-server communications. It doesn't seem designed for this technique.
+ //
+ // So we could support an alternate technique: A fixed control processing rate, in number of samples.
+ //
+ // Allow user to choose either a fixed rate or these 'packets' for LADSPA and DSSI plugins/synths,
+ // but make fixed-rate MANDATORY for DSSI-VST plugins and synths.
+ //
+ // Or K.I.S.S - Just use fixed rates only, but allow it to be changed. I'm worried about libraries and
+ // plugins other than DSSI-VST. What if they need the fixed-rate, too?
+ // How to tell, and manage it all...?
+ // But this 'packet' method sure seems to work nicely so far, so we'll throw it in...
+ //
+ // Must make this detectable for dssi vst synths, just like the plugins' in-place blacklist.
+ //const bool usefixedrate = true;
+ const bool usefixedrate = synth->_isDssiVst; // Try this.
+ // TODO Make this number a global setting.
+ // Note for dssi-vst this MUST equal audio period. It doesn't like broken-up runs (it stutters),
+ // even with fixed sizes. Could be a Wine + Jack thing, wanting a full Jack buffer's length.
+ //unsigned fixedsize = 2048;
+ unsigned fixedsize = n;
+
+ // For now, the fixed size is clamped to the audio buffer size.
+ // TODO: We could later add slower processing over several cycles -
+ // so that users can select a small audio period but a larger control period.
+ if(fixedsize > n)
+ fixedsize = n;
+
+ while(sample < n)
+ {
+ //unsigned nsamp = n;
+ //unsigned nsamp = n - sample;
+ unsigned nsamp = usefixedrate ? fixedsize : n - sample;
+ bool found = false;
+ unsigned frame = 0;
+ unsigned index = 0;
+ // 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.
+ // 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)
+ //|| (found && v.frame != frame)
+ //|| (!usefixedrate && found && !v.unique && v.frame != frame)
+ || (found && !v.unique && v.frame != 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.
+ //|| (found && v.idx == index))
+ //|| (usefixedrate && found && v.idx == index)) // Try this.
+ || (usefixedrate && found && v.unique && v.idx == index)) //
+ break;
+ _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
+ if(v.idx >= synth->_controlInPorts) // Sanity check.
+ break;
+ found = true;
+ frame = v.frame;
+ index = v.idx;
+ // Set the ladspa control port value.
+ controls[v.idx].val = v.value;
+ }
+
+ //if(found)
+ if(found && !usefixedrate)
+ //nsamp = frame - sample + 1;
+ nsamp = frame - sample;
+ 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.
+
+ // 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).
+ if(nsamp == 0)
+ continue;
+
+ nevents = 0;
+ // Process event list events...
+ for(; i != el->end(); ++i)
+ {
+ //if(i->time() >= (endPos + frameOffset)) // NOTE: frameOffset? Tested, examined printouts of times: Seems OK for playback.
+ if(i->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
+ break;
+
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData eventlist event time:%d\n", i->time());
+ #endif
+
+ // p3.3.39 Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
+ // Same code as in MidiPort::sendEvent()
+ if(synti->midiPort() != -1)
+ {
+ MidiPort* mp = &midiPorts[synti->midiPort()];
+ if(i->type() == ME_CONTROLLER)
+ {
+ int da = i->dataA();
+ int db = i->dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+ if(!mp->setHwCtrlState(i->channel(), da, db))
+ continue;
+ //mp->setHwCtrlState(i->channel(), da, db);
+ }
+ else
+ if(i->type() == ME_PITCHBEND)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA());
+ if(!mp->setHwCtrlState(i->channel(), CTRL_PITCH, da))
+ continue;
+ //mp->setHwCtrlState(i->channel(), CTRL_PITCH, da);
+ }
+ else
+ if(i->type() == ME_PROGRAM)
+ {
+ if(!mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA()))
+ continue;
+ //mp->setHwCtrlState(i->channel(), CTRL_PROGRAM, i->dataA());
+ }
+ }
+
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(*i, &events[nevents]))
+ {
+ // Time-stamp the event. p4.0.15 Tim.
+ int ft = i->time() - frameOffset - pos;
+ if(ft < 0)
+ ft = 0;
+ //if (ft >= (int)segmentSize)
+ if (ft >= int(sample + nsamp))
+ {
+ //printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d (seg=%d)\n", i->time(), pos, frameOffset, ft, segmentSize);
+ printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%d nsamp:%d\n", i->time(), pos, frameOffset, ft, sample, nsamp);
+ ///if (ft > (int)segmentSize)
+ //ft = segmentSize - 1;
+ ft = sample + nsamp - 1;
+ }
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
+ ++nevents;
+ }
+ }
+
+ // Now process putEvent events...
+ while(!synti->eventFifo.isEmpty())
+ {
+ //MidiPlayEvent e = synti->eventFifo.get();
+ MidiPlayEvent e = synti->eventFifo.peek();
+
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData eventFifo event time:%d\n", e.time());
+ #endif
+
+ //if(e.time() >= (endPos + frameOffset))
+ if(e.time() >= (pos + sample + nsamp + frameOffset))
+ break;
+
+ synti->eventFifo.remove(); // Done with ring buffer's event. Remove it.
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(e, &events[nevents]))
+ {
+ // Time-stamp the event. p4.0.15 Tim.
+ int ft = e.time() - frameOffset - pos;
+ if(ft < 0)
+ ft = 0;
+ //if (ft >= (int)segmentSize)
+ if (ft >= int(sample + nsamp))
+ {
+ //printf("DssiSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d (seg=%d)\n", e.time(), pos, frameOffset, ft, segmentSize);
+ printf("DssiSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%d nsamp:%d\n", e.time(), pos, frameOffset, ft, sample, nsamp);
+ ///if (ft > (int)segmentSize)
+ //ft = segmentSize - 1;
+ ft = sample + nsamp - 1;
+ }
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
+ ++nevents;
+ }
+ }
+
+ /*
+ //
+ // p3.3.39 Handle inputs...
+ //
+ //if((song->bounceTrack != this) && !noInRoute())
+ if(!((AudioTrack*)synti)->noInRoute())
+ {
+ RouteList* irl = ((AudioTrack*)synti)->inRoutes();
+ iRoute i = irl->begin();
+ if(!i->track->isMidiTrack())
+ {
+ //if(debugMsg)
+ printf("DssiSynthIF::getData: Error: First route is a midi track route!\n");
+ }
+ else
+ {
+ int ch = i->channel == -1 ? 0 : i->channel;
+ int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ int chs = i->channels == -1 ? 0 : i->channels;
+
+ // TODO:
+ //if(ch >= synth->_inports)
+ //iUsedIdx[ch] = true;
+ //if(chs == 2)
+ // iUsedIdx[ch + 1] = true;
+
+ //((AudioTrack*)i->track)->copyData(framePos, channels, nframe, bp);
+ ((AudioTrack*)i->track)->copyData(pos, ports,
+ //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,
+ i->channel,
+ i->channels,
+ n, bp);
+ }
+
+ //unsigned pos, int ports, unsigned n, float** buffer
+
+ ++i;
+ for(; i != irl->end(); ++i)
+ {
+ if(i->track->isMidiTrack())
+ {
+ //if(debugMsg)
+ printf("DssiSynthIF::getData: Error: Route is a midi track route!\n");
+ continue;
+ }
+ //((AudioTrack*)i->track)->addData(framePos, channels, nframe, bp);
+ ((AudioTrack*)i->track)->addData(framePos, channels,
+ //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,
+ i->channel,
+ i->channels,
+ nframe, bp);
+ }
+ }
+ */
+
+ k = 0;
+ // Connect the given buffers directly to the ports, up to a max of synth ports.
+ for(; k < nop; ++k)
+ descr->connect_port(handle, synth->oIdx[k], buffer[k] + sample);
+ // Connect the remaining ports to some local buffers (not used yet).
+ for(; k < synth->_outports; ++k)
+ descr->connect_port(handle, synth->oIdx[k], audioOutBuffers[k] + sample);
+ // Just connect all inputs to some local buffers (not used yet). TODO: Support inputs.
+ for(k = 0; k < synth->_inports; ++k)
+ descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample);
+
+ // Run the synth for a period of time. This processes events and gets/fills our local buffers...
+ if(synth->dssi->run_synth)
+ {
+ synth->dssi->run_synth(handle, nsamp, events, nevents);
+ }
+ else if (synth->dssi->run_multiple_synths)
+ {
+ snd_seq_event_t* ev = events;
+ synth->dssi->run_multiple_synths(1, &handle, nsamp, &ev, &nevents);
+ }
+
+ sample += nsamp;
+ loopcount++; // REMOVE Tim.
+ }
+
+ return i;
+}
+#endif
+
//---------------------------------------------------------
// putEvent
//---------------------------------------------------------
@@ -2607,7 +2965,7 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
//LADSPA_Data value = argv[1]->f;
#ifdef DSSI_DEBUG
- printf("DssiSynthIF::oscControl received oscControl port:%ld val:%f\n", port, value);
+ printf("DssiSynthIF::oscControl received oscControl port:%ld val:%f\n", port, value);
#endif
//int controlPorts = synth->_controlInPorts;
@@ -2641,19 +2999,17 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
// because dssi-vst is WAITING FOR A RESPONSE. (A CHANGE in the control port value).
// It will output something like "...4 events expected..." and count that number down as 4 actual control port value CHANGES
// are done here in response. Normally it says "...0 events expected..." when MusE is the one doing the DSSI control changes.
- // TODO: (Done) May need FIFOs on each control(!) so that the control changes get sent one per process cycle.
- // Observed countdown not actually going to zero upon string of changes.
//
// NOTE: NOTE: This line in RemoteVSTServer::setParameter(int p, float v) in dssi-vst-server.cpp :
//
// " if (tv.tv_sec > m_lastGuiComms.tv_sec + 10) "
//
// explains an observation that after ten seconds, the server automatically clears the expected number to 0.
- // TODO: Now MusE should forget about all the VST fifo events past ten+ (?) seconds. Add event timestamps...
// You can't send any 'new' values until either you a): send all the expected events or b): wait ten seconds.
// (Because the server simply ignores the 'expected' messages.)
//
// Well, at least here are the fifos. Try this ...
+ /*
OscControlFifo* cfifo = _oscif.oscFifo(cport);
if(cfifo)
{
@@ -2669,6 +3025,21 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%ld\n", cport);
}
}
+ */
+ // p4.0.21
+ ControlEvent ce;
+ ce.unique = synth->_isDssiVst; // Special for messages from vst gui to host - requires processing every message.
+ ce.idx = cport;
+ ce.value = 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();
+ if(_controlFifo.put(ce))
+ {
+ fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%ld\n", cport);
+ }
+
//const DSSI_Descriptor* dssi = synth->dssi;
//const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
@@ -2976,7 +3347,8 @@ int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi
///int i = synth->pIdx[id];
//int i = synth->pIdx[k];
- int i = controls[id].idx;
+ //int i = controls[id].idx;
+ unsigned i = controls[id].idx; // p4.0.21
//ladspaDefaultValue(ld, i, &controls[id].val);
@@ -3103,7 +3475,8 @@ int DssiSynthIF::totalInChannels() const
bool DssiSynthIF::on() const { return true; } // Synth is not part of a rack plugin chain. Always on.
void DssiSynthIF::setOn(bool /*val*/) { }
-int DssiSynthIF::pluginID() { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->UniqueID : 0; }
+//int DssiSynthIF::pluginID() { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->UniqueID : 0; }
+unsigned DssiSynthIF::pluginID() { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->UniqueID : 0; }
//int DssiSynthIF::id() { return 0; } // Synth is not part of a rack plugin chain. Always 0.
int DssiSynthIF::id() { return MAX_PLUGINS; } // Set for special block reserved for dssi synth. p4.0.20
QString DssiSynthIF::pluginLabel() const { return (synth && synth->dssi) ? QString(synth->dssi->LADSPA_Plugin->Label) : QString(); }
@@ -3112,18 +3485,27 @@ QString DssiSynthIF::lib() const { return synth ? sy
QString DssiSynthIF::dirPath() const { return synth ? synth->absolutePath() : QString(); }
QString DssiSynthIF::fileName() const { return synth ? synth->fileName() : QString(); }
AudioTrack* DssiSynthIF::track() { return (AudioTrack*)synti; }
-void DssiSynthIF::enableController(int i, bool v) { controls[i].enCtrl = v; }
-bool DssiSynthIF::controllerEnabled(int i) const { return controls[i].enCtrl; }
-bool DssiSynthIF::controllerEnabled2(int i) const { return controls[i].en2Ctrl; }
+//void DssiSynthIF::enableController(int i, bool v) { controls[i].enCtrl = v; }
+//bool DssiSynthIF::controllerEnabled(int i) const { return controls[i].enCtrl; }
+//bool DssiSynthIF::controllerEnabled2(int i) const { return controls[i].en2Ctrl; }
+void DssiSynthIF::enableController(unsigned i, bool v) { controls[i].enCtrl = v; }
+bool DssiSynthIF::controllerEnabled(unsigned i) const { return controls[i].enCtrl; }
+bool DssiSynthIF::controllerEnabled2(unsigned i) const { return controls[i].en2Ctrl; }
void DssiSynthIF::updateControllers() { }
void DssiSynthIF::writeConfiguration(int /*level*/, Xml& /*xml*/) { }
bool DssiSynthIF::readConfiguration(Xml& /*xml*/, bool /*readPreset*/) { return false; }
-int DssiSynthIF::parameters() const { return synth ? synth->_controlInPorts : 0; }
-void DssiSynthIF::setParam(int i, double val) { setParameter(i, val); }
-double DssiSynthIF::param(int i) const { return getParameter(i); }
-const char* DssiSynthIF::paramName(int i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortNames[controls[i].idx] : 0; }
+//int DssiSynthIF::parameters() const { return synth ? synth->_controlInPorts : 0; }
+//void DssiSynthIF::setParam(int i, double val) { setParameter(i, val); }
+//double DssiSynthIF::param(int i) const { return getParameter(i); }
+//const char* DssiSynthIF::paramName(int i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortNames[controls[i].idx] : 0; }
//LADSPA_PortRangeHint DssiSynthIF::range(int i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortRangeHints[i] : 0; }
-LADSPA_PortRangeHint DssiSynthIF::range(int i) { return synth->dssi->LADSPA_Plugin->PortRangeHints[controls[i].idx]; }
+//LADSPA_PortRangeHint DssiSynthIF::range(int i) { return synth->dssi->LADSPA_Plugin->PortRangeHints[controls[i].idx]; }
+unsigned DssiSynthIF::parameters() const { return synth ? synth->_controlInPorts : 0; }
+void DssiSynthIF::setParam(unsigned i, float val) { setParameter(i, val); }
+float DssiSynthIF::param(unsigned i) const { return getParameter(i); }
+const char* DssiSynthIF::paramName(unsigned i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortNames[controls[i].idx] : 0; }
+//LADSPA_PortRangeHint DssiSynthIF::range(unsigned i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortRangeHints[i] : 0; }
+LADSPA_PortRangeHint DssiSynthIF::range(unsigned i) { return synth->dssi->LADSPA_Plugin->PortRangeHints[controls[i].idx]; }
#else //DSSI_SUPPORT