From 499ccec21dd2ac636fb019c98a902c351b4ec165 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Mon, 25 Apr 2011 20:47:28 +0000 Subject: Overhaul plugin module and add variable run-length ladspa + dssi processing. Please see ChangeLog. --- muse2/ChangeLog | 6 + muse2/README.instruments | 40 +- muse2/muse/CMakeLists.txt | 1 + muse2/muse/audiotrack.cpp | 6 +- muse2/muse/controlfifo.cpp | 75 ++++ muse2/muse/controlfifo.h | 64 ++++ muse2/muse/ctrl.h | 3 +- muse2/muse/driver/alsamidi.h | 2 +- muse2/muse/driver/audiodev.h | 2 +- muse2/muse/driver/dummyaudio.cpp | 2 +- muse2/muse/driver/jackaudio.h | 2 +- muse2/muse/driver/jackmidi.h | 2 +- muse2/muse/dssihost.cpp | 430 ++++++++++++++++++++-- muse2/muse/dssihost.h | 29 +- muse2/muse/mididev.h | 2 +- muse2/muse/mixer/astrip.cpp | 28 +- muse2/muse/mixer/panknob.cpp | 5 +- muse2/muse/osc.cpp | 43 ++- muse2/muse/osc.h | 6 +- muse2/muse/plugin.cpp | 704 ++++++++++++++++++++++++++---------- muse2/muse/plugin.h | 140 ++++--- muse2/muse/synth.cpp | 5 +- muse2/muse/synth.h | 6 +- muse2/synti/deicsonze/deicsonze.cpp | 15 +- 24 files changed, 1284 insertions(+), 334 deletions(-) create mode 100644 muse2/muse/controlfifo.cpp create mode 100644 muse2/muse/controlfifo.h diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 204225e2..95cc84b3 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,6 +1,12 @@ 25.04.2011: - added a songChanged at the end of clear when loading a new song, intended effect was to clear GUI before loading new song to fix some nasty crashes, seems to work (rj) + - Overhaul plugin.cpp/h: Fix all float <-> double and int <-> unsigned usages. (p4.0.21 Tim) + - Improved ladspa and dssi controller responsiveness even with large audio buffer size. (Tim) + Implemented variable run-lengths for frame-accurate controller processing. + Improved volume, pan, and plugin control responsiveness - used track->setPluginCtrlVal() + instead of audio->msgSetPluginCtrlVal() which waits until next audio process. + Work in progress! Still not complete yet. Please bear with me. 24.04.2011: - Improved master list editor editing of keys, dropdown should not 'stay behind' anymore (rj) 21.04.2011: diff --git a/muse2/README.instruments b/muse2/README.instruments index a2693b4e..adb12dab 100644 --- a/muse2/README.instruments +++ b/muse2/README.instruments @@ -1,11 +1,12 @@ ================================================ MusE loadable Midi Instrument Definitions - (as of 10.09.2003) MusE 0.7.0 + (valid from around MusE 0.8.1, Edited by Tim APR.25.2010, at MusE 2.0alpha) ================================================ - File Extension ".idf" - searched in Subdirectory "instruments" (/usr/share/muse/instruments on my system) + - Can be viewed, created or edited with menu 'Midi -> Edit Instrument' All found instrument definitions are presented by MusE in Config->MidiPorts in Pulldown in column "Instrument". @@ -30,12 +31,8 @@ ... - - 0x4a - 0 - 127 - 0 - + + ... @@ -91,12 +88,24 @@ (6) Controller have the following porperties: name: arbitrary unique (short) string describing the controller - n: controller number, defines also the controller type: - values from 0x0 - 0x7f are 7Bit controller - values from 0x1000 - 0x1ffff are 14 bit controller with - MSB/LSB value pairs - values from 0x20000 - 0x2ffff are RPN's - values from 0x30000 - 0x3ffff are NRPN's + + type: Controller7 regular 7-bit controller + Controller14 14-bit controller + RPN registered parameter 7-bit + NRPN non registered parameter 7-bit + RPN14 registered parameter 14-bit + NRPN14 non registered parameter 14-bit + Pitch pitch mod wheel + Program program + + Default Controller7 if omitted. + Pitch and Program are convenience controllers which + wrap pitch or program functionality in one controller. + + h: controller number MSB. Default 0 if omitted. + l: controller number LSB. Default 0 if omitted. + For drum controllers, this can also be "pitch" indicating + each drum 'note' has its own controller. min: minimum value for controller max: maximum value for controller @@ -104,5 +113,8 @@ undefined after instrument reset, use the ''undefined'' value 0x10000 - the min/max/init values can be ommited + The min/max/init values can be omitted + Auto-biasing feature: If min is less than zero, such as with + pan = -64 -> 63, MusE automatically displays this range, + yet uses the true range of 0-127 'behind the scenes'. diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt index 2a630f84..2d2a9fe3 100644 --- a/muse2/muse/CMakeLists.txt +++ b/muse2/muse/CMakeLists.txt @@ -83,6 +83,7 @@ file (GLOB core_source_files cobject.cpp conf.cpp confmport.cpp + controlfifo.cpp ctrl.cpp dssihost.cpp event.cpp diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp index 98e74331..c427a55c 100644 --- a/muse2/muse/audiotrack.cpp +++ b/muse2/muse/audiotrack.cpp @@ -989,7 +989,8 @@ bool AudioTrack::readProperties(Xml& xml, const QString& tag) //PluginI* p = 0; PluginIBase* p = 0; bool ctlfound = false; - int m = l->id() & AC_PLUGIN_CTL_ID_MASK; + //int m = l->id() & AC_PLUGIN_CTL_ID_MASK; + unsigned m = l->id() & AC_PLUGIN_CTL_ID_MASK; // p4.0.21 int n = (l->id() >> AC_PLUGIN_CTL_BASE_POW) - 1; if(n >= 0 && n < PipelineDepth) { @@ -1163,7 +1164,8 @@ void AudioTrack::mapRackPluginsToControllers() // Ignore volume, pan, mute etc. if(id < AC_PLUGIN_CTL_BASE) continue; - int param = id & AC_PLUGIN_CTL_ID_MASK; + //int param = id & AC_PLUGIN_CTL_ID_MASK; + unsigned param = id & AC_PLUGIN_CTL_ID_MASK; // p4.0.21 int idx = (id >> AC_PLUGIN_CTL_BASE_POW) - 1; //PluginI* p = (*_efxPipe)[idx]; diff --git a/muse2/muse/controlfifo.cpp b/muse2/muse/controlfifo.cpp new file mode 100644 index 00000000..526e88c7 --- /dev/null +++ b/muse2/muse/controlfifo.cpp @@ -0,0 +1,75 @@ +//============================================================================= +// MusE +// Linux Music Editor +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "controlfifo.h" + +//--------------------------------------------------------- +// ControlFifo +// put +// return true on fifo overflow +//--------------------------------------------------------- + +bool ControlFifo::put(const ControlEvent& event) + { + if (size < CONTROL_FIFO_SIZE) { + fifo[wIndex] = event; + wIndex = (wIndex + 1) % CONTROL_FIFO_SIZE; + // q_atomic_increment(&size); + ++size; + return false; + } + return true; + } + +//--------------------------------------------------------- +// get +//--------------------------------------------------------- + +ControlEvent ControlFifo::get() + { + ControlEvent event(fifo[rIndex]); + rIndex = (rIndex + 1) % CONTROL_FIFO_SIZE; + // q_atomic_decrement(&size); + --size; + return event; + } + +//--------------------------------------------------------- +// peek +//--------------------------------------------------------- + +const ControlEvent& ControlFifo::peek(int n) + { + int idx = (rIndex + n) % CONTROL_FIFO_SIZE; + return fifo[idx]; + } + +//--------------------------------------------------------- +// remove +//--------------------------------------------------------- + +void ControlFifo::remove() + { + rIndex = (rIndex + 1) % CONTROL_FIFO_SIZE; + // q_atomic_decrement(&size); + --size; + } + + + diff --git a/muse2/muse/controlfifo.h b/muse2/muse/controlfifo.h new file mode 100644 index 00000000..a0b6bfd0 --- /dev/null +++ b/muse2/muse/controlfifo.h @@ -0,0 +1,64 @@ +//============================================================================= +// MusE +// Linux Music Editor +// +// Copyright (C) 1999-2010 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __CONTROLFIFO_H__ +#define __CONTROLFIFO_H__ + +#define CONTROL_FIFO_SIZE 8192 + +//--------------------------------------------------------- +// ControlEvent +// Item struct for ControlFifo. +//--------------------------------------------------------- + +struct ControlEvent +{ + // Unique: Whether the item must not be skipped, even if it has the same + // (possibly rounded) frame and index as the previous item. This is mainly for + // dssi-vst guis, they require acknowledgment of every message. + bool unique; + unsigned idx; + float value; + unsigned frame; +}; + +//--------------------------------------------------------- +// ControlFifo +//--------------------------------------------------------- + +class ControlFifo +{ + ControlEvent fifo[CONTROL_FIFO_SIZE]; + volatile int size; + int wIndex; + int rIndex; + + public: + ControlFifo() { clear(); } + bool put(const ControlEvent& event); // returns true on fifo overflow + ControlEvent get(); + const ControlEvent& peek(int n = 0); + void remove(); + bool isEmpty() const { return size == 0; } + void clear() { size = 0, wIndex = 0, rIndex = 0; } + int getSize() const { return size; } +}; + + +#endif \ No newline at end of file diff --git a/muse2/muse/ctrl.h b/muse2/muse/ctrl.h index 4d864b9f..955fd01f 100644 --- a/muse2/muse/ctrl.h +++ b/muse2/muse/ctrl.h @@ -23,7 +23,8 @@ const int AC_MUTE = 2; #define AC_PLUGIN_CTL_BASE_POW 12 #define AC_PLUGIN_CTL_ID_MASK 0xFFF -inline int genACnum(int plugin, int ctrl) { return (plugin + 1) * AC_PLUGIN_CTL_BASE + ctrl; } +//inline int genACnum(int plugin, int ctrl) { return (plugin + 1) * AC_PLUGIN_CTL_BASE + ctrl; } +inline unsigned genACnum(unsigned plugin, unsigned ctrl) { return (plugin + 1) * AC_PLUGIN_CTL_BASE + ctrl; } class Xml; diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h index 455ab1df..a2480c5c 100644 --- a/muse2/muse/driver/alsamidi.h +++ b/muse2/muse/driver/alsamidi.h @@ -44,7 +44,7 @@ class MidiAlsaDevice : public MidiDevice { virtual void* outClientPort() { return (void*)&adr; } // That is, ALSA midi client ports can be both r/w. virtual void writeRouting(int, Xml&) const; - virtual inline int deviceType() { return ALSA_MIDI; } + virtual inline int deviceType() const { return ALSA_MIDI; } }; extern bool initMidiAlsa(); diff --git a/muse2/muse/driver/audiodev.h b/muse2/muse/driver/audiodev.h index af53d7de..4685b89a 100644 --- a/muse2/muse/driver/audiodev.h +++ b/muse2/muse/driver/audiodev.h @@ -28,7 +28,7 @@ class AudioDevice { AudioDevice() {} virtual ~AudioDevice() {} - virtual int deviceType() = 0; // p3.3.52 + virtual int deviceType() const = 0; // p3.3.52 //virtual void start() = 0; virtual void start(int priority) = 0; diff --git a/muse2/muse/driver/dummyaudio.cpp b/muse2/muse/driver/dummyaudio.cpp index 597ecf2b..55f091c2 100644 --- a/muse2/muse/driver/dummyaudio.cpp +++ b/muse2/muse/driver/dummyaudio.cpp @@ -66,7 +66,7 @@ class DummyAudioDevice : public AudioDevice { free(buffer); } - virtual inline int deviceType() { return DUMMY_AUDIO; } // p3.3.52 + virtual inline int deviceType() const { return DUMMY_AUDIO; } // p3.3.52 //virtual void start(); virtual void start(int); diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h index d3132efe..5be0797f 100644 --- a/muse2/muse/driver/jackaudio.h +++ b/muse2/muse/driver/jackaudio.h @@ -38,7 +38,7 @@ class JackAudioDevice : public AudioDevice { virtual ~JackAudioDevice(); virtual void nullify_client() { _client = 0; } - virtual inline int deviceType() { return JACK_AUDIO; } // p3.3.52 + virtual inline int deviceType() const { return JACK_AUDIO; } // p3.3.52 void scanMidiPorts(); diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h index 842cbc2d..2dcf2fbb 100644 --- a/muse2/muse/driver/jackmidi.h +++ b/muse2/muse/driver/jackmidi.h @@ -129,7 +129,7 @@ class MidiJackDevice : public MidiDevice { //static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix. static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // p3.3.55 1:Writable 2: Readable 3: Writable + Readable - virtual inline int deviceType() { return JACK_MIDI; } + virtual inline int deviceType() const { return JACK_MIDI; } virtual void setName(const QString&); 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 diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h index a98cfd87..27c0eae4 100644 --- a/muse2/muse/dssihost.h +++ b/muse2/muse/dssihost.h @@ -75,6 +75,8 @@ class DssiSynth : public Synth { MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps DSSI port numbers to midi controller numbers. bool _hasGui; bool _inPlaceCapable; + // Hack: Special flag required. + bool _isDssiVst; public: //DssiSynth(const QFileInfo* fi, QString l) : Synth(fi, l) { @@ -236,7 +238,8 @@ class DssiSynthIF : public SynthIF, public PluginIBase //------------------------- bool on() const; void setOn(bool /*val*/); - int pluginID(); + //int pluginID(); + unsigned pluginID(); // p4.0.21 int id(); QString pluginLabel() const; QString name() const; @@ -244,17 +247,25 @@ class DssiSynthIF : public SynthIF, public PluginIBase QString dirPath() const; QString fileName() const; AudioTrack* track(); - void enableController(int /*i*/, bool v = true); - bool controllerEnabled(int /*i*/) const; - bool controllerEnabled2(int /*i*/) const; + //void enableController(int /*i*/, bool v = true); + //bool controllerEnabled(int /*i*/) const; + //bool controllerEnabled2(int /*i*/) const; + void enableController(unsigned /*i*/, bool v = true); // p4.0.21 + bool controllerEnabled(unsigned /*i*/) const; + bool controllerEnabled2(unsigned /*i*/) const; void updateControllers(); void writeConfiguration(int /*level*/, Xml& /*xml*/); bool readConfiguration(Xml& /*xml*/, bool readPreset=false); - int parameters() const; - void setParam(int /*i*/, double /*val*/); - double param(int /*i*/) const; - const char* paramName(int /*i*/); - LADSPA_PortRangeHint range(int /*i*/); + //int parameters() const; + //void setParam(int /*i*/, double /*val*/); + //double param(int /*i*/) const; + //const char* paramName(int /*i*/); + //LADSPA_PortRangeHint range(int /*i*/); + unsigned parameters() const; // p4.0.21 + void setParam(unsigned /*i*/, float /*val*/); + float param(unsigned /*i*/) const; + const char* paramName(unsigned /*i*/); + LADSPA_PortRangeHint range(unsigned /*i*/); friend class DssiSynth; }; diff --git a/muse2/muse/mididev.h b/muse2/muse/mididev.h index 6ac93729..275bd014 100644 --- a/muse2/muse/mididev.h +++ b/muse2/muse/mididev.h @@ -77,7 +77,7 @@ class MidiDevice { MidiDevice(const QString& name); virtual ~MidiDevice() {} - virtual int deviceType() = 0; + virtual int deviceType() const = 0; //virtual void* clientPort() { return 0; } // p3.3.55 diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index 2f1a2262..265061ad 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -430,7 +430,10 @@ void AudioStrip::volumeChanged(double val) else vol = pow(10.0, val/20.0); volume = vol; - audio->msgSetVolume((AudioTrack*)track, vol); + //audio->msgSetVolume((AudioTrack*)track, vol); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setVolume(vol); + ((AudioTrack*)track)->recordAutomation(AC_VOLUME, vol); song->update(SC_TRACK_MODIFIED); // for graphical automation update @@ -455,7 +458,10 @@ void AudioStrip::volumePressed() else vol = pow(10.0, val/20.0); volume = vol; - audio->msgSetVolume((AudioTrack*)track, volume); + //audio->msgSetVolume((AudioTrack*)track, volume); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setVolume(volume); + ((AudioTrack*)track)->startAutoRecord(AC_VOLUME, volume); } @@ -498,7 +504,10 @@ void AudioStrip::volLabelChanged(double val) vol = pow(10.0, val/20.0); volume = vol; slider->setValue(val); - audio->msgSetVolume((AudioTrack*)track, vol); + //audio->msgSetVolume((AudioTrack*)track, vol); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setVolume(vol); + ((AudioTrack*)track)->startAutoRecord(AC_VOLUME, vol); } @@ -513,7 +522,10 @@ void AudioStrip::panChanged(double val) track->enablePanController(false); panVal = val; - audio->msgSetPan(((AudioTrack*)track), val); + //audio->msgSetPan(((AudioTrack*)track), val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setPan(val); + ((AudioTrack*)track)->recordAutomation(AC_PAN, val); } @@ -528,7 +540,9 @@ void AudioStrip::panPressed() track->enablePanController(false); panVal = pan->value(); - audio->msgSetPan(((AudioTrack*)track), panVal); + //audio->msgSetPan(((AudioTrack*)track), panVal); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setPan(panVal); ((AudioTrack*)track)->startAutoRecord(AC_PAN, panVal); } @@ -563,7 +577,9 @@ void AudioStrip::panLabelChanged(double val) panVal = val; pan->setValue(val); - audio->msgSetPan((AudioTrack*)track, val); + //audio->msgSetPan((AudioTrack*)track, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + ((AudioTrack*)track)->setPan(val); ((AudioTrack*)track)->startAutoRecord(AC_PAN, val); } diff --git a/muse2/muse/mixer/panknob.cpp b/muse2/muse/mixer/panknob.cpp index 065c1bd1..c99f0bd5 100644 --- a/muse2/muse/mixer/panknob.cpp +++ b/muse2/muse/mixer/panknob.cpp @@ -8,6 +8,7 @@ #include "../audio.h" #include "panknob.h" +#include "track.h" //--------------------------------------------------------- // PanKnob @@ -26,7 +27,9 @@ PanKnob::PanKnob(QWidget* parent, AudioTrack* s) void PanKnob::valueChanged(double val) { - audio->msgSetPan(src, val); + //audio->msgSetPan(src, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + src->setPan(val); } diff --git a/muse2/muse/osc.cpp b/muse2/muse/osc.cpp index edaede1f..9f9a5531 100644 --- a/muse2/muse/osc.cpp +++ b/muse2/muse/osc.cpp @@ -405,6 +405,7 @@ void stopOSC() +/* //--------------------------------------------------------- // OscControlFifo // put @@ -456,7 +457,7 @@ void OscControlFifo::remove() // q_atomic_decrement(&size); --size; } - +*/ //--------------------------------------------------------- @@ -483,7 +484,7 @@ OscIF::OscIF() _oscGuiQProc = 0; _oscGuiVisible = false; - _oscControlFifos = 0; + //_oscControlFifos = 0; } OscIF::~OscIF() @@ -530,10 +531,11 @@ OscIF::~OscIF() if(_uiOscPath) free(_uiOscPath); - if(_oscControlFifos) - delete[] _oscControlFifos; + //if(_oscControlFifos) + // delete[] _oscControlFifos; } +/* //--------------------------------------------------------- // oscFifo //--------------------------------------------------------- @@ -544,6 +546,7 @@ OscControlFifo* OscIF::oscFifo(unsigned long i) const return 0; return &_oscControlFifos[i]; } +*/ //--------------------------------------------------------- // oscUpdate @@ -1135,15 +1138,15 @@ bool OscIF::oscGuiVisible() const void OscDssiIF::oscSetSynthIF(DssiSynthIF* s) { _oscSynthIF = s; - if(_oscControlFifos) - delete[] _oscControlFifos; - _oscControlFifos = 0; + //if(_oscControlFifos) + // delete[] _oscControlFifos; + //_oscControlFifos = 0; - if(_oscSynthIF && _oscSynthIF->dssiSynth()) - { - unsigned long ports = _oscSynthIF->dssiSynth()->inControls(); - _oscControlFifos = new OscControlFifo[ports]; - } + //if(_oscSynthIF && _oscSynthIF->dssiSynth()) + //{ + // unsigned long ports = _oscSynthIF->dssiSynth()->inControls(); + // _oscControlFifos = new OscControlFifo[ports]; + //} } //--------------------------------------------------------- @@ -1327,15 +1330,15 @@ bool OscDssiIF::oscInitGui() void OscEffectIF::oscSetPluginI(PluginI* s) { _oscPluginI = s; - if(_oscControlFifos) - delete[] _oscControlFifos; - _oscControlFifos = 0; + //if(_oscControlFifos) + // delete[] _oscControlFifos; + //_oscControlFifos = 0; - if(_oscPluginI && _oscPluginI->plugin()) - { - unsigned long ports = _oscPluginI->plugin()->controlInPorts(); - _oscControlFifos = new OscControlFifo[ports]; - } + //if(_oscPluginI && _oscPluginI->plugin()) + //{ + // unsigned long ports = _oscPluginI->plugin()->controlInPorts(); + // _oscControlFifos = new OscControlFifo[ports]; + //} } //--------------------------------------------------------- diff --git a/muse2/muse/osc.h b/muse2/muse/osc.h index ea94451b..02c30de4 100644 --- a/muse2/muse/osc.h +++ b/muse2/muse/osc.h @@ -34,6 +34,7 @@ class QString; class PluginI; class OscIF; +/* // Keep the OSC fifo small. There may be thousands of controls, and each control needs a fifo. // Oops, no, if the user keeps adjusting a slider without releasing the mouse button, then all of the // events are sent at once upon releasing the button, meaning there might be thousands of events at once. @@ -73,6 +74,7 @@ class OscControlFifo void clear() { size = 0, wIndex = 0, rIndex = 0; } int getSize() const { return size; } }; +*/ //--------------------------------------------------------- // OscIF @@ -137,7 +139,7 @@ class OscIF char* _uiOscShowPath; bool _oscGuiVisible; - OscControlFifo* _oscControlFifos; + //OscControlFifo* _oscControlFifos; virtual bool oscInitGui(const QString& /*typ*/, const QString& /*baseName*/, const QString& /*name*/, const QString& /*label*/, const QString& /*filePath*/, const QString& /*guiPath*/); @@ -146,7 +148,7 @@ class OscIF OscIF(); virtual ~OscIF(); - OscControlFifo* oscFifo(unsigned long) const; + //OscControlFifo* oscFifo(unsigned long) const; virtual int oscUpdate(lo_arg**); virtual int oscProgram(lo_arg**) { return 0; } diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 06e72e4e..7dd2486f 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -44,6 +44,7 @@ #include "slider.h" #include "midictrl.h" #include "plugin.h" +#include "controlfifo.h" #include "xml.h" #include "icons.h" #include "song.h" @@ -84,7 +85,8 @@ QStringList PluginDialog::sortItems = QStringList(); // ladspa2MidiControlValues //--------------------------------------------------------- -bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def) +//bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def) +bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum, int* min, int* max, int* def) { LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor; @@ -274,7 +276,8 @@ bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctl // midi2LadspaValue //--------------------------------------------------------- -float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val) +//float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val) +float midi2LadspaValue(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum, int val) { LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor; @@ -448,7 +451,8 @@ float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, in // ladspa2MidiController //--------------------------------------------------------- -MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, int port, int ctlnum) +//MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, int port, int ctlnum) +MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum) { int min, max, def; @@ -467,85 +471,96 @@ MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, int port, //--------------------------------------------------------------------------------- //float ladspaDefaultValue(const LADSPA_Descriptor* plugin, int k) -bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val) +//bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val) +bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, unsigned port, float* val) { - LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; - LADSPA_PortRangeHintDescriptor rh = range.HintDescriptor; -// bool isLog = LADSPA_IS_HINT_LOGARITHMIC(rh); - //double val = 1.0; - float m = (rh & LADSPA_HINT_SAMPLE_RATE) ? float(sampleRate) : 1.0f; - if (LADSPA_IS_HINT_DEFAULT_MINIMUM(rh)) + if(port < plugin->PortCount) { - *val = range.LowerBound * m; - return true; - } - else if (LADSPA_IS_HINT_DEFAULT_LOW(rh)) - { - if (LADSPA_IS_HINT_LOGARITHMIC(rh)) - { - *val = exp(fast_log10(range.LowerBound * m) * .75 + - log(range.UpperBound * m) * .25); - return true; - } - else - { - *val = range.LowerBound*.75*m + range.UpperBound*.25*m; + LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; + LADSPA_PortRangeHintDescriptor rh = range.HintDescriptor; + // bool isLog = LADSPA_IS_HINT_LOGARITHMIC(rh); + //double val = 1.0; + float m = (rh & LADSPA_HINT_SAMPLE_RATE) ? float(sampleRate) : 1.0f; + if (LADSPA_IS_HINT_DEFAULT_MINIMUM(rh)) + { + *val = range.LowerBound * m; + return true; + } + else if (LADSPA_IS_HINT_DEFAULT_LOW(rh)) + { + if (LADSPA_IS_HINT_LOGARITHMIC(rh)) + { + //*val = exp(fast_log10(range.LowerBound * m) * .75 + + // log(range.UpperBound * m) * .25); + // p4.0.21 And below... + *val = expf(fast_log10(range.LowerBound * m) * .75 + // Why fast_log10? + logf(range.UpperBound * m) * .25); + return true; + } + else + { + *val = range.LowerBound*.75*m + range.UpperBound*.25*m; + return true; + } + } + else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(rh)) + { + if (LADSPA_IS_HINT_LOGARITHMIC(rh)) + { + //*val = exp(log(range.LowerBound * m) * .5 + + // log10(range.UpperBound * m) * .5); + *val = expf(logf(range.LowerBound * m) * .5 + + log10f(range.UpperBound * m) * .5); // Why log10? + return true; + } + else + { + *val = range.LowerBound*.5*m + range.UpperBound*.5*m; + return true; + } + } + else if (LADSPA_IS_HINT_DEFAULT_HIGH(rh)) + { + if (LADSPA_IS_HINT_LOGARITHMIC(rh)) + { + //*val = exp(log(range.LowerBound * m) * .25 + + // log(range.UpperBound * m) * .75); + *val = expf(logf(range.LowerBound * m) * .25 + + logf(range.UpperBound * m) * .75); + return true; + } + else + { + *val = range.LowerBound*.25*m + range.UpperBound*.75*m; + return true; + } + } + else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(rh)) + { + *val = range.UpperBound*m; return true; - } - } - else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(rh)) - { - if (LADSPA_IS_HINT_LOGARITHMIC(rh)) - { - *val = exp(log(range.LowerBound * m) * .5 + - log10(range.UpperBound * m) * .5); + } + else if (LADSPA_IS_HINT_DEFAULT_0(rh)) + { + *val = 0.0; return true; - } - else - { - *val = range.LowerBound*.5*m + range.UpperBound*.5*m; + } + else if (LADSPA_IS_HINT_DEFAULT_1(rh)) + { + *val = 1.0; return true; - } - } - else if (LADSPA_IS_HINT_DEFAULT_HIGH(rh)) - { - if (LADSPA_IS_HINT_LOGARITHMIC(rh)) - { - *val = exp(log(range.LowerBound * m) * .25 + - log(range.UpperBound * m) * .75); + } + else if (LADSPA_IS_HINT_DEFAULT_100(rh)) + { + *val = 100.0; return true; - } - else - { - *val = range.LowerBound*.25*m + range.UpperBound*.75*m; + } + else if (LADSPA_IS_HINT_DEFAULT_440(rh)) + { + *val = 440.0; return true; - } - } - else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(rh)) - { - *val = range.UpperBound*m; - return true; + } } - else if (LADSPA_IS_HINT_DEFAULT_0(rh)) - { - *val = 0.0; - return true; - } - else if (LADSPA_IS_HINT_DEFAULT_1(rh)) - { - *val = 1.0; - return true; - } - else if (LADSPA_IS_HINT_DEFAULT_100(rh)) - { - *val = 100.0; - return true; - } - else if (LADSPA_IS_HINT_DEFAULT_440(rh)) - { - *val = 440.0; - return true; - } // No default found. Set return value to 1.0, but return false. *val = 1.0; @@ -556,9 +571,10 @@ bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val) // ladspaControlRange //--------------------------------------------------------- -void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max) +//void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max) +void ladspaControlRange(const LADSPA_Descriptor* plugin, unsigned port, float* min, float* max) { - LADSPA_PortRangeHint range = plugin->PortRangeHints[i]; + LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; LADSPA_PortRangeHintDescriptor desc = range.HintDescriptor; if (desc & LADSPA_HINT_TOGGLED) { *min = 0.0; @@ -690,7 +706,10 @@ Plugin::Plugin(QFileInfo* f, const LADSPA_Descriptor* d, bool isDssi) // EnsembleLite (EnsLite VST) has the flag set, but it is a vst synth and is not involved here! // Yet many (all?) ladspa vst effect plugins exhibit this problem. // Changed by Tim. p3.3.14 - 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; } @@ -756,7 +775,8 @@ int Plugin::incReferences(int val) if(dssi) { const DSSI_Descriptor* descr; - for(int i = 0;; ++i) + //for(int i = 0;; ++i) + for(unsigned i = 0;; ++i) // p4.0.21 { descr = dssi(i); if(descr == NULL) @@ -787,7 +807,8 @@ int Plugin::incReferences(int val) if(ladspadf) { const LADSPA_Descriptor* descr; - for(int i = 0;; ++i) + //for(int i = 0;; ++i) + for(unsigned i = 0;; ++i) // p4.0.21 { descr = ladspadf(i); if(descr == NULL) @@ -863,8 +884,10 @@ int Plugin::incReferences(int val) _inPlaceCapable = !LADSPA_IS_INPLACE_BROKEN(plugin->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; } } @@ -921,32 +944,46 @@ void Plugin::range(unsigned long i, float* min, float* max) const // defaultValue //--------------------------------------------------------- -double Plugin::defaultValue(unsigned long port) const +//double Plugin::defaultValue(unsigned long port) const +float Plugin::defaultValue(unsigned long port) const { + // p4.0.21 + float val; + ladspaDefaultValue(plugin, port, &val); + return val; + + /* if(port >= plugin->PortCount) return 0.0; LADSPA_PortRangeHint range = plugin->PortRangeHints[port]; LADSPA_PortRangeHintDescriptor rh = range.HintDescriptor; - double val = 1.0; + //double val = 1.0; + float val = 1.0; if (LADSPA_IS_HINT_DEFAULT_MINIMUM(rh)) val = range.LowerBound; else if (LADSPA_IS_HINT_DEFAULT_LOW(rh)) if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) - val = exp(fast_log10(range.LowerBound) * .75 + - log(range.UpperBound) * .25); + //val = exp(fast_log10(range.LowerBound) * .75 + + // log(range.UpperBound) * .25); + val = expf(fast_log10(range.LowerBound) * .75 + + logf(range.UpperBound) * .25); else val = range.LowerBound*.75 + range.UpperBound*.25; else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(rh)) if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) - val = exp(log(range.LowerBound) * .5 + - log(range.UpperBound) * .5); + //val = exp(log(range.LowerBound) * .5 + + // log(range.UpperBound) * .5); + val = expf(logf(range.LowerBound) * .5 + + logf(range.UpperBound) * .5); else val = range.LowerBound*.5 + range.UpperBound*.5; else if (LADSPA_IS_HINT_DEFAULT_HIGH(rh)) if (LADSPA_IS_HINT_LOGARITHMIC(range.HintDescriptor)) - val = exp(log(range.LowerBound) * .25 + - log(range.UpperBound) * .75); + //val = exp(log(range.LowerBound) * .25 + + // log(range.UpperBound) * .75); + val = expf(logf(range.LowerBound) * .25 + + logf(range.UpperBound) * .75); else val = range.LowerBound*.25 + range.UpperBound*.75; else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(rh)) @@ -961,6 +998,7 @@ double Plugin::defaultValue(unsigned long port) const val = 440.0; return val; + */ } //--------------------------------------------------------- @@ -981,7 +1019,8 @@ static void loadPluginLib(QFileInfo* fi) if(dssi) { const DSSI_Descriptor* descr; - for (int i = 0;; ++i) + //for (int i = 0;; ++i) + for (unsigned i = 0;; ++i) // p4.0.21 { descr = dssi(i); if (descr == 0) @@ -1033,7 +1072,8 @@ static void loadPluginLib(QFileInfo* fi) } const LADSPA_Descriptor* descr; - for (int i = 0;; ++i) + //for (int i = 0;; ++i) + for (unsigned i = 0;; ++i) // p4.0.21 { descr = ladspa(i); if (descr == NULL) @@ -1444,7 +1484,8 @@ bool Pipeline::nativeGuiVisible(int idx) // apply //--------------------------------------------------------- -void Pipeline::apply(int ports, unsigned long nframes, float** buffer1) +//void Pipeline::apply(int ports, unsigned long nframes, float** buffer1) +void Pipeline::apply(unsigned ports, unsigned nframes, float** buffer1) { // prepare a second set of buffers in case a plugin is not // capable of inPlace processing @@ -1467,26 +1508,31 @@ void Pipeline::apply(int ports, unsigned long nframes, float** buffer1) { if (swap) //p->connect(ports, buffer2, buffer2); - p->connect(ports, buffer, buffer); + //p->connect(ports, buffer, buffer); + p->apply(nframes, ports, buffer, buffer); // p4.0.21 else - p->connect(ports, buffer1, buffer1); + //p->connect(ports, buffer1, buffer1); + p->apply(nframes, ports, buffer1, buffer1); // } else { if (swap) //p->connect(ports, buffer2, buffer1); - p->connect(ports, buffer, buffer1); + //p->connect(ports, buffer, buffer1); + p->apply(nframes, ports, buffer, buffer1); // else //p->connect(ports, buffer1, buffer2); - p->connect(ports, buffer1, buffer); + //p->connect(ports, buffer1, buffer); + p->apply(nframes, ports, buffer1, buffer); // swap = !swap; } - p->apply(nframes); + //p->apply(nframes); // Rem. p4.0.21 } } if (swap) { - for (int i = 0; i < ports; ++i) + //for (int i = 0; i < ports; ++i) + for (unsigned i = 0; i < ports; ++i) // p4.0.21 //memcpy(buffer1[i], buffer2[i], sizeof(float) * nframes); //memcpy(buffer1[i], buffer[i], sizeof(float) * nframes); AL::dsp->cpy(buffer1[i], buffer[i], nframes); @@ -1648,10 +1694,13 @@ void PluginI::updateControllers() if(!_track) return; - for(int i = 0; i < controlPorts; ++i) + //for(int i = 0; i < controlPorts; ++i) + for(unsigned i = 0; i < controlPorts; ++i) //audio->msgSetPluginCtrlVal(this, genACnum(_id, i), controls[i].val); // p3.3.43 - audio->msgSetPluginCtrlVal(_track, genACnum(_id, i), controls[i].val); + //audio->msgSetPluginCtrlVal(_track, genACnum(_id, i), controls[i].val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + _track->setPluginCtrlVal(genACnum(_id, i), controls[i].val); } //--------------------------------------------------------- @@ -1722,8 +1771,10 @@ void PluginI::setChannels(int c) } } - int curPort = 0; - int curOutPort = 0; + //int curPort = 0; + //int curOutPort = 0; + unsigned long curPort = 0; // p4.0.21 + unsigned long curOutPort = 0; unsigned long ports = _plugin->ports(); for (unsigned long k = 0; k < ports; ++k) { @@ -1751,14 +1802,48 @@ void PluginI::setChannels(int c) activate(); } +//--------------------------------------------------------- +// setParam +//--------------------------------------------------------- + +void PluginI::setParam(unsigned i, float val) +{ + //controls[i].tmpVal = val; + + // p4.0.21 + if(i >= _plugin->_controlInPorts) + //if(i >= controlPorts) + { + printf("PluginI::setParameter param number %u out of range of ports:%ld\n", i, _plugin->_controlInPorts); + return; + } + ControlEvent ce; + ce.unique = false; + ce.idx = i; + ce.value = 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(); + if(_controlFifo.put(ce)) + { + fprintf(stderr, "PluginI::setParameter: fifo overflow: in control number:%u\n", i); + } + + // 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, + // and we don't want this interfering with oscUpdate which also sends the values. + //synti->_guiUpdateControls[n] = true; +} + //--------------------------------------------------------- // defaultValue //--------------------------------------------------------- -double PluginI::defaultValue(unsigned int param) const +//double PluginI::defaultValue(unsigned int param) const +float PluginI::defaultValue(unsigned param) const { -//#warning controlPorts should really be unsigned - if(param >= (unsigned)controlPorts) + if(param >= controlPorts) return 0.0; return _plugin->defaultValue(controls[param].idx); @@ -1872,8 +1957,10 @@ bool PluginI::initPluginInstance(Plugin* plug, int c) controls = new Port[controlPorts]; controlsOut = new Port[controlOutPorts]; - int i = 0; - int ii = 0; + //int i = 0; + //int ii = 0; + unsigned long curPort = 0; + unsigned long curOutPort = 0; for(unsigned long k = 0; k < ports; ++k) { LADSPA_PortDescriptor pd = _plugin->portd(k); @@ -1881,27 +1968,31 @@ bool PluginI::initPluginInstance(Plugin* plug, int c) { if(pd & LADSPA_PORT_INPUT) { - double val = _plugin->defaultValue(k); - controls[i].val = val; - controls[i].tmpVal = val; - controls[i].enCtrl = true; - controls[i].en2Ctrl = true; - ++i; + //double val = _plugin->defaultValue(k); + float val = _plugin->defaultValue(k); // p4.0.21 + controls[curPort].val = val; + controls[curPort].tmpVal = val; + controls[curPort].enCtrl = true; + controls[curPort].en2Ctrl = true; + ++curPort; } else if(pd & LADSPA_PORT_OUTPUT) { //double val = _plugin->defaultValue(k); - controlsOut[ii].val = 0.0; - controlsOut[ii].tmpVal = 0.0; - controlsOut[ii].enCtrl = false; - controlsOut[ii].en2Ctrl = false; - ++ii; + //float val = _plugin->defaultValue(k); + controlsOut[curOutPort].val = 0.0; + controlsOut[curOutPort].tmpVal = 0.0; + controlsOut[curOutPort].enCtrl = false; + controlsOut[curOutPort].en2Ctrl = false; + ++curOutPort; } } } - unsigned long curPort = 0; - unsigned long curOutPort = 0; + //unsigned long curPort = 0; + //unsigned long curOutPort = 0; + curPort = 0; + curOutPort = 0; for(unsigned long k = 0; k < ports; ++k) { LADSPA_PortDescriptor pd = _plugin->portd(k); @@ -1932,13 +2023,16 @@ bool PluginI::initPluginInstance(Plugin* plug, int c) // connect //--------------------------------------------------------- -void PluginI::connect(int ports, float** src, float** dst) +//void PluginI::connect(int ports, float** src, float** dst) +void PluginI::connect(unsigned ports, unsigned offset, float** src, float** dst) { - int port = 0; + //int port = 0; + unsigned port = 0; // p4.0.21 for (int i = 0; i < instances; ++i) { for (unsigned long k = 0; k < _plugin->ports(); ++k) { if (isAudioIn(k)) { - _plugin->connectPort(handle[i], k, src[port]); + //_plugin->connectPort(handle[i], k, src[port]); + _plugin->connectPort(handle[i], k, src[port] + offset); // p4.0.21 port = (port + 1) % ports; } } @@ -1947,7 +2041,8 @@ void PluginI::connect(int ports, float** src, float** dst) for (int i = 0; i < instances; ++i) { for (unsigned long k = 0; k < _plugin->ports(); ++k) { if (isAudioOut(k)) { - _plugin->connectPort(handle[i], k, dst[port]); + // _plugin->connectPort(handle[i], k, dst[port]); + _plugin->connectPort(handle[i], k, dst[port] + offset); // p4.0.21 port = (port + 1) % ports; // overwrite output? // ++port; // if (port >= ports) { @@ -1979,7 +2074,8 @@ void PluginI::activate() for (int i = 0; i < instances; ++i) _plugin->activate(handle[i]); if (initControlValues) { - for (int i = 0; i < controlPorts; ++i) { + //for (int i = 0; i < controlPorts; ++i) { + for (unsigned i = 0; i < controlPorts; ++i) { controls[i].val = controls[i].tmpVal; } } @@ -1987,7 +2083,8 @@ void PluginI::activate() // // get initial control values from plugin // - for (int i = 0; i < controlPorts; ++i) { + //for (int i = 0; i < controlPorts; ++i) { + for (unsigned i = 0; i < controlPorts; ++i) { controls[i].tmpVal = controls[i].val; } } @@ -1998,11 +2095,14 @@ void PluginI::activate() // set plugin instance controller value by name //--------------------------------------------------------- -bool PluginI::setControl(const QString& s, double val) +//bool PluginI::setControl(const QString& s, double val) +bool PluginI::setControl(const QString& s, float val) { - for (int i = 0; i < controlPorts; ++i) { + //for (int i = 0; i < controlPorts; ++i) { + for (unsigned i = 0; i < controlPorts; ++i) { if (_plugin->portName(controls[i].idx) == s) { - controls[i].val = controls[i].tmpVal = val; + //controls[i].val = controls[i].tmpVal = val; + setParam(i, val); // p4.0.21 return false; } } @@ -2023,8 +2123,10 @@ void PluginI::writeConfiguration(int level, Xml& xml) //_plugin->lib().toLatin1().constData(), _plugin->label().toLatin1().constData(), channel); Xml::xmlString(_plugin->lib()).toLatin1().constData(), Xml::xmlString(_plugin->label()).toLatin1().constData(), channel); - for (int i = 0; i < controlPorts; ++i) { - int idx = controls[i].idx; + //for (int i = 0; i < controlPorts; ++i) { + //int idx = controls[i].idx; + for (unsigned i = 0; i < controlPorts; ++i) { // p4.0.21 + unsigned idx = controls[i].idx; // QString s("control name=\"%1\" val=\"%2\" /"); //xml.tag(level, s.arg(_plugin->portName(idx)).arg(controls[i].tmpVal).toLatin1().constData()); xml.tag(level, s.arg(Xml::xmlString(_plugin->portName(idx)).toLatin1().constData()).arg(controls[i].tmpVal).toLatin1().constData()); @@ -2052,7 +2154,8 @@ bool PluginI::loadControl(Xml& xml) QString file; QString label; QString name("mops"); - double val = 0.0; + //double val = 0.0; + float val = 0.0; // p4.0.21 for (;;) { Xml::Token token = xml.parse(); @@ -2069,7 +2172,8 @@ bool PluginI::loadControl(Xml& xml) if (tag == "name") name = xml.s2(); else if (tag == "val") - val = xml.s2().toDouble(); + //val = xml.s2().toDouble(); + val = xml.s2().toFloat(); // p4.0.21 break; case Xml::TagEnd: if (tag == "control") { @@ -2307,7 +2411,8 @@ void PluginIBase::deleteGui() void PluginI::enableAllControllers(bool v) { - for(int i = 0; i < controlPorts; ++i) + //for(int i = 0; i < controlPorts; ++i) + for(unsigned i = 0; i < controlPorts; ++i) controls[i].enCtrl = v; } @@ -2317,7 +2422,8 @@ void PluginI::enableAllControllers(bool v) void PluginI::enable2AllControllers(bool v) { - for(int i = 0; i < controlPorts; ++i) + //for(int i = 0; i < controlPorts; ++i) + for(unsigned i = 0; i < controlPorts; ++i) controls[i].en2Ctrl = v; } @@ -2325,7 +2431,9 @@ void PluginI::enable2AllControllers(bool v) // apply //--------------------------------------------------------- -void PluginI::apply(int n) +/* +//void PluginI::apply(int n) +void PluginI::apply(unsigned n) { // Process control value changes. //if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1) @@ -2412,6 +2520,156 @@ void PluginI::apply(int n) _plugin->apply(handle[i], n); } } +*/ + +#if 1 +// p4.0.21 +void PluginI::apply(unsigned n, unsigned ports, float** bufIn, float** bufOut) +{ + // Process control value changes. + //if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1) + //{ + // for(int i = 0; i < controlPorts; ++i) + // { + // if( controls[i].enCtrl && controls[i].en2Ctrl ) + // controls[i].tmpVal = _track->pluginCtrlVal(genACnum(_id, i)); + // } + //} + + //unsigned endPos = pos + n; + int frameOffset = audio->getFrameOffset(); + + unsigned sample = 0; + int loopcount = 0; // REMOVE Tim. + + // Must make this detectable for dssi vst effects. + //const bool usefixedrate = true; + const bool usefixedrate = _plugin->_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; + + // 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 < controlPorts; ++k) + { + if(automation && _track && _track->automationType() != AUTO_OFF && _id != -1) + { + if(controls[k].enCtrl && controls[k].en2Ctrl ) + controls[k].tmpVal = _track->pluginCtrlVal(genACnum(_id, k)); + } + } + + 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("PluginI::apply 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) + if(v.frame < sample || v.frame >= 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 >= controlPorts) // Sanity check. + if(v.idx >= _plugin->_controlInPorts) + break; + found = true; + frame = v.frame; + 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) + { + // Since we are now in the audio thread context, there's no need to send a message, + // just modify directly. + //audio->msgSetPluginCtrlVal(this, genACnum(_id, k), controls[k].val); + // p3.3.43 + //audio->msgSetPluginCtrlVal(_track, genACnum(_id, k), controls[k].val); + _track->setPluginCtrlVal(genACnum(_id, v.idx), v.value); + + // Record automation. + // NO! Take care of this immediately in the OSC control handler, because we don't want + // any delay. + // OTOH Since this is the actual place and time where the control ports values + // are set, best to reflect what happens here to automation. + // However for dssi-vst it might be best to handle it that way. + + //AutomationType at = _track->automationType(); + // TODO: Taken from our native gui control handlers. + // This may need modification or may cause problems - + // we don't have the luxury of access to the dssi gui controls ! + //if(at == AUTO_WRITE || (audio->isPlaying() && at == AUTO_TOUCH)) + // enableController(k, false); + //_track->recordAutomation(id, v.value); + } + } + + // Now update the actual values from the temporary values... + for(unsigned long k = 0; k < controlPorts; ++k) + controls[k].val = controls[k].tmpVal; + + //if(found) + if(found && !usefixedrate) + //nsamp = frame - sample + 1; + nsamp = frame - sample; + if(sample + nsamp >= n) // Safety check. + nsamp = n - sample; + + //printf("PluginI::apply ports:%d n:%d frame:%d sample:%d nsamp:%d fOffset:%d loopcount:%d\n", + // ports, n, frame, sample, nsamp, 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; + + connect(ports, sample, bufIn, bufOut); + + for(int i = 0; i < instances; ++i) + { + //fprintf(stderr, "PluginI::apply handle %d\n", i); + _plugin->apply(handle[i], nsamp); + } + + sample += nsamp; + loopcount++; // REMOVE Tim. + } +} +#endif //--------------------------------------------------------- // oscConfigure @@ -2544,7 +2802,8 @@ int PluginI::oscUpdate() // Send current control values. //unsigned long ports = controlPorts; - for(int i = 0; i < controlPorts; ++i) + //for(int i = 0; i < controlPorts; ++i) + for(unsigned i = 0; i < controlPorts; ++i) { //unsigned long k = synth->pIdx(i); //_oscIF.oscSendControl(k, controls[i]); @@ -2576,15 +2835,15 @@ int PluginI::oscControl(unsigned long port, float value) //if(port >= controlPorts) //if(port < 0 || port >= _plugin->rpIdx.size()) - //{ - //fprintf(stderr, "DssiSynthIF::oscControl: port number:%d is out of range of number of ports:%d\n", port, controlPorts); - // fprintf(stderr, "PluginI::oscControl: port number:%d is out of range of index list size:%d\n", port, _plugin->rpIdx.size()); - // return 0; - //} + if(port >= _plugin->rpIdx.size()) + { + fprintf(stderr, "PluginI::oscControl: port number:%ld is out of range of index list size:%d\n", port, _plugin->rpIdx.size()); + return 0; + } // Convert from DSSI port number to control input port index. - //unsigned long cport = _plugin->rpIdx[port]; - unsigned long cport = _plugin->port2InCtrl(port); + unsigned long cport = _plugin->rpIdx[port]; + //unsigned long cport = _plugin->port2InCtrl(port); if((int)cport == -1) { @@ -2607,6 +2866,7 @@ int PluginI::oscControl(unsigned long port, float value) // TODO: 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. // Try this ... + /* OscControlFifo* cfifo = _oscif.oscFifo(cport); if(cfifo) { @@ -2622,16 +2882,32 @@ int PluginI::oscControl(unsigned long port, float value) fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%ld\n", cport); } } + */ + // p4.0.21 + ControlEvent ce; + ce.unique = _plugin->_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, "PluginI::oscControl: fifo overflow: in control number:%ld\n", cport); + } + // Record automation: // Take care of this immediately, because we don't want the silly delay associated with // processing the fifo one-at-a-time in the apply(). - // NOTE: Ahh crap! We don't receive control events until the user RELEASES a control ! + // NOTE: With some vsts we don't receive control events until the user RELEASES a control. // So the events all arrive at once when the user releases a control. // That makes this pretty useless... But what the heck... if(_track && _id != -1) { - int id = genACnum(_id, cport); + //int id = genACnum(_id, cport); + unsigned id = genACnum(_id, cport); AutomationType at = _track->automationType(); // TODO: Taken from our native gui control handlers. @@ -2880,10 +3156,14 @@ void PluginDialog::fillPlugs(int nbr) { pList->clear(); for (iPlugin i = plugins.begin(); i != plugins.end(); ++i) { - int ai = i->inports(); - int ao = i->outports(); - int ci = i->controlInPorts(); - int co = i->controlOutPorts(); + //int ai = i->inports(); + //int ao = i->outports(); + //int ci = i->controlInPorts(); + //int co = i->controlOutPorts(); + unsigned ai = i->inports(); // p4.0.21 + unsigned ao = i->outports(); + unsigned ci = i->controlInPorts(); + unsigned co = i->controlOutPorts(); bool addFlag = false; switch (nbr) { case SEL_SM: // stereo & mono @@ -2928,10 +3208,14 @@ void PluginDialog::fillPlugs(const QString &sortValue) { pList->clear(); for (iPlugin i = plugins.begin(); i != plugins.end(); ++i) { - int ai = i->inports(); - int ao = i->outports(); - int ci = i->controlInPorts(); - int co = i->controlOutPorts(); + //int ai = i->inports(); + //int ao = i->outports(); + //int ci = i->controlInPorts(); + //int co = i->controlOutPorts(); + unsigned ai = i->inports(); // p4.0.21 + unsigned ao = i->outports(); + unsigned ci = i->controlInPorts(); + unsigned co = i->controlOutPorts(); bool addFlag = false; @@ -3045,16 +3329,24 @@ PluginGui::PluginGui(PluginIBase* p) const char* name = ba.constData(); if (*name !='P') continue; - int parameter = -1; - sscanf(name, "P%d", ¶meter); - if (parameter == -1) - continue; + //int parameter = -1; + //sscanf(name, "P%d", ¶meter); + //if (parameter == -1) + // continue; + unsigned parameter; // p4.0.21 + int rv = sscanf(name, "P%u", ¶meter); + if(rv != 1) + continue; ++nobj; } it = l.begin(); gw = new GuiWidgets[nobj]; nobj = 0; QSignalMapper* mapper = new QSignalMapper(this); + + // FIXME: There's no unsigned for gui params. We would need to limit nobj to MAXINT. // p4.0.21 + // FIXME: Our Slider class uses doubles for values, giving some problems with float conversion. // p4.0.21 + connect(mapper, SIGNAL(mapped(int)), SLOT(guiParamChanged(int))); QSignalMapper* mapperPressed = new QSignalMapper(this); @@ -3068,10 +3360,14 @@ PluginGui::PluginGui(PluginIBase* p) const char* name = ba.constData(); if (*name !='P') continue; - int parameter = -1; - sscanf(name, "P%d", ¶meter); - if (parameter == -1) - continue; + //int parameter = -1; + //sscanf(name, "P%d", ¶meter); + //if (parameter == -1) + // continue; + unsigned parameter; // p4.0.21 + int rv = sscanf(name, "P%u", ¶meter); + if(rv != 1) + continue; mapper->setMapping(obj, nobj); mapperPressed->setMapping(obj, nobj); @@ -3085,7 +3381,8 @@ PluginGui::PluginGui(PluginIBase* p) gw[nobj].type = GuiWidgets::SLIDER; ((Slider*)obj)->setId(nobj); ((Slider*)obj)->setCursorHoming(true); - for(int i = 0; i < nobj; i++) + //for(int i = 0; i < nobj; i++) + for(unsigned i = 0; i < nobj; i++) // p4.0.21 { if(gw[i].type == GuiWidgets::DOUBLE_LABEL && gw[i].param == parameter) ((DoubleLabel*)gw[i].widget)->setSlider((Slider*)obj); @@ -3098,7 +3395,8 @@ PluginGui::PluginGui(PluginIBase* p) else if (strcmp(obj->metaObject()->className(), "DoubleLabel") == 0) { gw[nobj].type = GuiWidgets::DOUBLE_LABEL; ((DoubleLabel*)obj)->setId(nobj); - for(int i = 0; i < nobj; i++) + //for(int i = 0; i < nobj; i++) + for(unsigned i = 0; i < nobj; i++) { if(gw[i].type == GuiWidgets::SLIDER && gw[i].param == parameter) { @@ -3141,7 +3439,8 @@ PluginGui::PluginGui(PluginIBase* p) mw->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); - int n = plugin->parameters(); + //int n = plugin->parameters(); + unsigned n = plugin->parameters(); // p4.0.21 params = new GuiParam[n]; // Changed p3.3.43 @@ -3155,7 +3454,8 @@ PluginGui::PluginGui(PluginIBase* p) QFontMetrics fm = fontMetrics(); int h = fm.height() + 4; - for (int i = 0; i < n; ++i) { + //for (int i = 0; i < n; ++i) { + for (unsigned i = 0; i < n; ++i) { // p4.0.21 QLabel* label = 0; LADSPA_PortRangeHint range = plugin->range(i); double lower = 0.0; // default values @@ -3301,7 +3601,7 @@ void PluginGui::ctrlPressed(int param) if(params[param].type == GuiParam::GUI_SLIDER) { - double val = ((Slider*)params[param].actuator)->value(); + double val = ((Slider*)params[param].actuator)->value(); if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint)) val = pow(10.0, val/20.0); else if (LADSPA_IS_HINT_INTEGER(params[param].hint)) @@ -3315,14 +3615,17 @@ void PluginGui::ctrlPressed(int param) if(track) { // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); track->startAutoRecord(id, val); } } else if(params[param].type == GuiParam::GUI_SWITCH) { - double val = (double)((CheckBox*)params[param].actuator)->isChecked(); + //double val = (double)((CheckBox*)params[param].actuator)->isChecked(); + float val = (float)((CheckBox*)params[param].actuator)->isChecked(); // p4.0.21 plugin->setParam(param, val); // p3.3.43 @@ -3331,7 +3634,9 @@ void PluginGui::ctrlPressed(int param) if(track) { // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); track->startAutoRecord(id, val); } @@ -3423,7 +3728,9 @@ void PluginGui::sliderChanged(double val, int param) if(track) { // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); track->recordAutomation(id, val); } @@ -3465,7 +3772,9 @@ void PluginGui::labelChanged(double val, int param) if(track) { // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); track->startAutoRecord(id, val); } @@ -3596,7 +3905,8 @@ void PluginGui::setOn(bool val) void PluginGui::updateValues() { if (params) { - for (int i = 0; i < plugin->parameters(); ++i) { + //for (int i = 0; i < plugin->parameters(); ++i) { + for (unsigned i = 0; i < plugin->parameters(); ++i) { // p4.0.21 GuiParam* gp = ¶ms[i]; if (gp->type == GuiParam::GUI_SLIDER) { double lv = plugin->param(i); @@ -3617,17 +3927,20 @@ void PluginGui::updateValues() } } else if (gw) { - for (int i = 0; i < nobj; ++i) { + //for (int i = 0; i < nobj; ++i) { + for (unsigned i = 0; i < nobj; ++i) { // p4.0.21 QWidget* widget = gw[i].widget; int type = gw[i].type; - int param = gw[i].param; - double val = plugin->param(param); + //int param = gw[i].param; + //double val = plugin->param(param); + unsigned param = gw[i].param; // p4.0.21 + float val = plugin->param(param); switch(type) { case GuiWidgets::SLIDER: - ((Slider*)widget)->setValue(val); + ((Slider*)widget)->setValue(val); // Note conversion to double break; case GuiWidgets::DOUBLE_LABEL: - ((DoubleLabel*)widget)->setValue(val); + ((DoubleLabel*)widget)->setValue(val); // Note conversion to double break; case GuiWidgets::QCHECKBOX: ((QCheckBox*)widget)->setChecked(int(val)); @@ -3652,7 +3965,8 @@ void PluginGui::updateControls() if(at == AUTO_OFF) return; if (params) { - for (int i = 0; i < plugin->parameters(); ++i) { + //for (int i = 0; i < plugin->parameters(); ++i) { + for (unsigned i = 0; i < plugin->parameters(); ++i) { // p4.0.21 GuiParam* gp = ¶ms[i]; if (gp->type == GuiParam::GUI_SLIDER) { if( plugin->controllerEnabled(i) && plugin->controllerEnabled2(i) ) @@ -3698,10 +4012,12 @@ void PluginGui::updateControls() } } else if (gw) { - for (int i = 0; i < nobj; ++i) { + //for (int i = 0; i < nobj; ++i) { + for (unsigned i = 0; i < nobj; ++i) { // p4.0.21 QWidget* widget = gw[i].widget; int type = gw[i].type; - int param = gw[i].param; + //int param = gw[i].param; + unsigned param = gw[i].param; // p4.0.21 switch(type) { case GuiWidgets::SLIDER: if( plugin->controllerEnabled(param) && plugin->controllerEnabled2(param) ) @@ -3771,7 +4087,8 @@ void PluginGui::updateControls() void PluginGui::guiParamChanged(int idx) { QWidget* w = gw[idx].widget; - int param = gw[idx].param; + //int param = gw[idx].param; + unsigned param = gw[idx].param; // p4.0.21 int type = gw[idx].type; AutomationType at = AUTO_OFF; @@ -3798,7 +4115,8 @@ void PluginGui::guiParamChanged(int idx) break; } - for (int i = 0; i < nobj; ++i) { + //for (int i = 0; i < nobj; ++i) { + for (unsigned i = 0; i < nobj; ++i) { // p4.0.21 QWidget* widget = gw[i].widget; if (widget == w || param != gw[i].param) continue; @@ -3830,7 +4148,9 @@ void PluginGui::guiParamChanged(int idx) //if(track) //{ // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); switch(type) { @@ -3853,7 +4173,8 @@ void PluginGui::guiParamChanged(int idx) void PluginGui::guiParamPressed(int idx) { - int param = gw[idx].param; + //int param = gw[idx].param; + unsigned param = gw[idx].param; // p4.0.21 AutomationType at = AUTO_OFF; AudioTrack* track = plugin->track(); @@ -3893,7 +4214,8 @@ void PluginGui::guiParamPressed(int idx) void PluginGui::guiParamReleased(int idx) { - int param = gw[idx].param; + //int param = gw[idx].param; + unsigned param = gw[idx].param; // p4.0.21 int type = gw[idx].type; AutomationType at = AUTO_OFF; @@ -3938,7 +4260,8 @@ void PluginGui::guiParamReleased(int idx) void PluginGui::guiSliderPressed(int idx) { - int param = gw[idx].param; + //int param = gw[idx].param; + unsigned param = gw[idx].param; // p4.0.21 QWidget *w = gw[idx].widget; AutomationType at = AUTO_OFF; @@ -3961,12 +4284,15 @@ void PluginGui::guiSliderPressed(int idx) //audio->msgSetPluginCtrlVal(((PluginI*)plugin), id, val); // p3.3.43 - audio->msgSetPluginCtrlVal(track, id, val); + //audio->msgSetPluginCtrlVal(track, id, val); + // p4.0.21 audio->msgXXX waits. Do we really need to? + track->setPluginCtrlVal(id, val); track->startAutoRecord(id, val); // Needed so that paging a slider updates a label or other buddy control. - for (int i = 0; i < nobj; ++i) { + //for (int i = 0; i < nobj; ++i) { + for (unsigned i = 0; i < nobj; ++i) { // p4.0.21 QWidget* widget = gw[i].widget; if (widget == w || param != gw[i].param) continue; diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h index 41da1bfb..2d78a335 100644 --- a/muse2/muse/plugin.h +++ b/muse2/muse/plugin.h @@ -22,6 +22,7 @@ #include "globals.h" #include "globaldefs.h" #include "ctrl.h" +#include "controlfifo.h" //#include "stringparam.h" @@ -78,7 +79,10 @@ class PluginBase //--------------------------------------------------------- class Plugin { + protected: + friend class PluginI; + void* _handle; int _references; int _instNo; @@ -92,6 +96,9 @@ class Plugin { QString _copyright; bool _isDssi; + // Hack: Special flag required. + bool _isDssiVst; + #ifdef DSSI_SUPPORT const DSSI_Descriptor* dssi_descr; #endif @@ -138,11 +145,13 @@ class Plugin { if (plugin && plugin->cleanup) plugin->cleanup(handle); } - void connectPort(LADSPA_Handle handle, int port, float* value) { + //void connectPort(LADSPA_Handle handle, int port, float* value) { + void connectPort(LADSPA_Handle handle, unsigned port, float* value) { // p4.0.21 if(plugin) plugin->connect_port(handle, port, value); } - void apply(LADSPA_Handle handle, int n) { + //void apply(LADSPA_Handle handle, int n) { + void apply(LADSPA_Handle handle, unsigned n) { // p4.0.21 if(plugin) plugin->run(handle, n); } @@ -165,7 +174,8 @@ class Plugin { return plugin->PortRangeHints[i]; } - double defaultValue(unsigned long port) const; + //double defaultValue(unsigned long port) const; + float defaultValue(unsigned long port) const; // p4.0.21 void range(unsigned long i, float*, float*) const; const char* portName(unsigned long i) { @@ -173,7 +183,7 @@ class Plugin { } // Returns (int)-1 if not an input control. - unsigned long port2InCtrl(unsigned long p) { return p >= rpIdx.size() ? (unsigned long)-1 : rpIdx[p]; } + //unsigned long port2InCtrl(unsigned long p) { return p >= rpIdx.size() ? (unsigned long)-1 : rpIdx[p]; } unsigned long inports() const { return _inports; } unsigned long outports() const { return _outports; } @@ -218,7 +228,8 @@ class PluginList : public std::list { //--------------------------------------------------------- struct Port { - int idx; + //int idx; + unsigned idx; float val; float tmpVal; @@ -251,7 +262,8 @@ struct GuiWidgets { }; QWidget* widget; int type; - int param; + //int param; + unsigned param; // p4.0.21 }; class PluginI; @@ -296,6 +308,7 @@ class PluginBase class PluginIBase { protected: + ControlFifo _controlFifo; PluginGui* _gui; void makeGui(); @@ -305,7 +318,8 @@ class PluginIBase ~PluginIBase(); virtual bool on() const = 0; virtual void setOn(bool /*val*/) = 0; - virtual int pluginID() = 0; + //virtual int pluginID() = 0; + virtual unsigned pluginID() = 0; // p4.0.21 virtual int id() = 0; virtual QString pluginLabel() const = 0; virtual QString name() const = 0; @@ -315,19 +329,27 @@ class PluginIBase virtual AudioTrack* track() = 0; - virtual void enableController(int /*i*/, bool /*v*/ = true) = 0; - virtual bool controllerEnabled(int /*i*/) const = 0; - virtual bool controllerEnabled2(int /*i*/) const = 0; + //virtual void enableController(int /*i*/, bool /*v*/ = true) = 0; + //virtual bool controllerEnabled(int /*i*/) const = 0; + //virtual bool controllerEnabled2(int /*i*/) const = 0; + virtual void enableController(unsigned /*i*/, bool /*v*/ = true) = 0; // p4.0.21 + virtual bool controllerEnabled(unsigned /*i*/) const = 0; + virtual bool controllerEnabled2(unsigned /*i*/) const = 0; virtual void updateControllers() = 0; virtual void writeConfiguration(int /*level*/, Xml& /*xml*/) = 0; virtual bool readConfiguration(Xml& /*xml*/, bool /*readPreset*/=false) = 0; - virtual int parameters() const = 0; - virtual void setParam(int /*i*/, double /*val*/) = 0; - virtual double param(int /*i*/) const = 0; - virtual const char* paramName(int /*i*/) = 0; - virtual LADSPA_PortRangeHint range(int /*i*/) = 0; + //virtual int parameters() const = 0; + //virtual void setParam(int /*i*/, double /*val*/) = 0; + //virtual double param(int /*i*/) const = 0; + //virtual const char* paramName(int /*i*/) = 0; + //virtual LADSPA_PortRangeHint range(int /*i*/) = 0; + virtual unsigned parameters() const = 0; // p4.0.21 + virtual void setParam(unsigned /*i*/, float /*val*/) = 0; + virtual float param(unsigned /*i*/) const = 0; + virtual const char* paramName(unsigned /*i*/) = 0; + virtual LADSPA_PortRangeHint range(unsigned /*i*/) = 0; QString dssi_ui_filename() const; //virtual void showGui(bool) = 0; // p4.0.20 @@ -347,7 +369,8 @@ class PluginGui : public QMainWindow { PluginIBase* plugin; // plugin instance GuiParam* params; - int nobj; // number of widgets in gw + //int nobj; + unsigned nobj; // number of widgets in gw // p4.0.21 GuiWidgets* gw; QAction* onOff; @@ -404,8 +427,11 @@ class PluginI : public PluginIBase { Port* controls; Port* controlsOut; - int controlPorts; - int controlOutPorts; + //int controlPorts; + //int controlOutPorts; + unsigned controlPorts; // p4.0.21 + unsigned controlOutPorts; // + ///PluginGui* _gui; bool _on; bool initControlValues; @@ -436,20 +462,29 @@ class PluginI : public PluginIBase { void setTrack(AudioTrack* t) { _track = t; } AudioTrack* track() { return _track; } - int pluginID() { return _plugin->id(); } + //int pluginID() { return _plugin->id(); } + unsigned pluginID() { return _plugin->id(); } // p4.0.21 void setID(int i); int id() { return _id; } void updateControllers(); bool initPluginInstance(Plugin*, int channels); void setChannels(int); - void connect(int ports, float** src, float** dst); - void apply(int n); - - void enableController(int i, bool v = true) { controls[i].enCtrl = v; } - bool controllerEnabled(int i) const { return controls[i].enCtrl; } - void enable2Controller(int i, bool v = true) { controls[i].en2Ctrl = v; } - bool controllerEnabled2(int i) const { return controls[i].en2Ctrl; } + //void connect(int ports, float** src, float** dst); + //void apply(int n); + //void connect(unsigned ports, float** src, float** dst); + //void apply(unsigned n); + void connect(unsigned ports, unsigned offset, float** src, float** dst); // p4.0.21 + void apply(unsigned n, unsigned ports, float** bufIn, float** bufOut); // + + //void enableController(int i, bool v = true) { controls[i].enCtrl = v; } + //bool controllerEnabled(int i) const { return controls[i].enCtrl; } + //void enable2Controller(int i, bool v = true) { controls[i].en2Ctrl = v; } + //bool controllerEnabled2(int i) const { return controls[i].en2Ctrl; } + void enableController(unsigned i, bool v = true) { controls[i].enCtrl = v; } // p4.0.21 + bool controllerEnabled(unsigned i) const { return controls[i].enCtrl; } + void enable2Controller(unsigned i, bool v = true) { controls[i].en2Ctrl = v; } + bool controllerEnabled2(unsigned i) const { return controls[i].en2Ctrl; } void enableAllControllers(bool v = true); void enable2AllControllers(bool v = true); @@ -481,7 +516,8 @@ class PluginI : public PluginIBase { void writeConfiguration(int level, Xml& xml); bool readConfiguration(Xml& xml, bool readPreset=false); bool loadControl(Xml& xml); - bool setControl(const QString& s, double val); + //bool setControl(const QString& s, double val); + bool setControl(const QString& s, float val); // p4.0.21 void showGui(); void showGui(bool); bool isDssiPlugin() const { return _plugin->isDssiPlugin(); } @@ -490,17 +526,29 @@ class PluginI : public PluginIBase { bool isShowNativeGuiPending() { return _showNativeGuiPending; } bool guiVisible(); bool nativeGuiVisible(); - int parameters() const { return controlPorts; } - void setParam(int i, double val) { controls[i].tmpVal = val; } - double param(int i) const { return controls[i].val; } - double defaultValue(unsigned int param) const; - const char* paramName(int i) { return _plugin->portName(controls[i].idx); } - LADSPA_PortDescriptor portd(int i) const { return _plugin->portd(controls[i].idx); } - void range(int i, float* min, float* max) const { _plugin->range(controls[i].idx, min, max); } - bool isAudioIn(int k) { return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN; } - bool isAudioOut(int k) { return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT; } + //int parameters() const { return controlPorts; } + //void setParam(int i, double val) { controls[i].tmpVal = val; } + //double param(int i) const { return controls[i].val; } + //double defaultValue(unsigned int param) const; + //const char* paramName(int i) { return _plugin->portName(controls[i].idx); } + //LADSPA_PortDescriptor portd(int i) const { return _plugin->portd(controls[i].idx); } + //void range(int i, float* min, float* max) const { _plugin->range(controls[i].idx, min, max); } + //bool isAudioIn(int k) { return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN; } + //bool isAudioOut(int k) { return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT; } + //LADSPA_PortRangeHint range(int i) { return _plugin->range(controls[i].idx); } + // p4.0.21 + unsigned parameters() const { return controlPorts; } + //void setParam(unsigned i, float val) { controls[i].tmpVal = val; } + void setParam(unsigned i, float val); + float param(unsigned i) const { return controls[i].val; } + float defaultValue(unsigned param) const; + const char* paramName(unsigned i) { return _plugin->portName(controls[i].idx); } + LADSPA_PortDescriptor portd(unsigned i) const { return _plugin->portd(controls[i].idx); } + void range(unsigned i, float* min, float* max) const { _plugin->range(controls[i].idx, min, max); } + bool isAudioIn(unsigned k) { return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN; } + bool isAudioOut(unsigned k) { return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT; } + LADSPA_PortRangeHint range(unsigned i) { return _plugin->range(controls[i].idx); } bool inPlaceCapable() const { return _plugin->inPlaceCapable(); } - LADSPA_PortRangeHint range(int i) { return _plugin->range(controls[i].idx); } }; //--------------------------------------------------------- @@ -533,7 +581,8 @@ class Pipeline : public std::vector { void deleteAllGuis(); bool guiVisible(int); bool nativeGuiVisible(int); - void apply(int ports, unsigned long nframes, float** buffer); + //void apply(int ports, unsigned long nframes, float** buffer); + void apply(unsigned ports, unsigned nframes, float** buffer); // p4.0.21 void move(int idx, bool up); bool empty(int idx) const; void setChannels(int); @@ -581,11 +630,16 @@ class PluginDialog : public QDialog { extern void initPlugins(); extern PluginList plugins; -extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val); -extern void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max); -extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def); -//extern MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, int port, int ctlnum); -extern float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val); +//extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val); +//extern void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max); +//extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def); +//extern float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val); +// p4.0.21 +extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, unsigned port, float* val); +extern void ladspaControlRange(const LADSPA_Descriptor* plugin, unsigned port, float* min, float* max); +extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum, int* min, int* max, int* def); +extern float midi2LadspaValue(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum, int val); +//extern MidiController* ladspa2MidiController(const LADSPA_Descriptor* plugin, unsigned port, int ctlnum); #endif diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index 6212340f..521c7d63 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -917,8 +917,9 @@ void SynthI::preProcessAlways() // Clear any accumulated play events. playEvents()->clear(); // Eat up any fifo events. - while(!eventFifo.isEmpty()) - eventFifo.get(); + //while(!eventFifo.isEmpty()) + // eventFifo.get(); + eventFifo.clear(); // p4.0.21 Duh, clear is the same but faster AND safer, right? } } diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h index 100d7bd6..b11ea2d9 100644 --- a/muse2/muse/synth.h +++ b/muse2/muse/synth.h @@ -149,8 +149,8 @@ class SynthIF { virtual const char* getPatchName(int, int, MType, bool) = 0; virtual void populatePatchPopup(QMenu*, int, MType, bool) = 0; virtual void write(int level, Xml& xml) const = 0; - virtual float getParameter(unsigned long idx) const = 0; - virtual void setParameter(unsigned long idx, float value) = 0; + virtual float getParameter(unsigned long idx) const = 0; + virtual void setParameter(unsigned long idx, float value) = 0; virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval) = 0; }; @@ -211,7 +211,7 @@ class SynthI : public AudioTrack, public MidiDevice, //SynthI* clone() const { return new SynthI(*this); } SynthI* clone(bool /*cloneParts*/) const { return new SynthI(*this); } - virtual inline int deviceType() { return SYNTH_MIDI; } + virtual inline int deviceType() const { return SYNTH_MIDI; } SynthIF* sif() const { return _sif; } bool initInstance(Synth* s, const QString& instanceName); diff --git a/muse2/synti/deicsonze/deicsonze.cpp b/muse2/synti/deicsonze/deicsonze.cpp index 62abed5d..1da9fbc4 100644 --- a/muse2/synti/deicsonze/deicsonze.cpp +++ b/muse2/synti/deicsonze/deicsonze.cpp @@ -4316,10 +4316,7 @@ void DeicsOnze::process(float** buffer, int offset, int n) { if(_global.filter) _chorusFilter->process(tempOutputChorus[0], tempOutputChorus[1], n); //apply Chorus - ///_pluginIChorus->apply(n, 2, tempInputChorus, tempOutputChorus); - _pluginIChorus->connect(2, tempInputChorus, tempOutputChorus); - _pluginIChorus->apply(n); - + _pluginIChorus->apply(n, 2, tempInputChorus, tempOutputChorus); for(int i = 0; i < n; i++) { leftOutput[i] += tempOutputChorus[0][i] * _global.chorusReturn * _global.masterVolume; @@ -4333,10 +4330,7 @@ void DeicsOnze::process(float** buffer, int offset, int n) { if(_global.filter) _reverbFilter->process(tempOutputReverb[0], tempOutputReverb[1], n); //apply Reverb - ///_pluginIReverb->apply(n, 2, tempInputReverb, tempOutputReverb); - _pluginIReverb->connect(2, tempInputReverb, tempOutputReverb); - _pluginIReverb->apply(n); - + _pluginIReverb->apply(n, 2, tempInputReverb, tempOutputReverb); for(int i = 0; i < n; i++) { leftOutput[i] += tempOutputReverb[0][i] * _global.reverbReturn * _global.masterVolume; @@ -4350,10 +4344,7 @@ void DeicsOnze::process(float** buffer, int offset, int n) { if(_global.filter) _delayFilter->process(tempOutputDelay[0], tempOutputDelay[1], n); //apply Delay - ///_pluginIDelay->apply(n, 2, tempInputDelay, tempOutputDelay); - _pluginIDelay->connect(2, tempInputDelay, tempOutputDelay); - _pluginIDelay->apply(n); - + _pluginIDelay->apply(n, 2, tempInputDelay, tempOutputDelay); for(int i = 0; i < n; i++) { leftOutput[i] += tempOutputDelay[0][i] * _global.delayReturn * _global.masterVolume; -- cgit v1.2.3