summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
Diffstat (limited to 'muse2')
-rw-r--r--muse2/ChangeLog17
-rw-r--r--muse2/muse/app.cpp4
-rw-r--r--muse2/muse/arranger/arranger.cpp8
-rw-r--r--muse2/muse/arranger/pcanvas.cpp7
-rw-r--r--muse2/muse/audio.cpp2
-rw-r--r--muse2/muse/audiotrack.cpp497
-rw-r--r--muse2/muse/ctrl.cpp134
-rw-r--r--muse2/muse/ctrl.h33
-rw-r--r--muse2/muse/driver/audiodev.h1
-rw-r--r--muse2/muse/driver/dummyaudio.cpp21
-rw-r--r--muse2/muse/driver/jack.cpp45
-rw-r--r--muse2/muse/driver/jackaudio.h1
-rw-r--r--muse2/muse/dssihost.cpp1179
-rw-r--r--muse2/muse/dssihost.h39
-rw-r--r--muse2/muse/master/masteredit.cpp15
-rw-r--r--muse2/muse/midi.cpp50
-rw-r--r--muse2/muse/midiedit/dcanvas.cpp10
-rw-r--r--muse2/muse/midiedit/drumedit.cpp4
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp1
-rw-r--r--muse2/muse/midiedit/pianoroll.cpp4
-rw-r--r--muse2/muse/mixer/astrip.cpp186
-rw-r--r--muse2/muse/mixer/astrip.h5
-rw-r--r--muse2/muse/node.cpp895
-rw-r--r--muse2/muse/plugin.cpp1126
-rw-r--r--muse2/muse/plugin.h25
-rw-r--r--muse2/muse/song.cpp34
-rw-r--r--muse2/muse/song.h2
-rw-r--r--muse2/muse/songfile.cpp5
-rw-r--r--muse2/muse/synth.cpp56
-rw-r--r--muse2/muse/synth.h8
-rw-r--r--muse2/muse/ticksynth.cpp6
-rw-r--r--muse2/muse/track.cpp85
-rw-r--r--muse2/muse/track.h59
-rw-r--r--muse2/muse/vst.h6
-rw-r--r--muse2/muse/vst_native.cpp1008
-rw-r--r--muse2/muse/vst_native.h41
-rw-r--r--muse2/muse/waveedit/waveedit.cpp2
-rw-r--r--muse2/muse/wavetrack.cpp77
-rw-r--r--muse2/muse/widgets/scrollscale.cpp1
-rw-r--r--muse2/muse/widgets/sliderbase.cpp24
-rw-r--r--muse2/muse/widgets/tracks_duplicate_base.ui5
-rw-r--r--muse2/muse/widgets/vst_native_editor.cpp2
-rw-r--r--muse2/synti/deicsonze/deicsonze.cpp83
-rw-r--r--muse2/synti/deicsonze/deicsonze.h2
-rw-r--r--muse2/synti/deicsonze/deicsonzeplugin.cpp59
-rw-r--r--muse2/synti/deicsonze/deicsonzepreset.h4
-rw-r--r--muse2/synti/fluid/fluid.cpp2
-rw-r--r--muse2/synti/fluid/fluid.h2
-rw-r--r--muse2/synti/fluidsynth/fluidsynti.cpp2
-rw-r--r--muse2/synti/fluidsynth/fluidsynti.h2
-rw-r--r--muse2/synti/libsynti/mess.cpp2
-rw-r--r--muse2/synti/libsynti/mess.h2
-rw-r--r--muse2/synti/organ/organ.cpp2
-rw-r--r--muse2/synti/organ/organ.h2
-rw-r--r--muse2/synti/s1/s1.cpp4
-rw-r--r--muse2/synti/simpledrums2/simpledrums.cpp2
-rw-r--r--muse2/synti/simpledrums2/simpledrums.h2
-rw-r--r--muse2/synti/vam/vam.cpp4
58 files changed, 3483 insertions, 2423 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index d5d44367..bff1dfde 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,20 @@
+08.05.2013:
+ - Yet another MAJOR audio engine and plugin/synth process chain re-write. (Tim...)
+ - Track controllers (vol, pan) now sample-accurate.
+ - Track controllers (vol, pan) slope limited for near-noiseless operation. TODO: User settings.
+ - Fixed: "Duplicate Selected Tracks" crashes. Also now copies plugins and synths too.
+ - DSSI + Native VST: Fixed not remembering generic/native GUI pos/size. TODO: DSSI native GUI.
+ - Fixed regression by flo: Sliders were recording multiple automation points at same value.
+ - Fixed canvases not remembering position/zoom - everything reopens at exact same pos/zoom now.
+ - Fixed automatable audio GUI controls 'jumpy' in TOUCH mode if heavy graphics causing slowdowns.
+ When pressed, any control now truly 'disengages' from competing/intefering controller stream.
+ - Improved audio automation modes, + READ mode can now be interrupted by GUI or ext control.
+ - MESS synths (esp Deicsonze): Controls (like Track Info program) and synth controls now mirror
+ each other, both ways.
+ - Deicsonze softsynth: Fixed several problems: Not remembering settings + ladspa plugin settings,
+ midi controllers were in wrong domain - moved to NRPN14 type. TODO: Fix 'biased' midi controllers
+ like pan and detune etc.
+ - Native VST: Call idle periodically. Makes some plugins like Glitch work, as per LAD mail.
05.04.2013:
- Change window title when there are unsaved changes (rj)
- Add auto-save feature, when enabled tries to save after 5 minutes
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp
index e0212a82..ff0f7b8d 100644
--- a/muse2/muse/app.cpp
+++ b/muse2/muse/app.cpp
@@ -1281,7 +1281,9 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool doReadM
MusEGlobal::punchinAction->setChecked(MusEGlobal::song->punchin());
MusEGlobal::punchoutAction->setChecked(MusEGlobal::song->punchout());
MusEGlobal::loopAction->setChecked(MusEGlobal::song->loop());
- MusEGlobal::song->update();
+ // Inform the rest of the app the song changed, with all flags MINUS
+ // these flags which are already sent in the call to MusE::read() above:
+ MusEGlobal::song->update(~SC_TRACK_INSERTED);
MusEGlobal::song->updatePos();
arrangerView->clipboardChanged(); // enable/disable "Paste"
arrangerView->selectionChanged(); // enable/disable "Copy" & "Paste"
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp
index 89872bdf..31ee0451 100644
--- a/muse2/muse/arranger/arranger.cpp
+++ b/muse2/muse/arranger/arranger.cpp
@@ -741,8 +741,8 @@ void Arranger::writeStatus(int level, MusECore::Xml& xml)
xml.intTag(level, "info", ib->isChecked());
split->writeStatus(level, xml);
- xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "xmag", hscroll->mag());
+ xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "ypos", vscroll->value());
xml.etag(level, "arranger");
}
@@ -808,10 +808,8 @@ void Arranger::readStatus(MusECore::Xml& xml)
split->readStatus(xml);
else if (tag == "xmag")
hscroll->setMag(xml.parseInt());
- else if (tag == "xpos") {
- int hpos = xml.parseInt();
- hscroll->setPos(hpos);
- }
+ else if (tag == "xpos")
+ hscroll->setPos(xml.parseInt());
else if (tag == "ypos")
vscroll->setValue(xml.parseInt());
else
diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index bcbb3e58..646a9382 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -1025,6 +1025,8 @@ bool PartCanvas::mousePress(QMouseEvent* event)
foreach(int frame, automation.currentCtrlFrameList)
MusEGlobal::audio->msgEraseACEvent((MusECore::AudioTrack*)automation.currentTrack,
automation.currentCtrlList->id(), frame);
+ // User probably would like to hear results so make sure controller is enabled.
+ ((MusECore::AudioTrack*)automation.currentTrack)->enableController(automation.currentCtrlList->id(), true);
}
}
else {
@@ -3877,7 +3879,7 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint)
int frame = MusEGlobal::tempomap.tick2frame(pos.x());
// FIXME Inefficient to add with wait here, then remove and add with wait again below. Tim.
MusEGlobal::audio->msgAddACEvent((MusECore::AudioTrack*)automation.currentTrack, automation.currentCtrlList->id(), frame, 1.0 /*dummy value */);
-
+
MusECore::iCtrl ic=automation.currentCtrlList->begin();
for (; ic !=automation.currentCtrlList->end(); ++ic) {
MusECore::CtrlVal &cv = ic->second;
@@ -3956,6 +3958,9 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint)
MusEGlobal::audio->msgChangeACEvent((MusECore::AudioTrack*)automation.currentTrack, automation.currentCtrlList->id(), icc->second.frame, newFrame, cvval);
else
MusEGlobal::audio->msgAddACEvent((MusECore::AudioTrack*)automation.currentTrack, automation.currentCtrlList->id(), newFrame, cvval);
+
+ // User probably would like to hear results so make sure controller is enabled.
+ ((MusECore::AudioTrack*)automation.currentTrack)->enableController(automation.currentCtrlList->id(), true);
}
}
diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp
index 29d6971e..0c507fa2 100644
--- a/muse2/muse/audio.cpp
+++ b/muse2/muse/audio.cpp
@@ -353,6 +353,7 @@ void Audio::process(unsigned frames)
if (state == START_PLAY && jackState == PLAY) {
_loopCount = 0;
+ MusEGlobal::song->reenableTouchedControllers();
startRolling();
if (_bounce)
write(sigFd, "f", 1);
@@ -376,6 +377,7 @@ void Audio::process(unsigned frames)
}
else if (state == STOP && jackState == PLAY) {
_loopCount = 0;
+ MusEGlobal::song->reenableTouchedControllers();
startRolling();
}
else if (state == LOOP1 && jackState == PLAY)
diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp
index 44f72750..550725a0 100644
--- a/muse2/muse/audiotrack.cpp
+++ b/muse2/muse/audiotrack.cpp
@@ -4,6 +4,7 @@
// $Id: audiotrack.cpp,v 1.14.2.21 2009/12/20 05:00:35 terminator356 Exp $
//
// (C) Copyright 2004 Werner Schweer (ws@seh.de)
+// (C) Copyright 2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -43,6 +44,7 @@
#include "app.h"
#include "controlfifo.h"
#include "fastlog.h"
+#include "gconfig.h"
namespace MusECore {
@@ -94,6 +96,122 @@ void cacheJackRouteNames()
*/
//---------------------------------------------------------
+// init_buffers
+//---------------------------------------------------------
+
+void AudioTrack::initBuffers()
+{
+ int chans = _totalOutChannels;
+ // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
+ if(chans < MAX_CHANNELS)
+ chans = MAX_CHANNELS;
+ if(!outBuffers)
+ {
+ outBuffers = new float*[chans];
+ for(int i = 0; i < chans; ++i)
+ {
+ int rv = posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * MusEGlobal::segmentSize);
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: AudioTrack::init_buffers: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+ }
+ }
+ for(int i = 0; i < chans; ++i)
+ {
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ outBuffers[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(outBuffers[i], 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ if(!outBuffersExtraMix)
+ {
+ outBuffersExtraMix = new float*[MAX_CHANNELS];
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ int rv = posix_memalign((void**)&outBuffersExtraMix[i], 16, sizeof(float) * MusEGlobal::segmentSize);
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: AudioTrack::init_buffers: posix_memalign outBuffersMonoMix returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+ }
+ }
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ outBuffersExtraMix[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(outBuffersExtraMix[i], 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ if(!audioInSilenceBuf)
+ {
+ int rv = posix_memalign((void**)&audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: AudioTrack::init_buffers: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ audioInSilenceBuf[q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ if(!audioOutDummyBuf)
+ {
+ int rv = posix_memalign((void**)&audioOutDummyBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: AudioTrack::init_buffers: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ audioOutDummyBuf[q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(audioOutDummyBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+
+ if(!_controls && _controlPorts != 0)
+ {
+ _controls = new Port[_controlPorts];
+ ciCtrlList icl = _controller.begin();
+ for(unsigned long k = 0; k < _controlPorts; ++k)
+ {
+ float val = 0.0;
+ if(icl != _controller.end())
+ {
+ // Since the list is sorted by id, if no match is found just let k catch up to the id.
+ if((unsigned long)icl->second->id() == k)
+ {
+ val = icl->second->getDefault();
+ ++icl;
+ }
+ }
+ _controls[k].idx = k;
+ _controls[k].val = val;
+ _controls[k].tmpVal = val;
+ _controls[k].enCtrl = true;
+ }
+ }
+}
+
+//---------------------------------------------------------
// AudioTrack
//---------------------------------------------------------
@@ -106,32 +224,32 @@ AudioTrack::AudioTrack(TrackType t)
_prefader = false;
_efxPipe = new Pipeline();
recFileNumber = 1;
- //_recFile = 0; //unneeded, _recFile's ctor does this
_channels = 0;
_automationType = AUTO_OFF;
setChannels(2);
+
addController(new CtrlList(AC_VOLUME,"Volume",0.001,3.163 /* roughly 10 db */, VAL_LOG));
addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0, VAL_LINEAR));
addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0, VAL_LINEAR, true /*dont show in arranger */));
+ _controlPorts = 3;
+
+ _curVolume = 0.0;
+ _curVol1 = 0.0;
+ _curVol2 = 0.0;
- // for a lot of considerations and failures, see revision 1402 or earlier (flo)
- _totalOutChannels = MAX_CHANNELS;
- outBuffers = new float*[_totalOutChannels];
- for (int i = 0; i < _totalOutChannels; ++i)
- {
- int rv = posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * MusEGlobal::segmentSize);
- if(rv != 0)
- {
- fprintf(stderr, "ERROR: AudioTrack ctor: posix_memalign returned error:%d. Aborting!\n", rv);
- abort();
- }
- }
+ _controls = 0;
+ outBuffers = 0;
+ outBuffersExtraMix = 0;
+ audioInSilenceBuf = 0;
+ audioOutDummyBuf = 0;
+ _totalOutChannels = MAX_CHANNELS;
+
// This is only set by multi-channel syntis...
_totalInChannels = 0;
- bufferPos = INT_MAX;
-
+ initBuffers();
+
setVolume(1.0);
_gain = 1.0;
}
@@ -144,17 +262,27 @@ AudioTrack::AudioTrack(const AudioTrack& t, int flags)
_efxPipe = new Pipeline(); // Start off with a new pipeline.
recFileNumber = 1;
+ addController(new CtrlList(AC_VOLUME,"Volume",0.001,3.163 /* roughly 10 db */, VAL_LOG));
+ addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0, VAL_LINEAR));
+ addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0, VAL_LINEAR, true /*dont show in arranger */));
+ _controlPorts = 3;
+
+ _curVolume = 0.0;
+ _curVol1 = 0.0;
+ _curVol2 = 0.0;
+
// Don't allocate outBuffers here. Let internal_assign() call setTotalOutChannels to set them up.
+ _controls = 0;
outBuffers = 0;
+ outBuffersExtraMix = 0;
+ audioInSilenceBuf = 0;
+ audioOutDummyBuf = 0;
_totalOutChannels = 0;
// This is only set by multi-channel syntis...
_totalInChannels = 0;
- bufferPos = INT_MAX;
-
_recFile = NULL;
- _gain = t._gain;
internal_assign(t, flags | ASSIGN_PROPERTIES);
}
@@ -171,54 +299,169 @@ void AudioTrack::internal_assign(const Track& t, int flags)
_prefader = at._prefader;
_auxSend = at._auxSend;
_automationType = at._automationType;
-
+ _gain = at._gain;
+
if(!(flags & ASSIGN_STD_CTRLS))
{
- _controller.clearDelete();
- for(ciCtrlList icl = at._controller.begin(); icl != at._controller.end(); ++icl)
+ // Copy the standard controller block...
+ ciCtrlList icl = at._controller.begin();
+ ciCtrlList icl_this = _controller.begin();
+ ciCtrlList icl_end = at._controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ ciCtrlList icl_this_end = _controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ int id, id_this;
+ CtrlList* cl, *cl_this;
+ while(icl != icl_end && icl_this != icl_this_end)
+ {
+ cl = icl->second;
+ cl_this = icl_this->second;
+ id = cl->id();
+ id_this = cl_this->id();
+ if(id < id_this)
+ ++icl; // Let id catch up to this id.
+ else if(id > id_this)
+ ++icl_this; // Let this id catch up to id.
+ else
+ {
+ // Match found. Copy properties but not values.
+ cl_this->assign(*cl, CtrlList::ASSIGN_PROPERTIES);
+ ++icl;
+ ++icl_this;
+ }
+ }
+
+ // Copy the special synth controller block...
+ const int synth_id = (int)genACnum(MAX_PLUGINS, 0); // The beginning of the special synth controller block.
+ const int synth_id_end = synth_id + AC_PLUGIN_CTL_BASE; // The end of the special block.
+ icl = at._controller.lower_bound(synth_id);
+ icl_this = _controller.lower_bound(synth_id);
+ icl_end = at._controller.lower_bound(synth_id_end);
+ icl_this_end = _controller.lower_bound(synth_id_end);
+ while(icl != icl_end && icl_this != icl_this_end)
{
- CtrlList* cl = icl->second;
- // Copy all built-in controllers (id below AC_PLUGIN_CTL_BASE), but not plugin controllers.
- if(cl->id() >= AC_PLUGIN_CTL_BASE)
- continue;
- CtrlList* new_cl = new CtrlList();
- new_cl->assign(*cl, CtrlList::ASSIGN_PROPERTIES); // Don't copy values.
- addController(new_cl);
+ cl = icl->second;
+ cl_this = icl_this->second;
+ id = cl->id();
+ id_this = cl_this->id();
+ if(id < id_this)
+ ++icl; // Let id catch up to this id.
+ else if(id > id_this)
+ ++icl_this; // Let this id catch up to id.
+ else
+ {
+ // Match found. Copy properties but not values.
+ cl_this->assign(*cl, CtrlList::ASSIGN_PROPERTIES);
+ ++icl;
+ ++icl_this;
+ }
}
}
- // This will set up or reallocate the outBuffers.
+ // This will set up or reallocate the outBuffers. _controlPorts must be valid by now.
setTotalOutChannels(at._totalOutChannels);
// This is only set by multi-channel syntis...
setTotalInChannels(at._totalInChannels);
-
+
+ // FIXME: setChannels also called in setTotalOutChannels above, causing redundant efxpipe setChannels.
setChannels(at.channels()); // Set track channels (max 2).
+
+ unsigned long cp = _controlPorts;
+ if(at._controlPorts < cp)
+ cp = at._controlPorts;
+ for(unsigned long k = 0; k < cp; ++k)
+ _controls[k] = at._controls[k]; // Assign the structures.
}
if(flags & ASSIGN_PLUGINS)
{
delete _efxPipe;
- _efxPipe = new Pipeline(*(at._efxPipe)); // Make copies of the plugins.
+ _efxPipe = new Pipeline(*(at._efxPipe), this); // Make copies of the plugins.
}
if(flags & (ASSIGN_STD_CTRLS | ASSIGN_PLUGIN_CTRLS))
{
- _controller.clearDelete();
- for(ciCtrlList icl = at._controller.begin(); icl != at._controller.end(); ++icl)
+ const int synth_id = (int)genACnum(MAX_PLUGINS, 0); // The beginning of the special synth controller block.
+ const int synth_id_end = synth_id + AC_PLUGIN_CTL_BASE; // The end of the special block.
+ ciCtrlList icl, icl_end, icl_this, icl_this_end;
+ int id, id_this;
+ CtrlList* cl, *cl_this;
+
+ if(flags & ASSIGN_STD_CTRLS)
{
- CtrlList* cl = icl->second;
- // Discern between built-in controllers (id below AC_PLUGIN_CTL_BASE), and plugin controllers.
- if(cl->id() >= AC_PLUGIN_CTL_BASE)
+ // Copy the standard controller block...
+ icl = at._controller.begin();
+ icl_this = _controller.begin();
+ icl_end = at._controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ icl_this_end = _controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ while(icl != icl_end && icl_this != icl_this_end)
{
- if(!(flags & ASSIGN_PLUGIN_CTRLS))
- continue;
+ cl = icl->second;
+ cl_this = icl_this->second;
+ id = cl->id();
+ id_this = cl_this->id();
+ if(id < id_this)
+ ++icl; // Let id catch up to this id.
+ else if(id > id_this)
+ ++icl_this; // Let this id catch up to id.
+ else
+ {
+ // Match found. Copy properties and values.
+ cl_this->assign(*cl, CtrlList::ASSIGN_PROPERTIES | CtrlList::ASSIGN_VALUES);
+ ++icl;
+ ++icl_this;
+ }
}
- else if(!(flags & ASSIGN_STD_CTRLS))
- continue;
- CtrlList* new_cl = new CtrlList(*cl); // Let copy constructor handle the rest. Copy values.
- addController(new_cl);
+ // Copy the special synth controller block...
+ icl = at._controller.lower_bound(synth_id);
+ icl_this = _controller.lower_bound(synth_id);
+ icl_end = at._controller.lower_bound(synth_id_end);
+ icl_this_end = _controller.lower_bound(synth_id_end);
+ while(icl != icl_end && icl_this != icl_this_end)
+ {
+ cl = icl->second;
+ cl_this = icl_this->second;
+ id = cl->id();
+ id_this = cl_this->id();
+ if(id < id_this)
+ ++icl; // Let id catch up to this id.
+ else if(id > id_this)
+ ++icl_this; // Let this id catch up to id.
+ else
+ {
+ // Match found. Copy properties and values.
+ cl_this->assign(*cl, CtrlList::ASSIGN_PROPERTIES | CtrlList::ASSIGN_VALUES);
+ ++icl;
+ ++icl_this;
+ }
+ }
+ }
+
+ if(flags & ASSIGN_PLUGIN_CTRLS)
+ {
+ // Copy all plugin controller blocks...
+ icl = at._controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ icl_this = _controller.lower_bound(AC_PLUGIN_CTL_BASE);
+ icl_end = at._controller.lower_bound(synth_id);
+ icl_this_end = _controller.lower_bound(synth_id);
+ while(icl != icl_end && icl_this != icl_this_end)
+ {
+ cl = icl->second;
+ cl_this = icl_this->second;
+ id = cl->id();
+ id_this = cl_this->id();
+ if(id < id_this)
+ ++icl; // Let id catch up to this id.
+ else if(id > id_this)
+ ++icl_this; // Let this id catch up to id.
+ else
+ {
+ // Match found. Copy properties and values.
+ cl_this->assign(*cl, CtrlList::ASSIGN_PROPERTIES | CtrlList::ASSIGN_VALUES);
+ ++icl;
+ ++icl_this;
+ }
+ }
}
}
@@ -277,6 +520,22 @@ void AudioTrack::assign(const Track& t, int flags)
AudioTrack::~AudioTrack()
{
delete _efxPipe;
+
+ if(audioInSilenceBuf)
+ free(audioInSilenceBuf);
+
+ if(audioOutDummyBuf)
+ free(audioOutDummyBuf);
+
+ if(outBuffersExtraMix)
+ {
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ if(outBuffersExtraMix[i])
+ free(outBuffersExtraMix[i]);
+ }
+ delete[] outBuffersExtraMix;
+ }
int chans = _totalOutChannels;
// Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
@@ -291,7 +550,10 @@ AudioTrack::~AudioTrack()
}
delete[] outBuffers;
}
-
+
+ if(_controls)
+ delete[] _controls;
+
_controller.clearDelete();
}
@@ -348,13 +610,22 @@ void AudioTrack::addPlugin(PluginI* plugin, int idx)
}
}
efxPipe()->insert(plugin, idx);
- if (plugin)
+ setupPlugin(plugin, idx);
+}
+
+//---------------------------------------------------------
+// setupPlugin
+//---------------------------------------------------------
+
+void AudioTrack::setupPlugin(PluginI* plugin, int idx)
+{
+ if (plugin)
{
plugin->setID(idx);
plugin->setTrack(this);
-
+
int controller = plugin->parameters();
- for (int i = 0; i < controller; ++i)
+ for (int i = 0; i < controller; ++i)
{
int id = genACnum(idx, i);
const char* name = plugin->paramName(i);
@@ -770,7 +1041,7 @@ void AudioTrack::changeACEvent(int id, int frame, int newframe, double newval)
double AudioTrack::volume() const
{
return _controller.value(AC_VOLUME, MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation || automationType() == AUTO_OFF || !_volumeEnCtrl || !_volumeEn2Ctrl);
+ !MusEGlobal::automation || automationType() == AUTO_OFF || !_controls[AC_VOLUME].enCtrl);
}
//---------------------------------------------------------
@@ -795,7 +1066,7 @@ void AudioTrack::setVolume(double val)
double AudioTrack::pan() const
{
return _controller.value(AC_PAN, MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation || automationType() == AUTO_OFF || !_panEnCtrl || !_panEn2Ctrl);
+ !MusEGlobal::automation || automationType() == AUTO_OFF || !_controls[AC_PAN].enCtrl);
}
//---------------------------------------------------------
@@ -836,26 +1107,17 @@ void AudioTrack::setGain(double val)
double AudioTrack::pluginCtrlVal(int ctlID) const
{
- bool en_1 = true, en_2 = true;
+ bool en = true;
if(ctlID < AC_PLUGIN_CTL_BASE)
{
- if(ctlID == AC_VOLUME)
- {
- en_1 = _volumeEnCtrl;
- en_2 = _volumeEn2Ctrl;
- }
- else
- if(ctlID == AC_PAN)
- {
- en_1 = _panEnCtrl;
- en_2 = _panEn2Ctrl;
- }
+ if((unsigned long)ctlID < _controlPorts)
+ en = _controls[ctlID].enCtrl;
}
else
{
if(ctlID < (int)genACnum(MAX_PLUGINS, 0)) // The beginning of the special synth controller block.
{
- _efxPipe->controllersEnabled(ctlID, &en_1, &en_2);
+ en = _efxPipe->controllerEnabled(ctlID);
}
else
{
@@ -866,15 +1128,14 @@ double AudioTrack::pluginCtrlVal(int ctlID) const
if(sif)
{
int in_ctrl_idx = ctlID & AC_PLUGIN_CTL_ID_MASK;
- en_1 = sif->controllerEnabled(in_ctrl_idx);
- en_2 = sif->controllerEnabled2(in_ctrl_idx);
+ en = sif->controllerEnabled(in_ctrl_idx);
}
}
}
}
return _controller.value(ctlID, MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation || automationType() == AUTO_OFF || !en_1 || !en_2);
+ !MusEGlobal::automation || automationType() == AUTO_OFF || !en);
}
//---------------------------------------------------------
@@ -897,12 +1158,22 @@ void AudioTrack::setPluginCtrlVal(int param, double val)
bool AudioTrack::addScheduledControlEvent(int track_ctrl_id, float val, unsigned frame)
{
- if(track_ctrl_id < AC_PLUGIN_CTL_BASE) // FIXME: These controllers (three so far - vol, pan, mute) have no vari-run-length support.
+ if(track_ctrl_id < AC_PLUGIN_CTL_BASE)
{
- iCtrlList icl = _controller.find(track_ctrl_id);
- if(icl == _controller.end())
+ // Send these controllers directly to the track's own FIFO.
+ ControlEvent ce;
+ ce.unique = false;
+ ce.fromGui = false;
+ ce.idx = track_ctrl_id;
+ ce.value = val;
+ // Time-stamp the event. timestamp() is circular, which is making it impossible to deal with 'modulo' events which
+ // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead:
+ ce.frame = frame;
+ if(_controlFifo.put(ce))
+ {
+ fprintf(stderr, "AudioTrack::addScheduledControlEvent: fifo overflow: in control number:%d\n", track_ctrl_id);
return true;
- icl->second->setCurVal(val);
+ }
return false;
}
else
@@ -937,11 +1208,8 @@ void AudioTrack::enableController(int track_ctrl_id, bool en)
{
if(track_ctrl_id < AC_PLUGIN_CTL_BASE)
{
- if(track_ctrl_id == AC_VOLUME)
- enableVolumeController(en);
- else
- if(track_ctrl_id == AC_PAN)
- enablePanController(en);
+ if((unsigned long)track_ctrl_id < _controlPorts)
+ _controls[track_ctrl_id].enCtrl = en;
}
else
{
@@ -964,31 +1232,22 @@ void AudioTrack::enableController(int track_ctrl_id, bool en)
}
//---------------------------------------------------------
-// controllersEnabled
+// controllerEnabled
//---------------------------------------------------------
-void AudioTrack::controllersEnabled(int track_ctrl_id, bool* en1, bool* en2) const
+bool AudioTrack::controllerEnabled(int track_ctrl_id) const
{
- bool en_1 = true, en_2 = true;
if(track_ctrl_id < AC_PLUGIN_CTL_BASE)
{
- if(track_ctrl_id == AC_VOLUME)
- {
- en_1 = _volumeEnCtrl;
- en_2 = _volumeEn2Ctrl;
- }
- else
- if(track_ctrl_id == AC_PAN)
- {
- en_1 = _panEnCtrl;
- en_2 = _panEn2Ctrl;
- }
+ if((unsigned long)track_ctrl_id < _controlPorts)
+ return _controls[track_ctrl_id].enCtrl;
+ return false;
}
else
{
if(track_ctrl_id < (int)genACnum(MAX_PLUGINS, 0)) // The beginning of the special synth controller block.
{
- _efxPipe->controllersEnabled(track_ctrl_id, &en_1, &en_2);
+ return _efxPipe->controllerEnabled(track_ctrl_id);
}
else
{
@@ -999,19 +1258,46 @@ void AudioTrack::controllersEnabled(int track_ctrl_id, bool* en1, bool* en2) con
if(sif)
{
int in_ctrl_idx = track_ctrl_id & AC_PLUGIN_CTL_ID_MASK;
- en_1 = sif->controllerEnabled(in_ctrl_idx);
- en_2 = sif->controllerEnabled2(in_ctrl_idx);
+ return sif->controllerEnabled(in_ctrl_idx);
}
}
}
}
-
- if(en1)
- *en1 = en_1;
- if(en2)
- *en2 = en_2;
+ return false;
}
+//---------------------------------------------------------
+// enableAllControllers
+// Enable all track and plugin controllers, and synth controllers if applicable.
+//---------------------------------------------------------
+
+void AudioTrack::enableAllControllers()
+{
+ // Enable track controllers:
+ for(unsigned long i = 0; i < _controlPorts; ++i)
+ _controls[i].enCtrl = true;
+
+ // Enable plugin controllers:
+ Pipeline *pl = efxPipe();
+ PluginI *p;
+ for(iPluginI i = pl->begin(); i != pl->end(); ++i)
+ {
+ p = *i;
+ if(!p)
+ continue;
+ p->enableAllControllers(true);
+ }
+
+ // Enable synth controllers:
+ if(type() == AUDIO_SOFTSYNTH)
+ {
+ const SynthI* synth = static_cast<const SynthI*>(this);
+ SynthIF* sif = synth->sif();
+ if(sif)
+ sif->enableAllControllers(true);
+ }
+}
+
void AudioTrack::recordAutomation(int n, double v)
{
if(!MusEGlobal::automation)
@@ -1739,6 +2025,13 @@ AudioAux::AudioAux()
fprintf(stderr, "ERROR: AudioAux ctor: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ buffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(buffer[i], 0, sizeof(float) * MusEGlobal::segmentSize);
}
else
buffer[i] = 0;
@@ -1759,6 +2052,13 @@ AudioAux::AudioAux(const AudioAux& t, int flags)
fprintf(stderr, "ERROR: AudioAux ctor: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ buffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(buffer[i], 0, sizeof(float) * MusEGlobal::segmentSize);
}
else
buffer[i] = 0;
@@ -1858,6 +2158,13 @@ void AudioAux::setChannels(int n)
fprintf(stderr, "ERROR: AudioAux::setChannels: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ buffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(buffer[i], 0, sizeof(float) * MusEGlobal::segmentSize);
}
}
else if(n < channels())
diff --git a/muse2/muse/ctrl.cpp b/muse2/muse/ctrl.cpp
index 5ffaf99f..f32d1978 100644
--- a/muse2/muse/ctrl.cpp
+++ b/muse2/muse/ctrl.cpp
@@ -6,7 +6,7 @@
// controller handling for mixer automation
//
// (C) Copyright 2003 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011-2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -359,6 +359,13 @@ CtrlList::CtrlList(int id, QString name, double min, double max, CtrlValueType v
initColor(id);
}
+CtrlList::CtrlList(const CtrlList& l, int flags)
+{
+ _id = l._id;
+ _valueType = l._valueType;
+ assign(l, flags | ASSIGN_PROPERTIES);
+}
+
//---------------------------------------------------------
// assign
//---------------------------------------------------------
@@ -367,14 +374,12 @@ void CtrlList::assign(const CtrlList& l, int flags)
{
if(flags & ASSIGN_PROPERTIES)
{
- _id = l._id;
_default = l._default;
_curVal = l._curVal;
_mode = l._mode;
_name = l._name;
_min = l._min;
_max = l._max;
- _valueType = l._valueType;
_dontShow = l._dontShow;
_displayColor = l._displayColor;
_visible = l._visible;
@@ -388,6 +393,129 @@ void CtrlList::assign(const CtrlList& l, int flags)
}
//---------------------------------------------------------
+// getInterpolation
+// Fills CtrlInterpolate struct for given frame.
+// cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
+// CtrlInterpolate member eFrame can be -1 meaning no next value (wide-open, endless).
+//---------------------------------------------------------
+
+void CtrlList::getInterpolation(int frame, bool cur_val_only, CtrlInterpolate* interp)
+{
+ interp->eStop = false; // During processing, control FIFO ring buffers will set this true.
+
+ if(cur_val_only || empty())
+ {
+ interp->sFrame = 0;
+ interp->eFrame = -1;
+ interp->sVal = _curVal;
+ interp->eVal = _curVal;
+ interp->doInterp = false;
+ return;
+ }
+ ciCtrl i = upper_bound(frame); // get the index after current frame
+ if (i == end()) // if we are past all items just return the last value
+ {
+ --i;
+ interp->sFrame = 0;
+ interp->eFrame = -1;
+ interp->sVal = i->second.val;
+ interp->eVal = i->second.val;
+ interp->doInterp = false;
+ return;
+ }
+ else if(_mode == DISCRETE)
+ {
+ if(i == begin())
+ {
+ interp->sFrame = 0;
+ interp->eFrame = i->second.frame;
+ interp->sVal = i->second.val;
+ interp->eVal = i->second.val;
+ interp->doInterp = false;
+ }
+ else
+ {
+ interp->eFrame = i->second.frame;
+ interp->eVal = i->second.val;
+ --i;
+ interp->sFrame = i->second.frame;
+ interp->sVal = i->second.val;
+ interp->doInterp = false;
+ }
+ }
+ else // INTERPOLATE
+ {
+ if(i == begin())
+ {
+ interp->sFrame = 0;
+ interp->eFrame = i->second.frame;
+ interp->sVal = i->second.val;
+ interp->eVal = i->second.val;
+ interp->doInterp = false;
+ }
+ else
+ {
+ interp->eFrame = i->second.frame;
+ interp->eVal = i->second.val;
+ --i;
+ interp->sFrame = i->second.frame;
+ interp->sVal = i->second.val;
+ interp->doInterp = (interp->eVal != interp->sVal && interp->eFrame > interp->sFrame);
+ }
+ }
+}
+
+//---------------------------------------------------------
+// interpolate
+// Returns interpolated value at given frame, from a CtrlInterpolate struct.
+// For speed, no checking is done for frame = frame2, val1 = val2 or even CtrlInterpolate::doInterp.
+// Those are to be taken care of before calling this routine. See getInterpolation().
+//---------------------------------------------------------
+
+double CtrlList::interpolate(int frame, const CtrlInterpolate& interp)
+{
+ int frame1 = interp.sFrame;
+ int frame2 = interp.eFrame;
+ double val1 = interp.sVal;
+ double val2 = interp.eVal;
+ if(frame >= frame2) // frame2 can also be -1
+ {
+ if(_valueType == VAL_LOG)
+ {
+ const double min = exp10(MusEGlobal::config.minSlider / 20.0); // TODO Try fastexp10
+ if(val2 < min)
+ val2 = min;
+ }
+ return val2;
+ }
+ if(frame <= frame1)
+ {
+ if(_valueType == VAL_LOG)
+ {
+ const double min = exp10(MusEGlobal::config.minSlider / 20.0); // TODO Try fastexp10
+ if(val1 < min)
+ val1 = min;
+ }
+ return val1;
+ }
+
+ if(_valueType == VAL_LOG)
+ {
+ val1 = 20.0*fast_log10(val1);
+ if (val1 < MusEGlobal::config.minSlider)
+ val1=MusEGlobal::config.minSlider;
+ val2 = 20.0*fast_log10(val2);
+ if (val2 < MusEGlobal::config.minSlider)
+ val2=MusEGlobal::config.minSlider;
+ }
+ val2 -= val1;
+ val1 += (double(frame - frame1) * val2) / double(frame2 - frame1);
+ if (_valueType == VAL_LOG)
+ val1 = exp10(val1/20.0);
+ return val1;
+}
+
+//---------------------------------------------------------
// value
// Returns value at frame.
// cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
diff --git a/muse2/muse/ctrl.h b/muse2/muse/ctrl.h
index cfc1ef62..9e84d133 100644
--- a/muse2/muse/ctrl.h
+++ b/muse2/muse/ctrl.h
@@ -6,7 +6,7 @@
// controller for mixer automation
//
// (C) Copyright 2003-2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011-2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -51,6 +51,32 @@ enum CtrlValueType { VAL_LOG, VAL_LINEAR, VAL_INT, VAL_BOOL };
enum CtrlRecValueType { ARVT_VAL, ARVT_START, ARVT_STOP };
//---------------------------------------------------------
+// CtrlInterpolate
+// Controller interpolation values.
+// For speed: Can be filled once by CtrlList::getInterpolation(),
+// then passed repeatedly to CtrlList::interpolate().
+//---------------------------------------------------------
+
+struct CtrlInterpolate {
+ int sFrame; // Starting frame. Always valid. Can be less than any first CtrlList item's frame, or zero !
+ double sVal; // Value at starting frame.
+ int eFrame; // Ending frame. Can be -1 meaning endless.
+ double eVal; // Value at ending frame, or sVal if eFrame is -1.
+ bool eStop; // Whether to stop refreshing this struct from CtrlList upon eFrame. Control FIFO ring buffers
+ // set this true and replace eFrame and eVal. Upon the next run slice, if eStop is set, eval
+ // should be copied to sVal, eFrame to sFrame, doInterp cleared, and eFrame set to some frame or -1.
+ bool doInterp; // Whether to actually interpolate whenever this struct is passed to CtrlList::interpolate().
+ CtrlInterpolate(int sframe = 0, int eframe = -1, double sval = 0.0, double eval = 0.0, bool end_stop = false, bool do_interpolate = false) {
+ sFrame = sframe;
+ sVal = sval;
+ eFrame = eframe;
+ eVal = eval;
+ eStop = end_stop;
+ doInterp = do_interpolate;
+ }
+ };
+
+//---------------------------------------------------------
// CtrlVal
// controller "event"
//---------------------------------------------------------
@@ -159,6 +185,7 @@ class CtrlList : public std::map<int, CtrlVal, std::less<int> > {
CtrlList(bool dontShow=false);
CtrlList(int id, bool dontShow=false);
CtrlList(int id, QString name, double min, double max, CtrlValueType v, bool dontShow=false);
+ CtrlList(const CtrlList& l, int flags);
void assign(const CtrlList& l, int flags);
void swap(CtrlList&);
@@ -190,7 +217,9 @@ class CtrlList : public std::map<int, CtrlVal, std::less<int> > {
}
CtrlValueType valueType() const { return _valueType; }
void setValueType(CtrlValueType t) { _valueType = t; }
-
+ void getInterpolation(int frame, bool cur_val_only, CtrlInterpolate* interp);
+ double interpolate(int frame, const CtrlInterpolate& interp);
+
double value(int frame, bool cur_val_only = false, int* nextFrame = NULL) const;
void add(int frame, double value);
void del(int frame);
diff --git a/muse2/muse/driver/audiodev.h b/muse2/muse/driver/audiodev.h
index 08d6a9f0..d060b138 100644
--- a/muse2/muse/driver/audiodev.h
+++ b/muse2/muse/driver/audiodev.h
@@ -75,6 +75,7 @@ class AudioDevice {
virtual void setPortName(void* p, const char* n) = 0;
virtual void* findPort(const char* name) = 0;
virtual QString portName(void* port) = 0;
+ virtual unsigned int portLatency(void* port, bool capture) const = 0;
virtual int getState() = 0;
virtual unsigned getCurFrame() const = 0;
virtual bool isRealtime() = 0;
diff --git a/muse2/muse/driver/dummyaudio.cpp b/muse2/muse/driver/dummyaudio.cpp
index 172638b4..4e37bc33 100644
--- a/muse2/muse/driver/dummyaudio.cpp
+++ b/muse2/muse/driver/dummyaudio.cpp
@@ -135,6 +135,7 @@ class DummyAudioDevice : public AudioDevice {
virtual QString portName(void*) {
return QString("mops");
}
+ virtual unsigned int portLatency(void* /*port*/, bool /*capture*/) const { return 0; }
virtual int getState() {
// if(DEBUG_DUMMY)
// printf("DummyAudioDevice::getState %d\n", state);
@@ -224,17 +225,22 @@ DummyAudioDevice* dummyAudio = 0;
DummyAudioDevice::DummyAudioDevice()
{
- // Added by Tim. p3.3.15
- // p3.3.30
- //posix_memalign((void**)&buffer, 16, sizeof(float) * dummyFrames);
-
- int rv = posix_memalign((void**)&buffer, 16, sizeof(float) * MusEGlobal::config.dummyAudioBufSize);
+ MusEGlobal::sampleRate = MusEGlobal::config.dummyAudioSampleRate;
+ MusEGlobal::segmentSize = MusEGlobal::config.dummyAudioBufSize;
+ int rv = posix_memalign((void**)&buffer, 16, sizeof(float) * MusEGlobal::segmentSize);
if(rv != 0)
{
fprintf(stderr, "ERROR: DummyAudioDevice ctor: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
-
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ buffer[q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(buffer, 0, sizeof(float) * MusEGlobal::segmentSize);
+
dummyThread = 0;
realtimeFlag = false;
seekflag = false;
@@ -310,9 +316,8 @@ static void* dummyLoop(void* ptr)
// p3.3.30
//MusEGlobal::sampleRate = 25600;
- MusEGlobal::sampleRate = MusEGlobal::config.dummyAudioSampleRate;
//MusEGlobal::segmentSize = dummyFrames;
- MusEGlobal::segmentSize = MusEGlobal::config.dummyAudioBufSize;
+// MusEGlobal::segmentSize = MusEGlobal::config.dummyAudioBufSize;
#if 0
//unsigned int tickRate = MusEGlobal::sampleRate / dummyFrames;
unsigned int tickRate = MusEGlobal::sampleRate / MusEGlobal::segmentSize;
diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp
index 3deaf160..b1321cbc 100644
--- a/muse2/muse/driver/jack.cpp
+++ b/muse2/muse/driver/jack.cpp
@@ -1557,6 +1557,51 @@ QString JackAudioDevice::portName(void* port)
}
//---------------------------------------------------------
+// portLatency
+// If capture is true get the capture latency,
+// otherwise get the playback latency.
+//---------------------------------------------------------
+
+unsigned int JackAudioDevice::portLatency(void* port, bool capture) const
+{
+ // TODO: Experimental code... Finish it...
+
+ if(!checkJackClient(_client) || !port)
+ return 0;
+
+ QString s(jack_port_name((jack_port_t*)port));
+ //fprintf(stderr, "Jack::portName %p %s\n", port, s.toLatin1().constData());
+
+ jack_latency_range_t p_range;
+ jack_port_get_latency_range((jack_port_t*)port, JackPlaybackLatency, &p_range);
+ //fprintf(stderr, "JackAudioDevice::portLatency playback min:%u max:%u\n", p_range.min, p_range.max);
+ if(p_range.max != p_range.min)
+ {
+ //fprintf(stderr, "JackAudioDevice::portLatency min:%u != max:%u\n", p_range.min, p_range.max);
+ //return (p_range.max - p_range.min) / 2;
+ }
+
+ jack_latency_range_t c_range;
+ jack_port_get_latency_range((jack_port_t*)port, JackCaptureLatency, &c_range);
+ //fprintf(stderr, "JackAudioDevice::portLatency capture min:%u max:%u\n", c_range.min, c_range.max);
+ if(c_range.max != c_range.min)
+ {
+ //fprintf(stderr, "JackAudioDevice::portLatency capture min:%u != max:%u\n", c_range.min, c_range.max);
+
+ // TODO TEST Decide which method to use. Although, it is arbitrary.
+ //return (c_range.max - c_range.min) / 2;
+ //return c_range.max;
+ }
+
+ if(capture)
+ //return (c_range.max - c_range.min) / 2;
+ return c_range.max;
+
+ //return (p_range.max - p_range.min) / 2;
+ return p_range.max;
+}
+
+//---------------------------------------------------------
// unregisterPort
//---------------------------------------------------------
diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h
index aab60d88..fd47de07 100644
--- a/muse2/muse/driver/jackaudio.h
+++ b/muse2/muse/driver/jackaudio.h
@@ -96,6 +96,7 @@ class JackAudioDevice : public AudioDevice {
virtual void setPortName(void* p, const char* n) { jack_port_set_name((jack_port_t*)p, n); }
virtual void* findPort(const char* name);
virtual QString portName(void* port);
+ virtual unsigned int portLatency(void* port, bool capture) const;
virtual int getState();
virtual unsigned int getCurFrame() const;
virtual bool isRealtime() { return jack_is_realtime(_client); }
diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp
index 6b55c7e7..00956279 100644
--- a/muse2/muse/dssihost.cpp
+++ b/muse2/muse/dssihost.cpp
@@ -4,7 +4,7 @@
// $Id: dssihost.cpp,v 1.15.2.16 2009/12/15 03:39:58 terminator356 Exp $
//
// Copyright (C) 1999-2011 by Werner Schweer and others
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License
@@ -327,7 +327,6 @@ SynthIF* DssiSynth::createSIF(SynthI* synti)
iIdx.clear();
oIdx.clear();
rpIdx.clear();
- iUsedIdx.clear();
midiCtl2PortMap.clear();
port2MidiCtlMap.clear();
@@ -349,7 +348,6 @@ SynthIF* DssiSynth::createSIF(SynthI* synti)
{
++_inports;
iIdx.push_back(k);
- iUsedIdx.push_back(false); // Start out with all false.
}
else if (LADSPA_IS_PORT_OUTPUT(pd))
{
@@ -455,12 +453,42 @@ void DssiSynthIF::showGui(bool v)
}
//---------------------------------------------------------
+// getGeometry
+//---------------------------------------------------------
+
+void DssiSynthIF::getGeometry(int*x, int*y, int*w, int*h) const
+{
+ if(!_gui)
+ {
+ *x=0;*y=0;*w=0;*h=0;
+ return;
+ }
+
+ *x = _gui->x();
+ *y = _gui->y();
+ *w = _gui->width();
+ *h = _gui->height();
+}
+
+//---------------------------------------------------------
+// setGeometry
+//---------------------------------------------------------
+
+void DssiSynthIF::setGeometry(int x, int y, int w, int h)
+{
+ if(!_gui)
+ return;
+
+ _gui->setGeometry(x, y, w, h);
+}
+
+//---------------------------------------------------------
// receiveEvent
//---------------------------------------------------------
-MusECore::MidiPlayEvent DssiSynthIF::receiveEvent()
+MidiPlayEvent DssiSynthIF::receiveEvent()
{
- return MusECore::MidiPlayEvent();
+ return MidiPlayEvent();
}
//---------------------------------------------------------
@@ -473,10 +501,10 @@ bool DssiSynthIF::init(DssiSynth* s)
printf("DssiSynthIF::init\n");
#endif
- synth = s;
- const DSSI_Descriptor* dssi = synth->dssi;
+ _synth = s;
+ const DSSI_Descriptor* dssi = _synth->dssi;
const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
- handle = ld->instantiate(ld, MusEGlobal::sampleRate);
+ _handle = ld->instantiate(ld, MusEGlobal::sampleRate);
#ifdef OSC_SUPPORT
_oscif.oscSetSynthIF(this);
@@ -484,67 +512,86 @@ bool DssiSynthIF::init(DssiSynth* s)
queryPrograms();
- int inports = synth->_inports;
+ int inports = _synth->_inports;
if(inports != 0)
{
- int rv = posix_memalign((void**)&audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
+ int rv = posix_memalign((void**)&_audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize);
if(rv != 0)
{
fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioInSilenceBuf[q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
- audioInBuffers = new float*[inports];
+ _audioInBuffers = new float*[inports];
for(int k = 0; k < inports; ++k)
{
- int rv = posix_memalign((void**)&audioInBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
+ int rv = posix_memalign((void**)&_audioInBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
if(rv != 0)
{
fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(audioInBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
- ld->connect_port(handle, synth->iIdx[k], audioInBuffers[k]);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioInBuffers[k][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioInBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
+ _iUsedIdx.push_back(false); // Start out with all false.
+ ld->connect_port(_handle, _synth->iIdx[k], _audioInBuffers[k]);
}
}
- int outports = synth->_outports;
+ int outports = _synth->_outports;
if(outports != 0)
{
- audioOutBuffers = new float*[outports];
+ _audioOutBuffers = new float*[outports];
for(int k = 0; k < outports; ++k)
{
- int rv = posix_memalign((void**)&audioOutBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
+ int rv = posix_memalign((void**)&_audioOutBuffers[k], 16, sizeof(float) * MusEGlobal::segmentSize);
if(rv != 0)
{
fprintf(stderr, "ERROR: DssiSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(audioOutBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
- ld->connect_port(handle, synth->oIdx[k], audioOutBuffers[k]);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioOutBuffers[k][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioOutBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
+ ld->connect_port(_handle, _synth->oIdx[k], _audioOutBuffers[k]);
}
}
- int controlPorts = synth->_controlInPorts;
- int controlOutPorts = synth->_controlOutPorts;
+ int controlPorts = _synth->_controlInPorts;
+ int controlOutPorts = _synth->_controlOutPorts;
if(controlPorts != 0)
- controls = new Port[controlPorts];
+ _controls = new Port[controlPorts];
else
- controls = 0;
+ _controls = 0;
if(controlOutPorts != 0)
- controlsOut = new Port[controlOutPorts];
+ _controlsOut = new Port[controlOutPorts];
else
- controlsOut = 0;
+ _controlsOut = 0;
- synth->midiCtl2PortMap.clear();
- synth->port2MidiCtlMap.clear();
+ _synth->midiCtl2PortMap.clear();
+ _synth->port2MidiCtlMap.clear();
int cip = 0;
int cop = 0;
- for (unsigned long k = 0; k < synth->_portCount; ++k)
+ for (unsigned long k = 0; k < _synth->_portCount; ++k)
{
LADSPA_PortDescriptor pd = ld->PortDescriptors[k];
@@ -556,13 +603,12 @@ bool DssiSynthIF::init(DssiSynth* s)
{
if (LADSPA_IS_PORT_INPUT(pd))
{
- controls[cip].idx = k;
+ _controls[cip].idx = k;
float val;
ladspaDefaultValue(ld, k, &val);
- controls[cip].val = val;
- controls[cip].tmpVal = val;
- controls[cip].enCtrl = true;
- controls[cip].en2Ctrl = true;
+ _controls[cip].val = val;
+ _controls[cip].tmpVal = val;
+ _controls[cip].enCtrl = true;
#ifdef DSSI_DEBUG
printf("DssiSynthIF::init control port:%d port idx:%lu name:%s\n", cip, k, ld->PortNames[k]);
@@ -573,7 +619,7 @@ bool DssiSynthIF::init(DssiSynth* s)
int ctlnum = DSSI_NONE;
if(dssi->get_midi_controller_for_port)
- ctlnum = dssi->get_midi_controller_for_port(handle, k);
+ ctlnum = dssi->get_midi_controller_for_port(_handle, k);
// No controller number? Try to give it a unique one...
if(ctlnum == DSSI_NONE)
@@ -585,7 +631,7 @@ bool DssiSynthIF::init(DssiSynth* s)
// If CC Controller7 is chosen we must make sure to use only non-common numbers. An already limited range
// of 127 now becomes narrower. See the cool document midi-controllers.txt in the DSSI source for a
// nice roundup of numbers and how to choose them and how they relate to synths and DSSI synths etc. !
- ctlnum = MusECore::CTRL_NRPN14_OFFSET + 0x2000 + cip;
+ ctlnum = CTRL_NRPN14_OFFSET + 0x2000 + cip;
}
else
{
@@ -610,7 +656,7 @@ bool DssiSynthIF::init(DssiSynth* s)
printf("DssiSynthIF::init is NRPN control\n");
#endif
- ctlnum = DSSI_NRPN_NUMBER(c) + MusECore::CTRL_NRPN14_OFFSET;
+ ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
}
}
@@ -620,8 +666,8 @@ bool DssiSynthIF::init(DssiSynth* s)
#endif
// We have a controller number! Insert it and the DSSI port number into both maps.
- synth->midiCtl2PortMap.insert(std::pair<int, int>(ctlnum, cip));
- synth->port2MidiCtlMap.insert(std::pair<int, int>(cip, ctlnum));
+ _synth->midiCtl2PortMap.insert(std::pair<int, int>(ctlnum, cip));
+ _synth->port2MidiCtlMap.insert(std::pair<int, int>(cip, ctlnum));
// Support a special block for dssi synth ladspa controllers.
// Put the ID at a special block after plugins (far after).
@@ -630,42 +676,41 @@ bool DssiSynthIF::init(DssiSynth* s)
float min, max;
ladspaControlRange(ld, k, &min, &max);
CtrlList* cl;
- CtrlListList* cll = ((MusECore::AudioTrack*)synti)->controller();
+ CtrlListList* cll = track()->controller();
iCtrlList icl = cll->find(id);
if (icl == cll->end())
{
cl = new CtrlList(id);
cll->add(cl);
- cl->setCurVal(controls[cip].val);
+ cl->setCurVal(_controls[cip].val);
}
else
{
cl = icl->second;
- controls[cip].val = cl->curVal();
+ _controls[cip].val = cl->curVal();
}
cl->setRange(min, max);
cl->setName(QString(name));
cl->setValueType(ladspaCtrlValueType(ld, k));
cl->setMode(ladspaCtrlMode(ld, k));
- ld->connect_port(handle, k, &controls[cip].val);
+ ld->connect_port(_handle, k, &_controls[cip].val);
++cip;
}
else if (LADSPA_IS_PORT_OUTPUT(pd))
{
- controlsOut[cop].idx = k;
- controlsOut[cop].val = 0.0;
- controlsOut[cop].tmpVal = 0.0;
- controlsOut[cop].enCtrl = false;
- controlsOut[cop].en2Ctrl = false;
+ _controlsOut[cop].idx = k;
+ _controlsOut[cop].val = 0.0;
+ _controlsOut[cop].tmpVal = 0.0;
+ _controlsOut[cop].enCtrl = false;
#ifdef DSSI_DEBUG
printf("DssiSynthIF::init control output port:%d port idx:%lu name:%s\n", cop, k, ld->PortNames[k]);
#endif
// Control outs are not handled but still must be connected to something.
- ld->connect_port(handle, k, &controlsOut[cop].val);
+ ld->connect_port(_handle, k, &_controlsOut[cop].val);
++cop;
}
@@ -677,7 +722,7 @@ bool DssiSynthIF::init(DssiSynth* s)
// Set current configuration values.
if(dssi->configure)
{
- char *rv = dssi->configure(handle, DSSI_PROJECT_DIRECTORY_KEY,
+ char *rv = dssi->configure(_handle, DSSI_PROJECT_DIRECTORY_KEY,
MusEGlobal::museProject.toLatin1().constData()); //MusEGlobal::song->projectPath()
if(rv)
@@ -689,7 +734,7 @@ bool DssiSynthIF::init(DssiSynth* s)
for(ciStringParamMap r = synti->_stringParamMap.begin(); r != synti->_stringParamMap.end(); ++r)
{
rv = 0;
- rv = dssi->configure(handle, r->first.c_str(), r->second.c_str());
+ rv = dssi->configure(_handle, r->first.c_str(), r->second.c_str());
if(rv)
{
fprintf(stderr, "MusE: Warning: plugin config key: %s value: %s \"%s\"\n", r->first.c_str(), r->second.c_str(), rv);
@@ -700,7 +745,7 @@ bool DssiSynthIF::init(DssiSynth* s)
// Set current program.
if(dssi->select_program)
- doSelectProgram(handle, synti->_curBankL, synti->_curProgram);
+ doSelectProgram(_handle, synti->_curBankL, synti->_curProgram);
//
// For stored initial control values, let SynthI::initInstance() take care of that via ::setParameter().
@@ -719,13 +764,13 @@ DssiSynthIF::DssiSynthIF(SynthI* s)
#ifdef DSSI_DEBUG
printf("DssiSynthIF::DssiSynthIF\n");
#endif
- synth = 0;
- handle = NULL;
- controls = 0;
- controlsOut = 0;
- audioInBuffers = 0;
- audioInSilenceBuf = 0;
- audioOutBuffers = 0;
+ _synth = 0;
+ _handle = NULL;
+ _controls = 0;
+ _controlsOut = 0;
+ _audioInBuffers = 0;
+ _audioInSilenceBuf = 0;
+ _audioOutBuffers = 0;
}
//---------------------------------------------------------
@@ -742,19 +787,19 @@ DssiSynthIF::~DssiSynthIF()
_oscif.oscSetSynthIF(NULL);
#endif
- if(synth)
+ if(_synth)
{
#ifdef DSSI_DEBUG
printf("DssiSynthIF::~DssiSynthIF synth:%p\n", synth);
#endif
- if(synth->dssi)
+ if(_synth->dssi)
{
#ifdef DSSI_DEBUG
printf("DssiSynthIF::~DssiSynthIF synth->dssi:%p\n", synth->dssi);
#endif
- if(synth->dssi->LADSPA_Plugin)
+ if(_synth->dssi->LADSPA_Plugin)
{
#ifdef DSSI_DEBUG
printf("DssiSynthIF::~DssiSynthIFsynth->dssi->LADSPA_Plugin:%p\n", synth->dssi->LADSPA_Plugin);
@@ -763,9 +808,9 @@ DssiSynthIF::~DssiSynthIF()
}
}
- if(synth && synth->dssi && synth->dssi->LADSPA_Plugin)
+ if(_synth && _synth->dssi && _synth->dssi->LADSPA_Plugin)
{
- const DSSI_Descriptor* dssi = synth->dssi;
+ const DSSI_Descriptor* dssi = _synth->dssi;
const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
#ifdef DSSI_DEBUG
@@ -778,37 +823,37 @@ DssiSynthIF::~DssiSynthIF()
printf("DssiSynthIF::~DssiSynthIF calling cleanup function\n");
#endif
- descr->cleanup(handle);
+ descr->cleanup(_handle);
}
}
- if(audioInBuffers)
+ if(_audioInBuffers)
{
- for(unsigned long i = 0; i < synth->_inports; ++i)
+ for(unsigned long i = 0; i < _synth->_inports; ++i)
{
- if(audioInBuffers[i])
- free(audioInBuffers[i]);
+ if(_audioInBuffers[i])
+ free(_audioInBuffers[i]);
}
- delete[] audioInBuffers;
+ delete[] _audioInBuffers;
}
- if(audioInSilenceBuf)
- free(audioInSilenceBuf);
+ if(_audioInSilenceBuf)
+ free(_audioInSilenceBuf);
- if(audioOutBuffers)
+ if(_audioOutBuffers)
{
- for(unsigned long i = 0; i < synth->_outports; ++i)
+ for(unsigned long i = 0; i < _synth->_outports; ++i)
{
- if(audioOutBuffers[i])
- free(audioOutBuffers[i]);
+ if(_audioOutBuffers[i])
+ free(_audioOutBuffers[i]);
}
- delete[] audioOutBuffers;
+ delete[] _audioOutBuffers;
}
- if(controls)
- delete[] controls;
+ if(_controls)
+ delete[] _controls;
- if(controlsOut)
- delete[] controlsOut;
+ if(_controlsOut)
+ delete[] _controlsOut;
}
int DssiSynthIF::oldMidiStateHeader(const unsigned char** data) const
@@ -824,16 +869,16 @@ int DssiSynthIF::oldMidiStateHeader(const unsigned char** data) const
float DssiSynthIF::getParameter(unsigned long n) const
{
- if(n >= synth->_controlInPorts)
+ if(n >= _synth->_controlInPorts)
{
- printf("DssiSynthIF::getParameter param number %lu out of range of ports:%lu\n", n, synth->_controlInPorts);
+ printf("DssiSynthIF::getParameter param number %lu out of range of ports:%lu\n", n, _synth->_controlInPorts);
return 0.0;
}
- if(!controls)
+ if(!_controls)
return 0.0;
- return controls[n].val;
+ return _controls[n].val;
}
//---------------------------------------------------------
// getParameter
@@ -841,16 +886,16 @@ float DssiSynthIF::getParameter(unsigned long n) const
float DssiSynthIF::getParameterOut(unsigned long n) const
{
- if(n >= synth->_controlOutPorts)
+ if(n >= _synth->_controlOutPorts)
{
- printf("DssiSynthIF::getParameterOut param number %lu out of range of ports:%lu\n", n, synth->_controlOutPorts);
+ printf("DssiSynthIF::getParameterOut param number %lu out of range of ports:%lu\n", n, _synth->_controlOutPorts);
return 0.0;
}
- if(!controlsOut)
+ if(!_controlsOut)
return 0.0;
- return controlsOut[n].val;
+ return _controlsOut[n].val;
}
//---------------------------------------------------------
@@ -1006,9 +1051,9 @@ void DssiSynthIF::write(int level, Xml& xml) const
*/
// Store controls as parameters...
- for(unsigned long c = 0; c < synth->_controlInPorts; ++c)
+ for(unsigned long c = 0; c < _synth->_controlInPorts; ++c)
{
- float f = controls[c].val;
+ float f = _controls[c].val;
xml.floatTag(level, "param", f);
}
}
@@ -1027,9 +1072,9 @@ void DssiSynthIF::preProcessAlways()
// Return true if event pointer filled.
//--------------------------------------------------------
-bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t* event)
+bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
{
- const DSSI_Descriptor* dssi = synth->dssi;
+ const DSSI_Descriptor* dssi = _synth->dssi;
int chn = e.channel();
int a = e.dataA();
@@ -1050,9 +1095,9 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
switch(e.type())
{
- case MusECore::ME_NOTEON:
+ case ME_NOTEON:
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_NOTEON\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_NOTEON\n");
#endif
snd_seq_ev_clear(event);
@@ -1062,19 +1107,19 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
else
snd_seq_ev_set_noteoff(event, chn, a, 0);
break;
- case MusECore::ME_NOTEOFF:
+ case ME_NOTEOFF:
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_NOTEOFF\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_NOTEOFF\n");
#endif
snd_seq_ev_clear(event);
event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_noteoff(event, chn, a, 0);
break;
- case MusECore::ME_PROGRAM:
+ case ME_PROGRAM:
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_PROGRAM\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_PROGRAM\n");
#endif
int bank = (a >> 8) & 0xff;
@@ -1084,25 +1129,25 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
synti->_curProgram = prog;
if(dssi->select_program)
- doSelectProgram(handle, bank, prog);
+ doSelectProgram(_handle, bank, prog);
// Event pointer not filled. Return false.
return false;
}
break;
- case MusECore::ME_CONTROLLER:
+ case ME_CONTROLLER:
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_CONTROLLER\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER\n");
#endif
if((a == 0) || (a == 32))
return false;
- if(a == MusECore::CTRL_PROGRAM)
+ if(a == CTRL_PROGRAM)
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_PROGRAM\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PROGRAM\n");
#endif
int bank = (b >> 8) & 0xff;
@@ -1113,16 +1158,16 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
synti->_curProgram = prog;
if(dssi->select_program)
- doSelectProgram(handle, bank, prog);
+ doSelectProgram(_handle, bank, prog);
// Event pointer not filled. Return false.
return false;
}
- if(a == MusECore::CTRL_PITCH)
+ if(a == CTRL_PITCH)
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_PITCH\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PITCH\n");
#endif
snd_seq_ev_clear(event);
@@ -1132,10 +1177,10 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
return true;
}
- if(a == MusECore::CTRL_AFTERTOUCH)
+ if(a == CTRL_AFTERTOUCH)
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_AFTERTOUCH\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_AFTERTOUCH\n");
#endif
snd_seq_ev_clear(event);
@@ -1145,10 +1190,10 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
return true;
}
- if((a | 0xff) == MusECore::CTRL_POLYAFTER)
+ if((a | 0xff) == CTRL_POLYAFTER)
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_POLYAFTER\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_POLYAFTER\n");
#endif
snd_seq_ev_clear(event);
@@ -1160,14 +1205,14 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
- MusECore::ciMidiCtl2LadspaPort ip = synth->midiCtl2PortMap.find(a);
+ ciMidiCtl2LadspaPort ip = _synth->midiCtl2PortMap.find(a);
// Is it just a regular midi controller, not mapped to a LADSPA port (either by the plugin or by us)?
// NOTE: There's no way to tell which of these controllers is supported by the plugin.
// For example sustain footpedal or pitch bend may be supported, but not mapped to any LADSPA port.
- if(ip == synth->midiCtl2PortMap.end())
+ if(ip == _synth->midiCtl2PortMap.end())
{
int ctlnum = a;
- if(MusECore::midiControllerType(a) != MusECore::MidiController::Controller7)
+ if(midiControllerType(a) != MidiController::Controller7)
return false; // Event pointer not filled. Return false.
else
{
@@ -1189,20 +1234,20 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
}
unsigned long k = ip->second;
- unsigned long i = controls[k].idx;
+ unsigned long i = _controls[k].idx;
int ctlnum = DSSI_NONE;
if(dssi->get_midi_controller_for_port)
- ctlnum = dssi->get_midi_controller_for_port(handle, i);
+ ctlnum = dssi->get_midi_controller_for_port(_handle, i);
// No midi controller for the ladspa port? Send to ladspa control.
if(ctlnum == DSSI_NONE)
{
// Sanity check.
- if(k > synth->_controlInPorts)
+ if(k > _synth->_controlInPorts)
return false;
// Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
- ctlnum = k + (MusECore::CTRL_NRPN14_OFFSET + 0x2000);
+ ctlnum = k + (CTRL_NRPN14_OFFSET + 0x2000);
}
else
{
@@ -1228,7 +1273,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
else
if(DSSI_IS_NRPN(ctlnum))
{
- ctlnum = DSSI_NRPN_NUMBER(c) + MusECore::CTRL_NRPN14_OFFSET;
+ ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
#ifdef DSSI_DEBUG
printf("DssiSynthIF::processEvent is NRPN ctlnum:%x(h) %d(d)\n", ctlnum, ctlnum);
@@ -1244,7 +1289,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
#endif
// Set the ladspa port value.
- controls[k].val = val;
+ _controls[k].val = val;
// Need to update the automation value, otherwise it overwrites later with the last automation value.
if(id() != -1)
@@ -1255,25 +1300,25 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
return false;
}
break;
- case MusECore::ME_PITCHBEND:
+ case ME_PITCHBEND:
snd_seq_ev_clear(event);
event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_pitchbend(event, chn, a);
break;
- case MusECore::ME_AFTERTOUCH:
+ case ME_AFTERTOUCH:
snd_seq_ev_clear(event);
event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_chanpress(event, chn, a);
break;
- case MusECore::ME_POLYAFTER:
+ case ME_POLYAFTER:
snd_seq_ev_clear(event);
event->queue = SND_SEQ_QUEUE_DIRECT;
snd_seq_ev_set_keypress(event, chn, a & 0x7f, b & 0x7f);
break;
- case MusECore::ME_SYSEX:
+ case ME_SYSEX:
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_SYSEX\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_SYSEX\n");
#endif
const unsigned char* data = e.data();
@@ -1311,7 +1356,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
if (QString((const char*)e.data()).startsWith("PARAMSAVE"))
{
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is MusECore::ME_SYSEX PARAMSAVE\n");
+ fprintf(stderr, "DssiSynthIF::processEvent midi event is ME_SYSEX PARAMSAVE\n");
#endif
unsigned long dlen = e.len() - 9; // Minus "PARAMSAVE"
@@ -1362,7 +1407,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
//else
{
// NOTE: There is a limit on the size of a sysex. Got this:
- // "DssiSynthIF::processEvent midi event is MusECore::ME_SYSEX"
+ // "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);
@@ -1385,411 +1430,478 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t
//---------------------------------------------------------
// getData
+// If ports is 0, just process controllers only, not audio (do not 'run').
//---------------------------------------------------------
-MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MPEventList* el, MusECore::iMPEvent start_event, unsigned pos, int ports, unsigned nframes, float** buffer)
+iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent start_event, unsigned pos, int ports, unsigned nframes, float** buffer)
{
- // 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];
-
- int frameOffset = MusEGlobal::audio->getFrameOffset();
- unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
-
- #ifdef DSSI_DEBUG_PROCESS
- fprintf(stderr, "DssiSynthIF::getData: pos:%u ports:%d nframes:%u syncFrame:%lu nevents:%lu\n", pos, ports, nframes, syncFrame, nevents);
+ // We may not be using ev_buf_sz all at once - this will be just the maximum.
+ const unsigned long ev_buf_sz = el->size() + synti->eventFifo.getSize();
+ snd_seq_event_t events[ev_buf_sz];
+
+ const int frameOffset = MusEGlobal::audio->getFrameOffset();
+ const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
+
+ #ifdef DSSI_DEBUG_PROCESS
+ fprintf(stderr, "DssiSynthIF::getData: pos:%u ports:%d nframes:%u syncFrame:%lu ev_buf_sz:%lu\n", pos, ports, nframes, syncFrame, ev_buf_sz);
#endif
-
+
// All ports must be connected to something!
- unsigned long nop, k;
-
- nop = ((unsigned long) ports) > synth->_outports ? synth->_outports : ((unsigned long) ports);
-
- const DSSI_Descriptor* dssi = synth->dssi;
+ const unsigned long nop = ((unsigned long) ports) > _synth->_outports ? _synth->_outports : ((unsigned long) ports);
+
+ const DSSI_Descriptor* dssi = _synth->dssi;
const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin;
unsigned long sample = 0;
-
- // To remember the last retrieved value of each AudioTrack controller.
- //float prev_ctrl_values[synth->_controlInPorts];
-
- // 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.
+
+ // 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.
+ // 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,
+ // 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 = synth->_isDssiVst; // Try this. (was: true)
- // TODO Make this number a global setting.
- // Note for dssi-vst this MUST equal MusEGlobal::audio period. It doesn't like broken-up runs (it stutters),
+ const bool usefixedrate = _synth->_isDssiVst;
+ // Note for dssi-vst this MUST equal MusEGlobal::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 long fixedsize = nframes; // was: 2048
-
// For now, the fixed size is clamped to the MusEGlobal::audio buffer size.
// TODO: We could later add slower processing over several cycles -
- // so that users can select a small MusEGlobal::audio period but a larger control period.
- if(fixedsize > nframes)
- fixedsize = nframes;
-
- unsigned long min_per = MusEGlobal::config.minControlProcessPeriod; // Must be power of 2 !
- if(min_per > nframes)
- min_per = nframes;
-
- #ifdef DSSI_DEBUG_PROCESS
+ // so that users can select a small MusEGlobal::audio period but a larger control period.
+ const unsigned long min_per = (usefixedrate || MusEGlobal::config.minControlProcessPeriod > nframes) ? nframes : MusEGlobal::config.minControlProcessPeriod;
+ const unsigned long min_per_mask = min_per-1; // min_per must be power of 2
+
+ AudioTrack* atrack = track();
+ const AutomationType at = atrack->automationType();
+ const bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
+ const unsigned long in_ctrls = _synth->inControls();
+ CtrlListList* cll = atrack->controller();
+ ciCtrlList icl_first;
+ const int plug_id = id();
+ if(plug_id != -1 && ports != 0) // Don't bother if not 'running'.
+ icl_first = cll->lower_bound(genACnum(plug_id, 0));
+
+ #ifdef DSSI_DEBUG_PROCESS
fprintf(stderr, "DssiSynthIF::getData: Handling inputs...\n");
#endif
-
+
// Handle inputs...
- if(!((MusECore::AudioTrack*)synti)->noInRoute())
+ if(ports != 0) // Don't bother if not 'running'.
{
- RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes();
- iRoute i = irl->begin();
- if(!i->track->isMidiTrack())
+ if(!atrack->noInRoute())
{
- int ch = i->channel == -1 ? 0 : i->channel;
- int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
- int chs = i->channels == -1 ? 0 : i->channels;
-
- if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports)
- {
- int h = remch + chs;
- for(int j = remch; j < h; ++j)
- synth->iUsedIdx[j] = true;
-
- ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]);
- }
- }
-
- ++i;
- for(; i != irl->end(); ++i)
- {
- if(i->track->isMidiTrack())
- continue;
+ RouteList* irl = atrack->inRoutes();
+ iRoute i = irl->begin();
+ if(!i->track->isMidiTrack())
+ {
+ const int ch = i->channel == -1 ? 0 : i->channel;
+ const int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ const int chs = i->channels == -1 ? 0 : i->channels;
- int ch = i->channel == -1 ? 0 : i->channel;
- int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
- int chs = i->channels == -1 ? 0 : i->channels;
-
- if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports)
- {
- bool u1 = synth->iUsedIdx[remch];
- if(chs >= 2)
+ if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
{
- bool u2 = synth->iUsedIdx[remch + 1];
- if(u1 && u2)
- ((MusECore::AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]);
- else
- if(!u1 && !u2)
- ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]);
- else
- {
- if(u1)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]);
- else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]);
+ const int h = remch + chs;
+ for(int j = remch; j < h; ++j)
+ _iUsedIdx[j] = true;
- if(u2)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]);
- else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]);
- }
+ ((AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
}
- else
+ }
+
+ ++i;
+ for(; i != irl->end(); ++i)
+ {
+ if(i->track->isMidiTrack())
+ continue;
+
+ const int ch = i->channel == -1 ? 0 : i->channel;
+ const int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ const int chs = i->channels == -1 ? 0 : i->channels;
+
+ if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
{
- if(u1)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]);
+ const bool u1 = _iUsedIdx[remch];
+ if(chs >= 2)
+ {
+ const bool u2 = _iUsedIdx[remch + 1];
+ if(u1 && u2)
+ ((AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]);
+ if(!u1 && !u2)
+ ((AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
+ else
+ {
+ if(u1)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+
+ if(u2)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ }
+ }
+ else
+ {
+ if(u1)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
+
+ const int h = remch + chs;
+ for(int j = remch; j < h; ++j)
+ _iUsedIdx[j] = true;
}
-
- int h = remch + chs;
- for(int j = remch; j < h; ++j)
- synth->iUsedIdx[j] = true;
}
}
- }
-
- #ifdef DSSI_DEBUG_PROCESS
+ }
+
+ #ifdef DSSI_DEBUG_PROCESS
fprintf(stderr, "DssiSynthIF::getData: Processing automation control values...\n");
#endif
-
+
+ int cur_slice = 0;
while(sample < nframes)
{
- unsigned long nsamp = usefixedrate ? fixedsize : nframes - sample;
+ unsigned long nsamp = nframes - sample;
+ const unsigned long slice_frame = pos + sample;
//
- // Process automation control values, while also determining the maximum acceptable
- // size of this run. Further processing, from FIFOs for example, can lower the size
- // from there, but this section determines where the next highest maximum frame
+ // Process automation control values, while also determining the maximum acceptable
+ // size of this run. Further processing, from FIFOs for example, can lower the size
+ // from there, but this section determines where the next highest maximum frame
// absolutely needs to be for smooth playback of the controller value stream...
//
- if(id() != -1)
+ if(ports != 0) // Don't bother if not 'running'.
{
- unsigned long frame = pos + sample;
- AutomationType at = AUTO_OFF;
- at = synti->automationType();
- bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
- AudioTrack* track = (static_cast<AudioTrack*>(synti));
- int nextFrame;
- for(unsigned long k = 0; k < synth->_controlInPorts; ++k)
- {
- controls[k].val = track->controller()->value(genACnum(id(), k), frame,
- no_auto || !controls[k].enCtrl || !controls[k].en2Ctrl,
- &nextFrame);
-#ifdef DSSI_DEBUG_PROCESS
- printf("DssiSynthIF::getData k:%lu sample:%lu frame:%lu nextFrame:%d nsamp:%lu \n", k, sample, frame, nextFrame, nsamp);
-#endif
- if(MusEGlobal::audio->isPlaying() && !usefixedrate && nextFrame != -1)
+ ciCtrlList icl = icl_first;
+ for(unsigned long k = 0; k < in_ctrls; ++k)
+ {
+ CtrlList* cl = (cll && plug_id != -1 && icl != cll->end()) ? icl->second : NULL;
+ CtrlInterpolate& ci = _controls[k].interp;
+ // Always refresh the interpolate struct at first, since things may have changed.
+ // Or if the frame is outside of the interpolate range - and eStop is not true. // FIXME TODO: Be sure these comparisons are correct.
+ if(cur_slice == 0 || (!ci.eStop && MusEGlobal::audio->isPlaying() &&
+ (slice_frame < (unsigned long)ci.sFrame || (ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame)) ) )
{
- // Returned value of nextFrame can be zero meaning caller replaces with some (constant) value.
- unsigned long samps = (unsigned long)nextFrame;
- if(samps > frame + min_per)
+ if(cl && plug_id != -1 && (unsigned long)cl->id() == genACnum(plug_id, k))
+ {
+ cl->getInterpolation(slice_frame, no_auto || !_controls[k].enCtrl, &ci);
+ if(icl != cll->end())
+ ++icl;
+ }
+ else
{
- unsigned long diff = samps - frame;
- unsigned long mask = min_per-1; // min_per must be power of 2
- samps = diff & ~mask;
- if((diff & mask) != 0)
+ // No matching controller, or end. Just copy the current value into the interpolator.
+ // Keep the current icl iterator, because since they are sorted by frames,
+ // if the IDs didn't match it means we can just let k catch up with icl.
+ ci.sFrame = 0;
+ ci.eFrame = -1;
+ ci.sVal = _controls[k].val;
+ ci.eVal = ci.sVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ }
+ else
+ {
+ if(ci.eStop && ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame) // FIXME TODO: Get that comparison right.
+ {
+ // Clear the stop condition and set up the interp struct appropriately as an endless value.
+ ci.sFrame = 0; //ci->eFrame;
+ ci.eFrame = -1;
+ ci.sVal = ci.eVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ if(cl && cll && icl != cll->end())
+ ++icl;
+ }
+
+ if(!usefixedrate && MusEGlobal::audio->isPlaying())
+ {
+ unsigned long samps = nsamp;
+ if(ci.eFrame != -1)
+ samps = (unsigned long)ci.eFrame - slice_frame;
+
+ if(!ci.doInterp && samps > min_per)
+ {
+ samps &= ~min_per_mask;
+ if((samps & min_per_mask) != 0)
samps += min_per;
}
else
samps = min_per;
-
+
if(samps < nsamp)
nsamp = samps;
+
}
- }
-#ifdef DSSI_DEBUG
- printf("DssiSynthIF::getData sample:%lu nsamp:%lu\n", sample, nsamp);
+
+ if(ci.doInterp && cl)
+ _controls[k].val = cl->interpolate(MusEGlobal::audio->isPlaying() ? slice_frame : pos, ci);
+ else
+ _controls[k].val = ci.sVal;
+
+#ifdef DSSI_DEBUG_PROCESS
+ fprintf(stderr, "DssiSynthIF::getData k:%lu sample:%lu frame:%lu ci.eFrame:%d nsamp:%lu \n", k, sample, frame, ci.eFrame, nsamp);
#endif
+
+ }
}
-
+
+#ifdef DSSI_DEBUG_PROCESS
+ fprintf(stderr, "DssiSynthIF::getData sample:%lu nsamp:%lu\n", sample, nsamp);
+#endif
+
bool found = false;
- unsigned long frame = 0;
+ unsigned long frame = 0;
unsigned long index = 0;
- unsigned long evframe;
+ unsigned long evframe;
// Get all control ring buffer items valid for this time period...
while(!_controlFifo.isEmpty())
{
- ControlEvent v = _controlFifo.peek();
- // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
+ ControlEvent v = _controlFifo.peek();
+ // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
// If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.
- evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes;
+ evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes;
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::getData found:%d evframe:%lu frame:%lu event frame:%lu idx:%lu val:%f unique:%d\n",
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData found:%d evframe:%lu frame:%lu event frame:%lu idx:%lu val:%f unique:%d\n",
found, evframe, frame, v.frame, v.idx, v.value, v.unique);
#endif
// Protection. Observed this condition. Why? Supposed to be linear timestamps.
if(found && evframe < frame)
{
- printf("DssiSynthIF::getData *** Error: evframe:%lu < frame:%lu event: frame:%lu idx:%lu val:%f unique:%d\n",
- evframe, frame, v.frame, v.idx, v.value, v.unique);
+ fprintf(stderr, "DssiSynthIF::getData *** Error: evframe:%lu < frame:%lu event: frame:%lu idx:%lu val:%f unique:%d\n",
+ evframe, frame, v.frame, v.idx, v.value, v.unique);
// No choice but to ignore it.
_controlFifo.remove(); // Done with the ring buffer's item. Remove it.
continue;
- }
-
- if(evframe >= nframes // Next events are for a later period.
- || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
- || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
- || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
+ }
+
+ if(evframe >= nframes // Next events are for a later period.
+ || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
+ || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
+ || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
break;
_controlFifo.remove(); // Done with the ring buffer's item. Remove it.
- if(v.idx >= synth->_controlInPorts) // Sanity check.
+ if(v.idx >= in_ctrls) // Sanity check.
break;
+
found = true;
frame = evframe;
index = v.idx;
- // Set the ladspa control port value.
- controls[v.idx].val = v.value;
-
+
+ if(ports == 0) // Don't bother if not 'running'.
+ _controls[v.idx].val = v.value; // Might as well at least update these.
+ else
+ {
+ CtrlInterpolate* ci = &_controls[v.idx].interp;
+ // Tell it to stop the current ramp at this frame, when it does stop, set this value:
+ ci->eFrame = frame;
+ ci->eVal = v.value;
+ ci->eStop = true;
+ }
+
// Need to update the automation value, otherwise it overwrites later with the last automation value.
- if(id() != -1)
- synti->setPluginCtrlVal(genACnum(id(), v.idx), v.value);
+ if(plug_id != -1)
+ synti->setPluginCtrlVal(genACnum(plug_id, v.idx), v.value);
}
-
+
if(found && !usefixedrate) // If a control FIFO item was found, takes priority over automation controller stream.
nsamp = frame - sample;
-
- if(sample + nsamp >= nframes) // Safety check.
- nsamp = nframes - sample;
-
+
+ if(sample + nsamp > nframes) // Safety check.
+ nsamp = nframes - sample;
+
// TODO: 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(; start_event != el->end(); ++start_event)
+ if(nsamp != 0)
{
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::getData eventlist event time:%d pos:%u sample:%lu nsamp:%lu frameOffset:%d\n", start_event->time(), pos, sample, nsamp, frameOffset);
- #endif
-
- if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
+ unsigned long nevents = 0;
+ if(ports != 0) // Don't bother if not 'running'.
{
- #ifdef DSSI_DEBUG
- fprintf(stderr, " event is for future:%lu, breaking loop now\n", start_event->time() - frameOffset - pos - sample);
- #endif
- break;
- }
-
- // 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)
- {
- MusECore::MidiPort* mp = &MusEGlobal::midiPorts[synti->midiPort()];
- if(start_event->type() == MusECore::ME_CONTROLLER)
- {
- int da = start_event->dataA();
- int db = start_event->dataB();
- db = mp->limitValToInstrCtlRange(da, db);
- if(!mp->setHwCtrlState(start_event->channel(), da, db))
- continue;
- }
- else if(start_event->type() == MusECore::ME_PITCHBEND)
- {
- int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, start_event->dataA());
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PITCH, da))
- continue;
- }
- else if(start_event->type() == MusECore::ME_AFTERTOUCH)
- {
- int da = mp->limitValToInstrCtlRange(MusECore::CTRL_AFTERTOUCH, start_event->dataA());
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_AFTERTOUCH, da))
- continue;
- }
- else if(start_event->type() == MusECore::ME_POLYAFTER)
- {
- int ctl = (MusECore::CTRL_POLYAFTER & ~0xff) | (start_event->dataA() & 0x7f);
- int db = mp->limitValToInstrCtlRange(ctl, start_event->dataB());
- if(!mp->setHwCtrlState(start_event->channel(), ctl , db))
- continue;
- }
- else if(start_event->type() == MusECore::ME_PROGRAM)
+ // Process event list events...
+ for(; start_event != el->end(); ++start_event)
{
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PROGRAM, start_event->dataA()))
- continue;
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData eventlist event time:%d pos:%u sample:%lu nsamp:%lu frameOffset:%d\n", start_event->time(), pos, sample, nsamp, frameOffset);
+ #endif
+
+ if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
+ {
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, " event is for future:%lu, breaking loop now\n", start_event->time() - frameOffset - pos - sample);
+ #endif
+ break;
+ }
+
+ // 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 = &MusEGlobal::midiPorts[synti->midiPort()];
+ if(start_event->type() == ME_CONTROLLER)
+ {
+ int da = start_event->dataA();
+ int db = start_event->dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+ if(!mp->setHwCtrlState(start_event->channel(), da, db))
+ continue;
+ }
+ else if(start_event->type() == ME_PITCHBEND)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, start_event->dataA());
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PITCH, da))
+ continue;
+ }
+ else if(start_event->type() == ME_AFTERTOUCH)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_AFTERTOUCH, start_event->dataA());
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_AFTERTOUCH, da))
+ continue;
+ }
+ else if(start_event->type() == ME_POLYAFTER)
+ {
+ int ctl = (CTRL_POLYAFTER & ~0xff) | (start_event->dataA() & 0x7f);
+ int db = mp->limitValToInstrCtlRange(ctl, start_event->dataB());
+ if(!mp->setHwCtrlState(start_event->channel(), ctl , db))
+ continue;
+ }
+ else if(start_event->type() == ME_PROGRAM)
+ {
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PROGRAM, start_event->dataA()))
+ continue;
+ }
+ }
+
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(*start_event, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = start_event->time() - frameOffset - pos - sample;
+ if(ft < 0)
+ ft = 0;
+
+ if (ft >= int(nsamp))
+ {
+ fprintf(stderr, "DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);
+ ft = nsamp - 1;
+ }
+
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData eventlist: ft:%d current nevents:%lu\n", ft, nevents);
+ #endif
+
+ // "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;
+ }
}
}
-
- // Returns false if the event was not filled. It was handled, but some other way.
- if(processEvent(*start_event, &events[nevents]))
+
+ // Now process putEvent events...
+ while(!synti->eventFifo.isEmpty())
{
- // Time-stamp the event.
- int ft = start_event->time() - frameOffset - pos - sample;
- if(ft < 0)
- ft = 0;
+ MidiPlayEvent e = synti->eventFifo.peek();
+
+ #ifdef DSSI_DEBUG
+ fprintf(stderr, "DssiSynthIF::getData eventFifo event time:%d\n", e.time());
+ #endif
- if (ft >= int(nsamp))
+ if(e.time() >= (pos + sample + nsamp + frameOffset))
+ break;
+
+ synti->eventFifo.remove(); // Done with ring buffer's event. Remove it.
+ if(ports != 0) // Don't bother if not 'running'.
{
- printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);
- ft = nsamp - 1;
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(e, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = e.time() - frameOffset - pos - sample;
+ if(ft < 0)
+ ft = 0;
+ if (ft >= int(nsamp))
+ {
+ fprintf(stderr, "DssiSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", e.time(), pos, frameOffset, ft, sample, nsamp);
+ ft = 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;
+ }
}
-
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::getData eventlist: ft:%d current nevents:%lu\n", ft, nevents);
- #endif
-
- // "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())
- {
- MusECore::MidiPlayEvent e = synti->eventFifo.peek();
-
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::getData eventFifo event time:%d\n", e.time());
+
+ #ifdef DSSI_DEBUG_PROCESS
+ fprintf(stderr, "DssiSynthIF::getData: Connecting and running. sample:%lu nsamp:%lu nevents:%lu\n", sample, nsamp, nevents);
#endif
-
- 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]))
+
+ if(ports != 0) // Don't bother if not 'running'.
{
- // Time-stamp the event.
- int ft = e.time() - frameOffset - pos - sample;
- if(ft < 0)
- ft = 0;
- if (ft >= int(nsamp))
+ unsigned long 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);
+ // Connect all inputs either to some local buffers, or a silence buffer.
+ for(k = 0; k < _synth->_inports; ++k)
+ {
+ if(_iUsedIdx[k])
+ {
+ _iUsedIdx[k] = false; // Reset
+ descr->connect_port(_handle, _synth->iIdx[k], _audioInBuffers[k] + sample);
+ }
+ else
+ {
+ descr->connect_port(_handle, _synth->iIdx[k], _audioInSilenceBuf + sample);
+ }
+ }
+
+ // Run the synth for a period of time. This processes events and gets/fills our local buffers...
+ if(_synth->dssi->run_synth)
{
- printf("DssiSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", e.time(), pos, frameOffset, ft, sample, nsamp);
- ft = nsamp - 1;
+ _synth->dssi->run_synth(_handle, nsamp, events, nevents);
}
- // "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;
- }
- }
-
- #ifdef DSSI_DEBUG_PROCESS
- fprintf(stderr, "DssiSynthIF::getData: Connecting and running. sample:%lu nsamp:%lu nevents:%lu\n", sample, nsamp, nevents);
- #endif
-
- 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);
- // Connect all inputs either to some local buffers, or a silence buffer.
- for(k = 0; k < synth->_inports; ++k)
- {
- if(synth->iUsedIdx[k])
- {
- synth->iUsedIdx[k] = false; // Reset
- descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample);
+ else if (_synth->dssi->run_multiple_synths)
+ {
+ snd_seq_event_t* ev = events;
+ _synth->dssi->run_multiple_synths(1, &_handle, nsamp, &ev, &nevents);
+ }
+ // TIP: Until we add programs to plugins, uncomment these four checks to load dssi effects as synths, in order to have programs.
+ //else
+ //if(synth->dssi->LADSPA_Plugin->run)
+ //{
+ // synth->dssi->LADSPA_Plugin->run(handle, nsamp);
+ //}
}
- else
- {
- descr->connect_port(handle, synth->iIdx[k], audioInSilenceBuf + 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;
}
- // TIP: Until we add programs to plugins, uncomment these four checks to load dssi effects as synths, in order to have programs.
- //else
- //if(synth->dssi->LADSPA_Plugin->run)
- //{
- // synth->dssi->LADSPA_Plugin->run(handle, nsamp);
- //}
-
- sample += nsamp;
+
+ ++cur_slice; // Slice is done. Moving on to any next slice now...
}
-
+
return start_event;
}
@@ -1797,7 +1909,7 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP
// putEvent
//---------------------------------------------------------
-bool DssiSynthIF::putEvent(const MusECore::MidiPlayEvent& ev)
+bool DssiSynthIF::putEvent(const MidiPlayEvent& ev)
{
#ifdef DSSI_DEBUG
fprintf(stderr, "DssiSynthIF::putEvent midi event time:%d chn:%d a:%d b:%d\n", ev.time(), ev.channel(), ev.dataA(), ev.dataB());
@@ -1830,7 +1942,6 @@ void DssiSynth::incInstances(int val)
iIdx.clear();
oIdx.clear();
rpIdx.clear();
- iUsedIdx.clear();
midiCtl2PortMap.clear();
port2MidiCtlMap.clear();
}
@@ -1858,10 +1969,10 @@ void DssiSynthIF::guiHeartBeat()
_oscif.oscSendProgram(synti->_curProgram, synti->_curBankL);
// Update the gui's controls if needed.
- unsigned long ports = synth->_controlInPorts;
+ unsigned long ports = _synth->_controlInPorts;
for(unsigned long i = 0; i < ports; ++i)
- _oscif.oscSendControl(controls[i].idx, controls[i].val);
+ _oscif.oscSendControl(_controls[i].idx, _controls[i].val);
#endif
}
@@ -1890,10 +2001,10 @@ int DssiSynthIF::oscUpdate()
_oscif.oscSendProgram(synti->_curProgram, synti->_curBankL, true /*force*/);
// Send current control values.
- unsigned long ports = synth->_controlInPorts;
+ unsigned long ports = _synth->_controlInPorts;
for(unsigned long i = 0; i < ports; ++i)
{
- _oscif.oscSendControl(controls[i].idx, controls[i].val, true /*force*/);
+ _oscif.oscSendControl(_controls[i].idx, _controls[i].val, true /*force*/);
// Avoid overloading the GUI if there are lots and lots of ports.
if((i+1) % 50 == 0)
usleep(300000);
@@ -1920,7 +2031,7 @@ int DssiSynthIF::oscProgram(unsigned long program, unsigned long bank)
if(port != -1)
{
- MusECore::MidiPlayEvent event(0, port, ch, MusECore::ME_PROGRAM, (bank << 8) + program, 0);
+ MidiPlayEvent event(0, port, ch, ME_PROGRAM, (bank << 8) + program, 0);
#ifdef DSSI_DEBUG
fprintf(stderr, "DssiSynthIF::oscProgram midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB());
@@ -1950,14 +2061,14 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
printf("DssiSynthIF::oscControl received oscControl port:%lu val:%f\n", port, value);
#endif
- if(port >= synth->rpIdx.size())
+ if(port >= _synth->rpIdx.size())
{
- fprintf(stderr, "DssiSynthIF::oscControl: port number:%lu is out of range of index list size:%zd\n", port, synth->rpIdx.size());
+ fprintf(stderr, "DssiSynthIF::oscControl: port number:%lu is out of range of index list size:%zd\n", port, _synth->rpIdx.size());
return 0;
}
// Convert from DSSI port number to control input port index.
- unsigned long cport = synth->rpIdx[port];
+ unsigned long cport = _synth->rpIdx[port];
if((int)cport == -1)
{
@@ -1965,16 +2076,28 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
return 0;
}
+ // 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: 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(id() != -1)
+ {
+ unsigned long pid = genACnum(id(), cport);
+ synti->recordAutomation(pid, value);
+ }
+
// DELETETHIS????: is the below still correct? of so, then keep it of course!
// p3.3.39 Set the DSSI control input port's value.
// Observations: With a native DSSI synth like LessTrivialSynth, the native GUI's controls do not change the sound at all
- // ie. they don't update the DSSI control port values themselves.
+ // ie. they don't update the DSSI control port values themselves.
// Hence in response to the call to this oscControl, sent by the native GUI, it is required to that here.
/// controls[cport].val = value; DELETETHIS
// DSSI-VST synths however, unlike DSSI synths, DO change their OWN sound in response to their gui controls.
- // AND this function is called.
- // Despite the descrepency we are STILL required to update the DSSI control port values here
- // because dssi-vst is WAITING FOR A RESPONSE. (A CHANGE in the control port value).
+ // AND this function is called.
+ // Despite the descrepency we are STILL required to update the DSSI control port values here
+ // 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.
//
@@ -1987,62 +2110,21 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
// (Because the server simply ignores the 'expected' messages.)
//
// Well, at least here are the fifos. Try this ...
- // DELETETHIS 20 pretty old as well
- /*
- OscControlFifo* cfifo = _oscif.oscFifo(cport);
- if(cfifo)
- {
- OscControlValue cv;
- //cv.idx = cport;
- cv.value = value;
- // Time-stamp the event. Looks like no choice but to use the (possibly slow) call to gettimeofday via timestamp(),
- // because these are asynchronous events arriving from OSC. 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.) p4.0.15 Tim.
- cv.frame = MusEGlobal::audio->timestamp();
- if(cfifo->put(cv))
- {
- fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\n", cport);
- }
- }
- */
- // p4.0.21
+
+ // Schedules a timed control change:
ControlEvent ce;
- ce.unique = synth->_isDssiVst; // Special for messages from vst gui to host - requires processing every message.
- ce.fromGui = true; // It came form the plugin's own GUI.
+ ce.unique = _synth->_isDssiVst; // Special for messages from vst gui to host - requires processing every message.
+ ce.fromGui = true; // It came from the plugin's own GUI.
ce.idx = cport;
ce.value = value;
-
- ce.frame = MusEGlobal::audio->curFrame();
- // don't use timestamp(), because it's circular, which is making it impossible to deal
+ // Don't use timestamp(), because it's circular, which is making it impossible to deal
// with 'modulo' events which slip in 'under the wire' before processing the ring buffers.
-
-
+ ce.frame = MusEGlobal::audio->curFrame();
if(_controlFifo.put(ce))
- {
fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\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: 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(id() != -1)
- {
- unsigned long pid = genACnum(id(), cport);
- AutomationType at = synti->automationType();
+
+ enableController(cport, false); //TODO maybe re-enable the ctrl soon?
- // 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) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()))
- enableController(cport, false); //TODO maybe re-enable the ctrl soon?
-
- synti->recordAutomation(pid, value);
- }
-
return 0;
}
@@ -2052,8 +2134,8 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
int DssiSynthIF::oscMidi(int a, int b, int c)
{
- if (a == MusECore::ME_NOTEOFF) {
- a = MusECore::ME_NOTEON;
+ if (a == ME_NOTEOFF) {
+ a = ME_NOTEON;
c = 0;
}
int channel = 0; // TODO: ??
@@ -2061,7 +2143,7 @@ int DssiSynthIF::oscMidi(int a, int b, int c)
if(port != -1)
{
- MusECore::MidiPlayEvent event(0, port, channel, a, b, c);
+ MidiPlayEvent event(0, port, channel, a, b, c);
#ifdef DSSI_DEBUG
printf("DssiSynthIF::oscMidi midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB());
@@ -2104,10 +2186,10 @@ int DssiSynthIF::oscConfigure(const char *key, const char *value)
return 0;
}
- if (!synth->dssi->configure)
+ if (!_synth->dssi->configure)
return 0;
- char* message = synth->dssi->configure(handle, key, value);
+ char* message = _synth->dssi->configure(_handle, key, value);
if (message) {
printf("MusE: on configure '%s' '%s', plugin '%s' returned error '%s'\n",
key, value, synti->name().toLatin1().constData(), message);
@@ -2141,11 +2223,11 @@ void DssiSynthIF::queryPrograms()
}
programs.clear();
- if (!synth->dssi->get_program)
+ if (!_synth->dssi->get_program)
return;
for (int i = 0;; ++i) {
- const DSSI_Program_Descriptor* pd = synth->dssi->get_program(handle, i);
+ const DSSI_Program_Descriptor* pd = _synth->dssi->get_program(_handle, i);
if (pd == 0)
break;
DSSI_Program_Descriptor d;
@@ -2158,7 +2240,7 @@ void DssiSynthIF::queryPrograms()
void DssiSynthIF::doSelectProgram(LADSPA_Handle handle, int bank, int prog)
{
- const DSSI_Descriptor* dssi = synth->dssi;
+ const DSSI_Descriptor* dssi = _synth->dssi;
dssi->select_program(handle, bank, prog);
// Need to update the automation value, otherwise it overwrites later with the last automation value.
@@ -2167,10 +2249,10 @@ void DssiSynthIF::doSelectProgram(LADSPA_Handle handle, int bank, int prog)
// (This is the only circumstance in which a DSSI plugin is allowed to modify its own input ports.)" From dssi.h
if(id() != -1)
{
- for(unsigned long k = 0; k < synth->_controlInPorts; ++k)
+ for(unsigned long k = 0; k < _synth->_controlInPorts; ++k)
{
// We're in the audio thread context: no need to send a message, just modify directly.
- synti->setPluginCtrlVal(genACnum(id(), k), controls[k].val);
+ synti->setPluginCtrlVal(genACnum(id(), k), _controls[k].val);
}
}
}
@@ -2224,7 +2306,7 @@ void DssiSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int /*ch*/, bool
int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval)
{
- int controlPorts = synth->_controlInPorts;
+ int controlPorts = _synth->_controlInPorts;
if(id == controlPorts || id == controlPorts + 1)
{
//
@@ -2232,22 +2314,22 @@ int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi
// (channel and key pressure) midi messages, so add support for them now (as controllers).
//
if(id == controlPorts)
- *ctrl = MusECore::CTRL_POLYAFTER;
+ *ctrl = CTRL_POLYAFTER;
else if(id == controlPorts + 1)
- *ctrl = MusECore::CTRL_AFTERTOUCH;
+ *ctrl = CTRL_AFTERTOUCH;
*min = 0;
*max = 127;
- *initval = MusECore::CTRL_VAL_UNKNOWN;
+ *initval = CTRL_VAL_UNKNOWN;
*name = midiCtrlName(*ctrl).toLatin1().constData();
return ++id;
}
else if(id >= controlPorts + 2)
return 0;
- const DSSI_Descriptor* dssi = synth->dssi;
+ const DSSI_Descriptor* dssi = _synth->dssi;
const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
- unsigned long i = controls[id].idx;
+ unsigned long i = _controls[id].idx;
#ifdef DSSI_DEBUG
printf("DssiSynthIF::getControllerInfo control port:%d port idx:%lu name:%s\n", id, i, ld->PortNames[i]);
@@ -2255,14 +2337,14 @@ int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi
int ctlnum = DSSI_NONE;
if(dssi->get_midi_controller_for_port)
- ctlnum = dssi->get_midi_controller_for_port(handle, i);
+ ctlnum = dssi->get_midi_controller_for_port(_handle, i);
// No controller number? Give it one.
if(ctlnum == DSSI_NONE)
{
// Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
- ctlnum = MusECore::CTRL_NRPN14_OFFSET + 0x2000 + id;
+ ctlnum = CTRL_NRPN14_OFFSET + 0x2000 + id;
}
else
{
@@ -2292,15 +2374,15 @@ int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi
printf("DssiSynthIF::getControllerInfo is NRPN control\n");
#endif
- ctlnum = DSSI_NRPN_NUMBER(c) + MusECore::CTRL_NRPN14_OFFSET;
+ ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
}
}
- int def = MusECore::CTRL_VAL_UNKNOWN;
+ int def = CTRL_VAL_UNKNOWN;
if(ladspa2MidiControlValues(ld, i, ctlnum, min, max, &def))
*initval = def;
else
- *initval = MusECore::CTRL_VAL_UNKNOWN;
+ *initval = CTRL_VAL_UNKNOWN;
#ifdef DSSI_DEBUG
printf("DssiSynthIF::getControllerInfo passed ctlnum:%d min:%d max:%d initval:%d\n", ctlnum, *min, *max, *initval);
@@ -2313,17 +2395,17 @@ int DssiSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi
int DssiSynthIF::channels() const
{
- return ((int)synth->_outports) > MAX_CHANNELS ? MAX_CHANNELS : ((int)synth->_outports) ;
+ return ((int)_synth->_outports) > MAX_CHANNELS ? MAX_CHANNELS : ((int)_synth->_outports) ;
}
int DssiSynthIF::totalOutChannels() const
{
- return synth->_outports;
+ return _synth->_outports;
}
int DssiSynthIF::totalInChannels() const
{
- return synth->_inports;
+ return _synth->_inports;
}
void DssiSynthIF::deactivate3()
@@ -2336,42 +2418,28 @@ void DssiSynthIF::deactivate3()
// Methods for PluginIBase:
//--------------------------------
-//bool DssiSynthIF::on() const { return true; } // Synth is not part of a rack plugin chain. Always on.
-//void DssiSynthIF::setOn(bool /*val*/) { }
-unsigned long DssiSynthIF::pluginID() { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->UniqueID : 0; }
+unsigned long DssiSynthIF::pluginID() { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->UniqueID : 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(); }
-//QString DssiSynthIF::name() const { return synti->name(); }
-QString DssiSynthIF::lib() const { return synth ? synth->completeBaseName() : QString(); }
-QString DssiSynthIF::dirPath() const { return synth ? synth->absolutePath() : QString(); }
-QString DssiSynthIF::fileName() const { return synth ? synth->fileName() : QString(); }
-//QString DssiSynthIF::titlePrefix() const { return QString(); }
-//MusECore::AudioTrack* DssiSynthIF::track() { return (MusECore::AudioTrack*)synti; }
-void DssiSynthIF::enableController(unsigned long i, bool v) { controls[i].enCtrl = v; }
-bool DssiSynthIF::controllerEnabled(unsigned long i) const { return controls[i].enCtrl; }
-void DssiSynthIF::enable2Controller(unsigned long i, bool v) { controls[i].en2Ctrl = v; }
-bool DssiSynthIF::controllerEnabled2(unsigned long i) const { return controls[i].en2Ctrl; }
+QString DssiSynthIF::pluginLabel() const { return (_synth && _synth->dssi) ? QString(_synth->dssi->LADSPA_Plugin->Label) : QString(); }
+QString DssiSynthIF::lib() const { return _synth ? _synth->completeBaseName() : QString(); }
+QString DssiSynthIF::dirPath() const { return _synth ? _synth->absolutePath() : QString(); }
+QString DssiSynthIF::fileName() const { return _synth ? _synth->fileName() : QString(); }
+void DssiSynthIF::enableController(unsigned long i, bool v) { _controls[i].enCtrl = v; }
+bool DssiSynthIF::controllerEnabled(unsigned long i) const { return _controls[i].enCtrl; }
void DssiSynthIF::enableAllControllers(bool v)
{
- if(!synth)
+ if(!_synth)
return;
- for(unsigned long i = 0; i < synth->_controlInPorts; ++i)
- controls[i].enCtrl = v;
-}
-void DssiSynthIF::enable2AllControllers(bool v)
-{
- if(!synth)
- return;
- for(unsigned long i = 0; i < synth->_controlInPorts; ++i)
- controls[i].en2Ctrl = v;
+ for(unsigned long i = 0; i < _synth->_controlInPorts; ++i)
+ _controls[i].enCtrl = v;
}
void DssiSynthIF::updateControllers() { }
void DssiSynthIF::activate()
{
- if(synth && synth->dssi && synth->dssi->LADSPA_Plugin && synth->dssi->LADSPA_Plugin->activate)
+ if(_synth && _synth->dssi && _synth->dssi->LADSPA_Plugin && _synth->dssi->LADSPA_Plugin->activate)
//for (int i = 0; i < instances; ++i)
// _plugin->activate(handle[i]);
- synth->dssi->LADSPA_Plugin->activate(handle);
+ _synth->dssi->LADSPA_Plugin->activate(_handle);
// REMOVE Tim. Or keep? From PluginI::activate().
// if (initControlValues) {
@@ -2388,27 +2456,24 @@ void DssiSynthIF::activate()
}
void DssiSynthIF::deactivate()
{
- if(!synth || !synth->dssi || !synth->dssi->LADSPA_Plugin ||!synth->dssi->LADSPA_Plugin->deactivate)
+ if(!_synth || !_synth->dssi || !_synth->dssi->LADSPA_Plugin ||!_synth->dssi->LADSPA_Plugin->deactivate)
return;
//for (int i = 0; i < instances; ++i)
// synth->dssi->LADSPA_Plugin->deactivate(handle[i]);
- synth->dssi->LADSPA_Plugin->deactivate(handle);
+ _synth->dssi->LADSPA_Plugin->deactivate(_handle);
}
-//void DssiSynthIF::writeConfiguration(int /*level*/, Xml& /*xml*/) { }
-//bool DssiSynthIF::readConfiguration(Xml& /*xml*/, bool /*readPreset*/) { return false; }
-
-unsigned long DssiSynthIF::parameters() const { return synth ? synth->_controlInPorts : 0; }
-unsigned long DssiSynthIF::parametersOut() const { return synth ? synth->_controlOutPorts : 0; }
+unsigned long DssiSynthIF::parameters() const { return _synth ? _synth->_controlInPorts : 0; }
+unsigned long DssiSynthIF::parametersOut() const { return _synth ? _synth->_controlOutPorts : 0; }
void DssiSynthIF::setParam(unsigned long i, float val) { setParameter(i, val); }
float DssiSynthIF::param(unsigned long i) const { return getParameter(i); }
float DssiSynthIF::paramOut(unsigned long i) const { return getParameterOut(i); }
-const char* DssiSynthIF::paramName(unsigned long i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortNames[controls[i].idx] : 0; }
-const char* DssiSynthIF::paramOutName(unsigned long i) { return (synth && synth->dssi) ? synth->dssi->LADSPA_Plugin->PortNames[controlsOut[i].idx] : 0; }
-LADSPA_PortRangeHint DssiSynthIF::range(unsigned long i) { return synth->dssi->LADSPA_Plugin->PortRangeHints[controls[i].idx]; }
-LADSPA_PortRangeHint DssiSynthIF::rangeOut(unsigned long i) { return synth->dssi->LADSPA_Plugin->PortRangeHints[controlsOut[i].idx]; }
-CtrlValueType DssiSynthIF::ctrlValueType(unsigned long i) const { return ladspaCtrlValueType(synth->dssi->LADSPA_Plugin, controls[i].idx); }
-CtrlList::Mode DssiSynthIF::ctrlMode(unsigned long i) const { return ladspaCtrlMode(synth->dssi->LADSPA_Plugin, controls[i].idx); };
+const char* DssiSynthIF::paramName(unsigned long i) { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->PortNames[_controls[i].idx] : 0; }
+const char* DssiSynthIF::paramOutName(unsigned long i) { return (_synth && _synth->dssi) ? _synth->dssi->LADSPA_Plugin->PortNames[_controlsOut[i].idx] : 0; }
+LADSPA_PortRangeHint DssiSynthIF::range(unsigned long i) { return _synth->dssi->LADSPA_Plugin->PortRangeHints[_controls[i].idx]; }
+LADSPA_PortRangeHint DssiSynthIF::rangeOut(unsigned long i) { return _synth->dssi->LADSPA_Plugin->PortRangeHints[_controlsOut[i].idx]; }
+CtrlValueType DssiSynthIF::ctrlValueType(unsigned long i) const { return ladspaCtrlValueType(_synth->dssi->LADSPA_Plugin, _controls[i].idx); }
+CtrlList::Mode DssiSynthIF::ctrlMode(unsigned long i) const { return ladspaCtrlMode(_synth->dssi->LADSPA_Plugin, _controls[i].idx); };
} // namespace MusECore
diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h
index 27ef05a3..13d604a9 100644
--- a/muse2/muse/dssihost.h
+++ b/muse2/muse/dssihost.h
@@ -4,7 +4,7 @@
// $Id: dssihost.h,v 1.10.2.7 2009/12/06 10:05:00 terminator356 Exp $
//
// Copyright (C) 1999-2011 by Werner Schweer and others
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License
@@ -83,10 +83,9 @@ class DssiSynth : public Synth {
unsigned long _portCount, _inports, _outports, _controlInPorts, _controlOutPorts;
std::vector<unsigned long> iIdx; // Audio input index to port number.
std::vector<unsigned long> oIdx; // Audio output index to port number.
- std::vector<int> iUsedIdx; // During process, tells whether an audio input port was used by any input routes.
std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.
- MusECore::MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to DSSI port numbers.
- MusECore::MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps DSSI port numbers to midi controller numbers.
+ MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to DSSI port numbers.
+ MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps DSSI port numbers to midi controller numbers.
bool _hasGui;
bool _inPlaceCapable;
// Hack: Special flag required.
@@ -116,11 +115,11 @@ class DssiSynth : public Synth {
class DssiSynthIF : public SynthIF
{
- DssiSynth* synth;
- LADSPA_Handle handle;
+ DssiSynth* _synth;
+ LADSPA_Handle _handle;
- Port* controls;
- Port* controlsOut;
+ Port* _controls;
+ Port* _controlsOut;
#ifdef OSC_SUPPORT
OscDssiIF _oscif;
@@ -129,11 +128,12 @@ class DssiSynthIF : public SynthIF
std::vector<DSSI_Program_Descriptor> programs;
void queryPrograms();
void doSelectProgram(LADSPA_Handle handle, int bank, int prog);
- bool processEvent(const MusECore::MidiPlayEvent&, snd_seq_event_t*);
+ bool processEvent(const MidiPlayEvent&, snd_seq_event_t*);
- float** audioInBuffers;
- float** audioOutBuffers;
- float* audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence.
+ float** _audioInBuffers;
+ float** _audioOutBuffers;
+ float* _audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence.
+ std::vector<unsigned long> _iUsedIdx; // During process, tells whether an audio input port was used by any input routes.
public:
DssiSynthIF(SynthI* s);
@@ -145,7 +145,7 @@ class DssiSynthIF : public SynthIF
bool init(DssiSynth* s);
- virtual DssiSynth* dssiSynth() { return synth; }
+ virtual DssiSynth* dssiSynth() { return _synth; }
virtual SynthI* dssiSynthI() { return synti; }
virtual bool initGui();
@@ -156,15 +156,15 @@ class DssiSynthIF : public SynthIF
virtual bool nativeGuiVisible() const;
virtual void showNativeGui(bool);
virtual bool hasNativeGui() const { return !dssi_ui_filename().isEmpty(); }
- virtual void getGeometry(int*x, int*y, int*w, int*h) const { *x=0;*y=0;*w=0;*h=0; }
- virtual void setGeometry(int, int, int, int) {}
+ virtual void getGeometry(int*x, int*y, int*w, int*h) const;
+ virtual void setGeometry(int, int, int, int);
virtual void getNativeGeometry(int*x, int*y, int*w, int*h) const { *x=0;*y=0;*w=0;*h=0; }
virtual void setNativeGeometry(int, int, int, int) {}
virtual void preProcessAlways();
- virtual MusECore::iMPEvent getData(MusECore::MidiPort*, MusECore::MPEventList*, MusECore::iMPEvent, unsigned pos, int ports, unsigned n, float** buffer);
- virtual bool putEvent(const MusECore::MidiPlayEvent& ev);
- virtual MusECore::MidiPlayEvent receiveEvent();
+ virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned n, float** buffer);
+ virtual bool putEvent(const MidiPlayEvent& ev);
+ virtual MidiPlayEvent receiveEvent();
virtual int eventsPending() const { return 0; }
virtual int channels() const;
@@ -204,10 +204,7 @@ class DssiSynthIF : public SynthIF
QString fileName() const;
void enableController(unsigned long i, bool v = true);
bool controllerEnabled(unsigned long i) const;
- void enable2Controller(unsigned long i, bool v = true);
- bool controllerEnabled2(unsigned long i) const;
void enableAllControllers(bool v = true);
- void enable2AllControllers(bool v = true);
void updateControllers();
void activate();
void deactivate();
diff --git a/muse2/muse/master/masteredit.cpp b/muse2/muse/master/masteredit.cpp
index 90675d25..a134ef14 100644
--- a/muse2/muse/master/masteredit.cpp
+++ b/muse2/muse/master/masteredit.cpp
@@ -285,13 +285,14 @@ void MasterEdit::readStatus(MusECore::Xml& xml)
case MusECore::Xml::TagStart:
if (tag == "midieditor")
MidiEditor::readStatus(xml);
+ else if (tag == "xpos")
+ hscroll->setPos(xml.parseInt());
+ else if (tag == "xmag")
+ hscroll->setMag(xml.parseInt());
else if (tag == "ypos")
vscroll->setPos(xml.parseInt());
- else if (tag == "ymag") {
- // vscroll->setMag(xml.parseInt());
- int mag = xml.parseInt();
- vscroll->setMag(mag);
- }
+ else if (tag == "ymag")
+ vscroll->setMag(xml.parseInt());
else
xml.unknown("MasterEdit");
break;
@@ -324,8 +325,10 @@ void MasterEdit::readStatus(MusECore::Xml& xml)
void MasterEdit::writeStatus(int level, MusECore::Xml& xml) const
{
xml.tag(level++, "master");
- xml.intTag(level, "ypos", vscroll->pos());
+ xml.intTag(level, "xmag", hscroll->mag());
+ xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "ymag", vscroll->mag());
+ xml.intTag(level, "ypos", vscroll->pos());
MidiEditor::writeStatus(level, xml);
xml.tag(level, "/master");
}
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index 8f5ed22c..524329b1 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -819,7 +819,51 @@ void Audio::processMidi()
while (s->eventsPending())
{
MusECore::MidiRecordEvent ev = s->receiveEvent();
- md->recordEvent(ev);
+ // FIXME: This is for recording the events sent by GUI.
+ // It never gets a chance to be processed since reading of
+ // record FIFOs is done only by connected input ROUTES, below.
+ // To be useful, the synth itself must be allowed to be chosen
+ // as an input route, which is simple enough, but we currently don't
+ // list synths as inputs for fear of too many INCOMPATIBLE messages
+ // from DIFFERING synths. However, we could allow ONLY THIS synth
+ // to be listed and therefore be automatically connected too, if desired.
+ //md->recordEvent(ev);
+ //
+ // For now, instead of recording, here is the minimum that we must do:
+ //
+ // Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
+ // Same code as in MidiPort::sendEvent()
+ if(md->midiPort() != -1)
+ {
+ MidiPort* mp = &MusEGlobal::midiPorts[md->midiPort()];
+ if(ev.type() == ME_CONTROLLER)
+ {
+ int da = ev.dataA();
+ int db = ev.dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+ mp->setHwCtrlState(ev.channel(), da, db);
+ }
+ else if(ev.type() == ME_PITCHBEND)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, ev.dataA());
+ mp->setHwCtrlState(ev.channel(), CTRL_PITCH, da);
+ }
+ else if(ev.type() == ME_AFTERTOUCH)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_AFTERTOUCH, ev.dataA());
+ mp->setHwCtrlState(ev.channel(), CTRL_AFTERTOUCH, da);
+ }
+ else if(ev.type() == ME_POLYAFTER)
+ {
+ int ctl = (CTRL_POLYAFTER & ~0xff) | (ev.dataA() & 0x7f);
+ int db = mp->limitValToInstrCtlRange(ctl, ev.dataB());
+ mp->setHwCtrlState(ev.channel(), ctl , db);
+ }
+ else if(ev.type() == ME_PROGRAM)
+ {
+ mp->setHwCtrlState(ev.channel(), CTRL_PROGRAM, ev.dataA());
+ }
+ }
}
}
@@ -921,8 +965,8 @@ void Audio::processMidi()
// Unlike our built-in gui controls, there is not much choice here but to
// just do this:
if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- //if(isPlaying() && (at == AUTO_WRITE || at == AUTO_TOUCH)) DELETETHIS
+ (at == AUTO_READ && !MusEGlobal::audio->isPlaying()) ||
+ (at == AUTO_TOUCH) )
track->enableController(actrl, false);
if(isPlaying())
{
diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp
index ff30eb64..734871ef 100644
--- a/muse2/muse/midiedit/dcanvas.cpp
+++ b/muse2/muse/midiedit/dcanvas.cpp
@@ -1003,18 +1003,8 @@ void DrumCanvas::keyReleased(int, bool)
{
// release note:
if(_playEvents)
- {
- // REMOVE Tim.
- //int pitch, port, channel;
- //if(index2Note(index, &port, &channel, &pitch))
- //{
- // MusECore::MidiPlayEvent e(0, port, channel, 0x90, pitch, 0);
- // MusEGlobal::audio->msgPlayMidiEvent(&e);
- //}
stopPlayEvent();
}
- //playedPitch=-1;
- }
//---------------------------------------------------------
// mapChanged
diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp
index 3ddf6f7b..e2ba0ef1 100644
--- a/muse2/muse/midiedit/drumedit.cpp
+++ b/muse2/muse/midiedit/drumedit.cpp
@@ -986,10 +986,10 @@ void DrumEdit::writeStatus(int level, MusECore::Xml& xml) const
xml.intTag(level, "midiin", canvas->midiin());
xml.intTag(level, "tool", int(canvas->tool()));
xml.intTag(level, "playEvents", _playEvents);
- xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "xmag", hscroll->mag());
- xml.intTag(level, "ypos", vscroll->pos());
+ xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "ymag", vscroll->mag());
+ xml.intTag(level, "ypos", vscroll->pos());
xml.intTag(level, "ignore_hide", _ignore_hide);
xml.tag(level, "/drumedit");
}
diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp
index 492727cb..4ae702f1 100644
--- a/muse2/muse/midiedit/ecanvas.cpp
+++ b/muse2/muse/midiedit/ecanvas.cpp
@@ -527,7 +527,6 @@ void EventCanvas::stopPlayEvent()
if(playedPitch == -1 || playedPitchPort == -1 || playedPitchChannel == -1)
return;
// release note:
- //MusECore::MidiPlayEvent ev(0, playedPitchPort, playedPitchChannel, 0x90, playedPitch, 0); // REMOVE Tim.
MusECore::MidiPlayEvent ev(0, playedPitchPort, playedPitchChannel, MusECore::ME_NOTEOFF, playedPitch, playedVelocity);
MusEGlobal::audio->msgPlayMidiEvent(&ev);
playedPitch = playedPitchPort = playedPitchChannel = -1;
diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp
index 66e6c2fb..d0cb3f2a 100644
--- a/muse2/muse/midiedit/pianoroll.cpp
+++ b/muse2/muse/midiedit/pianoroll.cpp
@@ -1067,10 +1067,10 @@ void PianoRoll::writeStatus(int level, MusECore::Xml& xml) const
xml.intTag(level, "midiin", canvas->midiin());
xml.intTag(level, "tool", int(canvas->tool()));
xml.intTag(level, "playEvents", _playEvents);
- xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "xmag", hscroll->mag());
- xml.intTag(level, "ypos", vscroll->pos());
+ xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "ymag", vscroll->mag());
+ xml.intTag(level, "ypos", vscroll->pos());
xml.tag(level, "/pianoroll");
}
diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp
index 32504cc8..9381e3ec 100644
--- a/muse2/muse/mixer/astrip.cpp
+++ b/muse2/muse/mixer/astrip.cpp
@@ -4,7 +4,7 @@
// $Id: astrip.cpp,v 1.23.2.17 2009/11/16 01:55:55 terminator356 Exp $
//
// (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -69,6 +69,7 @@
#include "menutitleitem.h"
//#include "popupmenu.h"
#include "routepopup.h"
+#include "ctrl.h"
namespace MusEGui {
@@ -305,20 +306,21 @@ void AudioStrip::songChanged(MusECore::SongChangedFlags_t val)
void AudioStrip::updateVolume()
{
+ if(_volPressed) // Inhibit the controller stream if control is currently pressed.
+ return;
double vol = ((MusECore::AudioTrack*)track)->volume();
- if (vol != volume)
- {
- //printf("AudioStrip::updateVolume setting slider and label\n");
-
- slider->blockSignals(true);
- sl->blockSignals(true);
- double val = MusECore::fast_log10(vol) * 20.0;
- slider->setValue(val);
- sl->setValue(val);
- sl->blockSignals(false);
- slider->blockSignals(false);
- volume = vol;
- }
+ if (vol != volume)
+ {
+ //printf("AudioStrip::updateVolume setting slider and label\n");
+ slider->blockSignals(true);
+ sl->blockSignals(true);
+ double val = MusECore::fast_log10(vol) * 20.0;
+ slider->setValue(val);
+ sl->setValue(val);
+ sl->blockSignals(false);
+ slider->blockSignals(false);
+ volume = vol;
+ }
}
//---------------------------------------------------------
@@ -327,20 +329,21 @@ void AudioStrip::updateVolume()
void AudioStrip::updatePan()
{
+ if(_panPressed) // Inhibit the controller stream if control is currently pressed.
+ return;
double v = ((MusECore::AudioTrack*)track)->pan();
- if (v != panVal)
- {
- //printf("AudioStrip::updatePan setting slider and label\n");
-
- pan->blockSignals(true);
- panl->blockSignals(true);
- pan->setValue(v);
- panl->setValue(v);
- panl->blockSignals(false);
- pan->blockSignals(false);
- panVal = v;
- }
-}
+ if (v != panVal)
+ {
+ //printf("AudioStrip::updatePan setting slider and label\n");
+ pan->blockSignals(true);
+ panl->blockSignals(true);
+ pan->setValue(v);
+ panl->setValue(v);
+ panl->blockSignals(false);
+ pan->blockSignals(false);
+ panVal = v;
+ }
+}
//---------------------------------------------------------
// offToggled
@@ -469,11 +472,9 @@ void AudioStrip::auxLabelChanged(double val, unsigned int idx)
void AudioStrip::volumeChanged(double val, int, bool shift_pressed)
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- track->enableVolumeController(false);
-
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
double vol;
if (val <= MusEGlobal::config.minSlider) {
vol = 0.0;
@@ -482,10 +483,9 @@ void AudioStrip::volumeChanged(double val, int, bool shift_pressed)
else
vol = pow(10.0, val/20.0);
volume = vol;
- //MusEGlobal::audio->msgSetVolume((MusECore::AudioTrack*)track, vol);
- // p4.0.21 MusEGlobal::audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setVolume(vol);
- if (!shift_pressed) ((MusECore::AudioTrack*)track)->recordAutomation(MusECore::AC_VOLUME, vol);
+ if (!shift_pressed) t->recordAutomation(MusECore::AC_VOLUME, vol); // with shift, we get straight lines :)
+ t->setParam(MusECore::AC_VOLUME, vol); // Schedules a timed control change.
+ t->enableController(MusECore::AC_VOLUME, false);
}
//---------------------------------------------------------
@@ -494,10 +494,10 @@ void AudioStrip::volumeChanged(double val, int, bool shift_pressed)
void AudioStrip::volumePressed()
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- track->enableVolumeController(false);
-
+ if(track->isMidiTrack())
+ return;
+ _volPressed = true;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
double val = slider->value();
double vol;
if (val <= MusEGlobal::config.minSlider) {
@@ -507,10 +507,9 @@ void AudioStrip::volumePressed()
else
vol = pow(10.0, val/20.0);
volume = vol;
- //MusEGlobal::audio->msgSetVolume((MusECore::AudioTrack*)track, volume);
- // p4.0.21 MusEGlobal::audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setVolume(volume);
- ((MusECore::AudioTrack*)track)->startAutoRecord(MusECore::AC_VOLUME, volume);
+ t->startAutoRecord(MusECore::AC_VOLUME, vol);
+ t->setVolume(vol);
+ t->enableController(MusECore::AC_VOLUME, false);
}
//---------------------------------------------------------
@@ -519,11 +518,15 @@ void AudioStrip::volumePressed()
void AudioStrip::volumeReleased()
{
- AutomationType at = track->automationType();
- if (at == AUTO_OFF || at == AUTO_READ || at == AUTO_TOUCH)
- track->enableVolumeController(true);
-
- ((MusECore::AudioTrack*)track)->stopAutoRecord(MusECore::AC_VOLUME, volume);
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
+ AutomationType at = t->automationType();
+ t->stopAutoRecord(MusECore::AC_VOLUME, volume);
+ if(at == AUTO_OFF ||
+ at == AUTO_TOUCH)
+ t->enableController(MusECore::AC_VOLUME, true);
+ _volPressed = false;
}
//---------------------------------------------------------
@@ -540,11 +543,9 @@ void AudioStrip::volumeRightClicked(const QPoint &p)
void AudioStrip::volLabelChanged(double val)
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- track->enableVolumeController(false);
-
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
double vol;
if (val <= MusEGlobal::config.minSlider) {
vol = 0.0;
@@ -553,11 +554,12 @@ void AudioStrip::volLabelChanged(double val)
else
vol = pow(10.0, val/20.0);
volume = vol;
- slider->setValue(val);
- //audio->msgSetVolume((MusECore::AudioTrack*)track, vol);
- // p4.0.21 audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setVolume(vol);
- ((MusECore::AudioTrack*)track)->startAutoRecord(MusECore::AC_VOLUME, vol);
+ slider->blockSignals(true);
+ slider->setValue(val);
+ slider->blockSignals(false);
+ t->startAutoRecord(MusECore::AC_VOLUME, vol);
+ t->setParam(MusECore::AC_VOLUME, vol); // Schedules a timed control change.
+ t->enableController(MusECore::AC_VOLUME, false);
}
//---------------------------------------------------------
@@ -566,16 +568,13 @@ void AudioStrip::volLabelChanged(double val)
void AudioStrip::panChanged(double val, int, bool shift_pressed)
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- track->enablePanController(false);
-
- panVal = val;
- //MusEGlobal::audio->msgSetPan(((MusECore::AudioTrack*)track), val);
- // p4.0.21 MusEGlobal::audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setPan(val);
- if (!shift_pressed) ((MusECore::AudioTrack*)track)->recordAutomation(MusECore::AC_PAN, val);
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
+ panVal = val;
+ if (!shift_pressed) t->recordAutomation(MusECore::AC_PAN, val); // with shift, we get straight lines :)
+ t->setParam(MusECore::AC_PAN, val); // Schedules a timed control change.
+ t->enableController(MusECore::AC_PAN, false);
}
//---------------------------------------------------------
@@ -584,15 +583,14 @@ void AudioStrip::panChanged(double val, int, bool shift_pressed)
void AudioStrip::panPressed()
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- track->enablePanController(false);
-
- panVal = pan->value();
- //MusEGlobal::audio->msgSetPan(((MusECore::AudioTrack*)track), panVal);
- // p4.0.21 MusEGlobal::audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setPan(panVal);
- ((MusECore::AudioTrack*)track)->startAutoRecord(MusECore::AC_PAN, panVal);
+ if(track->isMidiTrack())
+ return;
+ _panPressed = true;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
+ panVal = pan->value();
+ t->startAutoRecord(MusECore::AC_PAN, panVal);
+ t->setPan(panVal);
+ t->enableController(MusECore::AC_PAN, false);
}
//---------------------------------------------------------
@@ -601,10 +599,15 @@ void AudioStrip::panPressed()
void AudioStrip::panReleased()
{
- AutomationType at = track->automationType();
- if (at == AUTO_OFF || at == AUTO_READ || at == AUTO_TOUCH)
- track->enablePanController(true);
- ((MusECore::AudioTrack*)track)->stopAutoRecord(MusECore::AC_PAN, panVal);
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
+ AutomationType at = t->automationType();
+ t->stopAutoRecord(MusECore::AC_PAN, panVal);
+ if(at == AUTO_OFF ||
+ at == AUTO_TOUCH)
+ t->enableController(MusECore::AC_PAN, true);
+ _panPressed = false;
}
//---------------------------------------------------------
@@ -621,17 +624,16 @@ void AudioStrip::panRightClicked(const QPoint &p)
void AudioStrip::panLabelChanged(double val)
{
- AutomationType at = ((MusECore::AudioTrack*)track)->automationType();
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- track->enablePanController(false);
-
+ if(track->isMidiTrack())
+ return;
+ MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
panVal = val;
+ pan->blockSignals(true);
pan->setValue(val);
- //MusEGlobal::audio->msgSetPan((MusECore::AudioTrack*)track, val);
- // p4.0.21 MusEGlobal::audio->msgXXX waits. Do we really need to?
- ((MusECore::AudioTrack*)track)->setPan(val);
- ((MusECore::AudioTrack*)track)->startAutoRecord(MusECore::AC_PAN, val);
+ pan->blockSignals(false);
+ t->startAutoRecord(MusECore::AC_PAN, val);
+ t->setParam(MusECore::AC_PAN, val); // Schedules a timed control change.
+ t->enableController(MusECore::AC_PAN, false);
}
//---------------------------------------------------------
@@ -772,6 +774,8 @@ AudioStrip::AudioStrip(QWidget* parent, MusECore::AudioTrack* at)
{
volume = -1.0;
panVal = 0;
+ _volPressed = false;
+ _panPressed = false;
record = 0;
off = 0;
diff --git a/muse2/muse/mixer/astrip.h b/muse2/muse/mixer/astrip.h
index 7088301f..3b32ec07 100644
--- a/muse2/muse/mixer/astrip.h
+++ b/muse2/muse/mixer/astrip.h
@@ -4,7 +4,7 @@
// $Id: astrip.h,v 1.8.2.6 2009/11/14 03:37:48 terminator356 Exp $
//
// (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -82,6 +82,9 @@ class AudioStrip : public Strip {
double volume;
double panVal;
+ bool _volPressed;
+ bool _panPressed;
+
//QToolButton* iR;
//QToolButton* oR;
diff --git a/muse2/muse/node.cpp b/muse2/muse/node.cpp
index 9ecd8a0a..73495d8f 100644
--- a/muse2/muse/node.cpp
+++ b/muse2/muse/node.cpp
@@ -4,7 +4,7 @@
// $Id: node.cpp,v 1.36.2.25 2009/12/20 05:00:35 terminator356 Exp $
//
// (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -364,13 +364,414 @@ void Track::setOff(bool val)
_off = val;
}
+//---------------------------------------------------------
+// applyTrackCtrls
+// If trackChans is 0, just process controllers only, not audio (do not 'run').
+//---------------------------------------------------------
+
+void AudioTrack::processTrackCtrls(unsigned pos, int trackChans, unsigned nframes, float** buffer)
+{
+ const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
+ const unsigned long min_per = (MusEGlobal::config.minControlProcessPeriod > nframes) ? nframes : MusEGlobal::config.minControlProcessPeriod;
+ unsigned long sample = 0;
+
+ const AutomationType at = automationType();
+ const bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
+ CtrlListList* cll = controller();
+ CtrlList* vol_ctrl = 0;
+ CtrlList* pan_ctrl = 0;
+ {
+ ciCtrlList icl = cll->find(AC_VOLUME);
+ if(icl == cll->end())
+ return;
+ vol_ctrl = icl->second;
+ icl = cll->find(AC_PAN);
+ if(icl == cll->end())
+ return;
+ pan_ctrl = icl->second;
+ }
+
+ int cur_slice = 0;
+ while(sample < nframes)
+ {
+ unsigned long nsamp = nframes - sample;
+ const unsigned long slice_frame = pos + sample;
+
+ // Process automation control values, while also determining the maximum acceptable
+ // size of this run. Further processing, from FIFOs for example, can lower the size
+ // from there, but this section determines where the next highest maximum frame
+ // absolutely needs to be for smooth playback of the controller value stream...
+ //
+ if(trackChans != 0 && !_prefader) // Don't bother if we don't want to run, or prefader is on.
+ {
+ ciCtrlList icl = cll->begin();
+ for(unsigned long k = 0; k < _controlPorts; ++k)
+ {
+ CtrlList* cl = (icl != cll->end() ? icl->second : NULL);
+ CtrlInterpolate& ci = _controls[k].interp;
+ // Always refresh the interpolate struct at first, since things may have changed.
+ // Or if the frame is outside of the interpolate range - and eStop is not true. // FIXME TODO: Be sure these comparisons are correct.
+ if(cur_slice == 0 || (!ci.eStop && MusEGlobal::audio->isPlaying() &&
+ (slice_frame < (unsigned long)ci.sFrame || (ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame)) ) )
+ {
+ if(cl && (unsigned long)cl->id() == k)
+ {
+ cl->getInterpolation(slice_frame, no_auto || !_controls[k].enCtrl, &ci);
+ if(icl != cll->end())
+ ++icl;
+ }
+ else
+ {
+ // No matching controller, or end. Just copy the current value into the interpolator.
+ // Keep the current icl iterator, because since they are sorted by frames,
+ // if the IDs didn't match it means we can just let k catch up with icl.
+ ci.sFrame = 0;
+ ci.eFrame = -1;
+ ci.sVal = _controls[k].val;
+ ci.eVal = ci.sVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ }
+ else
+ {
+ if(ci.eStop && ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame) // FIXME TODO: Get that comparison right.
+ {
+ // Clear the stop condition and set up the interp struct appropriately as an endless value.
+ ci.sFrame = 0; //ci->eFrame;
+ ci.eFrame = -1;
+ ci.sVal = ci.eVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ if(icl != cll->end())
+ ++icl;
+ }
+
+ if(MusEGlobal::audio->isPlaying())
+ {
+ unsigned long samps = nsamp;
+ if(ci.eFrame != -1)
+ samps = (unsigned long)ci.eFrame - slice_frame;
+ if(samps < nsamp)
+ nsamp = samps;
+ }
+
+#ifdef NODE_DEBUG_PROCESS
+ fprintf(stderr, "AudioTrack::processTrackCtrls k:%lu sample:%lu frame:%lu nextFrame:%d nsamp:%lu \n", k, sample, frame, ci.eFrame, nsamp);
+#endif
+ }
+ }
+
+#ifdef NODE_DEBUG_PROCESS
+ fprintf(stderr, "AudioTrack::processTrackCtrls sample:%lu nsamp:%lu\n", sample, nsamp);
+#endif
+
+ //
+ // Process all control ring buffer items valid for this time period...
+ //
+ bool found = false;
+ unsigned long frame = 0;
+ unsigned long evframe;
+ while(!_controlFifo.isEmpty())
+ {
+ ControlEvent v = _controlFifo.peek();
+ // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
+ // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.
+ evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes;
+
+ // Protection. Observed this condition. Why? Supposed to be linear timestamps.
+ if(found && evframe < frame)
+ {
+ fprintf(stderr, "AudioTrack::processTrackCtrls *** Error: evframe:%lu < frame:%lu idx:%lu val:%f unique:%d\n",
+ evframe, v.frame, v.idx, v.value, v.unique);
+
+ // No choice but to ignore it.
+ _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
+ continue;
+ }
+
+ if(evframe >= nframes // Next events are for a later period.
+ || (!found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
+ || (found && !v.unique && (evframe - sample >= min_per))) // Eat up events within minimum slice - they're too close.
+ break;
+ _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
+
+ if(v.idx >= _controlPorts) // Sanity check
+ break;
+
+ found = true;
+ frame = evframe;
+
+ if(trackChans != 0 && !_prefader) // Only if we want to run, and prefader is off.
+ {
+ CtrlInterpolate* ci = &_controls[v.idx].interp;
+ ci->eFrame = frame;
+ ci->eVal = v.value;
+ ci->eStop = true;
+ }
+
+ // Need to update the automation value, otherwise it overwrites later with the last automation value.
+ setPluginCtrlVal(v.idx, v.value);
+ }
+
+ if(found && trackChans != 0 && !_prefader) // If a control FIFO item was found, takes priority over automation controller stream.
+ nsamp = frame - sample;
+
+ if(sample + nsamp > nframes) // Safety check.
+ nsamp = nframes - sample;
+
+ // TODO: 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)
+ {
+ if(trackChans != 0 && !_prefader)
+ {
+ const CtrlInterpolate& vol_interp = _controls[AC_VOLUME].interp;
+ const CtrlInterpolate& pan_interp = _controls[AC_PAN].interp;
+ unsigned k;
+ //const float up_fact = 1.002711275; // 3.01.. dB / 256
+ //const float down_fact = 0.997296056;
+ const float up_fact = 1.003471749; // 3.01.. dB / 200
+ const float down_fact = 0.996540262;
+ float *sp1, *sp2, *dp1, *dp2;
+ float _volume, v, _pan, v1, v2;
+
+ if(trackChans == 1)
+ {
+ float* sp = buffer[0] + sample;
+ float* dp = outBuffers[0] + sample;
+ sp1 = sp2 = sp;
+ dp1 = outBuffersExtraMix[0] + sample;
+ dp2 = outBuffersExtraMix[1] + sample;
+ k = 0;
+ if(vol_interp.doInterp && MusEGlobal::audio->isPlaying())
+ {
+ for( ; k < nsamp; ++k)
+ {
+ _volume = vol_ctrl->interpolate(slice_frame + k, vol_interp);
+ v = _volume * _gain;
+ if(v > _curVolume)
+ {
+ if(_curVolume == 0.0)
+ _curVolume = 0.001; // Kick-start it from zero at -30dB.
+ _curVolume *= up_fact;
+ if(_curVolume >= v)
+ _curVolume = v;
+ }
+ else
+ if(v < _curVolume)
+ {
+ _curVolume *= down_fact;
+ if(_curVolume <= v || _curVolume <= 0.001) // Or if less than -30dB.
+ _curVolume = v;
+ }
+ *dp++ = *sp++ * _curVolume;
+ }
+ _controls[AC_VOLUME].val = _volume; // Update the port.
+ }
+ else
+ {
+ if(vol_interp.doInterp) // And not playing...
+ _volume = vol_ctrl->interpolate(pos, vol_interp);
+ else
+ _volume = vol_interp.sVal;
+ _controls[AC_VOLUME].val = _volume; // Update the port.
+ v = _volume * _gain;
+ if(v > _curVolume)
+ {
+ //fprintf(stderr, "A %f %f\n", v, _curVolume);
+ if(_curVolume == 0.0)
+ _curVolume = 0.001; // Kick-start it from zero at -30dB.
+ for( ; k < nsamp; ++k)
+ {
+ _curVolume *= up_fact;
+ if(_curVolume >= v)
+ {
+ _curVolume = v;
+ break;
+ }
+ *dp++ = *sp++ * _curVolume;
+ }
+ }
+ else
+ if(v < _curVolume)
+ {
+ //fprintf(stderr, "B %f %f\n", v, _curVolume);
+ for( ; k < nsamp; ++k)
+ {
+ _curVolume *= down_fact;
+ if(_curVolume <= v || _curVolume <= 0.001) // Or if less than -30dB.
+ {
+ _curVolume = v;
+ break;
+ }
+ *dp++ = *sp++ * _curVolume;
+ }
+ }
+ for( ; k < nsamp; ++k)
+ *dp++ = *sp++ * _curVolume;
+ }
+ }
+ else
+ if(trackChans >= 2)
+ {
+ sp1 = buffer[0] + sample;
+ sp2 = buffer[1] + sample;
+ dp1 = outBuffers[0] + sample;
+ dp2 = outBuffers[1] + sample;
+ }
+
+ k = 0;
+ if((vol_interp.doInterp || pan_interp.doInterp) && MusEGlobal::audio->isPlaying())
+ {
+ for( ; k < nsamp; ++k)
+ {
+ _volume = vol_ctrl->interpolate(slice_frame + k, vol_interp);
+ v = _volume * _gain;
+ _pan = pan_ctrl->interpolate(slice_frame + k, pan_interp);
+ v1 = v * (1.0 - _pan);
+ v2 = v * (1.0 + _pan);
+ if(v1 > _curVol1)
+ {
+ //fprintf(stderr, "C %f %f \n", v1, _curVol1);
+ if(_curVol1 == 0.0)
+ _curVol1 = 0.001; // Kick-start it from zero at -30dB.
+ _curVol1 *= up_fact;
+ if(_curVol1 >= v1)
+ _curVol1 = v1;
+ }
+ else
+ if(v1 < _curVol1)
+ {
+ //fprintf(stderr, "D %f %f \n", v1, _curVol1);
+ _curVol1 *= down_fact;
+ if(_curVol1 <= v1 || _curVol1 <= 0.001) // Or if less than -30dB.
+ _curVol1 = v1;
+ }
+ *dp1++ = *sp1++ * _curVol1;
+
+ if(v2 > _curVol2)
+ {
+ //fprintf(stderr, "E %f %f \n", v2, _curVol2);
+ if(_curVol2 == 0.0)
+ _curVol2 = 0.001; // Kick-start it from zero at -30dB.
+ _curVol2 *= up_fact;
+ if(_curVol2 >= v2)
+ _curVol2 = v2;
+ }
+ else
+ if(v2 < _curVol2)
+ {
+ //fprintf(stderr, "F %f %f \n", v2, _curVol2);
+ _curVol2 *= down_fact;
+ if(_curVol2 <= v2 || _curVol2 <= 0.001) // Or if less than -30dB.
+ _curVol2 = v2;
+ }
+ *dp2++ = *sp2++ * _curVol2;
+ }
+ _controls[AC_VOLUME].val = _volume; // Update the ports.
+ _controls[AC_PAN].val = _pan;
+ }
+ else
+ {
+ if(vol_interp.doInterp) // And not playing...
+ _volume = vol_ctrl->interpolate(pos, vol_interp);
+ else
+ _volume = vol_interp.sVal;
+ if(pan_interp.doInterp) // And not playing...
+ _pan = pan_ctrl->interpolate(pos, pan_interp);
+ else
+ _pan = pan_interp.sVal;
+ _controls[AC_VOLUME].val = _volume; // Update the ports.
+ _controls[AC_PAN].val = _pan;
+ v = _volume * _gain;
+ v1 = v * (1.0 - _pan);
+ v2 = v * (1.0 + _pan);
+ if(v1 > _curVol1)
+ {
+ //fprintf(stderr, "C %f %f \n", v1, _curVol1);
+ if(_curVol1 == 0.0)
+ _curVol1 = 0.001; // Kick-start it from zero at -30dB.
+ for( ; k < nsamp; ++k)
+ {
+ _curVol1 *= up_fact;
+ if(_curVol1 >= v1)
+ {
+ _curVol1 = v1;
+ break;
+ }
+ *dp1++ = *sp1++ * _curVol1;
+ }
+ }
+ else
+ if(v1 < _curVol1)
+ {
+ //fprintf(stderr, "D %f %f \n", v1, _curVol1);
+ for( ; k < nsamp; ++k)
+ {
+ _curVol1 *= down_fact;
+ if(_curVol1 <= v1 || _curVol1 <= 0.001) // Or if less than -30dB.
+ {
+ _curVol1 = v1;
+ break;
+ }
+ *dp1++ = *sp1++ * _curVol1;
+ }
+ }
+ for( ; k < nsamp; ++k)
+ *dp1++ = *sp1++ * _curVol1;
+
+ k = 0;
+ if(v2 > _curVol2)
+ {
+ //fprintf(stderr, "E %f %f \n", v2, _curVol2);
+ if(_curVol2 == 0.0)
+ _curVol2 = 0.001; // Kick-start it from zero at -30dB.
+ for( ; k < nsamp; ++k)
+ {
+ _curVol2 *= up_fact;
+ if(_curVol2 >= v2)
+ {
+ _curVol2 = v2;
+ break;
+ }
+ *dp2++ = *sp2++ * _curVol2;
+ }
+ }
+ else
+ if(v2 < _curVol2)
+ {
+ //fprintf(stderr, "F %f %f \n", v2, _curVol2);
+ for( ; k < nsamp; ++k)
+ {
+ _curVol2 *= down_fact;
+ if(_curVol2 <= v2 || _curVol2 <= 0.001) // Or if less than -30dB.
+ {
+ _curVol2 = v2;
+ break;
+ }
+ *dp2++ = *sp2++ * _curVol2;
+ }
+ }
+ for( ; k < nsamp; ++k)
+ *dp2++ = *sp2++ * _curVol2;
+ }
+ }
+
+ sample += nsamp;
+ }
+
+ ++cur_slice; // Slice is done. Moving on to any next slice now...
+ }
+}
//---------------------------------------------------------
// copyData
//---------------------------------------------------------
// this is also addData(). addData() just calls copyData(..., true);
-void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer, bool add /*=false*/)
+void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer, bool add)
{
//Changed by T356. 12/12/09.
// Overhaul and streamline to eliminate multiple processing during one process loop.
@@ -385,11 +786,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
if(srcStartChan == -1)
srcStartChan = 0;
- int trackChans = channels();
+ const int trackChans = channels();
int srcChans = (srcChannels == -1) ? trackChans : srcChannels;
- int srcTotalOutChans = totalOutChannels();
- if(channels() == 1)
- srcTotalOutChans = 1;
+ const int srcTotalOutChans = (channels() == 1) ? 1 : totalOutChannels();
// Special consideration for metronome: It is not part of the track list,
// and it has no in or out routes, yet multiple output tracks may call addData on it!
@@ -397,26 +796,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
// Not strictly necessary here because only addData is ever called, but just to be consistent...
int i;
-
- float* buffer[srcTotalOutChans];
+
+ float* buffer[srcTotalOutChans];
float data[nframes * srcTotalOutChans];
-
- // precalculate stereo volume
- double vol[2];
- double _volume = controller()->value(AC_VOLUME, pos,
- !MusEGlobal::automation || automationType() == AUTO_OFF || !_volumeEnCtrl || !_volumeEn2Ctrl);
- double _pan = controller()->value(AC_PAN, pos,
- !MusEGlobal::automation || automationType() == AUTO_OFF || !_panEnCtrl || !_panEn2Ctrl);
-
- vol[0] = _volume * (1.0 - _pan) * _gain;
- vol[1] = _volume * (1.0 + _pan) * _gain;
float meter[trackChans];
// Have we been here already during this process cycle?
if(processed())
{
- // If there is only one (or no) output routes, it's an error - we've been called more than once per process cycle!
- // No, this is no longer an error, it's deliberate. Processing no longer done in 'chains', now done randomly. p4.0.37
#ifdef NODE_DEBUG_PROCESS
printf("MusE: AudioTrack::copyData name:%s already processed _haveData:%d\n", name().toLatin1().constData(), _haveData);
#endif
@@ -424,9 +811,48 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
// Is there already some data gathered from a previous call during this process cycle?
if(_haveData)
{
- // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after.
- for(i = 0; i < srcTotalOutChans; ++i)
- buffer[i] = outBuffers[i];
+ if(srcChans == dstChannels)
+ {
+ for(int c = 0; c < dstChannels; ++c)
+ {
+ float* sp = outBuffers[c + srcStartChan];
+ float* dp = dstBuffer[c];
+ if (!add)
+ AL::dsp->cpy(dp, sp, nframes);
+ else
+ for(unsigned k = 0; k < nframes; ++k)
+ *dp++ += *sp++;
+ }
+ }
+ else if(srcChans == 1 && dstChannels == 2)
+ {
+ for(int c = 0; c < dstChannels; ++c)
+ {
+ float* sp;
+ if(!_prefader && srcStartChan == 0 && trackChans == 1)
+ sp = outBuffersExtraMix[c]; // Use the pre-panned mono-to-stereo extra buffers.
+ else
+ sp = outBuffers[srcStartChan]; // In all other cases use the main buffers.
+ float* dp = dstBuffer[c];
+ if (!add)
+ AL::dsp->cpy(dp, sp, nframes);
+ else
+ for(unsigned k = 0; k < nframes; ++k)
+ *dp++ += *sp++;
+ }
+ }
+ else if(srcChans == 2 && dstChannels == 1)
+ {
+ float* dp = dstBuffer[0];
+ float* sp1 = outBuffers[srcStartChan];
+ float* sp2 = outBuffers[srcStartChan + 1];
+ if (!add)
+ for(unsigned k = 0; k < nframes; ++k)
+ *dp++ = (*sp1++ + *sp2++);
+ else
+ for(unsigned k = 0; k < nframes; ++k)
+ *dp++ += (*sp1++ + *sp2++);
+ }
}
else
{
@@ -446,9 +872,8 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
memset(dstBuffer[i], 0, sizeof(float) * nframes);
}
}
- // else if (add) do nothing.
- return;
}
+ return;
}
else
{
@@ -463,7 +888,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
printf("MusE: AudioTrack::copyData name:%s dstChannels:%d Off, zeroing buffers\n", name().toLatin1().constData(), dstChannels);
#endif
- if (!add)
+ if(!add)
{
// Track is off. Zero the supplied buffers.
unsigned int q;
@@ -478,9 +903,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
memset(dstBuffer[i], 0, sizeof(float) * nframes);
}
}
- // else if (add) do nothing
-
- _efxPipe->apply(0, nframes, 0); // Just process controls only, not audio (do not 'run').
+
+ _efxPipe->apply(pos, 0, nframes, 0); // Just process controls only, not audio (do not 'run').
+ processTrackCtrls(pos, 0, nframes, 0);
for(i = 0; i < trackChans; ++i)
_meter[i] = 0.0;
@@ -489,14 +914,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
}
// Point the input buffers at a temporary stack buffer.
- for(i = 0; i < srcTotalOutChans; ++i)
+ for(i = 0; i < srcTotalOutChans; ++i)
buffer[i] = data + i * nframes;
// getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.
// For ex. if this is an audio input, Jack will set the pointers for us in AudioInput::getData!
// Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times,
// so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is !
- if(!getData(pos, srcTotalOutChans, nframes, buffer) || (!add && isMute() && !_prefader))
+ if(!getData(pos, srcTotalOutChans, nframes, buffer))
{
#ifdef NODE_DEBUG_PROCESS
printf("MusE: AudioTrack::copyData name:%s srcTotalOutChans:%d zeroing buffers\n", name().toLatin1().constData(), srcTotalOutChans);
@@ -520,17 +945,75 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
// apply plugin chain
//---------------------------------------------------
- _efxPipe->apply(trackChans, nframes, buffer);
+ // Allow it to process even if muted so that when mute is turned off, left-over buffers (reverb tails etc) can die away.
+ _efxPipe->apply(pos, trackChans, nframes, buffer);
//---------------------------------------------------
+ // apply volume, pan
+ //---------------------------------------------------
+
+ #ifdef NODE_DEBUG_PROCESS
+ printf("MusE: AudioTrack::copyData trackChans:%d srcTotalOutChans:%d srcStartChan:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcStartChan, srcChans, dstChannels);
+ #endif
+
+ processTrackCtrls(pos, trackChans, nframes, buffer);
+
+ const int valid_out_bufs = _prefader ? 0 : (trackChans >= 2 ? 2 : trackChans);
+
+ //---------------------------------------------------
+ // metering
+ //---------------------------------------------------
+
+ for(int c = 0; c < trackChans; ++c)
+ {
+ meter[c] = 0.0;
+ float* sp = (c >= valid_out_bufs) ? buffer[c] : outBuffers[c]; // Optimize: Don't all valid outBuffers just for meters
+ for(unsigned k = 0; k < nframes; ++k)
+ {
+ const double f = fabs(*sp++); // If the track is mono pan has no effect on meters.
+ if(f > meter[c])
+ meter[c] = f;
+ }
+ _meter[c] = meter[c];
+ if(_meter[c] > _peak[c])
+ _peak[c] = _meter[c];
+ }
+
+ if(isMute())
+ {
+ if (!add)
+ {
+ unsigned int q;
+ for(i = 0; i < dstChannels; ++i)
+ {
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(q = 0; q < nframes; q++)
+ dstBuffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(dstBuffer[i], 0, sizeof(float) * nframes);
+ }
+ }
+ return; // We're outta here.
+ }
+
+ // Copy whole blocks that we can get away with here outside of the track control processing loop.
+ for(i = valid_out_bufs; i < srcTotalOutChans; ++i)
+ AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
+
+ // We now have some data! Set to true.
+ _haveData = true;
+
+ //---------------------------------------------------
// aux sends
//---------------------------------------------------
- if(hasAuxSend() && !isMute())
+ if(hasAuxSend())
{
AuxList* al = MusEGlobal::song->auxs();
unsigned naux = al->size();
- for(unsigned k = 0; k < naux; ++k)
+ for(unsigned k = 0; k < naux; ++k)
{
float m = _auxSend[k];
if(m <= 0.0001) // optimize
@@ -538,209 +1021,98 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s
AudioAux* a = (AudioAux*)((*al)[k]);
float** dst = a->sendBuffer();
int auxChannels = a->channels();
- if((srcChans ==1 && auxChannels==1) || srcChans == 2)
+ if((srcChans ==1 && auxChannels==1) || srcChans == 2)
{
- for(int ch = 0; ch < srcChans; ++ch)
+ for(int ch = 0; ch < srcChans; ++ch)
{
float* db = dst[ch % a->channels()]; // no matter whether there's one or two dst buffers
- float* sb = buffer[ch];
- for(unsigned f = 0; f < nframes; ++f)
- *db++ += (*sb++ * m * vol[ch]); // add to mix
+ float* sb = outBuffers[ch];
+ for(unsigned f = 0; f < nframes; ++f)
+ *db++ += (*sb++ * m); // add to mix
}
}
else if(srcChans==1 && auxChannels==2) // copy mono to both channels
- {
- for(int ch = 0; ch < auxChannels; ++ch)
+ {
+ for(int ch = 0; ch < auxChannels; ++ch)
{
float* db = dst[ch % a->channels()];
- float* sb = buffer[0];
- for(unsigned f = 0; f < nframes; ++f)
- *db++ += (*sb++ * m * vol[ch]); // add to mix
+ float* sb = outBuffers[0];
+ for(unsigned f = 0; f < nframes; ++f)
+ *db++ += (*sb++ * m); // add to mix
}
}
}
}
//---------------------------------------------------
- // prefader metering
+ // copy to destination buffers
//---------------------------------------------------
- if(_prefader)
+ // Sanity check. Is source starting channel out of range? Just zero and return.
+ if(srcStartChan >= srcTotalOutChans)
{
- for(i = 0; i < trackChans; ++i)
+ if(!add)
{
- float* p = buffer[i];
- meter[i] = 0.0;
- for(unsigned k = 0; k < nframes; ++k)
+ unsigned int q;
+ for(i = 0; i < dstChannels; ++i)
{
- double f = fabs(*p++);
- if(f > meter[i])
- meter[i] = f;
- }
- _meter[i] = meter[i];
- if(_meter[i] > _peak[i])
- _peak[i] = _meter[i];
- }
- }
-
- if(isMute())
- {
- if (!add)
- {
- unsigned int q;
- for(i = 0; i < dstChannels; ++i)
+ if(MusEGlobal::config.useDenormalBias)
{
- if(MusEGlobal::config.useDenormalBias)
- {
- for(q = 0; q < nframes; q++)
- dstBuffer[i][q] = MusEGlobal::denormalBias;
- }
- else
- memset(dstBuffer[i], 0, sizeof(float) * nframes);
- }
+ for(q = 0; q < nframes; q++)
+ dstBuffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(dstBuffer[i], 0, sizeof(float) * nframes);
+ }
}
-
- if(!_prefader)
- for(i = 0; i < trackChans; ++i) // Must process ALL channels, even if unconnected. Only max 2 channels.
- _meter[i] = 0.0;
-
return;
}
-
- // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them.
- for(i = 0; i < srcTotalOutChans; ++i)
- AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
-
- // We have some data! Set to true.
- _haveData = true;
- }
-
- // Sanity check. Is source starting channel out of range? Just zero and return.
- if(srcStartChan >= srcTotalOutChans)
- {
- unsigned int q;
- for(i = 0; i < dstChannels; ++i)
- {
- if(MusEGlobal::config.useDenormalBias)
- {
- for(q = 0; q < nframes; q++)
- dstBuffer[i][q] = MusEGlobal::denormalBias;
- }
- else
- memset(dstBuffer[i], 0, sizeof(float) * nframes);
- }
- return;
- }
- // Force a source range to fit actual available total out channels.
- if((srcStartChan + srcChans) > srcTotalOutChans)
- srcChans = srcTotalOutChans - srcStartChan;
-
- //---------------------------------------------------
- // apply volume
- // postfader metering
- //---------------------------------------------------
+ // Force a source range to fit actual available total out channels.
+ if((srcStartChan + srcChans) > srcTotalOutChans)
+ srcChans = srcTotalOutChans - srcStartChan;
- #ifdef NODE_DEBUG_PROCESS
- printf("MusE: AudioTrack::copyData trackChans:%d srcTotalOutChans:%d srcStartChan:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcStartChan, srcChans, dstChannels);
- #endif
-
- if(!_prefader)
- {
- for(int c = 0; c < trackChans; ++c)
+ if(srcChans == dstChannels)
{
- meter[c] = 0.0;
- double v = (trackChans == 1 ? _volume : vol[c]);
- float* sp = buffer[c];
- for(unsigned k = 0; k < nframes; ++k)
- {
- float val = *sp++ * v; // If the track is mono pan has no effect on meters.
- double f = fabs(val);
- if(f > meter[c])
- meter[c] = f;
- }
- _meter[c] = meter[c];
- if(_meter[c] > _peak[c])
- _peak[c] = _meter[c];
- }
- }
-
- if(srcChans == dstChannels)
- {
- for(int c = 0; c < dstChannels; ++c)
- {
- double v;
- if(srcStartChan > 2 || _prefader) // Don't apply pan or volume to extra channels above 2. Or if prefader on.
- v = 1.0;
- else
- if(srcChans >= 2) // If 2 channels apply pan normally.
- v = vol[c];
- else
- if(trackChans < 2) // If 1 channel and track is 1 channel, don't apply pan.
- v = _volume;
- else
- v = vol[srcStartChan]; // Otherwise 1 channel but track is 2 channels. Apply the channel volume.
-
- float* sp = buffer[c + srcStartChan];
- float* dp = dstBuffer[c];
-
- if (!add)
- {
- for(unsigned k = 0; k < nframes; ++k)
- *dp++ = (*sp++ * v);
- }
- else // if (add)
+ for(int c = 0; c < dstChannels; ++c)
{
+ float* sp = outBuffers[c + srcStartChan];
+ float* dp = dstBuffer[c];
+ if (!add)
+ AL::dsp->cpy(dp, sp, nframes);
+ else
for(unsigned k = 0; k < nframes; ++k)
- *dp++ += (*sp++ * v);
+ *dp++ += *sp++;
}
}
- }
- else if(srcChans == 1 && dstChannels == 2)
- {
- for(int c = 0; c < dstChannels; ++c)
+ else if(srcChans == 1 && dstChannels == 2)
{
- double v;
- if(srcStartChan > 2 || _prefader) // Don't apply pan or volume to extra channels above 2. Or if prefader on.
- v = 1.0;
- else
- if(trackChans <= 1) // If track is mono apply pan.
- v = vol[c];
- else
- v = vol[srcStartChan]; // Otherwise track is stereo, apply the same channel volume to both.
-
- float* sp = buffer[srcStartChan];
- float* dp = dstBuffer[c];
-
- if (!add)
- {
- for(unsigned k = 0; k < nframes; ++k)
- *dp++ = (*sp++ * v);
- }
- else // if (add)
+ for(int c = 0; c < dstChannels; ++c)
{
+ float* sp;
+ if(!_prefader && srcStartChan == 0 && trackChans == 1)
+ sp = outBuffersExtraMix[c]; // Use the pre-panned mono-to-stereo extra buffers.
+ else
+ sp = outBuffers[srcStartChan]; // In all other cases use the main buffers.
+ float* dp = dstBuffer[c];
+ if (!add)
+ AL::dsp->cpy(dp, sp, nframes);
+ else
for(unsigned k = 0; k < nframes; ++k)
- *dp++ += (*sp++ * v);
+ *dp++ += *sp++;
}
}
- }
- else if(srcChans == 2 && dstChannels == 1)
- {
- double v1 = ((srcStartChan > 2 || _prefader) ? 1.0 : vol[srcStartChan]); // Don't apply pan or volume to extra channels above 2. Or if prefader on.
- double v2 = ((srcStartChan > 2 || _prefader) ? 1.0 : vol[srcStartChan + 1]); //
- float* dp = dstBuffer[0];
- float* sp1 = buffer[srcStartChan];
- float* sp2 = buffer[srcStartChan + 1];
-
- if (!add)
+ else if(srcChans == 2 && dstChannels == 1)
{
+ float* dp = dstBuffer[0];
+ float* sp1 = outBuffers[srcStartChan];
+ float* sp2 = outBuffers[srcStartChan + 1];
+ if (!add)
for(unsigned k = 0; k < nframes; ++k)
- *dp++ = (*sp1++ * v1 + *sp2++ * v2);
- }
- else // if (add)
- {
+ *dp++ = (*sp1++ + *sp2++);
+ else
for(unsigned k = 0; k < nframes; ++k)
- *dp++ += (*sp1++ * v1 + *sp2++ * v2);
+ *dp++ += (*sp1++ + *sp2++);
}
}
}
@@ -753,6 +1125,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr
{
copyData(pos,dstChannels,srcStartChan,srcChannels,nframes,dstBuffer, true);
}
+
//---------------------------------------------------------
// readVolume
//---------------------------------------------------------
@@ -785,67 +1158,6 @@ void AudioTrack::readVolume(Xml& xml)
}
}
-// DELETETHIS 56
-// Removed by T356
-// "recfile" tag not saved anymore
-/*
-
-THIS CODE IS OBSOLETE! _recFile has been changed from SndFile* to SndFileR.
-this code has NOT been adapted!
-
-//---------------------------------------------------------
-// readRecfile
-//---------------------------------------------------------
-
-void AudioTrack::readRecfile(Xml& xml)
- {
- QString path;
- int channels = 2;
- int format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
-
- for (;;) {
- Xml::Token token = xml.parse();
- if (token == Xml::Error || token == Xml::End)
- break;
- const QString& tag = xml.s1();
- switch (token) {
- case Xml::TagStart:
- if (tag == "path")
- path = xml.parse1();
- else if (tag == "channels")
- channels = xml.parseInt();
- else if (tag == "format")
- format = xml.parseInt();
- else if (tag == "samplebits")
- ;
- else
- xml.unknown("recfile");
- break;
- case Xml::TagEnd:
- if (tag == "recfile") {
- if (QFile::exists(path)) {
- setRecFile(getWave(path, true));
- }
- else {
- setRecFile(new SndFile(path));
- recFile()->setFormat(format, channels, sampleRate);
- if (recFile()->openWrite()) {
- fprintf(stderr, "create wave file(%s) failed: %s\n",
- path.toLatin1().constData(), recFile()->strerror().toLatin1().constData());
- delete _recFile;
- _recFile = 0;
- }
- }
- return;
- }
- default:
- break;
- }
- }
- }
-*/
-
-
//---------------------------------------------------------
// setChannels
//---------------------------------------------------------
@@ -949,6 +1261,10 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe
for (int ch = 0; ch < channels; ++ch)
{
void* jackPort = jackPorts[ch];
+
+ // REMOVE Tim. Just a test.
+ //if(jackPort)
+ // MusEGlobal::audioDevice->portLatency(jackPort, true);
// Do not get buffers of unconnected client ports. Causes repeating leftover data, can be loud, or DC !
if (jackPort && MusEGlobal::audioDevice->connections(jackPort))
@@ -1183,6 +1499,9 @@ void AudioOutput::processInit(unsigned nframes)
if (!MusEGlobal::checkAudioDevice()) return;
for (int i = 0; i < channels(); ++i) {
if (jackPorts[i]) {
+
+ //MusEGlobal::audioDevice->portLatency(jackPorts[i], true); // REMOVE Tim. Just a test.
+
buffer[i] = MusEGlobal::audioDevice->getBuffer(jackPorts[i], nframes);
if (MusEGlobal::config.useDenormalBias) {
for (unsigned int j=0; j < nframes; j++)
@@ -1452,6 +1771,23 @@ void Fifo::add()
muse_atomic_inc(&count);
}
+//---------------------------------------------------------
+// setParam
+//---------------------------------------------------------
+
+void AudioTrack::setParam(unsigned long i, float val)
+{
+ addScheduledControlEvent(i, val, MusEGlobal::audio->curFrame());
+}
+
+//---------------------------------------------------------
+// param
+//---------------------------------------------------------
+
+float AudioTrack::param(unsigned long i) const
+{
+ return _controls[i].val;
+}
//---------------------------------------------------------
// setChannels
@@ -1473,35 +1809,30 @@ void AudioTrack::setTotalOutChannels(int num)
int chans = _totalOutChannels;
if(num != chans)
{
- // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
- if(chans < MAX_CHANNELS)
- chans = MAX_CHANNELS;
- if(outBuffers)
- {
- for(int i = 0; i < chans; ++i)
- {
- if(outBuffers[i])
- free(outBuffers[i]);
- }
- delete[] outBuffers;
- }
-
_totalOutChannels = num;
- chans = num;
- // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
+ int new_chans = num;
+ // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
+ if(new_chans < MAX_CHANNELS)
+ new_chans = MAX_CHANNELS;
if(chans < MAX_CHANNELS)
chans = MAX_CHANNELS;
-
- outBuffers = new float*[chans];
- for (int i = 0; i < chans; ++i)
+ if(new_chans != chans)
{
- int rv = posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * MusEGlobal::segmentSize);
- if(rv != 0)
+ if(outBuffers)
{
- fprintf(stderr, "ERROR: AudioTrack::setTotalOutChannels: posix_memalign returned error:%d. Aborting!\n", rv);
- abort();
+ for(int i = 0; i < chans; ++i)
+ {
+ if(outBuffers[i])
+ {
+ free(outBuffers[i]);
+ outBuffers[i] = NULL;
+ }
+ }
+ delete[] outBuffers;
+ outBuffers = NULL;
}
}
+ initBuffers();
}
chans = num;
// Limit the actual track (meters, copying etc, all 'normal' operation) to two-channel stereo.
diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp
index 3029e618..f42a62b8 100644
--- a/muse2/muse/plugin.cpp
+++ b/muse2/muse/plugin.cpp
@@ -4,7 +4,7 @@
// $Id: plugin.cpp,v 1.21.2.23 2009/12/15 22:07:12 spamatica Exp $
//
// (C) Copyright 2000 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -1165,15 +1165,9 @@ Plugin* PluginList::find(const QString& file, const QString& name)
Pipeline::Pipeline()
: std::vector<PluginI*>()
{
- for (int i = 0; i < MAX_CHANNELS; ++i)
- {
- int rv = posix_memalign((void**)(buffer + i), 16, sizeof(float) * MusEGlobal::segmentSize);
- if(rv != 0)
- {
- fprintf(stderr, "ERROR: Pipeline ctor: posix_memalign returned error:%d. Aborting!\n", rv);
- abort();
- }
- }
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ buffer[i] = NULL;
+ initBuffers();
for (int i = 0; i < PipelineDepth; ++i)
push_back(0);
@@ -1183,22 +1177,38 @@ Pipeline::Pipeline()
// Pipeline copy constructor
//---------------------------------------------------------
-Pipeline::Pipeline(const Pipeline& /*p*/)
+Pipeline::Pipeline(const Pipeline& p, AudioTrack* t)
: std::vector<PluginI*>()
{
- for (int i = 0; i < MAX_CHANNELS; ++i)
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ buffer[i] = NULL;
+ initBuffers();
+
+ for(int i = 0; i < PipelineDepth; ++i)
{
- int rv = posix_memalign((void**)(buffer + i), 16, sizeof(float) * MusEGlobal::segmentSize);
- if(rv != 0)
+ PluginI* pli = p[i];
+ if(pli)
{
- fprintf(stderr, "ERROR: Pipeline copy ctor: posix_memalign returned error:%d. Aborting!\n", rv);
- abort();
+ Plugin* pl = pli->plugin();
+ if(pl)
+ {
+ PluginI* new_pl = new PluginI();
+ if(new_pl->initPluginInstance(pl, t->channels())) {
+ fprintf(stderr, "cannot instantiate plugin <%s>\n",
+ pl->name().toLatin1().constData());
+ delete new_pl;
+ }
+ else
+ {
+ // Assigns valid ID and track to plugin, and creates controllers for plugin.
+ t->setupPlugin(new_pl, i);
+ push_back(new_pl);
+ continue;
+ }
+ }
}
+ push_back(NULL); // No plugin. Initialize with NULL.
}
-
- // TODO: Copy plug-ins !
- for (int i = 0; i < PipelineDepth; ++i)
- push_back(0);
}
//---------------------------------------------------------
@@ -1213,6 +1223,33 @@ Pipeline::~Pipeline()
::free(buffer[i]);
}
+void Pipeline::initBuffers()
+{
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ if(!buffer[i])
+ {
+ int rv = posix_memalign((void**)(buffer + i), 16, sizeof(float) * MusEGlobal::segmentSize);
+ if(rv != 0)
+ {
+ fprintf(stderr, "ERROR: Pipeline ctor: posix_memalign returned error:%d. Aborting!\n", rv);
+ abort();
+ }
+ }
+ }
+
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ buffer[i][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(buffer[i], 0, sizeof(float) * MusEGlobal::segmentSize);
+ }
+}
+
//---------------------------------------------------------
// addScheduledControlEvent
// track_ctrl_id is the fully qualified track audio controller number
@@ -1235,29 +1272,24 @@ bool Pipeline::addScheduledControlEvent(int track_ctrl_id, float val, unsigned f
}
//---------------------------------------------------------
-// controllersEnabled
+// controllerEnabled
// Returns whether automation control stream is enabled or disabled.
// Used during automation recording to inhibit gui controls
//---------------------------------------------------------
-void Pipeline::controllersEnabled(int track_ctrl_id, bool* en1, bool* en2)
+bool Pipeline::controllerEnabled(int track_ctrl_id)
{
// If a track controller, or the special dssi synth controller block, just return.
if(track_ctrl_id < AC_PLUGIN_CTL_BASE || track_ctrl_id >= (int)genACnum(MAX_PLUGINS, 0))
- return;
+ return false;
int rack_idx = (track_ctrl_id - AC_PLUGIN_CTL_BASE) >> AC_PLUGIN_CTL_BASE_POW;
for (int i = 0; i < PipelineDepth; ++i)
{
PluginI* p = (*this)[i];
if(p && p->id() == rack_idx)
- {
- if(en1)
- *en1 = p->controllerEnabled(track_ctrl_id & AC_PLUGIN_CTL_ID_MASK);
- if(en2)
- *en2 = p->controllerEnabled2(track_ctrl_id & AC_PLUGIN_CTL_ID_MASK);
- return;
- }
+ return p->controllerEnabled(track_ctrl_id & AC_PLUGIN_CTL_ID_MASK);
}
+ return false;
}
//---------------------------------------------------------
@@ -1529,7 +1561,7 @@ bool Pipeline::nativeGuiVisible(int idx)
// If ports is 0, just process controllers only, not audio (do not 'run').
//---------------------------------------------------------
-void Pipeline::apply(unsigned long ports, unsigned long nframes, float** buffer1)
+void Pipeline::apply(unsigned pos, unsigned long ports, unsigned long nframes, float** buffer1)
{
bool swap = false;
@@ -1543,22 +1575,22 @@ void Pipeline::apply(unsigned long ports, unsigned long nframes, float** buffer1
if (p->inPlaceCapable())
{
if (swap)
- p->apply(nframes, ports, buffer, buffer);
+ p->apply(pos, nframes, ports, buffer, buffer);
else
- p->apply(nframes, ports, buffer1, buffer1);
+ p->apply(pos, nframes, ports, buffer1, buffer1);
}
else
{
if (swap)
- p->apply(nframes, ports, buffer, buffer1);
+ p->apply(pos, nframes, ports, buffer, buffer1);
else
- p->apply(nframes, ports, buffer1, buffer);
+ p->apply(pos, nframes, ports, buffer1, buffer);
swap = !swap;
}
}
else
{
- p->apply(nframes, 0, 0, 0); // Do not process (run) audio, process controllers only.
+ p->apply(pos, nframes, 0, 0, 0); // Do not process (run) audio, process controllers only.
}
}
}
@@ -1937,44 +1969,24 @@ bool PluginI::initPluginInstance(Plugin* plug, int c)
{
if(pd & LADSPA_PORT_INPUT)
{
+ controls[curPort].idx = k;
float val = _plugin->defaultValue(k);
controls[curPort].val = val;
controls[curPort].tmpVal = val;
controls[curPort].enCtrl = true;
- controls[curPort].en2Ctrl = true;
+ for(int i = 0; i < instances; ++i)
+ _plugin->connectPort(handle[i], k, &controls[curPort].val);
++curPort;
}
else
if(pd & LADSPA_PORT_OUTPUT)
{
+ controlsOut[curOutPort].idx = k;
controlsOut[curOutPort].val = 0.0;
controlsOut[curOutPort].tmpVal = 0.0;
controlsOut[curOutPort].enCtrl = false;
- controlsOut[curOutPort].en2Ctrl = false;
- ++curOutPort;
- }
- }
- }
- curPort = 0;
- curOutPort = 0;
- for(unsigned long k = 0; k < ports; ++k)
- {
- LADSPA_PortDescriptor pd = _plugin->portd(k);
- if(pd & LADSPA_PORT_CONTROL)
- {
- if(pd & LADSPA_PORT_INPUT)
- {
- for(int i = 0; i < instances; ++i)
- _plugin->connectPort(handle[i], k, &controls[curPort].val);
- controls[curPort].idx = k;
- ++curPort;
- }
- else
- if(pd & LADSPA_PORT_OUTPUT)
- {
for(int i = 0; i < instances; ++i)
_plugin->connectPort(handle[i], k, &controlsOut[curOutPort].val);
- controlsOut[curOutPort].idx = k;
++curOutPort;
}
}
@@ -2375,16 +2387,6 @@ void PluginI::enableAllControllers(bool v)
}
//---------------------------------------------------------
-// enable2AllControllers
-//---------------------------------------------------------
-
-void PluginI::enable2AllControllers(bool v)
-{
- for(unsigned long i = 0; i < controlPorts; ++i)
- controls[i].en2Ctrl = v;
-}
-
-//---------------------------------------------------------
// titlePrefix
//---------------------------------------------------------
@@ -2400,246 +2402,217 @@ QString PluginI::titlePrefix() const
// If ports is 0, just process controllers only, not audio (do not 'run').
//---------------------------------------------------------
-
-void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut)
+void PluginI::apply(unsigned pos, unsigned long n, unsigned long ports, float** bufIn, float** bufOut)
{
- unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
- unsigned long sample = 0;
-
- // Must make this detectable for dssi vst effects.
- const bool usefixedrate = _plugin->_isDssiVst; // Try this. (was: = true; )
+ const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
+ unsigned long sample = 0;
+
+ // Must make this detectable for dssi vst effects.
+ const bool usefixedrate = _plugin->_isDssiVst;
+
+ // 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.
+ // 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.
+ const unsigned long min_per = (usefixedrate || MusEGlobal::config.minControlProcessPeriod > n) ? n : MusEGlobal::config.minControlProcessPeriod;
+ const unsigned long min_per_mask = min_per-1; // min_per must be power of 2
+
+ AutomationType at = AUTO_OFF;
+ CtrlListList* cll = NULL;
+ ciCtrlList icl_first;
+ if(_track)
+ {
+ at = _track->automationType();
+ cll = _track->controller();
+ if(_id != -1 && ports != 0) // Don't bother if not 'running'.
+ icl_first = cll->lower_bound(genACnum(_id, 0));
+ }
+ const bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
+ const unsigned long in_ctrls = _plugin->controlInPorts();
- // 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 long fixedsize = n; // was: 2048
-
- // 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;
-
- unsigned long min_per = MusEGlobal::config.minControlProcessPeriod;
- if(min_per > n)
- min_per = n;
-
- // CtrlListList* cll = NULL; // WIP
- AutomationType at = AUTO_OFF;
- if(_track)
- {
- at = _track->automationType();
- //cll = _track->controller(); // WIP
- }
- bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
-
- while(sample < n)
+ // Special for plugins: Deal with tmpVal. TODO: Get rid of tmpVal, maybe by using the FIFO...
+ for(unsigned long k = 0; k < controlPorts; ++k)
+ controls[k].val = controls[k].tmpVal;
+
+ int cur_slice = 0;
+ while(sample < n)
+ {
+ unsigned long nsamp = n - sample;
+ const unsigned long slice_frame = pos + sample;
+
+ // Process automation control values, while also determining the maximum acceptable
+ // size of this run. Further processing, from FIFOs for example, can lower the size
+ // from there, but this section determines where the next highest maximum frame
+ // absolutely needs to be for smooth playback of the controller value stream...
+ //
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ ciCtrlList icl = icl_first;
+ for(unsigned long k = 0; k < controlPorts; ++k)
{
- // nsamp is the number of samples the plugin->process() call will be supposed to do
- unsigned long nsamp = usefixedrate ? fixedsize : n - sample;
-
- //
- // Process automation control values, while also determining the maximum acceptable
- // size of this run. Further processing, from FIFOs for example, can lower the size
- // from there, but this section determines where the next highest maximum frame
- // absolutely needs to be for smooth playback of the controller value stream...
- //
- if(_track && _id != -1 && ports != 0) // Don't bother if not 'running'.
+ CtrlList* cl = (cll && _id != -1 && icl != cll->end()) ? icl->second : NULL;
+ CtrlInterpolate& ci = controls[k].interp;
+ // Always refresh the interpolate struct at first, since things may have changed.
+ // Or if the frame is outside of the interpolate range - and eStop is not true. // FIXME TODO: Be sure these comparisons are correct.
+ if(cur_slice == 0 || (!ci.eStop && MusEGlobal::audio->isPlaying() &&
+ (slice_frame < (unsigned long)ci.sFrame || (ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame)) ) )
{
- unsigned long frame = MusEGlobal::audio->pos().frame() + sample;
- int nextFrame;
- //double val; // WIP
- for(unsigned long k = 0; k < controlPorts; ++k)
+ if(cl && _id != -1 && (unsigned long)cl->id() == genACnum(_id, k))
+ {
+ cl->getInterpolation(slice_frame, no_auto || !controls[k].enCtrl, &ci);
+ if(icl != cll->end())
+ ++icl;
+ }
+ else
{
+ // No matching controller, or end. Just copy the current value into the interpolator.
+ // Keep the current icl iterator, because since they are sorted by frames,
+ // if the IDs didn't match it means we can just let k catch up with icl.
+ ci.sFrame = 0;
+ ci.eFrame = -1;
+ ci.sVal = controls[k].val;
+ ci.eVal = ci.sVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ }
+ else
+ {
+ if(ci.eStop && ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame) // FIXME TODO: Get that comparison right.
+ {
+ // Clear the stop condition and set up the interp struct appropriately as an endless value.
+ ci.sFrame = 0; //ci->eFrame;
+ ci.eFrame = -1;
+ ci.sVal = ci.eVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ if(cl && cll && icl != cll->end())
+ ++icl;
+ }
-
-#if 0 // WIP - Work in progress. Tim.
+ if(!usefixedrate && MusEGlobal::audio->isPlaying())
+ {
+ unsigned long samps = nsamp;
+ if(ci.eFrame != -1)
+ samps = (unsigned long)ci.eFrame - slice_frame;
- ciCtrlList icl = cll->find(genACnum(_id, k));
- if(icl == cll->end())
- continue;
- CtrlList* cl = icl->second;
- if(no_auto || !controls[k].enCtrl || !controls[k].en2Ctrl || cl->empty())
- {
- nextFrame = -1;
- val = cl->curVal();
- }
- else
- {
- ciCtrl i = cl->upper_bound(frame); // get the index after current frame
- if (i == cl->end()) { // if we are past all items just return the last value
- --i;
- nextFrame = -1;
- val = i->second.val;
- }
- else if(cl->mode() == CtrlList::DISCRETE)
- {
- if(i == cl->begin())
- {
- nextFrame = i->second.frame;
- val = i->second.val;
- }
- else
- {
- nextFrame = i->second.frame;
- --i;
- val = i->second.val;
- }
- }
- else { // INTERPOLATE
- if (i == cl->begin()) {
- nextFrame = i->second.frame;
- val = i->second.val;
- }
- else {
- int frame2 = i->second.frame;
- double val2 = i->second.val;
- --i;
- int frame1 = i->second.frame;
- double val1 = i->second.val;
-
-
- if(val2 != val1)
- nextFrame = 0; // Zero signifies the next frame should be determined by caller.
- else
- nextFrame = frame2;
-
- if (cl->valueType() == VAL_LOG) {
- val1 = 20.0*fast_log10(val1);
- if (val1 < MusEGlobal::config.minSlider)
- val1=MusEGlobal::config.minSlider;
- val2 = 20.0*fast_log10(val2);
- if (val2 < MusEGlobal::config.minSlider)
- val2=MusEGlobal::config.minSlider;
- }
+ if(!ci.doInterp && samps > min_per)
+ {
+ samps &= ~min_per_mask;
+ if((samps & min_per_mask) != 0)
+ samps += min_per;
+ }
+ else
+ samps = min_per;
- val2 -= val1;
- val1 += (double(frame - frame1) * val2)/double(frame2 - frame1);
-
- if (cl->valueType() == VAL_LOG) {
- val1 = exp10(val1/20.0);
- }
+ if(samps < nsamp)
+ nsamp = samps;
+
+ }
+
+ if(ci.doInterp && cl)
+ controls[k].val = cl->interpolate(MusEGlobal::audio->isPlaying() ? slice_frame : pos, ci);
+ else
+ controls[k].val = ci.sVal;
+
+ controls[k].tmpVal = controls[k].val; // Special for plugins: Deal with tmpVal.
- val = val1;
- }
- }
- }
-
- controls[k].tmpVal = val;
-
-
-#else
- controls[k].tmpVal = _track->controller()->value(genACnum(_id, k), frame,
- no_auto || !controls[k].enCtrl || !controls[k].en2Ctrl,
- &nextFrame);
-#endif
-
-
#ifdef PLUGIN_DEBUGIN_PROCESS
- printf("PluginI::apply k:%lu sample:%lu frame:%lu nextFrame:%d nsamp:%lu \n", k, sample, frame, nextFrame, nsamp);
+ printf("PluginI::apply k:%lu sample:%lu frame:%lu nextFrame:%d nsamp:%lu \n", k, sample, frame, ci.eFrame, nsamp);
#endif
- if(MusEGlobal::audio->isPlaying() && !usefixedrate && nextFrame != -1)
- {
- // Returned value of nextFrame can be zero meaning caller replaces with some (constant) value.
- unsigned long samps = (unsigned long)nextFrame;
- if(samps > frame + min_per)
- {
- unsigned long diff = samps - frame;
- unsigned long mask = min_per-1; // min_per must be power of 2
- samps = diff & ~mask;
- if((diff & mask) != 0)
- samps += min_per;
- }
- else
- samps = min_per;
-
- if(samps < nsamp)
- nsamp = samps;
- }
- }
-
+ }
+ }
+
#ifdef PLUGIN_DEBUGIN_PROCESS
- printf("PluginI::apply sample:%lu nsamp:%lu\n", sample, nsamp);
+ printf("PluginI::apply sample:%lu nsamp:%lu\n", sample, nsamp);
#endif
- }
-
- //
- // Process all control ring buffer items valid for this time period...
- //
- bool found = false;
- unsigned long frame = 0;
- unsigned long index = 0;
- unsigned long evframe;
- while(!_controlFifo.isEmpty())
- {
- ControlEvent v = _controlFifo.peek();
- // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
- // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.
- evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n;
- // Process only items in this time period. Make sure to process all
- // subsequent items which have the same frame.
-
- // Protection. Observed this condition. Why? Supposed to be linear timestamps.
- if(found && evframe < frame)
- {
- printf("PluginI::apply *** Error: evframe:%lu < frame:%lu idx:%lu val:%f unique:%d\n",
- evframe, v.frame, v.idx, v.value, v.unique);
- // No choice but to ignore it.
- _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
- continue;
- }
-
- // process control events up to the end of our processing cycle.
- // but stop after a control event was found (then process(),
- // then loop here again), but ensure that process() must process
- // at least min_per frames.
- if(evframe >= n // Next events are for a later period.
- || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
- || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
- || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
- break;
- _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
+ //
+ // Process all control ring buffer items valid for this time period...
+ //
+ bool found = false;
+ unsigned long frame = 0;
+ unsigned long index = 0;
+ unsigned long evframe;
+ // Get all control ring buffer items valid for this time period...
+ while(!_controlFifo.isEmpty())
+ {
+ ControlEvent v = _controlFifo.peek();
+ // The events happened in the last period or even before that. Shift into this period with + n. This will sync with audio.
+ // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.
+ evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n;
+
+ #ifdef PLUGIN_DEBUGIN_PROCESS
+ fprintf(stderr, "PluginI::apply found:%d evframe:%lu frame:%lu event frame:%lu idx:%lu val:%f unique:%d\n",
+ found, evframe, frame, v.frame, v.idx, v.value, v.unique);
+ #endif
- if(v.idx >= _plugin->_controlInPorts) // Sanity check
- break;
+ // Protection. Observed this condition. Why? Supposed to be linear timestamps.
+ if(found && evframe < frame)
+ {
+ fprintf(stderr, "PluginI::apply *** Error: evframe:%lu < frame:%lu event: frame:%lu idx:%lu val:%f unique:%d\n",
+ evframe, frame, v.frame, v.idx, v.value, v.unique);
+
+ // No choice but to ignore it.
+ _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
+ continue;
+ }
- found = true;
- frame = evframe;
- index = v.idx;
+ if(evframe >= n // Next events are for a later period.
+ || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
+ || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
+ || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
+ break;
+ _controlFifo.remove(); // Done with the ring buffer's item. Remove it.
- 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)
- _track->setPluginCtrlVal(genACnum(_id, v.idx), v.value);
- }
+ if(v.idx >= in_ctrls) // Sanity check
+ break;
- // 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 && !usefixedrate) // If a control FIFO item was found, takes priority over automation controller stream.
- nsamp = frame - sample;
+ found = true;
+ frame = evframe;
+ index = v.idx;
- if(sample + nsamp >= n) // Safety check.
- nsamp = n - sample;
-
- // TODO: 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;
-
- if(ports != 0)
- {
- connect(ports, sample, bufIn, bufOut);
-
- for(int i = 0; i < instances; ++i)
- _plugin->apply(handle[i], nsamp);
- }
-
- sample += nsamp;
+ if(ports == 0) // Don't bother if not 'running'.
+ controls[v.idx].val = controls[v.idx].tmpVal = v.value; // Might as well at least update these.
+ else
+ {
+ CtrlInterpolate* ci = &controls[v.idx].interp;
+ // Tell it to stop the current ramp at this frame, when it does stop, set this value:
+ ci->eFrame = frame;
+ ci->eVal = v.value;
+ ci->eStop = true;
}
+
+ // Need to update the automation value, otherwise it overwrites later with the last automation value.
+ if(_track && _id != -1)
+ _track->setPluginCtrlVal(genACnum(_id, v.idx), v.value);
+ }
+
+ if(found && !usefixedrate) // If a control FIFO item was found, takes priority over automation controller stream.
+ nsamp = frame - sample;
+
+ if(sample + nsamp > n) // Safety check.
+ nsamp = n - sample;
+
+ // TODO: 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)
+ {
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ connect(ports, sample, bufIn, bufOut);
+
+ for(int i = 0; i < instances; ++i)
+ _plugin->apply(handle[i], nsamp);
+ }
+
+ sample += nsamp;
+ }
+
+ ++cur_slice; // Slice is done. Moving on to any next slice now...
+ }
}
//---------------------------------------------------------
@@ -2783,7 +2756,6 @@ int PluginI::oscControl(unsigned long port, float value)
// Convert from DSSI port number to control input port index.
unsigned long cport = _plugin->rpIdx[port];
- //unsigned long cport = _plugin->port2InCtrl(port);
if((int)cport == -1)
{
@@ -2791,77 +2763,48 @@ int PluginI::oscControl(unsigned long port, float value)
return 0;
}
+ // 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: 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)
+ {
+ unsigned long id = genACnum(_id, cport);
+ _track->recordAutomation(id, value);
+ }
+
// (From DSSI module).
// p3.3.39 Set the DSSI control input port's value.
// Observations: With a native DSSI synth like LessTrivialSynth, the native GUI's controls do not change the sound at all
- // ie. they don't update the DSSI control port values themselves.
+ // ie. they don't update the DSSI control port values themselves.
// Hence in response to the call to this oscControl, sent by the native GUI, it is required to that here.
/// controls[cport].val = value;
// DSSI-VST synths however, unlike DSSI synths, DO change their OWN sound in response to their gui controls.
- // AND this function is called !
- // Despite the descrepency we are STILL required to update the DSSI control port values here
- // because dssi-vst is WAITING FOR A RESPONSE! (A CHANGE in the control port value).
+ // AND this function is called !
+ // Despite the descrepency we are STILL required to update the DSSI control port values here
+ // 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: May need FIFOs on each control(!) so that the control changes get sent one per process cycle!
+ // 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 ...
- /* DELETETHIS 20
- OscControlFifo* cfifo = _oscif.oscFifo(cport);
- if(cfifo)
- {
- OscControlValue cv;
- //cv.idx = cport;
- cv.value = value;
- // Time-stamp the event. Looks like no choice but to use the (possibly slow) call to gettimeofday via timestamp(),
- // because these are asynchronous events arriving from OSC. 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.) p4.0.15 Tim.
- cv.frame = MusEGlobal::audio->timestamp();
- if(cfifo->put(cv))
- {
- fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%lu\n", cport);
- }
- }
- */
+
+ // Schedules a timed control change:
ControlEvent ce;
ce.unique = _plugin->_isDssiVst; // Special for messages from vst gui to host - requires processing every message.
- ce.fromGui = true; // It came form the plugin's own GUI.
+ ce.fromGui = true; // It came from the plugin's own GUI.
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 = MusEGlobal::audio->timestamp();
- // p4.0.23 timestamp() is circular, which is making it impossible to deal with 'modulo' events which
- // slip in 'under the wire' before processing the ring buffers. So try this linear timestamp instead:
- ce.frame = MusEGlobal::audio->curFrame();
+ // Don't use timestamp(), because it's circular, which is making it impossible to deal
+ // with 'modulo' events which slip in 'under the wire' before processing the ring buffers.
+ ce.frame = MusEGlobal::audio->curFrame();
if(_controlFifo.put(ce))
- {
fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%lu\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: 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)
- {
- unsigned long id = genACnum(_id, cport);
- 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) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()))
- enableController(cport, false); //TODO maybe re-enable the ctrl soon?
-
- _track->recordAutomation(id, value);
- }
-
+
+ enableController(cport, false); //TODO maybe re-enable the ctrl soon?
+
/* DELETETHIS 12
const DSSI_Descriptor* dssi = synth->dssi;
const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
@@ -3478,9 +3421,10 @@ PluginGui::PluginGui(MusECore::PluginIBase* p)
mapperReleased->setMapping(obj, nobj);
mapperContextMenuReq->setMapping(obj, nobj);
- gw[nobj].widget = (QWidget*)obj;
- gw[nobj].param = parameter;
- gw[nobj].type = -1;
+ gw[nobj].widget = (QWidget*)obj;
+ gw[nobj].param = parameter;
+ gw[nobj].type = -1;
+ gw[nobj].pressed = false;
if (strcmp(obj->metaObject()->className(), "MusEGui::Slider") == 0) {
gw[nobj].type = GuiWidgets::SLIDER;
@@ -3559,6 +3503,7 @@ PluginGui::PluginGui(MusECore::PluginIBase* p)
double dupper = upper;
double val = plugin->param(i);
double dval = val;
+ params[i].pressed = false;
params[i].hint = range.HintDescriptor;
getPluginConvertedValues(range, lower, upper, dlower, dupper, dval);
@@ -3636,11 +3581,12 @@ PluginGui::PluginGui(MusECore::PluginIBase* p)
QLabel* label = 0;
LADSPA_PortRangeHint range = plugin->rangeOut(i);
double lower = 0.0; // default values
- double upper = 1.0;
+ double upper = 32768.0; // Many latency outs have no hints so set this arbitrarily high
double dlower = lower;
double dupper = upper;
double val = plugin->paramOut(i);
double dval = val;
+ paramsOut[i].pressed = false;
paramsOut[i].hint = range.HintDescriptor;
getPluginConvertedValues(range, lower, upper, dlower, dupper, dval);
@@ -3733,48 +3679,39 @@ void PluginGui::heartBeat()
void PluginGui::ctrlPressed(int param)
{
- AutomationType at = AUTO_OFF;
+ params[param].pressed = true;
MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- plugin->enableController(param, false);
-
int id = plugin->id();
-
- if(id == -1)
- return;
-
- id = MusECore::genACnum(id, param);
-
- if(params[param].type == GuiParam::GUI_SLIDER)
+ if(id != -1)
{
- 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))
- val = rint(val);
- plugin->setParam(param, val);
- ((DoubleLabel*)params[param].label)->setValue(val);
-
- if(track)
+ id = MusECore::genACnum(id, param);
+ if(params[param].type == GuiParam::GUI_SLIDER)
{
- track->setPluginCtrlVal(id, val);
- track->startAutoRecord(id, val);
+ 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))
+ val = rint(val);
+ params[param].label->blockSignals(true);
+ params[param].label->setValue(val);
+ params[param].label->blockSignals(false);
+ if(track)
+ {
+ track->startAutoRecord(id, val);
+ track->setPluginCtrlVal(id, val);
+ }
}
- }
- else if(params[param].type == GuiParam::GUI_SWITCH)
- {
- float val = (float)((CheckBox*)params[param].actuator)->isChecked();
- plugin->setParam(param, val);
-
- if(track)
+ else if(params[param].type == GuiParam::GUI_SWITCH)
{
- track->setPluginCtrlVal(id, val);
- track->startAutoRecord(id, val);
+ float val = (float)((CheckBox*)params[param].actuator)->isChecked();
+ if(track)
+ {
+ track->startAutoRecord(id, val);
+ track->setPluginCtrlVal(id, val);
+ }
}
}
+ plugin->enableController(param, false);
}
//---------------------------------------------------------
@@ -3787,28 +3724,29 @@ void PluginGui::ctrlReleased(int param)
MusECore::AudioTrack* track = plugin->track();
if(track)
at = track->automationType();
-
+
+ int id = plugin->id();
+ if(track && id != -1)
+ {
+ id = MusECore::genACnum(id, param);
+ if(params[param].type == GuiParam::GUI_SLIDER)
+ {
+ 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))
+ val = rint(val);
+ track->stopAutoRecord(id, val);
+ }
+ }
+
// Special for switch - don't enable controller until transport stopped.
if ((at == AUTO_OFF) ||
- (at == AUTO_READ) ||
(at == AUTO_TOUCH && (params[param].type != GuiParam::GUI_SWITCH ||
!MusEGlobal::audio->isPlaying()) ) )
plugin->enableController(param, true);
- int id = plugin->id();
- if(!track || id == -1)
- return;
- id = MusECore::genACnum(id, param);
-
- if(params[param].type == GuiParam::GUI_SLIDER)
- {
- 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))
- val = rint(val);
- track->stopAutoRecord(id, val);
- }
+ params[param].pressed = false;
}
//---------------------------------------------------------
@@ -3828,35 +3766,24 @@ void PluginGui::ctrlRightClicked(const QPoint &p, int param)
void PluginGui::sliderChanged(double val, int param, bool shift_pressed)
{
- AutomationType at = AUTO_OFF;
MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- plugin->enableController(param, false);
-
+
if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
val = pow(10.0, val/20.0);
else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
val = rint(val);
-
- if (plugin->param(param) != val) {
- plugin->setParam(param, val);
- ((DoubleLabel*)params[param].label)->setValue(val);
- }
-
+
+ params[param].label->blockSignals(true);
+ params[param].label->setValue(val);
+ params[param].label->blockSignals(false);
int id = plugin->id();
- if(id == -1)
- return;
- id = MusECore::genACnum(id, param);
-
- if(track)
+ if(track && id != -1)
{
- track->setPluginCtrlVal(id, val);
+ id = MusECore::genACnum(id, param);
if (!shift_pressed) track->recordAutomation(id, val); //with shift, we get straight lines :)
- }
+ }
+ plugin->setParam(param, val); // Schedules a timed control change.
+ plugin->enableController(param, false);
}
//---------------------------------------------------------
@@ -3865,36 +3792,24 @@ void PluginGui::sliderChanged(double val, int param, bool shift_pressed)
void PluginGui::labelChanged(double val, int param)
{
- AutomationType at = AUTO_OFF;
MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- plugin->enableController(param, false);
-
+
double dval = val;
if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
dval = MusECore::fast_log10(val) * 20.0;
else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
dval = rint(val);
- if (plugin->param(param) != val) {
- plugin->setParam(param, val);
- ((Slider*)params[param].actuator)->setValue(dval);
- }
-
+ params[param].actuator->blockSignals(true);
+ ((Slider*)params[param].actuator)->setValue(dval);
+ params[param].actuator->blockSignals(false);
int id = plugin->id();
- if(id == -1)
- return;
-
- id = MusECore::genACnum(id, param);
-
- if(track)
+ if(track && id != -1)
{
- track->setPluginCtrlVal(id, val);
+ id = MusECore::genACnum(id, param);
track->startAutoRecord(id, val);
- }
+ }
+ plugin->setParam(param, val); // Schedules a timed control change.
+ plugin->enableController(param, false);
}
//---------------------------------------------------------
@@ -4032,12 +3947,18 @@ void PluginGui::updateValues()
{
sv = rint(lv);
lv = sv;
- }
+ }
+ gp->label->blockSignals(true);
+ gp->actuator->blockSignals(true);
gp->label->setValue(lv);
((Slider*)(gp->actuator))->setValue(sv);
+ gp->label->blockSignals(false);
+ gp->actuator->blockSignals(false);
}
else if (gp->type == GuiParam::GUI_SWITCH) {
+ gp->actuator->blockSignals(true);
((CheckBox*)(gp->actuator))->setChecked(int(plugin->param(i)));
+ gp->actuator->blockSignals(false);
}
}
}
@@ -4047,6 +3968,7 @@ void PluginGui::updateValues()
int type = gw[i].type;
unsigned long param = gw[i].param;
float val = plugin->param(param);
+ widget->blockSignals(true);
switch(type) {
case GuiWidgets::SLIDER:
((Slider*)widget)->setValue(val); // Note conversion to double
@@ -4061,6 +3983,7 @@ void PluginGui::updateValues()
((QComboBox*)widget)->setCurrentIndex(int(val));
break;
}
+ widget->blockSignals(false);
}
}
}
@@ -4098,126 +4021,93 @@ void PluginGui::updateControls()
if (params) {
- for (unsigned long i = 0; i < plugin->parameters(); ++i) {
- GuiParam* gp = &params[i];
- if (gp->type == GuiParam::GUI_SLIDER) {
- {
- double lv = plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), i),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(i) ||
- !plugin->controllerEnabled2(i));
- double sv = lv;
- if (LADSPA_IS_HINT_LOGARITHMIC(params[i].hint))
- sv = MusECore::fast_log10(lv) * 20.0;
- else
- if (LADSPA_IS_HINT_INTEGER(params[i].hint))
- {
- sv = rint(lv);
- lv = sv;
- }
- if(((Slider*)(gp->actuator))->value() != sv)
+ for (unsigned long i = 0; i < plugin->parameters(); ++i) {
+ GuiParam* gp = &params[i];
+ if(gp->pressed) // Inhibit the controller stream if control is currently pressed.
+ continue;
+ double v = plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), i),
+ MusEGlobal::audio->curFramePos(),
+ !MusEGlobal::automation ||
+ plugin->track()->automationType() == AUTO_OFF ||
+ !plugin->controllerEnabled(i));
+ if (gp->type == GuiParam::GUI_SLIDER) {
{
- gp->label->blockSignals(true);
- ((Slider*)(gp->actuator))->blockSignals(true);
- ((Slider*)(gp->actuator))->setValue(sv);
- gp->label->setValue(lv);
- ((Slider*)(gp->actuator))->blockSignals(false);
- gp->label->blockSignals(false);
- }
+ double sv = v;
+ if (LADSPA_IS_HINT_LOGARITHMIC(params[i].hint))
+ sv = MusECore::fast_log10(v) * 20.0;
+ else
+ if (LADSPA_IS_HINT_INTEGER(params[i].hint))
+ {
+ sv = rint(v);
+ v = sv;
+ }
+ if(((Slider*)(gp->actuator))->value() != sv)
+ {
+ gp->label->blockSignals(true);
+ gp->actuator->blockSignals(true);
+ ((Slider*)(gp->actuator))->setValue(sv);
+ gp->label->setValue(v);
+ gp->actuator->blockSignals(false);
+ gp->label->blockSignals(false);
+ }
+ }
}
- }
- else if (gp->type == GuiParam::GUI_SWITCH) {
- {
- bool v = (int)plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), i),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(i) ||
- !plugin->controllerEnabled2(i));
- if(((CheckBox*)(gp->actuator))->isChecked() != v)
+ else if (gp->type == GuiParam::GUI_SWITCH) {
{
- ((CheckBox*)(gp->actuator))->blockSignals(true);
- ((CheckBox*)(gp->actuator))->setChecked(v);
- ((CheckBox*)(gp->actuator))->blockSignals(false);
- }
+ bool b = (int)v;
+ if(((CheckBox*)(gp->actuator))->isChecked() != b)
+ {
+ gp->actuator->blockSignals(true);
+ ((CheckBox*)(gp->actuator))->setChecked(b);
+ gp->actuator->blockSignals(false);
+ }
+ }
}
- }
- }
+ }
}
else if (gw) {
- for (unsigned long i = 0; i < nobj; ++i) {
+ for (unsigned long i = 0; i < nobj; ++i) {
+ if(gw[i].pressed) // Inhibit the controller stream if control is currently pressed.
+ continue;
QWidget* widget = gw[i].widget;
int type = gw[i].type;
- unsigned long param = gw[i].param;
+ unsigned long param = gw[i].param;
+ double v = plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), param),
+ MusEGlobal::audio->curFramePos(),
+ !MusEGlobal::automation ||
+ plugin->track()->automationType() == AUTO_OFF ||
+ !plugin->controllerEnabled(param));
+ widget->blockSignals(true);
switch(type) {
case GuiWidgets::SLIDER:
{
- double v = plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), param),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(param) ||
- !plugin->controllerEnabled2(param));
if(((Slider*)widget)->value() != v)
- {
- ((Slider*)widget)->blockSignals(true);
((Slider*)widget)->setValue(v);
- ((Slider*)widget)->blockSignals(false);
- }
}
break;
case GuiWidgets::DOUBLE_LABEL:
{
- double v = plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), param),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(param) ||
- !plugin->controllerEnabled2(param));
if(((DoubleLabel*)widget)->value() != v)
- {
- ((DoubleLabel*)widget)->blockSignals(true);
((DoubleLabel*)widget)->setValue(v);
- ((DoubleLabel*)widget)->blockSignals(false);
- }
}
break;
case GuiWidgets::QCHECKBOX:
- {
- bool b = (bool) plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), param),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(param) ||
- !plugin->controllerEnabled2(param));
+ {
+ bool b = (bool)v;
if(((QCheckBox*)widget)->isChecked() != b)
- {
- ((QCheckBox*)widget)->blockSignals(true);
((QCheckBox*)widget)->setChecked(b);
- ((QCheckBox*)widget)->blockSignals(false);
- }
}
break;
case GuiWidgets::QCOMBOBOX:
- {
- int n = (int) plugin->track()->controller()->value(MusECore::genACnum(plugin->id(), param),
- MusEGlobal::audio->curFramePos(),
- !MusEGlobal::automation ||
- plugin->track()->automationType() == AUTO_OFF ||
- !plugin->controllerEnabled(param) ||
- !plugin->controllerEnabled2(param));
+ {
+ int n = (int)v;
if(((QComboBox*)widget)->currentIndex() != n)
- {
- ((QComboBox*)widget)->blockSignals(true);
((QComboBox*)widget)->setCurrentIndex(n);
- ((QComboBox*)widget)->blockSignals(false);
- }
}
break;
}
- }
+ widget->blockSignals(false);
+ }
}
}
@@ -4228,18 +4118,11 @@ void PluginGui::updateControls()
void PluginGui::guiParamChanged(int idx)
{
QWidget* w = gw[idx].widget;
- unsigned long param = gw[idx].param;
+ unsigned long param = gw[idx].param;
int type = gw[idx].type;
- AutomationType at = AUTO_OFF;
MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
- if ( (at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
- plugin->enableController(param, false);
-
+
double val = 0.0;
switch(type) {
case GuiWidgets::SLIDER:
@@ -4256,11 +4139,12 @@ void PluginGui::guiParamChanged(int idx)
break;
}
- for (unsigned long i = 0; i < nobj; ++i) {
+ for (unsigned long i = 0; i < nobj; ++i) {
QWidget* widget = gw[i].widget;
if (widget == w || param != gw[i].param)
continue;
int type = gw[i].type;
+ widget->blockSignals(true);
switch(type) {
case GuiWidgets::SLIDER:
((Slider*)widget)->setValue(val);
@@ -4275,14 +4159,14 @@ void PluginGui::guiParamChanged(int idx)
((QComboBox*)widget)->setCurrentIndex(int(val));
break;
}
+ widget->blockSignals(false);
}
-
+
int id = plugin->id();
if(track && id != -1)
{
id = MusECore::genACnum(id, param);
- track->setPluginCtrlVal(id, val);
- switch(type)
+ switch(type)
{
case GuiWidgets::DOUBLE_LABEL:
case GuiWidgets::QCHECKBOX:
@@ -4290,10 +4174,12 @@ void PluginGui::guiParamChanged(int idx)
break;
default:
track->recordAutomation(id, val);
- break;
- }
- }
- plugin->setParam(param, val);
+ break;
+ }
+ }
+
+ plugin->setParam(param, val); // Schedules a timed control change.
+ plugin->enableController(param, false);
}
//---------------------------------------------------------
@@ -4302,27 +4188,20 @@ void PluginGui::guiParamChanged(int idx)
void PluginGui::guiParamPressed(int idx)
{
- unsigned long param = gw[idx].param;
-
- AutomationType at = AUTO_OFF;
- MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- plugin->enableController(param, false);
-
- int id = plugin->id();
- if(!track || id == -1)
- return;
-
- id = MusECore::genACnum(id, param);
-
+ gw[idx].pressed = true;
+ unsigned long param = gw[idx].param;
+ plugin->enableController(param, false);
+
+ //MusECore::AudioTrack* track = plugin->track();
+ //int id = plugin->id();
+ //if(!track || id == -1)
+ // return;
+ //id = MusECore::genACnum(id, param);
// NOTE: For this to be of any use, the freeverb gui 2142.ui
// would have to be used, and changed to use CheckBox and ComboBox
// instead of QCheckBox and QComboBox, since both of those would
// need customization (Ex. QCheckBox doesn't check on click). RECHECK: Qt4 it does?
- /*
+ /*
switch(type) {
case GuiWidgets::QCHECKBOX:
double val = (double)((CheckBox*)w)->isChecked();
@@ -4333,7 +4212,7 @@ void PluginGui::guiParamPressed(int idx)
track->startAutoRecord(id, val);
break;
}
- */
+ */
}
//---------------------------------------------------------
@@ -4352,18 +4231,14 @@ void PluginGui::guiParamReleased(int idx)
// Special for switch - don't enable controller until transport stopped.
if ((at == AUTO_OFF) ||
- (at == AUTO_READ) ||
(at == AUTO_TOUCH && (type != GuiWidgets::QCHECKBOX ||
!MusEGlobal::audio->isPlaying()) ) )
plugin->enableController(param, true);
- int id = plugin->id();
-
- if(!track || id == -1)
- return;
-
- id = MusECore::genACnum(id, param);
-
+ //int id = plugin->id();
+ //if(!track || id == -1)
+ // return;
+ //id = MusECore::genACnum(id, param);
// NOTE: For this to be of any use, the freeverb gui 2142.ui
// would have to be used, and changed to use CheckBox and ComboBox
// instead of QCheckBox and QComboBox, since both of those would
@@ -4380,6 +4255,8 @@ void PluginGui::guiParamReleased(int idx)
break;
}
*/
+
+ gw[idx].pressed = false;
}
//---------------------------------------------------------
@@ -4387,53 +4264,44 @@ void PluginGui::guiParamReleased(int idx)
//---------------------------------------------------------
void PluginGui::guiSliderPressed(int idx)
- {
- unsigned long param = gw[idx].param;
+{
+ gw[idx].pressed = true;
+ unsigned long param = gw[idx].param;
QWidget *w = gw[idx].widget;
-
- AutomationType at = AUTO_OFF;
MusECore::AudioTrack* track = plugin->track();
- if(track)
- at = track->automationType();
-
int id = plugin->id();
-
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- plugin->enableController(param, false);
-
- if(!track || id == -1)
- return;
-
- id = MusECore::genACnum(id, param);
-
- double val = ((Slider*)w)->value();
- plugin->setParam(param, val);
-
- track->setPluginCtrlVal(id, val);
- track->startAutoRecord(id, val);
-
- // Needed so that paging a slider updates a label or other buddy control.
- for (unsigned long i = 0; i < nobj; ++i) {
- QWidget* widget = gw[i].widget;
- if (widget == w || param != gw[i].param)
- continue;
- int type = gw[i].type;
- switch(type) {
- case GuiWidgets::SLIDER:
- ((Slider*)widget)->setValue(val);
- break;
- case GuiWidgets::DOUBLE_LABEL:
- ((DoubleLabel*)widget)->setValue(val);
- break;
- case GuiWidgets::QCHECKBOX:
- ((QCheckBox*)widget)->setChecked(int(val));
- break;
- case GuiWidgets::QCOMBOBOX:
- ((QComboBox*)widget)->setCurrentIndex(int(val));
- break;
- }
- }
+ if(track && id != -1)
+ {
+ id = MusECore::genACnum(id, param);
+ double val = ((Slider*)w)->value();
+ track->startAutoRecord(id, val);
+ // Needed so that paging a slider updates a label or other buddy control.
+ for (unsigned long i = 0; i < nobj; ++i) {
+ QWidget* widget = gw[i].widget;
+ if (widget == w || param != gw[i].param)
+ continue;
+ int type = gw[i].type;
+ widget->blockSignals(true);
+ switch(type) {
+ case GuiWidgets::SLIDER:
+ ((Slider*)widget)->setValue(val);
+ break;
+ case GuiWidgets::DOUBLE_LABEL:
+ ((DoubleLabel*)widget)->setValue(val);
+ break;
+ case GuiWidgets::QCHECKBOX:
+ ((QCheckBox*)widget)->setChecked(int(val));
+ break;
+ case GuiWidgets::QCOMBOBOX:
+ ((QComboBox*)widget)->setCurrentIndex(int(val));
+ break;
+ }
+ widget->blockSignals(false);
+ }
+ track->setPluginCtrlVal(id, val);
}
+ plugin->enableController(param, false);
+}
//---------------------------------------------------------
// guiSliderReleased
@@ -4449,23 +4317,21 @@ void PluginGui::guiSliderReleased(int idx)
if(track)
at = track->automationType();
- /* equivalent to
- if ((at == AUTO_OFF) ||
- (at == AUTO_READ) ||
- (at == AUTO_TOUCH && (type != GuiWidgets::QCHECKBOX || <--- this type is SLIDER != CHECKBOX -> true
- !MusEGlobal::audio->isPlaying()) ) ) <--- above==true -> this doesn't matter */
- if (at == AUTO_OFF || at == AUTO_READ || at == AUTO_TOUCH)
- plugin->enableController(param, true);
-
int id = plugin->id();
- if(!track || id == -1)
- return;
+ if(track && id != -1)
+ {
+ id = MusECore::genACnum(id, param);
+
+ double val = ((Slider*)w)->value();
+ track->stopAutoRecord(id, val);
+ }
- id = MusECore::genACnum(id, param);
+ if (at == AUTO_OFF ||
+ at == AUTO_TOUCH)
+ plugin->enableController(param, true);
- double val = ((Slider*)w)->value();
- track->stopAutoRecord(id, val);
+ gw[idx].pressed = false;
}
//---------------------------------------------------------
diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h
index 822bafbd..e1682569 100644
--- a/muse2/muse/plugin.h
+++ b/muse2/muse/plugin.h
@@ -4,7 +4,7 @@
// $Id: plugin.h,v 1.9.2.13 2009/12/06 01:25:21 terminator356 Exp $
//
// (C) Copyright 2000 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -233,9 +233,8 @@ struct Port {
unsigned long idx;
float val;
float tmpVal;
-
bool enCtrl; // Enable controller stream.
- bool en2Ctrl; // Second enable controller stream (and'ed with enCtrl).
+ CtrlInterpolate interp;
};
//---------------------------------------------------------
@@ -268,10 +267,7 @@ class PluginIBase
virtual void enableController(unsigned long i, bool v = true) = 0;
virtual bool controllerEnabled(unsigned long i) const = 0;
- virtual void enable2Controller(unsigned long i, bool v = true) = 0;
- virtual bool controllerEnabled2(unsigned long i) const = 0;
virtual void enableAllControllers(bool v = true) = 0;
- virtual void enable2AllControllers(bool v = true) = 0;
virtual void updateControllers() = 0;
virtual void activate() = 0;
@@ -352,14 +348,11 @@ class PluginI : public PluginIBase {
bool initPluginInstance(Plugin*, int channels);
void setChannels(int);
void connect(unsigned long ports, unsigned long offset, float** src, float** dst);
- void apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut);
+ void apply(unsigned pos, unsigned long n, unsigned long ports, float** bufIn, float** bufOut);
void enableController(unsigned long i, bool v = true) { controls[i].enCtrl = v; }
bool controllerEnabled(unsigned long i) const { return controls[i].enCtrl; }
- void enable2Controller(unsigned long i, bool v = true) { controls[i].en2Ctrl = v; }
- bool controllerEnabled2(unsigned long i) const { return controls[i].en2Ctrl; }
void enableAllControllers(bool v = true);
- void enable2AllControllers(bool v = true);
void activate();
void deactivate();
@@ -418,11 +411,12 @@ class PluginI : public PluginIBase {
//---------------------------------------------------------
class Pipeline : public std::vector<PluginI*> {
+ private:
float* buffer[MAX_CHANNELS];
-
+ void initBuffers();
public:
Pipeline();
- Pipeline(const Pipeline&);
+ Pipeline(const Pipeline&, AudioTrack*);
~Pipeline();
void insert(PluginI* p, int index);
void remove(int index);
@@ -439,14 +433,13 @@ class Pipeline : public std::vector<PluginI*> {
void deleteAllGuis();
bool guiVisible(int);
bool nativeGuiVisible(int);
- void apply(unsigned long ports, unsigned long nframes, float** buffer);
+ void apply(unsigned pos, unsigned long ports, unsigned long nframes, float** buffer);
void move(int idx, bool up);
bool empty(int idx) const;
void setChannels(int);
bool addScheduledControlEvent(int track_ctrl_id, float val, unsigned frame); // returns true if event cannot be delivered
void enableController(int track_ctrl_id, bool en);
- void enable2Controller(int track_ctrl_id, bool en);
- void controllersEnabled(int track_ctrl_id, bool* en1, bool* en2);
+ bool controllerEnabled(int track_ctrl_id);
};
typedef Pipeline::iterator iPluginI;
@@ -489,6 +482,7 @@ struct GuiParam {
};
int type;
int hint;
+ bool pressed;
MusEGui::DoubleLabel* label;
QWidget* actuator; // Slider or Toggle Button (SWITCH)
@@ -505,6 +499,7 @@ struct GuiWidgets {
QWidget* widget;
int type;
unsigned long param;
+ bool pressed;
};
//---------------------------------------------------------
diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp
index 412b52f1..d13f8398 100644
--- a/muse2/muse/song.cpp
+++ b/muse2/muse/song.cpp
@@ -393,10 +393,6 @@ void Song::duplicateTracks()
if((*it)->selected())
{
Track::TrackType type = (*it)->type();
- // TODO: Handle synths. p4.0.47
- if(type == Track::AUDIO_SOFTSYNTH)
- continue;
-
if(type == Track::DRUM)
++drum_found;
else if(type == Track::NEW_DRUM)
@@ -507,7 +503,6 @@ void Song::duplicateTracks()
{
new_track->assign(*track, flags);
#else
- if(track->type() != Track::AUDIO_SOFTSYNTH) // TODO: Handle synths. p4.0.47
{
Track* new_track = track->clone(flags);
#endif
@@ -519,7 +514,7 @@ void Song::duplicateTracks()
addUndo(MusECore::UndoOp(MusECore::UndoOp::AddTrack, idx, new_track));
msgInsertTrack(new_track, idx, false); // No undo.
insertTrack3(new_track, idx);
- }
+ }
}
}
--trackno;
@@ -2458,14 +2453,10 @@ int Song::execAutomationCtlPopup(AudioTrack* track, const QPoint& menupos, int a
{
CtrlList *cl = icl->second;
canAdd = true;
-
frame = MusEGlobal::audio->pos().frame();
-
- bool en1, en2;
- track->controllersEnabled(acid, &en1, &en2);
-
+ bool en = track->controllerEnabled(acid);
AutomationType at = track->automationType();
- if(!MusEGlobal::automation || at == AUTO_OFF || !en1 || !en2)
+ if(!MusEGlobal::automation || at == AUTO_OFF || !en)
ctlval = cl->curVal();
else
ctlval = cl->value(frame);
@@ -2830,6 +2821,25 @@ void Song::updateSoloStates()
}
//---------------------------------------------------------
+// reenableTouchedControllers
+// Enable all track and plugin controllers, and synth controllers if applicable, which are NOT in AUTO_WRITE mode.
+//---------------------------------------------------------
+
+void Song::reenableTouchedControllers()
+{
+ for(iTrack it = _tracks.begin(); it != _tracks.end(); ++it)
+ {
+ if((*it)->isMidiTrack())
+ continue;
+ AudioTrack* t = static_cast<AudioTrack*>(*it);
+ AutomationType at = t->automationType();
+ if(at == AUTO_WRITE) // Exclude write mode because controls need to remain disabled if pressed before play.
+ continue;
+ t->enableAllControllers();
+ }
+}
+
+//---------------------------------------------------------
// clearRecAutomation
//---------------------------------------------------------
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index b9ab5dd5..6621de35 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -329,6 +329,8 @@ class Song : public QObject {
void readRoute(Xml& xml);
void recordEvent(MidiTrack*, Event&);
void msgInsertTrack(Track* track, int idx, bool u = true);
+ // Enable all track and plugin controllers, and synth controllers if applicable, which are NOT in AUTO_WRITE mode.
+ void reenableTouchedControllers();
void clearRecAutomation(bool clearList);
void processAutomationEvents();
void processMasterRec();
diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp
index 90805175..b07d1243 100644
--- a/muse2/muse/songfile.cpp
+++ b/muse2/muse/songfile.cpp
@@ -1462,6 +1462,11 @@ void MusE::read(MusECore::Xml& xml, bool doReadMidiPorts, bool isTemplate)
{
MusEGlobal::song->read(xml, isTemplate);
MusEGlobal::audio->msgUpdateSoloStates();
+ // Inform the rest of the app that the song (may) have changed, using these flags.
+ // After this function is called, the caller can do a general Song::update() MINUS these flags,
+ // like in MusE::loadProjectFile1() - the only place calling so far, as of this writing.
+ // Some existing windows need this, like arranger, some don't which are dynamically created after this.
+ MusEGlobal::song->update(SC_TRACK_INSERTED);
}
else if (tag == "midiport")
readMidiport(xml);
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index e04b55c8..d8d09048 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -92,10 +92,7 @@ QString SynthIF::titlePrefix() const { return QString(); }
MusECore::AudioTrack* SynthIF::track() { return static_cast < MusECore::AudioTrack* > (synti); }
void SynthIF::enableController(unsigned long, bool) { }
bool SynthIF::controllerEnabled(unsigned long) const { return true;}
-void SynthIF::enable2Controller(unsigned long, bool) { }
-bool SynthIF::controllerEnabled2(unsigned long) const { return true; }
void SynthIF::enableAllControllers(bool) { }
-void SynthIF::enable2AllControllers(bool) { }
void SynthIF::updateControllers() { }
void SynthIF::activate() { }
void SynthIF::deactivate() { }
@@ -310,6 +307,44 @@ SynthI::SynthI()
setPan(0.0);
}
+SynthI::SynthI(const SynthI& si, int flags)
+ : AudioTrack(si, flags)
+ {
+ synthesizer = 0;
+ _sif = 0;
+ _rwFlags = 1;
+ _openFlags = 1;
+ _readEnable = false;
+ _writeEnable = false;
+
+ _curBankH = 0;
+ _curBankL = 0;
+ _curProgram = 0;
+
+ setVolume(1.0);
+ setPan(0.0);
+
+ Synth* s = si.synth();
+ if (s) {
+ QString n;
+ n.setNum(s->instances());
+ QString instance_name = s->name() + "-" + n;
+ if(!initInstance(s, instance_name)) { // false if success
+ return;
+ }
+ }
+ fprintf(stderr, "SynthI copy ctor: error initializing synth s:%p\n", s);
+ }
+
+//---------------------------------------------------------
+// ~SynthI
+//---------------------------------------------------------
+
+SynthI::~SynthI()
+ {
+ deactivate2();
+ deactivate3();
+ }
//---------------------------------------------------------
// height in arranger
@@ -582,17 +617,6 @@ void MessSynthIF::deactivate3()
}
//---------------------------------------------------------
-// ~SynthI
-//---------------------------------------------------------
-
-SynthI::~SynthI()
- {
- deactivate2();
- deactivate3();
- }
-
-
-//---------------------------------------------------------
// initMidiSynth
// search for software MusEGlobal::synthis and advertise
//---------------------------------------------------------
@@ -1068,7 +1092,7 @@ iMPEvent MessSynthIF::getData(MidiPort* mp, MPEventList* el, iMPEvent i, unsigne
fprintf(stderr, "should not happen - no _mess\n");
else
{
- _mess->process(buffer, curPos-pos, frame - curPos);
+ _mess->process(pos, buffer, curPos-pos, frame - curPos);
}
}
curPos = frame;
@@ -1088,7 +1112,7 @@ iMPEvent MessSynthIF::getData(MidiPort* mp, MPEventList* el, iMPEvent i, unsigne
fprintf(stderr, "should not happen - no _mess\n");
else
{
- _mess->process(buffer, curPos - off, endPos - curPos);
+ _mess->process(pos, buffer, curPos - off, endPos - curPos);
}
}
return i;
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index 6b42c1f5..273e314c 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -175,13 +175,10 @@ class SynthIF : public PluginIBase {
virtual QString dirPath() const;
virtual QString fileName() const;
virtual QString titlePrefix() const;
- virtual MusECore::AudioTrack* track();
+ virtual AudioTrack* track();
virtual void enableController(unsigned long i, bool v = true);
virtual bool controllerEnabled(unsigned long i) const;
- virtual void enable2Controller(unsigned long i, bool v = true);
- virtual bool controllerEnabled2(unsigned long i) const;
virtual void enableAllControllers(bool v = true);
- virtual void enable2AllControllers(bool v = true);
virtual void updateControllers();
virtual void activate();
virtual void deactivate();
@@ -252,8 +249,9 @@ class SynthI : public AudioTrack, public MidiDevice,
friend class VstNativeSynthIF;
SynthI();
+ SynthI(const SynthI& si, int flags);
virtual ~SynthI();
- SynthI* clone(int /*flags*/) const { return new SynthI(*this); }
+ SynthI* clone(int flags) const { return new SynthI(*this, flags); }
virtual inline int deviceType() const { return SYNTH_MIDI; }
diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp
index 60d41806..a523ba86 100644
--- a/muse2/muse/ticksynth.cpp
+++ b/muse2/muse/ticksynth.cpp
@@ -111,6 +111,12 @@ class MetronomeSynthIF : public SynthIF
virtual float getParameter(unsigned long) const { return 0.0; }
virtual void setParameter(unsigned long, float) {}
virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) { return 0; }
+
+ //-------------------------
+ // Methods for PluginIBase:
+ //-------------------------
+
+ virtual bool addScheduledControlEvent(unsigned long /*i*/, float /*val*/, unsigned /*frame*/) { return true; } // returns true if event cannot be delivered
};
//---------------------------------------------------------
diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp
index 65580793..cc1e56ac 100644
--- a/muse2/muse/track.cpp
+++ b/muse2/muse/track.cpp
@@ -217,12 +217,6 @@ void Track::init()
_internalSolo = 0;
_off = false;
_channels = 0; // 1 - mono, 2 - stereo
-
- _volumeEnCtrl = true;
- _volumeEn2Ctrl = true;
- _panEnCtrl = true;
- _panEn2Ctrl = true;
-
_selected = false;
_height = MusEGlobal::config.trackHeight;
_locked = false;
@@ -240,11 +234,28 @@ Track::Track(Track::TrackType t)
Track::Track(const Track& t, int flags)
{
- internal_assign(t, flags | ASSIGN_PROPERTIES);
- for (int i = 0; i < MAX_CHANNELS; ++i) {
- _meter[i] = 0.0;
- _peak[i] = 0.0;
- }
+ _type = t.type();
+ _name = t.name() + " #";
+ for(int i = 2; true; ++i)
+ {
+ QString n;
+ n.setNum(i);
+ QString s = _name + n;
+ Track* track = MusEGlobal::song->findTrack(s);
+ if(track == 0)
+ {
+ // Do not call setName here. Audio Input and Output override it and try to set
+ // Jack ports, which have not been initialized yet here. Must wait until
+ // Audio Input and Output copy constructors or assign are called.
+ _name = s;
+ break;
+ }
+ }
+ internal_assign(t, flags | ASSIGN_PROPERTIES);
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ _meter[i] = 0.0;
+ _peak[i] = 0.0;
+ }
}
Track::~Track()
@@ -275,35 +286,11 @@ void Track::internal_assign(const Track& t, int flags)
_internalSolo = t._internalSolo;
_off = t._off;
_channels = t._channels;
-
- _volumeEnCtrl = t._volumeEnCtrl;
- _volumeEn2Ctrl = t._volumeEn2Ctrl;
- _panEnCtrl = t._panEnCtrl;
- _panEn2Ctrl = t._panEn2Ctrl;
-
_selected = t.selected();
_y = t._y;
_height = t._height;
_comment = t.comment();
- _type = t.type();
_locked = t.locked();
-
- _name = t.name() + " #";
- for(int i = 2; true; ++i)
- {
- QString n;
- n.setNum(i);
- QString s = _name + n;
- Track* track = MusEGlobal::song->findTrack(s);
- if(track == 0)
- {
- // Do not call setName here. Audio Input and Output override it and try to set
- // Jack ports, which have not been initialized yet here. Must wait until
- // Audio Input and Output copy constructors or assign are called.
- _name = s;
- break;
- }
- }
}
}
@@ -366,33 +353,11 @@ void Track::setDefaultName(QString base)
void Track::clearRecAutomation(bool clearList)
{
- _volumeEnCtrl = true;
- _volumeEn2Ctrl = true;
- _panEnCtrl = true;
- _panEn2Ctrl = true;
-
if(isMidiTrack())
return;
-
- AudioTrack *t = (AudioTrack*)this;
- Pipeline *pl = t->efxPipe();
- PluginI *p;
- for(iPluginI i = pl->begin(); i != pl->end(); ++i)
- {
- p = *i;
- if(!p)
- continue;
- p->enableAllControllers(true);
- }
-
- if(type() == AUDIO_SOFTSYNTH)
- {
- const SynthI* synth = static_cast<const SynthI*>(this);
- SynthIF* sif = synth->sif();
- if(sif)
- sif->enableAllControllers(true);
- }
-
+ AudioTrack *t = static_cast<AudioTrack*>(this);
+ // Re-enable all track and plugin controllers, and synth controllers if applicable.
+ t->enableAllControllers();
if(clearList)
t->recEvents()->clear();
}
diff --git a/muse2/muse/track.h b/muse2/muse/track.h
index 1c1b28f6..664364ba 100644
--- a/muse2/muse/track.h
+++ b/muse2/muse/track.h
@@ -4,7 +4,7 @@
// $Id: track.h,v 1.39.2.17 2009/12/20 05:00:35 terminator356 Exp $
//
// (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)
+// (C) Copyright 2011-2013 Tim E. Real (terminator356 on sourceforge)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -38,6 +38,7 @@
#include "ctrl.h"
#include "globaldefs.h"
#include "cleftypes.h"
+#include "controlfifo.h"
namespace MusECore {
class MPEventList;
@@ -47,6 +48,7 @@ class SynthI;
class Xml;
class DrumMap;
class ControlEvent;
+struct Port;
//---------------------------------------------------------
// Track
@@ -88,11 +90,6 @@ class Track {
bool _off;
int _channels; // 1 - mono, 2 - stereo
- bool _volumeEnCtrl;
- bool _volumeEn2Ctrl;
- bool _panEnCtrl;
- bool _panEn2Ctrl;
-
int _activity;
int _lastActivity;
double _meter[MAX_CHANNELS];
@@ -127,14 +124,6 @@ class Track {
bool locked() const { return _locked; }
void setLocked(bool b) { _locked = b; }
- bool volumeControllerEnabled() const { return _volumeEnCtrl; }
- bool volumeControllerEnabled2() const { return _volumeEn2Ctrl; }
- bool panControllerEnabled() const { return _panEnCtrl; }
- bool panControllerEnabled2() const { return _panEn2Ctrl; }
- void enableVolumeController(bool b) { _volumeEnCtrl = b; }
- void enable2VolumeController(bool b) { _volumeEn2Ctrl = b; }
- void enablePanController(bool b) { _panEnCtrl = b; }
- void enable2PanController(bool b) { _panEn2Ctrl = b; }
void clearRecAutomation(bool clearList);
const QString& name() const { return _name; }
@@ -340,9 +329,17 @@ class MidiTrack : public Track {
class AudioTrack : public Track {
bool _haveData; // Whether we have data from a previous process call during current cycle.
- CtrlListList _controller;
+ CtrlListList _controller; // Holds all controllers including internal, plugin and synth.
+ ControlFifo _controlFifo; // For internal controllers like volume and pan. Plugins/synths have their own.
CtrlRecList _recEvents; // recorded automation events
+ unsigned long _controlPorts;
+ Port* _controls; // For internal controllers like volume and pan. Plugins/synths have their own.
+
+ float _curVolume;
+ float _curVol1;
+ float _curVol2;
+
bool _prefader; // prefader metering
std::vector<double> _auxSend;
void readAuxSend(Xml& xml);
@@ -352,14 +349,29 @@ class AudioTrack : public Track {
AutomationType _automationType;
Pipeline* _efxPipe;
double _gain;
+
+ void initBuffers();
void internal_assign(const Track&, int flags);
+ void processTrackCtrls(unsigned pos, int trackChans, unsigned nframes, float** buffer);
protected:
+ // Cached audio data for all channels. If prefader is not on, the first two channels
+ // have volume and pan applied if track is stereo, or the first channel has just
+ // volume applied if track is mono.
float** outBuffers;
+ // Extra cached audio data.
+ float** outBuffersExtraMix;
+ // Just all zeros all the time, so we don't have to clear for silence.
+ float* audioInSilenceBuf;
+ // Just a place to connect all unused audio outputs.
+ float* audioOutDummyBuf;
+
+ // These two are not the same as the number of track channels which is always either 1 (mono) or 2 (stereo):
+ // Total number of output channels.
int _totalOutChannels;
+ // Total number of input channels.
int _totalInChannels;
- unsigned bufferPos;
virtual bool getData(unsigned, int, unsigned, float**);
SndFileR _recFile;
Fifo fifo; // fifo -> _recFile
@@ -396,6 +408,10 @@ class AudioTrack : public Track {
void setRecFile(SndFileR sf) { _recFile = sf; }
CtrlListList* controller() { return &_controller; }
+ // For setting/getting the _controls 'port' values.
+ unsigned long parameters() const { return _controlPorts; }
+ void setParam(unsigned long i, float val);
+ float param(unsigned long i) const;
virtual void setChannels(int n);
virtual void setTotalOutChannels(int num);
@@ -434,7 +450,10 @@ class AudioTrack : public Track {
Pipeline* efxPipe() { return _efxPipe; }
void deleteAllEfxGuis();
void clearEfxList();
+ // Removes any existing plugin and inserts plugin into effects rack, and calls setupPlugin.
void addPlugin(PluginI* plugin, int idx);
+ // Assigns valid ID and track to plugin, and creates controllers for plugin.
+ void setupPlugin(PluginI* plugin, int idx);
double pluginCtrlVal(int ctlID) const;
void setPluginCtrlVal(int param, double val);
@@ -452,8 +471,10 @@ class AudioTrack : public Track {
void processAutomationEvents();
CtrlRecList* recEvents() { return &_recEvents; }
bool addScheduledControlEvent(int track_ctrl_id, float val, unsigned frame); // return true if event cannot be delivered
- void enableController(int track_ctrl_id, bool en);
- void controllersEnabled(int track_ctrl_id, bool* en1, bool* en2) const;
+ void enableController(int track_ctrl_id, bool en);
+ bool controllerEnabled(int track_ctrl_id) const;
+ // Enable all track and plugin controllers, and synth controllers if applicable.
+ void enableAllControllers();
void recordAutomation(int n, double v);
void startAutoRecord(int, double);
void stopAutoRecord(int, double);
@@ -507,7 +528,6 @@ class AudioOutput : public AudioTrack {
float* buffer1[MAX_CHANNELS];
unsigned long _nframes;
static bool _isVisible;
- float* _monitorBuffer[MAX_CHANNELS];
void internal_assign(const Track& t, int flags);
public:
@@ -530,7 +550,6 @@ class AudioOutput : public AudioTrack {
void silence(unsigned);
virtual bool canRecord() const { return true; }
- float** monitorBuffer() { return _monitorBuffer; }
static void setVisible(bool t) { _isVisible = t; }
static bool visible() { return _isVisible; }
virtual int height() const;
diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h
index 1143d56e..5d759af7 100644
--- a/muse2/muse/vst.h
+++ b/muse2/muse/vst.h
@@ -99,6 +99,12 @@ class VstSynthIF : public SynthIF
virtual float getParameter(unsigned long idx) const;
virtual void setParameter(unsigned long idx, float value);
virtual int getControllerInfo(int, const char**, int*, int*, int*, int*) { return 0; }
+
+ //-------------------------
+ // Methods for PluginIBase:
+ //-------------------------
+
+ virtual bool addScheduledControlEvent(unsigned long /*i*/, float /*val*/, unsigned /*frame*/) { return true; } // returns true if event cannot be delivered
};
} // namespace MusECore
diff --git a/muse2/muse/vst_native.cpp b/muse2/muse/vst_native.cpp
index de206313..063d0895 100644
--- a/muse2/muse/vst_native.cpp
+++ b/muse2/muse/vst_native.cpp
@@ -3,7 +3,7 @@
// Linux Music Editor
//
// vst_native.cpp
-// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2012-2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -598,7 +598,7 @@ void VstNativeSynth::incInstances(int val)
// instantiate
//---------------------------------------------------------
-AEffect* VstNativeSynth::instantiate()
+AEffect* VstNativeSynth::instantiate(VstNativeSynthIF* sif)
{
int inst_num = _instances;
inst_num++;
@@ -680,6 +680,7 @@ AEffect* VstNativeSynth::instantiate()
else if(MusEGlobal::debugMsg)
fprintf(stderr, "Plugin supports processReplacing\n");
+ plugin->user = sif;
plugin->dispatcher(plugin, effOpen, 0, 0, NULL, 0);
// "2 = VST2.x, older versions return 0". Observed 2400 on all the ones tested so far.
@@ -693,8 +694,7 @@ AEffect* VstNativeSynth::instantiate()
++_instances;
_handle = hnd;
-
- plugin->dispatcher(plugin, effOpen, 0, 0, NULL, 0);
+
//plugin->dispatcher(plugin, effSetProgram, 0, 0, NULL, 0.0f); // REMOVE Tim. Or keep?
return plugin;
@@ -723,8 +723,10 @@ SynthIF* VstNativeSynth::createSIF(SynthI* s)
VstNativeSynthIF::VstNativeSynthIF(SynthI* s) : SynthIF(s)
{
_guiVisible = false;
+ _gw = NULL;
_synth = NULL;
_plugin = NULL;
+ _active = false;
_editor = NULL;
_inProcess = false;
_controls = NULL;
@@ -767,6 +769,9 @@ VstNativeSynthIF::~VstNativeSynthIF()
if(_controls)
delete[] _controls;
+
+ if(_gw)
+ delete[] _gw;
}
//---------------------------------------------------------
@@ -776,10 +781,9 @@ VstNativeSynthIF::~VstNativeSynthIF()
bool VstNativeSynthIF::init(Synth* s)
{
_synth = (VstNativeSynth*)s;
- _plugin = _synth->instantiate();
+ _plugin = _synth->instantiate(this);
if(!_plugin)
return false;
- _plugin->user = this;
queryPrograms();
@@ -795,7 +799,13 @@ bool VstNativeSynthIF::init(Synth* s)
fprintf(stderr, "ERROR: VstNativeSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(_audioOutBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioOutBuffers[k][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioOutBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
}
}
@@ -811,7 +821,13 @@ bool VstNativeSynthIF::init(Synth* s)
fprintf(stderr, "ERROR: VstNativeSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(_audioInBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioInBuffers[k][q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioInBuffers[k], 0, sizeof(float) * MusEGlobal::segmentSize);
_iUsedIdx.push_back(false); // Start out with all false.
}
@@ -821,20 +837,28 @@ bool VstNativeSynthIF::init(Synth* s)
fprintf(stderr, "ERROR: VstNativeSynthIF::init: posix_memalign returned error:%d. Aborting!\n", rv);
abort();
}
- memset(_audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
+ if(MusEGlobal::config.useDenormalBias)
+ {
+ for(unsigned q = 0; q < MusEGlobal::segmentSize; ++q)
+ _audioInSilenceBuf[q] = MusEGlobal::denormalBias;
+ }
+ else
+ memset(_audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize);
}
+ _controls = NULL;
+ _gw = NULL;
unsigned long controlPorts = _synth->inControls();
if(controlPorts != 0)
+ {
_controls = new Port[controlPorts];
- else
- _controls = NULL;
-
- //_synth->midiCtl2PortMap.clear();
- //_synth->port2MidiCtlMap.clear();
+ _gw = new VstNativeGuiWidgets[controlPorts];
+ }
for(unsigned long i = 0; i < controlPorts; ++i)
{
+ _gw[i].pressed = false;
+
_controls[i].idx = i;
//float val; // TODO
//ladspaDefaultValue(ld, k, &val); // FIXME TODO
@@ -842,7 +866,6 @@ bool VstNativeSynthIF::init(Synth* s)
_controls[i].val = val;
_controls[i].tmpVal = val;
_controls[i].enCtrl = true;
- _controls[i].en2Ctrl = true;
// Support a special block for synth ladspa controllers.
// Put the ID at a special block after plugins (far after).
@@ -855,7 +878,7 @@ bool VstNativeSynthIF::init(Synth* s)
float min = 0.0, max = 1.0;
CtrlList* cl;
- CtrlListList* cll = ((MusECore::AudioTrack*)synti)->controller();
+ CtrlListList* cll = track()->controller();
iCtrlList icl = cll->find(id);
if (icl == cll->end())
{
@@ -941,14 +964,15 @@ VstIntPtr VstNativeSynthIF::hostCallback(VstInt32 opcode, VstInt32 index, VstInt
case audioMasterCurrentId:
// returns the unique id of a plug that's currently
// loading
- return 0;
+ ///return 0;
+ return _plugin->uniqueID;
case audioMasterIdle:
// call application idle routine (this will
// call effEditIdle for all open editors too)
//_plugin->updateParamValues(false);
//_plugin->dispatcher(_plugin, effEditIdle, 0, 0, NULL, 0.0f);
- idleEditor();
+ ///idleEditor(); // REMOVE Tim. Or keep.
return 0;
case audioMasterGetTime:
@@ -958,8 +982,12 @@ VstIntPtr VstNativeSynthIF::hostCallback(VstInt32 opcode, VstInt32 index, VstInt
// (see valid masks above), as some items may require extensive
// conversions
+ // FIXME TODO: Optimizations: This may be called many times in one process call
+ // due to our multi-run slices. Some of the (costly) info will be redundant.
+ // So try to add some flag to try to only call some or all of this once per cycle.
+
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::hostCallback master time: valid: nanos:%d ppqpos:%d tempo:%d bars:%d cyclepos:%d sig:%d smpte:%d clock:%d\n", // REMOVE Tim.
+ fprintf(stderr, "VstNativeSynthIF::hostCallback master time: valid: nanos:%d ppqpos:%d tempo:%d bars:%d cyclepos:%d sig:%d smpte:%d clock:%d\n",
(bool)(value & kVstNanosValid),
(bool)(value & kVstPpqPosValid),
(bool)(value & kVstTempoValid),
@@ -1249,9 +1277,35 @@ void VstNativeSynthIF::idleEditor()
fprintf(stderr, "VstNativeSynthIF::idleEditor %p\n", this);
#endif
- _plugin->dispatcher(_plugin, effEditIdle, 0, 0, NULL, 0.0f);
- if(_editor)
- _editor->update();
+ // REMOVE Tim. Or keep.
+ //_plugin->dispatcher(_plugin, effEditIdle, 0, 0, NULL, 0.0f);
+ //if(_editor)
+ // _editor->update();
+}
+
+//---------------------------------------------------------
+// guiHeartBeat
+//---------------------------------------------------------
+
+void VstNativeSynthIF::guiHeartBeat()
+{
+#ifdef VST_NATIVE_DEBUG
+ fprintf(stderr, "VstNativeSynthIF::guiHeartBeat %p\n", this);
+#endif
+
+ // REMOVE Tim. Or keep.
+ if(_plugin && _active)
+ {
+//#ifdef VST_FORCE_DEPRECATED // REMOVE Tim. Or keep
+ //_plugin->dispatcher(_plugin, effIdle, 0, 0, NULL, 0.0f);
+//#endif
+ if(_guiVisible)
+ {
+ _plugin->dispatcher(_plugin, effEditIdle, 0, 0, NULL, 0.0f);
+ if(_editor)
+ _editor->update();
+ }
+ }
}
//---------------------------------------------------------
@@ -1330,6 +1384,66 @@ void VstNativeSynthIF::showNativeGui(bool v)
}
//---------------------------------------------------------
+// getGeometry
+//---------------------------------------------------------
+
+void VstNativeSynthIF::getGeometry(int*x, int*y, int*w, int*h) const
+{
+ if(!_gui)
+ {
+ *x=0;*y=0;*w=0;*h=0;
+ return;
+ }
+
+ *x = _gui->x();
+ *y = _gui->y();
+ *w = _gui->width();
+ *h = _gui->height();
+}
+
+//---------------------------------------------------------
+// setGeometry
+//---------------------------------------------------------
+
+void VstNativeSynthIF::setGeometry(int x, int y, int w, int h)
+{
+ if(!_gui)
+ return;
+
+ _gui->setGeometry(x, y, w, h);
+}
+
+//---------------------------------------------------------
+// editorOpened
+//---------------------------------------------------------
+
+void VstNativeSynthIF::getNativeGeometry(int*x, int*y, int*w, int*h) const
+{
+ if(!_editor)
+ {
+ *x=0;*y=0;*w=0;*h=0;
+ return;
+ }
+
+ *x = _editor->x();
+ *y = _editor->y();
+ *w = _editor->width();
+ *h = _editor->height();
+}
+
+//---------------------------------------------------------
+// editorOpened
+//---------------------------------------------------------
+
+void VstNativeSynthIF::setNativeGeometry(int x, int y, int w, int h)
+{
+ if(!_editor)
+ return;
+
+ _editor->setGeometry(x, y, w, h);
+}
+
+//---------------------------------------------------------
// editorOpened
//---------------------------------------------------------
@@ -1380,7 +1494,6 @@ bool VstNativeSynthIF::hasNativeGui() const
int VstNativeSynthIF::channels() const
{
- //return _plugin->numOutputs;
return _plugin->numOutputs > MAX_CHANNELS ? MAX_CHANNELS : _plugin->numOutputs ;
}
@@ -1614,7 +1727,6 @@ float VstNativeSynthIF::getParameter(unsigned long idx) const
void VstNativeSynthIF::setParameter(unsigned long idx, float value)
{
- //_plugin->setParameter(_plugin, idx, value);
addScheduledControlEvent(idx, value, MusEGlobal::audio->curFrame());
}
@@ -1624,53 +1736,44 @@ void VstNativeSynthIF::setParameter(unsigned long idx, float value)
void VstNativeSynthIF::guiAutomationBegin(unsigned long param_idx)
{
- AutomationType at = AUTO_OFF;
- MusECore::AudioTrack* t = track();
- if(t)
- at = t->automationType();
-
- // FIXME TODO: This stuff should probably be sent as control FIFO events.
- // And probably not safe - accessing from gui and audio threads...
-
- if (at == AUTO_READ || at == AUTO_TOUCH || at == AUTO_WRITE)
- enableController(param_idx, false);
-
+ _gw[param_idx].pressed = true;
+ AudioTrack* t = track();
int plug_id = id();
+ if(t && plug_id != -1)
+ {
+ plug_id = genACnum(plug_id, param_idx);
- if(plug_id == -1)
- return;
-
- plug_id = MusECore::genACnum(plug_id, param_idx);
-
- //if(params[param].type == GuiParam::GUI_SLIDER)
- //{
- //double val = ((Slider*)params[param].actuator)->value();
- float val = param(param_idx);
- // FIXME TODO:
- //if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
- // val = pow(10.0, val/20.0);
- //else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
- // val = rint(val);
- //plugin->setParam(param, val);
- //((DoubleLabel*)params[param].label)->setValue(val);
-
- if(t)
- {
- t->setPluginCtrlVal(plug_id, val);
- t->startAutoRecord(plug_id, val);
- }
- //}
-// else if(params[param].type == GuiParam::GUI_SWITCH)
-// {
-// float val = (float)((CheckBox*)params[param].actuator)->isChecked();
-// plugin->setParam(param, val);
-//
-// if(t)
-// {
-// t->setPluginCtrlVal(plug_id, val);
-// t->startAutoRecord(plug_id, val);
-// }
-// }
+ //if(params[param].type == GuiParam::GUI_SLIDER)
+ //{
+ //double val = ((Slider*)params[param].actuator)->value();
+ float val = param(param_idx);
+ // FIXME TODO:
+ //if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
+ // val = pow(10.0, val/20.0);
+ //else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
+ // val = rint(val);
+ //plugin->setParam(param, val);
+ //((DoubleLabel*)params[param].label)->setValue(val);
+
+ //if(t)
+ //{
+ t->startAutoRecord(plug_id, val);
+ t->setPluginCtrlVal(plug_id, val);
+ //}
+ //}
+ // else if(params[param].type == GuiParam::GUI_SWITCH)
+ // {
+ // float val = (float)((CheckBox*)params[param].actuator)->isChecked();
+ // plugin->setParam(param, val);
+ //
+ // //if(t)
+ // //{
+ // t->startAutoRecord(plug_id, val);
+ // t->setPluginCtrlVal(plug_id, val);
+ // //}
+ // }
+ }
+ enableController(param_idx, false);
}
//---------------------------------------------------------
@@ -1680,40 +1783,39 @@ void VstNativeSynthIF::guiAutomationBegin(unsigned long param_idx)
void VstNativeSynthIF::guiAutomationEnd(unsigned long param_idx)
{
AutomationType at = AUTO_OFF;
- MusECore::AudioTrack* t = track();
+ AudioTrack* t = track();
if(t)
at = t->automationType();
- // FIXME TODO: This stuff should probably be sent as control FIFO events.
- // And probably not safe - accessing from gui and audio threads...
-
+ int plug_id = id();
+ if(t && plug_id != -1)
+ {
+ plug_id = genACnum(plug_id, param_idx);
+
+ //if(params[param].type == GuiParam::GUI_SLIDER)
+ //{
+ //double val = ((Slider*)params[param].actuator)->value();
+ float val = param(param_idx);
+ // FIXME TODO:
+ //if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
+ // val = pow(10.0, val/20.0);
+ //else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
+ // val = rint(val);
+ t->stopAutoRecord(plug_id, val);
+ //}
+ }
+
// Special for switch - don't enable controller until transport stopped.
if ((at == AUTO_OFF) ||
- (at == AUTO_READ) ||
(at == AUTO_TOUCH)) // && (params[param].type != GuiParam::GUI_SWITCH || // FIXME TODO
// !MusEGlobal::audio->isPlaying()) ) )
enableController(param_idx, true);
-
- int plug_id = id();
- if(!t || plug_id == -1)
- return;
- plug_id = MusECore::genACnum(plug_id, param_idx);
-
- //if(params[param].type == GuiParam::GUI_SLIDER)
- //{
- //double val = ((Slider*)params[param].actuator)->value();
- float val = param(param_idx);
- // FIXME TODO:
- //if (LADSPA_IS_HINT_LOGARITHMIC(params[param].hint))
- // val = pow(10.0, val/20.0);
- //else if (LADSPA_IS_HINT_INTEGER(params[param].hint))
- // val = rint(val);
- t->stopAutoRecord(plug_id, val);
- //}
+
+ _gw[param_idx].pressed = false;
}
-
+
//---------------------------------------------------------
-// guiControlEventHandler
+// guiControlChanged
//---------------------------------------------------------
int VstNativeSynthIF::guiControlChanged(unsigned long param_idx, float value)
@@ -1728,37 +1830,29 @@ int VstNativeSynthIF::guiControlChanged(unsigned long param_idx, float value)
return 0;
}
+ // Record automation:
+ // Take care of this immediately rather than in the fifo processing.
+ if(id() != -1)
+ {
+ unsigned long pid = genACnum(id(), param_idx);
+ synti->recordAutomation(pid, value);
+ }
+
+ // Schedules a timed control change:
ControlEvent ce;
- ce.unique = false; // Not used for native vst.
- ce.fromGui = true; // It came form the plugin's own GUI.
+ ce.unique = false; // Not used for native vst.
+ ce.fromGui = true; // It came from the plugin's own GUI.
ce.idx = param_idx;
ce.value = value;
- // don't use timestamp(), because it's circular, which is making it impossible to deal
+ // Don't use timestamp(), because it's circular, which is making it impossible to deal
// with 'modulo' events which slip in 'under the wire' before processing the ring buffers.
ce.frame = MusEGlobal::audio->curFrame();
if(_controlFifo.put(ce))
- {
fprintf(stderr, "VstNativeSynthIF::guiControlChanged: fifo overflow: in control number:%lu\n", param_idx);
- }
- // FIXME TODO: This stuff should probably be sent as control FIFO events.
- // And probably not safe - accessing from gui and audio threads...
+ enableController(param_idx, false);
- // Record automation:
- // Take care of this immediately rather than in the fifo processing.
- if(id() != -1)
- {
- unsigned long pid = genACnum(id(), param_idx);
- AutomationType at = synti->automationType();
-
- if ((at == AUTO_WRITE) ||
- (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()))
- enableController(param_idx, false);
-
- synti->recordAutomation(pid, value);
- }
-
return 0;
}
@@ -1844,7 +1938,7 @@ void VstNativeSynthIF::setVstEvent(VstMidiEvent* event, int a, int b, int c, int
// getData
//---------------------------------------------------------
-bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEvent* event)
+bool VstNativeSynthIF::processEvent(const MidiPlayEvent& e, VstMidiEvent* event)
{
int type = e.type();
int chn = e.channel();
@@ -1857,22 +1951,22 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
switch(type)
{
- case MusECore::ME_NOTEON:
+ case ME_NOTEON:
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_NOTEON\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_NOTEON\n");
#endif
setVstEvent(event, (type | chn) & 0xff, a & 0x7f, b & 0x7f);
break;
- case MusECore::ME_NOTEOFF:
+ case ME_NOTEOFF:
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_NOTEOFF\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_NOTEOFF\n");
#endif
setVstEvent(event, (type | chn) & 0xff, a & 0x7f, 0);
break;
- case MusECore::ME_PROGRAM:
+ case ME_PROGRAM:
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_PROGRAM\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_PROGRAM\n");
#endif
int bankH = (a >> 16) & 0xff;
@@ -1885,19 +1979,19 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
return false; // Event pointer not filled. Return false.
}
break;
- case MusECore::ME_CONTROLLER:
+ case ME_CONTROLLER:
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER\n");
#endif
if((a == 0) || (a == 32))
return false;
- if(a == MusECore::CTRL_PROGRAM)
+ if(a == CTRL_PROGRAM)
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_PROGRAM\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PROGRAM\n");
#endif
int bankH = (b >> 16) & 0xff;
@@ -1911,36 +2005,36 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
return false; // Event pointer not filled. Return false.
}
- if(a == MusECore::CTRL_PITCH)
+ if(a == CTRL_PITCH)
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_PITCH\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_PITCH\n");
#endif
int v = b + 8192;
setVstEvent(event, (type | chn) & 0xff, v & 0x7f, (v >> 7) & 0x7f);
return true;
}
- if(a == MusECore::CTRL_AFTERTOUCH)
+ if(a == CTRL_AFTERTOUCH)
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_AFTERTOUCH\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_AFTERTOUCH\n");
#endif
setVstEvent(event, (type | chn) & 0xff, b & 0x7f);
return true;
}
- if((a | 0xff) == MusECore::CTRL_POLYAFTER)
+ if((a | 0xff) == CTRL_POLYAFTER)
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is MusECore::CTRL_POLYAFTER\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER, dataA is CTRL_POLYAFTER\n");
#endif
setVstEvent(event, (type | chn) & 0xff, a & 0x7f, b & 0x7f);
return true;
}
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_CONTROLLER, dataA is:%d\n", a);
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_CONTROLLER, dataA is:%d\n", a);
#endif
// Regular controller. Pass it on.
@@ -1952,14 +2046,14 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
//
// const LADSPA_Descriptor* ld = dssi->LADSPA_Plugin;
//
-// MusECore::ciMidiCtl2LadspaPort ip = synth->midiCtl2PortMap.find(a);
+// ciMidiCtl2LadspaPort ip = synth->midiCtl2PortMap.find(a);
// // Is it just a regular midi controller, not mapped to a LADSPA port (either by the plugin or by us)?
// // NOTE: There's no way to tell which of these controllers is supported by the plugin.
// // For example sustain footpedal or pitch bend may be supported, but not mapped to any LADSPA port.
// if(ip == synth->midiCtl2PortMap.end())
// {
// int ctlnum = a;
-// if(MusECore::midiControllerType(a) != MusECore::MidiController::Controller7)
+// if(midiControllerType(a) != MidiController::Controller7)
// return false; // Event pointer not filled. Return false.
// else
// {
@@ -1994,7 +2088,7 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
// return false;
//
// // Simple but flawed solution: Start them at 0x60000 + 0x2000 = 0x62000. Max NRPN number is 0x3fff.
-// ctlnum = k + (MusECore::CTRL_NRPN14_OFFSET + 0x2000);
+// ctlnum = k + (CTRL_NRPN14_OFFSET + 0x2000);
// }
// else
// {
@@ -2020,7 +2114,7 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
// else
// if(DSSI_IS_NRPN(ctlnum))
// {
-// ctlnum = DSSI_NRPN_NUMBER(c) + MusECore::CTRL_NRPN14_OFFSET;
+// ctlnum = DSSI_NRPN_NUMBER(c) + CTRL_NRPN14_OFFSET;
//
// #ifdef VST_NATIVE_DEBUG
// fprintf(stderr, "VstNativeSynthIF::processEvent is NRPN ctlnum:%x(h) %d(d)\n", ctlnum, ctlnum);
@@ -2047,22 +2141,22 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
// return false;
}
break;
- case MusECore::ME_PITCHBEND:
+ case ME_PITCHBEND:
{
int v = a + 8192;
setVstEvent(event, (type | chn) & 0xff, v & 0x7f, (v >> 7) & 0x7f);
}
break;
- case MusECore::ME_AFTERTOUCH:
+ case ME_AFTERTOUCH:
setVstEvent(event, (type | chn) & 0xff, a & 0x7f);
break;
- case MusECore::ME_POLYAFTER:
+ case ME_POLYAFTER:
setVstEvent(event, (type | chn) & 0xff, a & 0x7f, b & 0x7f);
break;
- case MusECore::ME_SYSEX:
+ case ME_SYSEX:
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_SYSEX\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_SYSEX\n");
#endif
const unsigned char* data = e.data();
@@ -2109,7 +2203,7 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
if (QString((const char*)e.data()).startsWith("PARAMSAVE"))
{
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::processEvent midi event is MusECore::ME_SYSEX PARAMSAVE\n");
+ fprintf(stderr, "VstNativeSynthIF::processEvent midi event is ME_SYSEX PARAMSAVE\n");
#endif
unsigned long dlen = e.len() - 9; // Minus "PARAMSAVE"
@@ -2170,7 +2264,7 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
//len += 2;
// NOTE: There is a limit on the size of a sysex. Got this:
- // "VstNativeSynthIF::processEvent midi event is MusECore::ME_SYSEX"
+ // "VstNativeSynthIF::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);
@@ -2193,43 +2287,48 @@ bool VstNativeSynthIF::processEvent(const MusECore::MidiPlayEvent& e, VstMidiEve
//---------------------------------------------------------
// getData
+// If ports is 0, just process controllers only, not audio (do not 'run').
//---------------------------------------------------------
iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent start_event, unsigned pos, int ports, unsigned nframes, float** buffer)
{
- // We may not be using nevents all at once - this will be just the maximum.
- unsigned long nevents = el->size() + synti->eventFifo.getSize();
- VstMidiEvent events[nevents];
- char evbuf[sizeof(VstMidiEvent*) * nevents + sizeof(VstEvents)];
+ // We may not be using ev_buf_sz all at once - this will be just the maximum.
+ const unsigned long ev_buf_sz = el->size() + synti->eventFifo.getSize();
+ VstMidiEvent events[ev_buf_sz];
+ char evbuf[sizeof(VstMidiEvent*) * ev_buf_sz + sizeof(VstEvents)];
VstEvents *vst_events = (VstEvents*)evbuf;
vst_events->numEvents = 0;
vst_events->reserved = 0;
- int frameOffset = MusEGlobal::audio->getFrameOffset();
- unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
+ const int frameOffset = MusEGlobal::audio->getFrameOffset();
+ const unsigned long syncFrame = MusEGlobal::audio->curSyncFrame();
#ifdef VST_NATIVE_DEBUG_PROCESS
- fprintf(stderr, "VstNativeSynthIF::getData: pos:%u ports:%d nframes:%u syncFrame:%lu nevents:%lu\n", pos, ports, nframes, syncFrame, nevents);
+ fprintf(stderr, "VstNativeSynthIF::getData: pos:%u ports:%d nframes:%u syncFrame:%lu ev_buf_sz:%lu\n", pos, ports, nframes, syncFrame, ev_buf_sz);
#endif
- unsigned long nop, k;
- nop = ((unsigned long) ports) > _synth->outPorts() ? _synth->outPorts() : ((unsigned long) ports);
+ const unsigned long nop = ((unsigned long) ports) > _synth->outPorts() ? _synth->outPorts() : ((unsigned long) ports);
unsigned long sample = 0;
// I read that some plugins do not like changing sample run length (compressors etc). Some are OK with it.
// TODO: In order to support this effectively, must be user selectable, per-plugin. ENABLED for now.
- const bool usefixedrate = false;
- unsigned long fixedsize = nframes;
+ const bool usefixedrate = false;
// 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 > nframes)
- fixedsize = nframes;
-
- unsigned long min_per = MusEGlobal::config.minControlProcessPeriod; // Must be power of 2 !
- if(min_per > nframes)
- min_per = nframes;
+ const unsigned long min_per = (usefixedrate || MusEGlobal::config.minControlProcessPeriod > nframes) ? nframes : MusEGlobal::config.minControlProcessPeriod;
+ const unsigned long min_per_mask = min_per-1; // min_per must be power of 2
+
+ AudioTrack* atrack = track();
+ const AutomationType at = atrack->automationType();
+ const bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
+ const unsigned long in_ctrls = _synth->inControls();
+ CtrlListList* cll = atrack->controller();
+ ciCtrlList icl_first;
+ const int plug_id = id();
+ if(plug_id != -1 && ports != 0) // Don't bother if not 'running'.
+ icl_first = cll->lower_bound(genACnum(plug_id, 0));
// Inform the host callback we are in the audio thread.
_inProcess = true;
@@ -2239,71 +2338,74 @@ iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent s
#endif
// Handle inputs...
- if(!((MusECore::AudioTrack*)synti)->noInRoute())
+ if(ports != 0) // Don't bother if not 'running'.
{
- RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes();
- iRoute i = irl->begin();
- if(!i->track->isMidiTrack())
+ if(!atrack->noInRoute())
{
- int ch = i->channel == -1 ? 0 : i->channel;
- int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
- int chs = i->channels == -1 ? 0 : i->channels;
-
- if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
+ RouteList* irl = atrack->inRoutes();
+ iRoute i = irl->begin();
+ if(!i->track->isMidiTrack())
{
- int h = remch + chs;
- for(int j = remch; j < h; ++j)
- _iUsedIdx[j] = true;
+ const int ch = i->channel == -1 ? 0 : i->channel;
+ const int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ const int chs = i->channels == -1 ? 0 : i->channels;
+
+ if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
+ {
+ const int h = remch + chs;
+ for(int j = remch; j < h; ++j)
+ _iUsedIdx[j] = true;
- ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
+ ((AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
+ }
}
- }
- ++i;
- for(; i != irl->end(); ++i)
- {
- if(i->track->isMidiTrack())
- continue;
+ ++i;
+ for(; i != irl->end(); ++i)
+ {
+ if(i->track->isMidiTrack())
+ continue;
- int ch = i->channel == -1 ? 0 : i->channel;
- int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
- int chs = i->channels == -1 ? 0 : i->channels;
+ const int ch = i->channel == -1 ? 0 : i->channel;
+ const int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel;
+ const int chs = i->channels == -1 ? 0 : i->channels;
- if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
- {
- bool u1 = _iUsedIdx[remch];
- if(chs >= 2)
+ if((unsigned)ch < _synth->inPorts() && (unsigned)(ch + chs) <= _synth->inPorts())
{
- bool u2 = _iUsedIdx[remch + 1];
- if(u1 && u2)
- ((MusECore::AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
- else
- if(!u1 && !u2)
- ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
- else
+ const bool u1 = _iUsedIdx[remch];
+ if(chs >= 2)
{
- if(u1)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+ const bool u2 = _iUsedIdx[remch + 1];
+ if(u1 && u2)
+ ((AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
-
- if(u2)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ if(!u1 && !u2)
+ ((AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &_audioInBuffers[remch]);
else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ {
+ if(u1)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &_audioInBuffers[remch]);
+
+ if(u2)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &_audioInBuffers[remch + 1]);
+ }
+ }
+ else
+ {
+ if(u1)
+ ((AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
+ else
+ ((AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
}
- }
- else
- {
- if(u1)
- ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
- else
- ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &_audioInBuffers[remch]);
- }
- int h = remch + chs;
- for(int j = remch; j < h; ++j)
- _iUsedIdx[j] = true;
+ const int h = remch + chs;
+ for(int j = remch; j < h; ++j)
+ _iUsedIdx[j] = true;
+ }
}
}
}
@@ -2312,9 +2414,11 @@ iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent s
fprintf(stderr, "VstNativeSynthIF::getData: Processing automation control values...\n");
#endif
+ int cur_slice = 0;
while(sample < nframes)
{
- unsigned long nsamp = usefixedrate ? fixedsize : nframes - sample;
+ unsigned long nsamp = nframes - sample;
+ const unsigned long slice_frame = pos + sample;
//
// Process automation control values, while also determining the maximum acceptable
@@ -2322,51 +2426,62 @@ iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent s
// from there, but this section determines where the next highest maximum frame
// absolutely needs to be for smooth playback of the controller value stream...
//
- if(id() != -1)
+ if(ports != 0) // Don't bother if not 'running'.
{
- unsigned long frame = pos + sample;
- AutomationType at = AUTO_OFF;
- at = synti->automationType();
- bool no_auto = !MusEGlobal::automation || at == AUTO_OFF;
- AudioTrack* track = (static_cast<AudioTrack*>(synti));
- int nextFrame;
- const unsigned long in_ctrls = _synth->inControls();
+ ciCtrlList icl = icl_first;
for(unsigned long k = 0; k < in_ctrls; ++k)
{
- const float v = track->controller()->value(genACnum(id(), k), frame,
- no_auto || !_controls[k].enCtrl || !_controls[k].en2Ctrl,
- &nextFrame);
- if(_controls[k].val != v)
+ CtrlList* cl = (cll && plug_id != -1 && icl != cll->end()) ? icl->second : NULL;
+ CtrlInterpolate& ci = _controls[k].interp;
+ // Always refresh the interpolate struct at first, since things may have changed.
+ // Or if the frame is outside of the interpolate range - and eStop is not true. // FIXME TODO: Be sure these comparisons are correct.
+ if(cur_slice == 0 || (!ci.eStop && MusEGlobal::audio->isPlaying() &&
+ (slice_frame < (unsigned long)ci.sFrame || (ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame)) ) )
{
- _controls[k].val = v;
-#ifndef VST_VESTIGE_SUPPORT
- if(dispatch(effCanBeAutomated, k, 0, NULL, 0.0f) == 1)
+ if(cl && plug_id != -1 && (unsigned long)cl->id() == genACnum(plug_id, k))
{
-#endif
- if(_plugin->getParameter(_plugin, k) != v)
- _plugin->setParameter(_plugin, k, v);
-#ifndef VST_VESTIGE_SUPPORT
+ cl->getInterpolation(slice_frame, no_auto || !_controls[k].enCtrl, &ci);
+ if(icl != cll->end())
+ ++icl;
}
- #ifdef VST_NATIVE_DEBUG
else
- fprintf(stderr, "VstNativeSynthIF::getData %s parameter:%lu cannot be automated\n", name().toLatin1().constData(), k);
- #endif
-#endif
+ {
+ // No matching controller, or end. Just copy the current value into the interpolator.
+ // Keep the current icl iterator, because since they are sorted by frames,
+ // if the IDs didn't match it means we can just let k catch up with icl.
+ ci.sFrame = 0;
+ ci.eFrame = -1;
+ ci.sVal = _controls[k].val;
+ ci.eVal = ci.sVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
}
-
-#ifdef VST_NATIVE_DEBUG_PROCESS
- fprintf(stderr, "VstNativeSynthIF::getData k:%lu sample:%lu frame:%lu nextFrame:%d nsamp:%lu \n", k, sample, frame, nextFrame, nsamp);
-#endif
- if(MusEGlobal::audio->isPlaying() && !usefixedrate && nextFrame != -1)
+ else
{
- // Returned value of nextFrame can be zero meaning caller replaces with some (constant) value.
- unsigned long samps = (unsigned long)nextFrame;
- if(samps > frame + min_per)
+ if(ci.eStop && ci.eFrame != -1 && slice_frame >= (unsigned long)ci.eFrame) // FIXME TODO: Get that comparison right.
{
- unsigned long diff = samps - frame;
- unsigned long mask = min_per-1; // min_per must be power of 2
- samps = diff & ~mask;
- if((diff & mask) != 0)
+ // Clear the stop condition and set up the interp struct appropriately as an endless value.
+ ci.sFrame = 0; //ci->eFrame;
+ ci.eFrame = -1;
+ ci.sVal = ci.eVal;
+ ci.doInterp = false;
+ ci.eStop = false;
+ }
+ if(cl && cll && icl != cll->end())
+ ++icl;
+ }
+
+ if(!usefixedrate && MusEGlobal::audio->isPlaying())
+ {
+ unsigned long samps = nsamp;
+ if(ci.eFrame != -1)
+ samps = (unsigned long)ci.eFrame - slice_frame;
+
+ if(!ci.doInterp && samps > min_per)
+ {
+ samps &= ~min_per_mask;
+ if((samps & min_per_mask) != 0)
samps += min_per;
}
else
@@ -2374,12 +2489,42 @@ iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent s
if(samps < nsamp)
nsamp = samps;
+
+ }
+
+ float new_val;
+ if(ci.doInterp && cl)
+ new_val = cl->interpolate(MusEGlobal::audio->isPlaying() ? slice_frame : pos, ci);
+ else
+ new_val = ci.sVal;
+ if(_controls[k].val != new_val)
+ {
+ _controls[k].val = new_val;
+#ifndef VST_VESTIGE_SUPPORT
+ if(dispatch(effCanBeAutomated, k, 0, NULL, 0.0f) == 1)
+ {
+#endif
+ if(_plugin->getParameter(_plugin, k) != new_val)
+ _plugin->setParameter(_plugin, k, new_val);
+#ifndef VST_VESTIGE_SUPPORT
+ }
+ #ifdef VST_NATIVE_DEBUG
+ else
+ fprintf(stderr, "VstNativeSynthIF::getData %s parameter:%lu cannot be automated\n", name().toLatin1().constData(), k);
+ #endif
+#endif
}
+
+#ifdef VST_NATIVE_DEBUG_PROCESS
+ fprintf(stderr, "VstNativeSynthIF::getData k:%lu sample:%lu frame:%lu ci.eFrame:%d nsamp:%lu \n", k, sample, frame, ci.eFrame, nsamp);
+#endif
+
}
+ }
+
#ifdef VST_NATIVE_DEBUG_PROCESS
fprintf(stderr, "VstNativeSynthIF::getData sample:%lu nsamp:%lu\n", sample, nsamp);
#endif
- }
bool found = false;
unsigned long frame = 0;
@@ -2409,218 +2554,231 @@ iMPEvent VstNativeSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent s
continue;
}
- if(evframe >= nframes // Next events are for a later period.
- || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
- || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
- || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
+ if(evframe >= nframes // Next events are for a later period.
+ || (!usefixedrate && !found && !v.unique && (evframe - sample >= nsamp)) // Next events are for a later run in this period. (Autom took prio.)
+ || (found && !v.unique && (evframe - sample >= min_per)) // Eat up events within minimum slice - they're too close.
+ || (usefixedrate && found && v.unique && v.idx == index)) // Special for dssi-vst: Fixed rate and must reply to all.
break;
_controlFifo.remove(); // Done with the ring buffer's item. Remove it.
- if(v.idx >= _synth->inControls()) // Sanity check.
+ if(v.idx >= in_ctrls) // Sanity check.
break;
+
found = true;
frame = evframe;
index = v.idx;
- //if(_controls[v.idx].val != v.value) // Mm nah, force it always. REMOVE Tim.
- //{
- _controls[v.idx].val = v.value;
-#ifndef VST_VESTIGE_SUPPORT
- if(dispatch(effCanBeAutomated, v.idx, 0, NULL, 0.0f) == 1)
- {
-#endif
- if(v.value != _plugin->getParameter(_plugin, v.idx))
- _plugin->setParameter(_plugin, v.idx, v.value);
-#ifndef VST_VESTIGE_SUPPORT
- }
- #ifdef VST_NATIVE_DEBUG
- else
- fprintf(stderr, "VstNativeSynthIF::getData %s parameter:%lu cannot be automated\n", name().toLatin1().constData(), v.idx);
- #endif
-#endif
- // Need to update the automation value, otherwise it overwrites later with the last automation value.
- if(id() != -1)
- synti->setPluginCtrlVal(genACnum(id(), v.idx), v.value);
- //}
+ if(ports == 0) // Don't bother if not 'running'.
+ {
+ _controls[v.idx].val = v.value; // Might as well at least update these.
+// #ifndef VST_VESTIGE_SUPPORT
+// if(dispatch(effCanBeAutomated, v.idx, 0, NULL, 0.0f) == 1)
+// {
+// #endif
+// if(v.value != _plugin->getParameter(_plugin, v.idx))
+// _plugin->setParameter(_plugin, v.idx, v.value);
+// #ifndef VST_VESTIGE_SUPPORT
+// }
+// #ifdef VST_NATIVE_DEBUG
+// else
+// fprintf(stderr, "VstNativeSynthIF::getData %s parameter:%lu cannot be automated\n", name().toLatin1().constData(), v.idx);
+// #endif
+// #endif
+ }
+ else
+ {
+ CtrlInterpolate* ci = &_controls[v.idx].interp;
+ // Tell it to stop the current ramp at this frame, when it does stop, set this value:
+ ci->eFrame = frame;
+ ci->eVal = v.value;
+ ci->eStop = true;
+ }
+
+ // Need to update the automation value, otherwise it overwrites later with the last automation value.
+ if(plug_id != -1)
+ synti->setPluginCtrlVal(genACnum(plug_id, v.idx), v.value);
}
if(found && !usefixedrate) // If a control FIFO item was found, takes priority over automation controller stream.
nsamp = frame - sample;
- if(sample + nsamp >= nframes) // Safety check.
+ if(sample + nsamp > nframes) // Safety check.
nsamp = nframes - sample;
// TODO: 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(; start_event != el->end(); ++start_event)
+ if(nsamp != 0)
{
- #ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::getData eventlist event time:%d pos:%u sample:%lu nsamp:%lu frameOffset:%d\n", start_event->time(), pos, sample, nsamp, frameOffset);
- #endif
-
- if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
- {
- #ifdef VST_NATIVE_DEBUG
- fprintf(stderr, " event is for future:%lu, breaking loop now\n", start_event->time() - frameOffset - pos - sample);
- #endif
- break;
- }
-
- // 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)
+ unsigned long nevents = 0;
+ if(ports != 0) // Don't bother if not 'running'.
{
- MusECore::MidiPort* mp = &MusEGlobal::midiPorts[synti->midiPort()];
- if(start_event->type() == MusECore::ME_CONTROLLER)
+ // Process event list events...
+ for(; start_event != el->end(); ++start_event)
{
- int da = start_event->dataA();
- int db = start_event->dataB();
- db = mp->limitValToInstrCtlRange(da, db);
- if(!mp->setHwCtrlState(start_event->channel(), da, db))
- continue;
- }
- else if(start_event->type() == MusECore::ME_PITCHBEND)
- {
- int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, start_event->dataA());
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PITCH, da))
- continue;
- }
- else if(start_event->type() == MusECore::ME_AFTERTOUCH)
- {
- int da = mp->limitValToInstrCtlRange(MusECore::CTRL_AFTERTOUCH, start_event->dataA());
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_AFTERTOUCH, da))
- continue;
- }
- else if(start_event->type() == MusECore::ME_POLYAFTER)
- {
- int ctl = (MusECore::CTRL_POLYAFTER & ~0xff) | (start_event->dataA() & 0x7f);
- int db = mp->limitValToInstrCtlRange(ctl, start_event->dataB());
- if(!mp->setHwCtrlState(start_event->channel(), ctl , db))
- continue;
- }
- else if(start_event->type() == MusECore::ME_PROGRAM)
- {
- if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PROGRAM, start_event->dataA()))
- continue;
- }
- }
+ #ifdef VST_NATIVE_DEBUG
+ fprintf(stderr, "VstNativeSynthIF::getData eventlist event time:%d pos:%u sample:%lu nsamp:%lu frameOffset:%d\n", start_event->time(), pos, sample, nsamp, frameOffset);
+ #endif
- // Returns false if the event was not filled. It was handled, but some other way.
- if(processEvent(*start_event, &events[nevents]))
- {
- // Time-stamp the event.
- int ft = start_event->time() - frameOffset - pos - sample;
- if(ft < 0)
- ft = 0;
+ if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again...
+ {
+ #ifdef VST_NATIVE_DEBUG
+ fprintf(stderr, " event is for future:%lu, breaking loop now\n", start_event->time() - frameOffset - pos - sample);
+ #endif
+ break;
+ }
- if (ft >= int(nsamp))
- {
- fprintf(stderr, "VstNativeSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);
- ft = nsamp - 1;
+ // 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 = &MusEGlobal::midiPorts[synti->midiPort()];
+ if(start_event->type() == ME_CONTROLLER)
+ {
+ int da = start_event->dataA();
+ int db = start_event->dataB();
+ db = mp->limitValToInstrCtlRange(da, db);
+ if(!mp->setHwCtrlState(start_event->channel(), da, db))
+ continue;
+ }
+ else if(start_event->type() == ME_PITCHBEND)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_PITCH, start_event->dataA());
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PITCH, da))
+ continue;
+ }
+ else if(start_event->type() == ME_AFTERTOUCH)
+ {
+ int da = mp->limitValToInstrCtlRange(CTRL_AFTERTOUCH, start_event->dataA());
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_AFTERTOUCH, da))
+ continue;
+ }
+ else if(start_event->type() == ME_POLYAFTER)
+ {
+ int ctl = (CTRL_POLYAFTER & ~0xff) | (start_event->dataA() & 0x7f);
+ int db = mp->limitValToInstrCtlRange(ctl, start_event->dataB());
+ if(!mp->setHwCtrlState(start_event->channel(), ctl , db))
+ continue;
+ }
+ else if(start_event->type() == ME_PROGRAM)
+ {
+ if(!mp->setHwCtrlState(start_event->channel(), CTRL_PROGRAM, start_event->dataA()))
+ continue;
+ }
+ }
+
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(*start_event, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = start_event->time() - frameOffset - pos - sample;
+ if(ft < 0)
+ ft = 0;
+
+ if (ft >= int(nsamp))
+ {
+ fprintf(stderr, "VstNativeSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);
+ ft = nsamp - 1;
+ }
+
+ #ifdef VST_NATIVE_DEBUG
+ fprintf(stderr, "VstNativeSynthIF::getData eventlist: ft:%d current nevents:%lu\n", ft, nevents);
+ #endif
+
+ vst_events->events[nevents] = (VstEvent*)&events[nevents];
+ events[nevents].deltaFrames = ft;
+ ++nevents;
+ }
}
+ }
+
+ // Now process putEvent events...
+ while(!synti->eventFifo.isEmpty())
+ {
+ MidiPlayEvent e = synti->eventFifo.peek();
#ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::getData eventlist: ft:%d current nevents:%lu\n", ft, nevents);
+ fprintf(stderr, "VstNativeSynthIF::getData eventFifo event time:%d\n", e.time());
#endif
- vst_events->events[nevents] = (VstEvent*)&events[nevents];
- events[nevents].deltaFrames = ft;
- ++nevents;
- }
- }
+ if(e.time() >= (pos + sample + nsamp + frameOffset))
+ break;
- // Now process putEvent events...
- while(!synti->eventFifo.isEmpty())
- {
- MusECore::MidiPlayEvent e = synti->eventFifo.peek();
+ synti->eventFifo.remove(); // Done with ring buffer's event. Remove it.
+ if(ports != 0) // Don't bother if not 'running'.
+ {
+ // Returns false if the event was not filled. It was handled, but some other way.
+ if(processEvent(e, &events[nevents]))
+ {
+ // Time-stamp the event.
+ int ft = e.time() - frameOffset - pos - sample;
+ if(ft < 0)
+ ft = 0;
+ if (ft >= int(nsamp))
+ {
+ fprintf(stderr, "VstNativeSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", e.time(), pos, frameOffset, ft, sample, nsamp);
+ ft = nsamp - 1;
+ }
+ vst_events->events[nevents] = (VstEvent*)&events[nevents];
+ events[nevents].deltaFrames = ft;
- #ifdef VST_NATIVE_DEBUG
- fprintf(stderr, "VstNativeSynthIF::getData eventFifo event time:%d\n", e.time());
- #endif
+ ++nevents;
+ }
+ }
+ }
- if(e.time() >= (pos + sample + nsamp + frameOffset))
- break;
+ #ifdef VST_NATIVE_DEBUG_PROCESS
+ fprintf(stderr, "VstNativeSynthIF::getData: Connecting and running. sample:%lu nsamp:%lu nevents:%lu\n", sample, nsamp, nevents);
+ #endif
- 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]))
+ if(ports != 0) // Don't bother if not 'running'.
{
- // Time-stamp the event.
- int ft = e.time() - frameOffset - pos - sample;
- if(ft < 0)
- ft = 0;
- if (ft >= int(nsamp))
+ // Set the events pointer.
+ if(nevents > 0)
{
- fprintf(stderr, "VstNativeSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", e.time(), pos, frameOffset, ft, sample, nsamp);
- ft = nsamp - 1;
+ vst_events->numEvents = nevents;
+ dispatch(effProcessEvents, 0, 0, vst_events, 0.0f);
}
- vst_events->events[nevents] = (VstEvent*)&events[nevents];
- events[nevents].deltaFrames = ft;
-
- ++nevents;
- }
- }
-
- #ifdef VST_NATIVE_DEBUG_PROCESS
- fprintf(stderr, "VstNativeSynthIF::getData: Connecting and running. sample:%lu nsamp:%lu nevents:%lu\n", sample, nsamp, nevents);
- #endif
- // Set the events pointer.
- if(nevents > 0)
- {
- vst_events->numEvents = nevents;
- dispatch(effProcessEvents, 0, 0, vst_events, 0.0f);
- }
+ float* in_bufs[_synth->inPorts()];
+ float* out_bufs[_synth->outPorts()];
+
+ unsigned long k = 0;
+ // Connect the given buffers directly to the ports, up to a max of synth ports.
+ for(; k < nop; ++k)
+ out_bufs[k] = buffer[k] + sample;
+ // Connect the remaining ports to some local buffers (not used yet).
+ const unsigned long op =_synth->outPorts();
+ for(; k < op; ++k)
+ out_bufs[k] = _audioOutBuffers[k] + sample;
+ // Connect all inputs either to some local buffers, or a silence buffer.
+ const unsigned long ip =_synth->inPorts();
+ for(k = 0; k < ip; ++k)
+ {
+ if(_iUsedIdx[k])
+ {
+ _iUsedIdx[k] = false; // Reset
+ in_bufs[k] = _audioInBuffers[k] + sample;
+ }
+ else
+ in_bufs[k] = _audioInSilenceBuf + sample;
+ }
- float* in_bufs[_synth->inPorts()];
- float* out_bufs[_synth->outPorts()];
-
- k = 0;
- // Connect the given buffers directly to the ports, up to a max of synth ports.
- for(; k < nop; ++k)
- out_bufs[k] = buffer[k] + sample;
- // Connect the remaining ports to some local buffers (not used yet).
- const unsigned long op =_synth->outPorts();
- for(; k < op; ++k)
- out_bufs[k] = _audioOutBuffers[k] + sample;
- // Connect all inputs either to some local buffers, or a silence buffer.
- const unsigned long ip =_synth->inPorts();
- for(k = 0; k < ip; ++k)
- {
- if(_iUsedIdx[k])
- {
- _iUsedIdx[k] = false; // Reset
- in_bufs[k] = _audioInBuffers[k] + sample;
+ // Run the synth for a period of time. This processes events and gets/fills our local buffers...
+ if((_plugin->flags & effFlagsCanReplacing) && _plugin->processReplacing)
+ {
+ _plugin->processReplacing(_plugin, in_bufs, out_bufs, nsamp);
+ }
}
- else
- in_bufs[k] = _audioInSilenceBuf + sample;
+
+ sample += nsamp;
}
- // Run the synth for a period of time. This processes events and gets/fills our local buffers...
- if((_plugin->flags & effFlagsCanReplacing) && _plugin->processReplacing)
- {
- _plugin->processReplacing(_plugin, in_bufs, out_bufs, nsamp);
- }
-#if 0 //ifdef VST_FORCE_DEPRECATED
- else
- {
- // TODO: This is not right, we don't accumulate data here. Depricated now, and frowned upon anyway...
- if(_plugin->process)
- _plugin->process(_plugin, in_bufs, out_bufs, nsamp);
- }
-#endif
-
- sample += nsamp;
+ ++cur_slice; // Slice is done. Moving on to any next slice now...
}
-
- // Inform the host callback we will be no longer in the audio thread.
- _inProcess = true;
+ // Inform the host callback we will be no longer in the audio thread.
+ _inProcess = false;
+
return start_event;
}
@@ -2652,8 +2810,6 @@ QString VstNativeSynthIF::dirPath() const { return _synt
QString VstNativeSynthIF::fileName() const { return _synth ? _synth->fileName() : QString(); }
void VstNativeSynthIF::enableController(unsigned long i, bool v) { _controls[i].enCtrl = v; }
bool VstNativeSynthIF::controllerEnabled(unsigned long i) const { return _controls[i].enCtrl;}
-void VstNativeSynthIF::enable2Controller(unsigned long i, bool v) { _controls[i].en2Ctrl = v; }
-bool VstNativeSynthIF::controllerEnabled2(unsigned long i) const { return _controls[i].en2Ctrl; }
void VstNativeSynthIF::enableAllControllers(bool v)
{
if(!_synth)
@@ -2662,14 +2818,6 @@ void VstNativeSynthIF::enableAllControllers(bool v)
for(unsigned long i = 0; i < sic; ++i)
_controls[i].enCtrl = v;
}
-void VstNativeSynthIF::enable2AllControllers(bool v)
-{
- if(!_synth)
- return;
- const unsigned long sic = _synth->inControls();
- for(unsigned long i = 0; i < sic; ++i)
- _controls[i].en2Ctrl = v;
-}
void VstNativeSynthIF::updateControllers() { }
void VstNativeSynthIF::activate()
{
@@ -2694,9 +2842,11 @@ void VstNativeSynthIF::activate()
// controls[i].tmpVal = controls[i].val;
// }
// }
+ _active = true;
}
void VstNativeSynthIF::deactivate()
{
+ _active = false;
//for (unsigned short i = 0; i < instances(); ++i) {
#ifndef VST_VESTIGE_SUPPORT
//dispatch(i, effStopProcess, 0, 0, NULL, 0.0f);
diff --git a/muse2/muse/vst_native.h b/muse2/muse/vst_native.h
index 4bbe1411..0d7f5441 100644
--- a/muse2/muse/vst_native.h
+++ b/muse2/muse/vst_native.h
@@ -3,7 +3,7 @@
// Linux Music Editor
//
// vst_native.h
-// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2012-2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -118,8 +118,8 @@ class VstNativeSynth : public Synth {
std::vector<unsigned long> iIdx; // Audio input index to port number.
std::vector<unsigned long> oIdx; // Audio output index to port number.
std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.
- MusECore::MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to vst port numbers.
- MusECore::MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps vst port numbers to midi controller numbers.
+ MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to vst port numbers.
+ MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps vst port numbers to midi controller numbers.
bool _hasGui;
bool _inPlaceCapable;
bool _hasChunks;
@@ -130,7 +130,7 @@ class VstNativeSynth : public Synth {
virtual ~VstNativeSynth() {}
virtual Type synthType() const { return VST_NATIVE_SYNTH; }
virtual void incInstances(int val);
- virtual AEffect* instantiate();
+ virtual AEffect* instantiate(VstNativeSynthIF*);
virtual SynthIF* createSIF(SynthI*);
unsigned long inPorts() const { return _inports; }
unsigned long outPorts() const { return _outports; }
@@ -143,6 +143,21 @@ class VstNativeSynth : public Synth {
};
//---------------------------------------------------------
+// VstNativeGuiWidgets
+//---------------------------------------------------------
+
+struct VstNativeGuiWidgets {
+ // TODO: Remove Tim. Or keep.
+ //enum {
+ // SLIDER, DOUBLE_LABEL, QCHECKBOX, QCOMBOBOX
+ // };
+ //QWidget* widget;
+ //int type;
+ //unsigned long param;
+ bool pressed;
+ };
+
+//---------------------------------------------------------
// VstNativeSynthIF
// VSTi synthesizer instance
//---------------------------------------------------------
@@ -154,10 +169,13 @@ class VstNativeSynthIF : public SynthIF
VstNativeSynth* _synth;
AEffect* _plugin;
+ bool _active; // Whether it's safe to call effIdle or effEditIdle.
MusEGui::VstNativeEditor* _editor;
bool _guiVisible;
bool _inProcess; // To inform the callback of the 'process level' - are we in the audio thread?
+ // Struct array to keep track of pressed flags and so on. // TODO: Not used yet. REMOVE Tim. Or keep.
+ VstNativeGuiWidgets* _gw;
Port* _controls;
float** _audioOutBuffers;
float** _audioInBuffers;
@@ -167,7 +185,7 @@ class VstNativeSynthIF : public SynthIF
std::vector<VST_Program> programs;
void queryPrograms();
void doSelectProgram(int bankH, int bankL, int prog);
- bool processEvent(const MusECore::MidiPlayEvent&, VstMidiEvent*);
+ bool processEvent(const MidiPlayEvent&, VstMidiEvent*);
void setVstEvent(VstMidiEvent* event, int a = 0, int b = 0, int c = 0, int d = 0);
void editorDeleted();
@@ -188,17 +206,17 @@ class VstNativeSynthIF : public SynthIF
bool resizeEditor(int w, int h);
virtual bool initGui() { return true; };
- virtual void guiHeartBeat() { }
+ virtual void guiHeartBeat();
virtual bool guiVisible() const;
virtual void showGui(bool);
virtual bool hasGui() const { return true; }
virtual bool nativeGuiVisible() const;
virtual void showNativeGui(bool v);
virtual bool hasNativeGui() const;
- virtual void getGeometry(int*x, int*y, int*w, int*h) const { *x=0;*y=0;*w=0;*h=0; }
- virtual void setGeometry(int, int, int, int) {}
- virtual void getNativeGeometry(int*x, int*y, int*w, int*h) const { *x=0;*y=0;*w=0;*h=0; }
- virtual void setNativeGeometry(int, int, int, int) {}
+ virtual void getGeometry(int*x, int*y, int*w, int*h) const;
+ virtual void setGeometry(int, int, int, int);
+ virtual void getNativeGeometry(int*x, int*y, int*w, int*h) const ;
+ virtual void setNativeGeometry(int, int, int, int);
virtual void preProcessAlways() { };
virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned nframes, float** buffer) ;
virtual bool putEvent(const MidiPlayEvent& ev);
@@ -230,10 +248,7 @@ class VstNativeSynthIF : public SynthIF
QString fileName() const;
void enableController(unsigned long i, bool v = true);
bool controllerEnabled(unsigned long i) const;
- void enable2Controller(unsigned long i, bool v = true);
- bool controllerEnabled2(unsigned long i) const;
void enableAllControllers(bool v = true);
- void enable2AllControllers(bool v = true);
void updateControllers();
void activate();
void deactivate();
diff --git a/muse2/muse/waveedit/waveedit.cpp b/muse2/muse/waveedit/waveedit.cpp
index a8477bbc..7294e7c3 100644
--- a/muse2/muse/waveedit/waveedit.cpp
+++ b/muse2/muse/waveedit/waveedit.cpp
@@ -529,8 +529,8 @@ void WaveEdit::writeStatus(int level, MusECore::Xml& xml) const
xml.tag(level++, "waveedit");
MidiEditor::writeStatus(level, xml);
xml.intTag(level, "tool", int(canvas->tool()));
- xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "xmag", hscroll->mag());
+ xml.intTag(level, "xpos", hscroll->pos());
xml.intTag(level, "ymag", ymag->value());
xml.tag(level, "/waveedit");
}
diff --git a/muse2/muse/wavetrack.cpp b/muse2/muse/wavetrack.cpp
index c9997eae..363f8966 100644
--- a/muse2/muse/wavetrack.cpp
+++ b/muse2/muse/wavetrack.cpp
@@ -252,31 +252,25 @@ Part* WaveTrack::newPart(Part*p, bool clone)
bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float** bp)
{
+ bool have_data = false;
if ((MusEGlobal::song->bounceTrack != this) && !noInRoute()) {
RouteList* irl = inRoutes();
- ciRoute i = irl->begin();
- if(i->track->isMidiTrack())
- return false;
-
- ((AudioTrack*)i->track)->copyData(framePos, channels,
- i->channel,
- i->channels,
- nframe, bp);
-
- ++i;
- for (; i != irl->end(); ++i)
+ for(ciRoute i = irl->begin(); i != irl->end(); ++i)
{
if(i->track->isMidiTrack())
continue;
- ((AudioTrack*)i->track)->addData(framePos, channels,
- i->channel,
+ ((AudioTrack*)i->track)->copyData(framePos, channels,
+ i->channel,
i->channels,
- nframe, bp);
-
+ nframe, bp, have_data);
+ have_data = true;
}
+
if (recordFlag()) {
- if (MusEGlobal::audio->isRecording() && recFile()) {
+ //if (have_data && recordFlag()) {
+ //if (MusEGlobal::audio->isRecording() && recFile()) {
+ if (have_data && MusEGlobal::audio->isRecording() && recFile()) {
if (MusEGlobal::audio->freewheel()) {
}
else {
@@ -295,39 +289,42 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float*
framePos, channels, nframe);
}
}
- return true;
+ //return true; // REMOVE Tim. Can't hear existing parts while recording, even while simply armed.
+ // FIXME TODO Remove this. But first code below needs to become ADDITIVE/REPLACING (don't just take over buffers).
+ return have_data;
}
}
if (!MusEGlobal::audio->isPlaying())
return false;
+ //return have_data;
- if (MusEGlobal::audio->freewheel()) {
-
- // when freewheeling, read data direct from file:
- // Indicate do not seek file before each read.
- fetchData(framePos, nframe, bp, false);
-
+ if (MusEGlobal::audio->freewheel()) {
+
+ // when freewheeling, read data direct from file:
+ // Indicate do not seek file before each read.
+ fetchData(framePos, nframe, bp, false);
+
+ }
+ else {
+ unsigned pos;
+ if (_prefetchFifo.get(channels, nframe, bp, &pos)) {
+ printf("WaveTrack::getData(%s) fifo underrun\n",
+ name().toLatin1().constData());
+ return false;
}
- else {
- unsigned pos;
- if (_prefetchFifo.get(channels, nframe, bp, &pos)) {
- printf("WaveTrack::getData(%s) fifo underrun\n",
- name().toLatin1().constData());
- return false;
- }
- if (pos != framePos) {
- if (MusEGlobal::debugMsg)
- printf("fifo get error expected %d, got %d\n",
- framePos, pos);
- while (pos < framePos) {
- if (_prefetchFifo.get(channels, nframe, bp, &pos)) {
- printf("WaveTrack::getData(%s) fifo underrun\n",
- name().toLatin1().constData());
- return false;
- }
+ if (pos != framePos) {
+ if (MusEGlobal::debugMsg)
+ printf("fifo get error expected %d, got %d\n",
+ framePos, pos);
+ while (pos < framePos) {
+ if (_prefetchFifo.get(channels, nframe, bp, &pos)) {
+ printf("WaveTrack::getData(%s) fifo underrun\n",
+ name().toLatin1().constData());
+ return false;
}
}
}
+ }
return true;
}
diff --git a/muse2/muse/widgets/scrollscale.cpp b/muse2/muse/widgets/scrollscale.cpp
index fcf36e1b..5664bfc2 100644
--- a/muse2/muse/widgets/scrollscale.cpp
+++ b/muse2/muse/widgets/scrollscale.cpp
@@ -198,7 +198,6 @@ void ScrollScale::setRange ( int min, int max )
void ScrollScale::setPos ( unsigned pos )
{
-
scroll->setValue ( pos );
}
diff --git a/muse2/muse/widgets/sliderbase.cpp b/muse2/muse/widgets/sliderbase.cpp
index 5909c64d..3dfbfa40 100644
--- a/muse2/muse/widgets/sliderbase.cpp
+++ b/muse2/muse/widgets/sliderbase.cpp
@@ -386,17 +386,19 @@ void SliderBase::mouseMoveEvent(QMouseEvent *e)
double ms = 0.0;
if (d_scrollMode == ScrMouse )
{
- setPosition(e->pos());
- if (d_mass > 0.0)
- {
- ms = double(d_time.elapsed());
- if (ms < 1.0) ms = 1.0;
- d_speed = (exactValue() - exactPrevValue()) / ms;
- d_time.start();
- }
- if (value() != prevValue())
- emit sliderMoved(value(), _id);
- emit sliderMoved(value(), _id, (bool)(e->modifiers() & Qt::ShiftModifier));
+ setPosition(e->pos());
+ if (d_mass > 0.0)
+ {
+ ms = double(d_time.elapsed());
+ if (ms < 1.0) ms = 1.0;
+ d_speed = (exactValue() - exactPrevValue()) / ms;
+ d_time.start();
+ }
+ if (value() != prevValue())
+ {
+ emit sliderMoved(value(), _id);
+ emit sliderMoved(value(), _id, (bool)(e->modifiers() & Qt::ShiftModifier));
+ }
}
}
diff --git a/muse2/muse/widgets/tracks_duplicate_base.ui b/muse2/muse/widgets/tracks_duplicate_base.ui
index 601c9f25..8c5b6a71 100644
--- a/muse2/muse/widgets/tracks_duplicate_base.ui
+++ b/muse2/muse/widgets/tracks_duplicate_base.ui
@@ -110,7 +110,7 @@
<item>
<widget class="QCheckBox" name="standardCtrlsCheckBox">
<property name="text">
- <string>Copy standard controllers (vol, pan)</string>
+ <string>Copy standard (vol, pan) and synth controllers</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -119,9 +119,6 @@
</item>
<item>
<widget class="QCheckBox" name="pluginsCheckBox">
- <property name="enabled">
- <bool>false</bool>
- </property>
<property name="text">
<string>Copy effects rack plugins</string>
</property>
diff --git a/muse2/muse/widgets/vst_native_editor.cpp b/muse2/muse/widgets/vst_native_editor.cpp
index b194529d..651d817f 100644
--- a/muse2/muse/widgets/vst_native_editor.cpp
+++ b/muse2/muse/widgets/vst_native_editor.cpp
@@ -157,7 +157,7 @@ void VstNativeEditor::open(MusECore::VstNativeSynthIF* sif)
show();
raise();
activateWindow();
- _sif->idleEditor();
+ ///_sif->idleEditor(); // REMOVE Tim. Or keep.
}
#if defined(Q_WS_X11)
diff --git a/muse2/synti/deicsonze/deicsonze.cpp b/muse2/synti/deicsonze/deicsonze.cpp
index ef5644fa..1051c9eb 100644
--- a/muse2/synti/deicsonze/deicsonze.cpp
+++ b/muse2/synti/deicsonze/deicsonze.cpp
@@ -4096,7 +4096,7 @@ void DeicsOnze::processMessages()
// write
// synthesize n samples into buffer+offset
//---------------------------------------------------------
-void DeicsOnze::process(float** buffer, int offset, int n) {
+void DeicsOnze::process(unsigned pos, float** buffer, int offset, int n) {
/*
//Process messages from the gui
while (_gui->fifoSize()) {
@@ -4432,46 +4432,61 @@ void DeicsOnze::process(float** buffer, int offset, int n) {
//apply Filter
if(_global.filter) _dryFilter->process(leftOutput, rightOutput, n);
//Chorus
- if(_pluginIChorus && _global.isChorusActivated) {
- //apply Filter
- if(_global.filter) _chorusFilter->process(tempOutputChorus[0],
- tempOutputChorus[1], n);
- //apply Chorus
- _pluginIChorus->apply(n, 2, tempInputChorus, tempOutputChorus);
- for(int i = 0; i < n; i++) {
- leftOutput[i] +=
- tempOutputChorus[0][i] * _global.chorusReturn * _global.masterVolume;
- rightOutput[i] +=
- tempOutputChorus[1][i] * _global.chorusReturn * _global.masterVolume;
+ if(_pluginIChorus) {
+ if(_global.isChorusActivated)
+ {
+ //apply Filter
+ if(_global.filter) _chorusFilter->process(tempOutputChorus[0],
+ tempOutputChorus[1], n);
+ //apply Chorus
+ _pluginIChorus->apply(pos, n, 2, tempInputChorus, tempOutputChorus);
+ for(int i = 0; i < n; i++) {
+ leftOutput[i] +=
+ tempOutputChorus[0][i] * _global.chorusReturn * _global.masterVolume;
+ rightOutput[i] +=
+ tempOutputChorus[1][i] * _global.chorusReturn * _global.masterVolume;
+ }
}
+ else
+ _pluginIChorus->apply(pos, n, 0, 0, 0); // Just process controls only, not audio (do not 'run'). Tim.
}
//Reverb
- if(_pluginIReverb && _global.isReverbActivated) {
- //apply Filter
- if(_global.filter) _reverbFilter->process(tempOutputReverb[0],
- tempOutputReverb[1], n);
- //apply Reverb
- _pluginIReverb->apply(n, 2, tempInputReverb, tempOutputReverb);
- for(int i = 0; i < n; i++) {
- leftOutput[i] +=
- tempOutputReverb[0][i] * _global.reverbReturn * _global.masterVolume;
- rightOutput[i] +=
- tempOutputReverb[1][i] * _global.reverbReturn * _global.masterVolume;
+ if(_pluginIReverb) {
+ if(_global.isReverbActivated)
+ {
+ //apply Filter
+ if(_global.filter) _reverbFilter->process(tempOutputReverb[0],
+ tempOutputReverb[1], n);
+ //apply Reverb
+ _pluginIReverb->apply(pos, n, 2, tempInputReverb, tempOutputReverb);
+ for(int i = 0; i < n; i++) {
+ leftOutput[i] +=
+ tempOutputReverb[0][i] * _global.reverbReturn * _global.masterVolume;
+ rightOutput[i] +=
+ tempOutputReverb[1][i] * _global.reverbReturn * _global.masterVolume;
+ }
}
+ else
+ _pluginIReverb->apply(pos, n, 0, 0, 0); // Just process controls only, not audio (do not 'run'). Tim.
}
//Delay
- if(_pluginIDelay && _global.isDelayActivated) {
- //apply Filter
- if(_global.filter) _delayFilter->process(tempOutputDelay[0],
- tempOutputDelay[1], n);
- //apply Delay
- _pluginIDelay->apply(n, 2, tempInputDelay, tempOutputDelay);
- for(int i = 0; i < n; i++) {
- leftOutput[i] +=
- tempOutputDelay[0][i] * _global.delayReturn * _global.masterVolume;
- rightOutput[i] +=
- tempOutputDelay[1][i] * _global.delayReturn * _global.masterVolume;
+ if(_pluginIDelay) {
+ if(_global.isDelayActivated)
+ {
+ //apply Filter
+ if(_global.filter) _delayFilter->process(tempOutputDelay[0],
+ tempOutputDelay[1], n);
+ //apply Delay
+ _pluginIDelay->apply(pos, n, 2, tempInputDelay, tempOutputDelay);
+ for(int i = 0; i < n; i++) {
+ leftOutput[i] +=
+ tempOutputDelay[0][i] * _global.delayReturn * _global.masterVolume;
+ rightOutput[i] +=
+ tempOutputDelay[1][i] * _global.delayReturn * _global.masterVolume;
+ }
}
+ else
+ _pluginIDelay->apply(pos, n, 0, 0, 0); // Just process controls only, not audio (do not 'run'). Tim.
}
}
diff --git a/muse2/synti/deicsonze/deicsonze.h b/muse2/synti/deicsonze/deicsonze.h
index 2df235e3..cf4b444b 100644
--- a/muse2/synti/deicsonze/deicsonze.h
+++ b/muse2/synti/deicsonze/deicsonze.h
@@ -604,7 +604,7 @@ class DeicsOnze : public Mess {
virtual bool playNote(int channel, int pitch, int velo);
virtual void processMessages();
- virtual void process(float** buffer, int offset, int n);
+ virtual void process(unsigned pos, float** buffer, int offset, int n);
// GUI interface routines
//virtual bool hasGui() const { return true; }
diff --git a/muse2/synti/deicsonze/deicsonzeplugin.cpp b/muse2/synti/deicsonze/deicsonzeplugin.cpp
index a9eec657..ba25e58a 100644
--- a/muse2/synti/deicsonze/deicsonzeplugin.cpp
+++ b/muse2/synti/deicsonze/deicsonzeplugin.cpp
@@ -125,7 +125,8 @@ void DeicsOnze::initPluginDelay(MusECore::Plugin* pluginDelay) {
*/
//setChorusParam(i, pluginDelay->defaultValue(i));
- setDelayParam(i, _pluginIDelay->defaultValue(i));
+ //setDelayParam(i, _pluginIDelay->defaultValue(i));
+ _pluginIDelay->putParam(i, _pluginIDelay->defaultValue(i));
}
//setDelayDryWet(1);
@@ -406,36 +407,44 @@ void DeicsOnzeGui::buildGuiChorus() {
//of the parameter because it sends a double and does not
//change any thing
void DeicsOnzeGui::setReverbCheckBox(double v, int i) {
- if(i>=256) {
- printf("setReverbCheckBox Error : controller index >= 256\n");
- return;
- }
- float f = (float)v;
- unsigned char message[sizeof(float)+4];
- message[0]=MUSE_SYNTH_SYSEX_MFG_ID;
- message[1]=DEICSONZE_UNIQUE_ID;
- message[2]=SYSEX_REVERBPARAM;
- message[3]=(unsigned char)i;
- memcpy(&message[4], &f, sizeof(float));
- sendSysex(message, sizeof(float)+4);
+// REMOVE Tim. Or keep. TESTING...
+// if(i>=256) {
+// printf("setReverbCheckBox Error : controller index >= 256\n");
+// return;
+// }
+// float f = (float)v;
+// unsigned char message[sizeof(float)+4];
+// message[0]=MUSE_SYNTH_SYSEX_MFG_ID;
+// message[1]=DEICSONZE_UNIQUE_ID;
+// message[2]=SYSEX_REVERBPARAM;
+// message[3]=(unsigned char)i;
+// memcpy(&message[4], &f, sizeof(float));
+// sendSysex(message, sizeof(float)+4);
+
+ // Putting directly to the control FIFO without SYSEX should be OK. Tim.
+ _deicsOnze->setReverbParam(i, v);
}
//setChorusCheckBox is used, by the way, to send the value
//of the parameter because it sends a double and does not
//change any thing
void DeicsOnzeGui::setChorusCheckBox(double v, int i) {
- if(i>=256) {
- printf("setChorusCheckBox Error : controller index >= 256\n");
- return;
- }
- float f = (float)v;
- unsigned char message[sizeof(float)+4];
- message[0]=MUSE_SYNTH_SYSEX_MFG_ID;
- message[1]=DEICSONZE_UNIQUE_ID;
- message[2]=SYSEX_CHORUSPARAM;
- message[3]=(unsigned char)i;
- memcpy(&message[4], &f, sizeof(float));
- sendSysex(message, sizeof(float)+4);
+// REMOVE Tim. Or keep. TESTING...
+// if(i>=256) {
+// printf("setChorusCheckBox Error : controller index >= 256\n");
+// return;
+// }
+// float f = (float)v;
+// unsigned char message[sizeof(float)+4];
+// message[0]=MUSE_SYNTH_SYSEX_MFG_ID;
+// message[1]=DEICSONZE_UNIQUE_ID;
+// message[2]=SYSEX_CHORUSPARAM;
+// message[3]=(unsigned char)i;
+// memcpy(&message[4], &f, sizeof(float));
+// sendSysex(message, sizeof(float)+4);
+
+ // Putting directly to the control FIFO without SYSEX should be OK. Tim.
+ _deicsOnze->setChorusParam(i, v);
}
void DeicsOnzeGui::setReverbFloatEntry(double v, int i) {
diff --git a/muse2/synti/deicsonze/deicsonzepreset.h b/muse2/synti/deicsonze/deicsonzepreset.h
index e9bfb185..637350e9 100644
--- a/muse2/synti/deicsonze/deicsonzepreset.h
+++ b/muse2/synti/deicsonze/deicsonzepreset.h
@@ -33,6 +33,7 @@
#include <vector>
#include <string>
#include "al/xml.h"
+#include "muse/midictrl.h"
#define NBROP 4 //do not change
#define MAXCHARTAG 64
@@ -46,7 +47,8 @@
// number of ctrl
// following the internal DX11 organization (c.f T81Z manual)
//---------------------------------------------------------
-#define CTRLOFFSET 0x100
+//#define CTRLOFFSET 0x100
+#define CTRLOFFSET (MusECore::CTRL_NRPN14_OFFSET)
#define DECAPAR1 13
#define ARSTR "AR"
#define ARLONGSTR "AttackRate"
diff --git a/muse2/synti/fluid/fluid.cpp b/muse2/synti/fluid/fluid.cpp
index 5ee3835f..81d914eb 100644
--- a/muse2/synti/fluid/fluid.cpp
+++ b/muse2/synti/fluid/fluid.cpp
@@ -355,7 +355,7 @@ void ISynth::processMessages()
// Called from host, ONLY if output path is connected.
//---------------------------------------------------------
-void ISynth::process(float** ports, int offset, int n)
+void ISynth::process(unsigned /*pos*/, float** ports, int offset, int n)
{
if (!_busy) {
/*
diff --git a/muse2/synti/fluid/fluid.h b/muse2/synti/fluid/fluid.h
index a9891f3f..152af2d8 100644
--- a/muse2/synti/fluid/fluid.h
+++ b/muse2/synti/fluid/fluid.h
@@ -70,7 +70,7 @@ class ISynth : public Mess {
void resetAllController(int);
virtual void processMessages();
- virtual void process(float**, int, int);
+ virtual void process(unsigned pos, float**, int, int);
virtual bool playNote(int channel, int pitch, int velo);
virtual bool setController(int, int, int);
virtual bool sysex(int len, const unsigned char* p);
diff --git a/muse2/synti/fluidsynth/fluidsynti.cpp b/muse2/synti/fluidsynth/fluidsynti.cpp
index eddedc87..2e19b79a 100644
--- a/muse2/synti/fluidsynth/fluidsynti.cpp
+++ b/muse2/synti/fluidsynth/fluidsynti.cpp
@@ -220,7 +220,7 @@ void FluidSynth::processMessages()
// Called from host, ONLY if output path is connected.
//---------------------------------------------------------
-void FluidSynth::process(float** ports, int offset, int len)
+void FluidSynth::process(unsigned /*pos*/, float** ports, int offset, int len)
{
/*
//Process messages from the gui
diff --git a/muse2/synti/fluidsynth/fluidsynti.h b/muse2/synti/fluidsynth/fluidsynti.h
index ca24f6f8..19d682c8 100644
--- a/muse2/synti/fluidsynth/fluidsynti.h
+++ b/muse2/synti/fluidsynth/fluidsynti.h
@@ -132,7 +132,7 @@ public:
// This is only a kludge required to support old songs' midistates. Do not use in any new synth.
virtual int oldMidiStateHeader(const unsigned char** data) const;
virtual void processMessages();
- virtual void process(float**, int, int);
+ virtual void process(unsigned pos, float**, int, int);
virtual bool playNote(int channel, int pitch, int velo);
virtual bool sysex(int, const unsigned char*);
virtual bool setController(int, int, int);
diff --git a/muse2/synti/libsynti/mess.cpp b/muse2/synti/libsynti/mess.cpp
index de24ac00..08dc8223 100644
--- a/muse2/synti/libsynti/mess.cpp
+++ b/muse2/synti/libsynti/mess.cpp
@@ -149,6 +149,8 @@ bool Mess::processEvent(const MusECore::MidiPlayEvent& ev)
return setController(ev.channel(), MusECore::CTRL_PITCH, ev.dataA());
case MusECore::ME_AFTERTOUCH:
return setController(ev.channel(), MusECore::CTRL_AFTERTOUCH, ev.dataA());
+ case MusECore::ME_PROGRAM:
+ return setController(ev.channel(), MusECore::CTRL_PROGRAM, ev.dataA());
}
return false;
}
diff --git a/muse2/synti/libsynti/mess.h b/muse2/synti/libsynti/mess.h
index db74c1c8..66022bf7 100644
--- a/muse2/synti/libsynti/mess.h
+++ b/muse2/synti/libsynti/mess.h
@@ -76,7 +76,7 @@ class Mess {
void setSampleRate(int r) { _sampleRate = r; }
virtual void processMessages() { };
- virtual void process(float** data, int offset, int len) = 0;
+ virtual void process(unsigned pos, float** data, int offset, int len) = 0;
// the synti has to (re-)implement processEvent() or provide
// some of the next three functions:
diff --git a/muse2/synti/organ/organ.cpp b/muse2/synti/organ/organ.cpp
index fdcd02aa..93b4c8cf 100644
--- a/muse2/synti/organ/organ.cpp
+++ b/muse2/synti/organ/organ.cpp
@@ -230,7 +230,7 @@ void Organ::processMessages()
// Called from host, ONLY if output path is connected.
//---------------------------------------------------------
-void Organ::process(float** ports, int offset, int sampleCount)
+void Organ::process(unsigned /*pos*/, float** ports, int offset, int sampleCount)
{
/*
//
diff --git a/muse2/synti/organ/organ.h b/muse2/synti/organ/organ.h
index 8a7de162..9ca4bbd0 100644
--- a/muse2/synti/organ/organ.h
+++ b/muse2/synti/organ/organ.h
@@ -193,7 +193,7 @@ class Organ : public Mess {
public:
virtual void processMessages();
- virtual void process(float**, int, int);
+ virtual void process(unsigned pos, float**, int, int);
virtual bool playNote(int channel, int pitch, int velo);
virtual bool setController(int channel, int ctrl, int val);
diff --git a/muse2/synti/s1/s1.cpp b/muse2/synti/s1/s1.cpp
index 8dd40ff8..890acdf9 100644
--- a/muse2/synti/s1/s1.cpp
+++ b/muse2/synti/s1/s1.cpp
@@ -59,7 +59,7 @@ class S1 : public MessMono {
virtual void note(int channel, int pitch, int velo);
//virtual void processMessages();
- virtual void process(float** buffer, int offset, int n);
+ virtual void process(unsigned pos, float** buffer, int offset, int n);
//virtual bool hasGui() const { return true; }
//virtual bool guiVisible() const { return _showGui; }
//virtual void showGui(bool);
@@ -143,7 +143,7 @@ void S1::note(int /*channel*/, int pitch, int velo)
// synthesize n samples into buffer+offset
//---------------------------------------------------------
-void S1::process(float** buffer, int offset, int n)
+void S1::process(unsigned /*pos*/, float** buffer, int offset, int n)
{
if (gate == 0)
return;
diff --git a/muse2/synti/simpledrums2/simpledrums.cpp b/muse2/synti/simpledrums2/simpledrums.cpp
index a0d2b75b..734a6feb 100644
--- a/muse2/synti/simpledrums2/simpledrums.cpp
+++ b/muse2/synti/simpledrums2/simpledrums.cpp
@@ -812,7 +812,7 @@ void SimpleSynth::processMessages()
\param len - nr of samples to process
*/
//---------------------------------------------------------
-void SimpleSynth::process(float** out, int offset, int len)
+void SimpleSynth::process(unsigned /*pos*/, float** out, int offset, int len)
{
/*
//Process messages from the gui
diff --git a/muse2/synti/simpledrums2/simpledrums.h b/muse2/synti/simpledrums2/simpledrums.h
index f4bf27ee..fdeaa946 100644
--- a/muse2/synti/simpledrums2/simpledrums.h
+++ b/muse2/synti/simpledrums2/simpledrums.h
@@ -147,7 +147,7 @@ class SimpleSynth : public Mess
virtual const MidiPatch* getPatchInfo(int arg1, const MidiPatch* arg2) const;
virtual int getControllerInfo(int arg1, const char** arg2, int* arg3, int* arg4, int* arg5, int* arg6) const;
virtual void processMessages();
- virtual void process(float** data, int offset, int len);
+ virtual void process(unsigned pos, float** data, int offset, int len);
//virtual void showGui(bool arg1);
virtual void showNativeGui(bool arg1);
///virtual void getInitData(int*, const unsigned char**) const;
diff --git a/muse2/synti/vam/vam.cpp b/muse2/synti/vam/vam.cpp
index 713d8a59..c194a3a5 100644
--- a/muse2/synti/vam/vam.cpp
+++ b/muse2/synti/vam/vam.cpp
@@ -206,7 +206,7 @@ class VAM : public MessMono {
virtual void getNativeGeometry(int* x, int* y, int* w, int* h) const;
virtual void setNativeGeometry(int x, int y, int w, int h);
virtual void processMessages();
- virtual void process(float**, int, int);
+ virtual void process(unsigned pos, float**, int, int);
virtual void note(int channel, int pitch, int velo);
virtual bool setController(int channel, int ctrl, int val);
virtual bool sysex(int, const unsigned char*);
@@ -471,7 +471,7 @@ void VAM::processMessages()
// Called from host, ONLY if output path is connected.
//---------------------------------------------------------
-void VAM::process(float** ports, int offset, int sampleCount)
+void VAM::process(unsigned /*pos*/, float** ports, int offset, int sampleCount)
{
/*
//