summaryrefslogtreecommitdiff
path: root/muse2/muse/audiotrack.cpp
diff options
context:
space:
mode:
authorRobert Jonsson <spamatica@gmail.com>2010-10-13 19:34:22 +0000
committerRobert Jonsson <spamatica@gmail.com>2010-10-13 19:34:22 +0000
commit8a2c2824a59d7644e13bc52c9a0ecbd641f21f95 (patch)
tree064ad3f2bf8daab0ad27b128abd86a9bbdb1e496 /muse2/muse/audiotrack.cpp
parenta27706d9629e8b592cca4659f865b70adef24e6d (diff)
new branch muse2, first checkin
Diffstat (limited to 'muse2/muse/audiotrack.cpp')
-rw-r--r--muse2/muse/audiotrack.cpp1639
1 files changed, 1639 insertions, 0 deletions
diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp
new file mode 100644
index 00000000..189e39d1
--- /dev/null
+++ b/muse2/muse/audiotrack.cpp
@@ -0,0 +1,1639 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: audiotrack.cpp,v 1.14.2.21 2009/12/20 05:00:35 terminator356 Exp $
+//
+// (C) Copyright 2004 Werner Schweer (ws@seh.de)
+//=========================================================
+
+#include <values.h>
+#include <stdlib.h>
+#include <qmessagebox.h>
+#include <map>
+#include "track.h"
+#include "event.h"
+#include "song.h"
+#include "audio.h"
+#include "wave.h"
+#include "xml.h"
+#include "plugin.h"
+#include "audiodev.h"
+
+// By T356. For caching jack in/out routing names BEFORE file save.
+// Jack often shuts down during file save, causing the routes to be lost in the file.
+// cacheJackRouteNames() is ONLY called from MusE::save() in app.cpp
+// Update: Not required any more because the real problem was Jack RT priority, which has been fixed.
+/*
+typedef std::multimap <const int, QString> jackRouteNameMap;
+std::map <const AudioTrack*, jackRouteNameMap > jackRouteNameCache;
+typedef std::multimap <const int, QString>::const_iterator ciJackRouteNameMap;
+typedef std::map <const AudioTrack*, jackRouteNameMap>::const_iterator ciJackRouteNameCache;
+void cacheJackRouteNames()
+{
+ jackRouteNameCache.clear();
+ const InputList* il = song->inputs();
+ for(ciAudioInput iai = il->begin(); iai != il->end(); ++iai)
+ {
+ const RouteList* rl = (*iai)->inRoutes();
+ if(!rl->empty())
+ {
+ jackRouteNameMap rm = jackRouteNameMap();
+ for(ciRoute r = rl->begin(); r != rl->end(); ++r)
+ rm.insert(std::pair<const int, QString>(r->channel, r->name()));
+ jackRouteNameCache.insert(std::pair<const AudioTrack*, jackRouteNameMap>(*iai, rm));
+ }
+ }
+ const OutputList* ol = song->outputs();
+ for(ciAudioOutput iao = ol->begin(); iao != ol->end(); ++iao)
+ {
+ const RouteList* rl = (*iao)->outRoutes();
+ if(!rl->empty())
+ {
+ jackRouteNameMap rm = jackRouteNameMap();
+ for(ciRoute r = rl->begin(); r != rl->end(); ++r)
+ rm.insert(std::pair<const int, QString>(r->channel, r->name()));
+ jackRouteNameCache.insert(std::pair<const AudioTrack*, jackRouteNameMap>(*iao, rm));
+ }
+ }
+}
+*/
+
+//---------------------------------------------------------
+// AudioTrack
+//---------------------------------------------------------
+
+AudioTrack::AudioTrack(TrackType t)
+//AudioTrack::AudioTrack(TrackType t, int num_out_bufs)
+ : Track(t)
+ {
+ //_totalOutChannels = num_out_bufs; // Is either parameter-default MAX_CHANNELS, or custom value passed (used by syntis).
+ _processed = false;
+ _haveData = false;
+ _sendMetronome = false;
+ _prefader = false;
+ _efxPipe = new Pipeline();
+ _recFile = 0;
+ _channels = 0;
+ _automationType = AUTO_OFF;
+ //setChannels(1);
+ setChannels(2);
+ addController(new CtrlList(AC_VOLUME,"Volume",0.0,1.0));
+ addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0));
+ addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0));
+
+ // Changed by Tim. p3.3.15
+ //outBuffers = new float*[MAX_CHANNELS];
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // outBuffers[i] = new float[segmentSize];
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize);
+
+ // Let's allocate it all in one block, and just point the remaining buffer pointers into the block
+ // which allows faster one-shot buffer copying.
+ // Nope. Nice but interferes with possibility we don't know if other buffers are contiguous (jack buffers, local stack buffers etc.).
+ //posix_memalign((void**)(outBuffers), 16, sizeof(float) * segmentSize * MAX_CHANNELS);
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // *(outBuffers + i) = sizeof(float) * segmentSize * i;
+
+ // p3.3.38
+ // Easy way, less desirable... Start out with enough for MAX_CHANNELS. Then multi-channel syntis can re-allocate,
+ // via a call to (a modified!) setChannels().
+ // Hard way, more desirable... Creating a synti instance passes the total channels to this constructor, overriding MAX_CHANNELS.
+ _totalOutChannels = MAX_CHANNELS;
+ outBuffers = new float*[_totalOutChannels];
+ for (int i = 0; i < _totalOutChannels; ++i)
+ posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * segmentSize);
+
+ // This is only set by multi-channel syntis...
+ _totalInChannels = 0;
+
+ bufferPos = MAXINT;
+
+ setVolume(1.0);
+ }
+
+//AudioTrack::AudioTrack(const AudioTrack& t)
+// : Track(t)
+AudioTrack::AudioTrack(const AudioTrack& t, bool cloneParts)
+ : Track(t, cloneParts)
+ {
+ _totalOutChannels = t._totalOutChannels; // Is either MAX_CHANNELS, or custom value (used by syntis).
+ _processed = false;
+ _haveData = false;
+ _sendMetronome = t._sendMetronome;
+ _controller = t._controller;
+ _prefader = t._prefader;
+ _auxSend = t._auxSend;
+ _efxPipe = new Pipeline(*(t._efxPipe));
+ _automationType = t._automationType;
+ _inRoutes = t._inRoutes;
+ _outRoutes = t._outRoutes;
+ // Changed by Tim. p3.3.15
+ //outBuffers = new float*[MAX_CHANNELS];
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // outBuffers[i] = new float[segmentSize];
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // posix_memalign((void**)(outBuffers + i), 16, sizeof(float) * segmentSize);
+
+ // p3.3.38
+ 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;
+ outBuffers = new float*[chans];
+ for (int i = 0; i < chans; ++i)
+ posix_memalign((void**)&outBuffers[i], 16, sizeof(float) * segmentSize);
+
+ bufferPos = MAXINT;
+ _recFile = t._recFile;
+ }
+
+AudioTrack::~AudioTrack()
+{
+ delete _efxPipe;
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // delete[] outBuffers[i];
+ //delete[] outBuffers;
+
+ // p3.3.15
+ //for(int i = 0; i < MAX_CHANNELS; ++i)
+ //{
+ // if(outBuffers[i])
+ // free(outBuffers[i]);
+ //}
+
+ // p3.3.38
+ 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;
+ for(int i = 0; i < chans; ++i)
+ {
+ if(outBuffers[i])
+ free(outBuffers[i]);
+ }
+ delete[] outBuffers;
+
+}
+
+//---------------------------------------------------------
+// deleteAllEfxGuis
+//---------------------------------------------------------
+
+void AudioTrack::deleteAllEfxGuis()
+{
+ if(_efxPipe)
+ _efxPipe->deleteAllGuis();
+}
+
+//---------------------------------------------------------
+// clearEfxList
+//---------------------------------------------------------
+
+void AudioTrack::clearEfxList()
+{
+ if(_efxPipe)
+ for(int i = 0; i < PipelineDepth; i++)
+ (*_efxPipe)[i] = 0;
+}
+
+//---------------------------------------------------------
+// newPart
+//---------------------------------------------------------
+
+Part* AudioTrack::newPart(Part*, bool /*clone*/)
+ {
+ return 0;
+ }
+
+//---------------------------------------------------------
+// addPlugin
+//---------------------------------------------------------
+
+void AudioTrack::addPlugin(PluginI* plugin, int idx)
+{
+ if (plugin == 0)
+ {
+ PluginI* oldPlugin = (*_efxPipe)[idx];
+ if (oldPlugin)
+ {
+ oldPlugin->setID(-1);
+ oldPlugin->setTrack(0);
+
+ int controller = oldPlugin->parameters();
+ for (int i = 0; i < controller; ++i)
+ {
+ int id = genACnum(idx, i);
+ removeController(id);
+ }
+ }
+ }
+ efxPipe()->insert(plugin, idx);
+ if (plugin)
+ {
+ plugin->setID(idx);
+ plugin->setTrack(this);
+
+ int controller = plugin->parameters();
+ for (int i = 0; i < controller; ++i)
+ {
+ int id = genACnum(idx, i);
+ const char* name = plugin->paramName(i);
+ float min, max;
+ plugin->range(i, &min, &max);
+ CtrlValueType t = plugin->valueType();
+ CtrlList* cl = new CtrlList(id);
+ cl->setRange(min, max);
+ cl->setName(QString(name));
+ cl->setValueType(t);
+ LADSPA_PortRangeHint range = plugin->range(i);
+ if(LADSPA_IS_HINT_TOGGLED(range.HintDescriptor))
+ cl->setMode(CtrlList::DISCRETE);
+ else
+ cl->setMode(CtrlList::INTERPOLATE);
+ cl->setCurVal(plugin->param(i));
+ addController(cl);
+ }
+ }
+}
+
+//---------------------------------------------------------
+// addAuxSend
+//---------------------------------------------------------
+
+void AudioTrack::addAuxSend(int n)
+ {
+ int nn = _auxSend.size();
+ for (int i = nn; i < n; ++i) {
+ _auxSend.push_back(0.0);
+ _auxSend[i] = 0.0; //??
+ }
+ }
+
+//---------------------------------------------------------
+// addController
+//---------------------------------------------------------
+
+void AudioTrack::addController(CtrlList* list)
+ {
+ _controller.add(list);
+ }
+
+//---------------------------------------------------------
+// removeController
+//---------------------------------------------------------
+
+void AudioTrack::removeController(int id)
+ {
+ iCtrlList i = _controller.find(id);
+ if (i == _controller.end()) {
+ printf("AudioTrack::removeController id %d not found\n", id);
+ return;
+ }
+ _controller.erase(i);
+ }
+
+//---------------------------------------------------------
+// swapControllerIDX
+//---------------------------------------------------------
+
+void AudioTrack::swapControllerIDX(int idx1, int idx2)
+{
+ // FIXME This code is ugly.
+ // At best we would like to modify the keys (IDXs) in-place and
+ // do some kind of deferred re-sort, but it can't be done...
+
+ if(idx1 == idx2)
+ return;
+
+ if(idx1 < 0 || idx2 < 0 || idx1 >= PipelineDepth || idx2 >= PipelineDepth)
+ return;
+
+ CtrlList *cl;
+ CtrlList *newcl;
+ int id1 = (idx1 + 1) * AC_PLUGIN_CTL_BASE;
+ int id2 = (idx2 + 1) * AC_PLUGIN_CTL_BASE;
+ int i, j;
+
+ CtrlListList tmpcll;
+ CtrlVal cv(0, 0.0);
+
+ for(ciCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl)
+ {
+ cl = icl->second;
+ i = cl->id() & AC_PLUGIN_CTL_ID_MASK;
+ j = cl->id() & ~((unsigned long)AC_PLUGIN_CTL_ID_MASK);
+ if(j == id1 || j == id2)
+ {
+ newcl = new CtrlList(i | (j == id1 ? id2 : id1));
+ newcl->setMode(cl->mode());
+ newcl->setValueType(cl->valueType());
+ newcl->setName(cl->name());
+ double min, max;
+ cl->range(&min, &max);
+ newcl->setRange(min, max);
+ newcl->setCurVal(cl->curVal());
+ newcl->setDefault(cl->getDefault());
+ for(iCtrl ic = cl->begin(); ic != cl->end(); ++ic)
+ {
+ cv = ic->second;
+ newcl->insert(std::pair<const int, CtrlVal>(cv.frame, cv));
+ }
+ tmpcll.insert(std::pair<const int, CtrlList*>(newcl->id(), newcl));
+ }
+ else
+ {
+ newcl = new CtrlList();
+ *newcl = *cl;
+ tmpcll.insert(std::pair<const int, CtrlList*>(newcl->id(), newcl));
+ }
+ }
+
+ for(iCtrlList ci = _controller.begin(); ci != _controller.end(); ++ci)
+ delete (*ci).second;
+
+ _controller.clear();
+
+ for(ciCtrlList icl = tmpcll.begin(); icl != tmpcll.end(); ++icl)
+ {
+ newcl = icl->second;
+ _controller.insert(std::pair<const int, CtrlList*>(newcl->id(), newcl));
+ }
+
+
+ /*
+ unsigned int idmask = ~AC_PLUGIN_CTL_ID_MASK;
+
+ CtrlList* cl;
+ CtrlList* ctl1 = 0;
+ CtrlList* ctl2 = 0;
+ CtrlList* newcl1 = 0;
+ CtrlList* newcl2 = 0;
+ CtrlVal cv(0, 0.0);
+ int id1 = (idx1 + 1) * AC_PLUGIN_CTL_BASE;
+ int id2 = (idx2 + 1) * AC_PLUGIN_CTL_BASE;
+ int i, j;
+ double min, max;
+
+ for(ciCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl)
+ {
+ cl = icl->second;
+ i = cl->id() & AC_PLUGIN_CTL_ID_MASK;
+ j = cl->id() & idmask;
+
+ if(j == id1)
+ {
+ ctl1 = cl;
+ newcl1 = new CtrlList( i | id2 );
+ newcl1->setMode(cl->mode());
+ newcl1->setValueType(cl->valueType());
+ newcl1->setName(cl->name());
+ cl->range(&min, &max);
+ newcl1->setRange(min, max);
+ newcl1->setCurVal(cl->curVal());
+ newcl1->setDefault(cl->getDefault());
+ for(iCtrl ic = cl->begin(); ic != cl->end(); ++ic)
+ {
+ cv = ic->second;
+ newcl1->insert(std::pair<const int, CtrlVal>(cv.frame, cv));
+ }
+ }
+ //else
+ if(j == id2)
+ {
+ ctl2 = cl;
+ newcl2 = new CtrlList( i | id1 );
+ newcl2->setMode(cl->mode());
+ newcl2->setValueType(cl->valueType());
+ newcl2->setName(cl->name());
+ cl->range(&min, &max);
+ newcl2->setRange(min, max);
+ newcl2->setCurVal(cl->curVal());
+ newcl2->setDefault(cl->getDefault());
+ for(iCtrl ic = cl->begin(); ic != cl->end(); ++ic)
+ {
+ cv = ic->second;
+ newcl2->insert(std::pair<const int, CtrlVal>(cv.frame, cv));
+ }
+ }
+ }
+ if(ctl1)
+ _controller.erase(ctl1->id());
+ if(ctl2)
+ _controller.erase(ctl2->id());
+ if(newcl1)
+ //_controller.add(newcl1);
+ _controller.insert(std::pair<const int, CtrlList*>(newcl1->id(), newcl1));
+ if(newcl2)
+ _controller.insert(std::pair<const int, CtrlList*>(newcl2->id(), newcl2));
+ //_controller.add(newcl2);
+ */
+}
+
+//---------------------------------------------------------
+// setAutomationType
+//---------------------------------------------------------
+
+void AudioTrack::setAutomationType(AutomationType t)
+{
+ // Clear pressed and touched and rec event list.
+ clearRecAutomation(true);
+
+ // Now set the type.
+ _automationType = t;
+}
+
+//---------------------------------------------------------
+// processAutomationEvents
+//---------------------------------------------------------
+
+void AudioTrack::processAutomationEvents()
+{
+ if (_automationType != AUTO_TOUCH && _automationType != AUTO_WRITE)
+ return;
+
+ for (iCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl)
+ {
+ CtrlList* cl = icl->second;
+ int id = cl->id();
+
+ // Remove old events from record region.
+ if (_automationType == AUTO_WRITE)
+ {
+ int start = audio->getStartRecordPos().frame();
+ int end = audio->getEndRecordPos().frame();
+ iCtrl s = cl->lower_bound(start);
+ iCtrl e = cl->lower_bound(end);
+
+ // Erase old events only if there were recorded events.
+ for(iCtrlRec icr = _recEvents.begin(); icr != _recEvents.end(); ++icr)
+ {
+ if(icr->id == id) // && icr->type == ARVT_VAL && icr->frame >= s->frame && icr->frame <= e->frame)
+ {
+ cl->erase(s, e);
+ break;
+ }
+ }
+ }
+ else
+ { // type AUTO_TOUCH
+ for (iCtrlRec icr = _recEvents.begin(); icr != _recEvents.end(); ++icr)
+ {
+ // Don't bother looking for start, it's OK, just take the first one.
+ // Needed for mousewheel and paging etc.
+ //if (icr->id == id && icr->type == ARVT_START)
+ if (icr->id == id)
+ {
+ int start = icr->frame;
+
+ if(icr == _recEvents.end())
+ {
+ int end = audio->getEndRecordPos().frame();
+ iCtrl s = cl->lower_bound(start);
+ iCtrl e = cl->lower_bound(end);
+ cl->erase(s, e);
+ break;
+ }
+
+ iCtrlRec icrlast = icr;
+ ++icr;
+ for(; ; ++icr)
+ {
+ if(icr == _recEvents.end())
+ {
+ int end = icrlast->frame;
+ iCtrl s = cl->lower_bound(start);
+ iCtrl e = cl->lower_bound(end);
+ cl->erase(s, e);
+ break;
+ }
+
+ if(icr->id == id && icr->type == ARVT_STOP)
+ {
+ int end = icr->frame;
+ // Erase everything up to, not including, this stop event's frame.
+ // Because an event was already stored directly when slider released.
+ if(end > start)
+ --end;
+
+ iCtrl s = cl->lower_bound(start);
+ iCtrl e = cl->lower_bound(end);
+
+ cl->erase(s, e);
+
+ break;
+ }
+
+ if(icr->id == id)
+ icrlast = icr;
+ }
+ if (icr == _recEvents.end())
+ break;
+ }
+ }
+ }
+
+ // Extract all recorded events for controller "id"
+ // from CtrlRecList and put into cl.
+ for (iCtrlRec icr = _recEvents.begin(); icr != _recEvents.end(); ++icr)
+ {
+ if (icr->id == id && (icr->type == ARVT_VAL || icr->type == ARVT_START))
+ cl->add(icr->frame, icr->val);
+ }
+ }
+
+ // Done with the recorded automation event list. Clear it.
+ _recEvents.clear();
+
+ // Try muse without this, so that the user can remain in automation write mode
+ // after a stop.
+ /*
+ if (automationType() == AUTO_WRITE)
+ {
+ setAutomationType(AUTO_READ);
+ song->update(SC_AUTOMATION);
+ }
+ */
+
+}
+
+//---------------------------------------------------------
+// setControllerMode
+//---------------------------------------------------------
+
+void AudioTrack::setControllerMode(int ctlID, CtrlList::Mode m)
+ {
+ ciCtrlList cl = _controller.find(ctlID);
+ if(cl == _controller.end())
+ return;
+
+ cl->second->setMode(m);
+ }
+
+//---------------------------------------------------------
+// clearControllerEvents
+//---------------------------------------------------------
+
+void AudioTrack::clearControllerEvents(int id)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+ cl->clear();
+ return;
+}
+
+//---------------------------------------------------------
+// seekPrevACEvent
+//---------------------------------------------------------
+
+void AudioTrack::seekPrevACEvent(int id)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+ if(cl->empty())
+ return;
+
+ iCtrl s = cl->lower_bound(song->cPos().frame());
+ if(s != cl->begin())
+ --s;
+ song->setPos(Song::CPOS, Pos(s->second.frame, false), true, false, true);
+ return;
+}
+
+//---------------------------------------------------------
+// seekNextACEvent
+//---------------------------------------------------------
+
+void AudioTrack::seekNextACEvent(int id)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+ if(cl->empty())
+ return;
+
+ iCtrl s = cl->upper_bound(song->cPos().frame());
+ if(s == cl->end())
+ {
+ --s;
+ }
+
+ song->setPos(Song::CPOS, Pos(s->second.frame, false), true, false, true);
+ return;
+}
+
+//---------------------------------------------------------
+// eraseACEvent
+//---------------------------------------------------------
+
+void AudioTrack::eraseACEvent(int id, int frame)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+ if(cl->empty())
+ return;
+
+ iCtrl s = cl->find(frame);
+ if(s != cl->end())
+ cl->erase(s);
+ return;
+}
+
+//---------------------------------------------------------
+// eraseRangeACEvents
+//---------------------------------------------------------
+
+void AudioTrack::eraseRangeACEvents(int id, int frame1, int frame2)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+ if(cl->empty())
+ return;
+
+ iCtrl s = cl->lower_bound(frame1);
+ iCtrl e = cl->lower_bound(frame2);
+ cl->erase(s, e);
+ return;
+}
+
+//---------------------------------------------------------
+// addACEvent
+//---------------------------------------------------------
+
+void AudioTrack::addACEvent(int id, int frame, double val)
+{
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ return;
+
+ CtrlList* cl = icl->second;
+
+ // Add will replace if found.
+ cl->add(frame, val);
+ return;
+}
+
+//---------------------------------------------------------
+// volume
+//---------------------------------------------------------
+
+double AudioTrack::volume() const
+ {
+ ciCtrlList cl = _controller.find(AC_VOLUME);
+ if (cl == _controller.end())
+ return 0.0;
+
+ if (automation &&
+ automationType() != AUTO_OFF && _volumeEnCtrl && _volumeEn2Ctrl )
+ return cl->second->value(song->cPos().frame());
+ else
+ return cl->second->curVal();
+ }
+
+//---------------------------------------------------------
+// setVolume
+//---------------------------------------------------------
+
+void AudioTrack::setVolume(double val)
+ {
+ iCtrlList cl = _controller.find(AC_VOLUME);
+ if (cl == _controller.end()) {
+ printf("no volume controller %s %zd\n",
+ name().latin1(), _controller.size());
+ return;
+ }
+ cl->second->setCurVal(val);
+ }
+
+//---------------------------------------------------------
+// pan
+//---------------------------------------------------------
+
+double AudioTrack::pan() const
+ {
+ ciCtrlList cl = _controller.find(AC_PAN);
+ if (cl == _controller.end())
+ return 0.0;
+
+ if (automation &&
+ automationType() != AUTO_OFF && _panEnCtrl && _panEn2Ctrl )
+ return cl->second->value(song->cPos().frame());
+ else
+ return cl->second->curVal();
+ }
+
+//---------------------------------------------------------
+// setPan
+//---------------------------------------------------------
+
+void AudioTrack::setPan(double val)
+ {
+ iCtrlList cl = _controller.find(AC_PAN);
+ if (cl == _controller.end()) {
+ printf("no pan controller\n");
+ return;
+ }
+ cl->second->setCurVal(val);
+ }
+
+//---------------------------------------------------------
+// pluginCtrlVal
+//---------------------------------------------------------
+
+double AudioTrack::pluginCtrlVal(int ctlID) const
+ {
+ ciCtrlList cl = _controller.find(ctlID);
+ if (cl == _controller.end())
+ return 0.0;
+
+ if (automation && (automationType() != AUTO_OFF))
+ return cl->second->value(song->cPos().frame());
+ else
+ return cl->second->curVal();
+ }
+
+//---------------------------------------------------------
+// setPluginCtrlVal
+//---------------------------------------------------------
+
+void AudioTrack::setPluginCtrlVal(int param, double val)
+{
+ iCtrlList cl = _controller.find(param);
+ if (cl == _controller.end())
+ return;
+
+ cl->second->setCurVal(val);
+}
+
+void AudioTrack::recordAutomation(int n, double v)
+ {
+ if(!automation)
+ return;
+ if(audio->isPlaying())
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v));
+ else
+ {
+ if(automationType() == AUTO_WRITE)
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v));
+ else
+ if(automationType() == AUTO_TOUCH)
+ // In touch mode and not playing. Send directly to controller list.
+ {
+ iCtrlList cl = _controller.find(n);
+ if (cl == _controller.end())
+ return;
+ // Add will replace if found.
+ cl->second->add(song->cPos().frame(), v);
+ }
+ }
+ }
+
+void AudioTrack::startAutoRecord(int n, double v)
+ {
+ if(!automation)
+ return;
+ if(audio->isPlaying())
+ {
+ if(automationType() == AUTO_TOUCH)
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v, ARVT_START));
+ else
+ if(automationType() == AUTO_WRITE)
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v));
+ }
+ else
+ {
+ if(automationType() == AUTO_TOUCH)
+ // In touch mode and not playing. Send directly to controller list.
+ {
+ iCtrlList cl = _controller.find(n);
+ if (cl == _controller.end())
+ return;
+ // Add will replace if found.
+ cl->second->add(song->cPos().frame(), v);
+ }
+ else
+ if(automationType() == AUTO_WRITE)
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v));
+ }
+ }
+
+void AudioTrack::stopAutoRecord(int n, double v)
+ {
+ if(!automation)
+ return;
+ if(audio->isPlaying())
+ {
+ if(automationType() == AUTO_TOUCH)
+ {
+ audio->msgAddACEvent(this, n, song->cPos().frame(), v);
+ _recEvents.push_back(CtrlRecVal(song->cPos().frame(), n, v, ARVT_STOP));
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// AudioTrack::writeProperties
+//---------------------------------------------------------
+
+void AudioTrack::writeProperties(int level, Xml& xml) const
+ {
+ Track::writeProperties(level, xml);
+ xml.intTag(level, "prefader", prefader());
+ xml.intTag(level, "sendMetronome", sendMetronome());
+ xml.intTag(level, "automation", int(automationType()));
+ if (hasAuxSend()) {
+ int naux = song->auxs()->size();
+ for (int idx = 0; idx < naux; ++idx) {
+ QString s("<auxSend idx=%1>%2</auxSend>\n");
+ xml.nput(level, s.arg(idx).arg(_auxSend[idx]));
+ }
+ }
+ for (ciPluginI ip = _efxPipe->begin(); ip != _efxPipe->end(); ++ip) {
+ if (*ip)
+ (*ip)->writeConfiguration(level, xml);
+ }
+ for (ciCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl) {
+ const CtrlList* cl = icl->second;
+ QString s("controller id=\"%1\" cur=\"%2\"");
+ xml.tag(level++, s.arg(cl->id()).arg(cl->curVal()));
+ int i = 0;
+ for (ciCtrl ic = cl->begin(); ic != cl->end(); ++ic) {
+ QString s("%1 %2, ");
+ xml.nput(level, s.arg(ic->second.frame).arg(ic->second.val));
+ ++i;
+ if (i >= 4) {
+ xml.put(level, "");
+ i = 0;
+ }
+ }
+ if (i)
+ xml.put(level, "");
+ xml.etag(level--, "controller");
+ }
+ }
+
+//---------------------------------------------------------
+// readAuxSend
+//---------------------------------------------------------
+
+void AudioTrack::readAuxSend(Xml& xml)
+ {
+ unsigned idx = 0;
+ double val;
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::Attribut:
+ if (tag == "idx")
+ idx = xml.s2().toInt();
+ break;
+ case Xml::Text:
+ val = tag.toDouble();
+ break;
+ case Xml::TagEnd:
+ if (xml.s1() == "auxSend") {
+ if (_auxSend.size() < idx+1)
+ _auxSend.push_back(val);
+ else
+ _auxSend[idx] = val;
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// AudioTrack::readProperties
+//---------------------------------------------------------
+
+bool AudioTrack::readProperties(Xml& xml, const QString& tag)
+ {
+ if (tag == "plugin")
+ {
+ int rackpos;
+ for(rackpos = 0; rackpos < PipelineDepth; ++rackpos)
+ {
+ if(!(*_efxPipe)[rackpos])
+ break;
+ }
+ if(rackpos < PipelineDepth)
+ {
+ PluginI* pi = new PluginI();
+ pi->setTrack(this);
+ pi->setID(rackpos);
+ if(pi->readConfiguration(xml, false))
+ delete pi;
+ else
+ (*_efxPipe)[rackpos] = pi;
+ }
+ else
+ printf("can't load plugin - plugin rack is already full\n");
+ }
+ else if (tag == "auxSend")
+ readAuxSend(xml);
+ else if (tag == "prefader")
+ _prefader = xml.parseInt();
+ else if (tag == "sendMetronome")
+ _sendMetronome = xml.parseInt();
+ else if (tag == "automation")
+ setAutomationType(AutomationType(xml.parseInt()));
+ // Removed by T356
+ // "recfile" tag not saved anymore
+ //else if (tag == "recfile")
+ // readRecfile(xml);
+ else if (tag == "controller") {
+ CtrlList* l = new CtrlList();
+ l->read(xml);
+
+ // Since (until now) muse wrote a 'zero' for plugin controller current value
+ // in the XML file, we can't use that value, now that plugin automation is added.
+ // We must take the value from the plugin control value.
+ // Otherwise we break all existing .med files with plugins, because the gui
+ // controls would all be set to zero.
+ // But we will allow for the (unintended, useless) possibility of a controller
+ // with no matching plugin control.
+ PluginI* p = 0;
+ bool ctlfound = false;
+ int m = l->id() & AC_PLUGIN_CTL_ID_MASK;
+ int n = (l->id() >> AC_PLUGIN_CTL_BASE_POW) - 1;
+ if(n >= 0 && n < PipelineDepth)
+ {
+ p = (*_efxPipe)[n];
+ if(p && m < p->parameters())
+ ctlfound = true;
+ }
+
+ iCtrlList icl = _controller.find(l->id());
+ if (icl == _controller.end())
+ _controller.add(l);
+ else {
+ CtrlList* d = icl->second;
+ for (iCtrl i = l->begin(); i != l->end(); ++i)
+ d->insert(std::pair<const int, CtrlVal> (i->first, i->second));
+
+ if(!ctlfound)
+ d->setCurVal(l->curVal());
+
+ d->setDefault(l->getDefault());
+ delete l;
+ l = d;
+ }
+
+ if(ctlfound)
+ {
+ l->setCurVal(p->param(m));
+ LADSPA_PortRangeHint range = p->range(m);
+ if(LADSPA_IS_HINT_TOGGLED(range.HintDescriptor))
+ l->setMode(CtrlList::DISCRETE);
+ else
+ l->setMode(CtrlList::INTERPOLATE);
+ }
+ }
+ else
+ return Track::readProperties(xml, tag);
+ return false;
+ }
+
+//---------------------------------------------------------
+// showPendingPluginNativeGuis
+// This is needed because OSC needs all tracks with plugins to be already
+// added to their track lists so it can find them and show their native guis.
+//---------------------------------------------------------
+
+void AudioTrack::showPendingPluginNativeGuis()
+{
+ for(int idx = 0; idx < PipelineDepth; ++idx)
+ {
+ PluginI* p = (*_efxPipe)[idx];
+ if(!p)
+ continue;
+
+ if(p->isShowNativeGuiPending())
+ p->showNativeGui(true);
+ }
+}
+
+//---------------------------------------------------------
+// mapRackPluginsToControllers
+//---------------------------------------------------------
+
+void AudioTrack::mapRackPluginsToControllers()
+{
+ // Iterate all possible plugin controller indexes...
+ for(int idx = PipelineDepth - 1; idx >= 0; idx--)
+ {
+ iCtrlList icl = _controller.lower_bound((idx + 1) * AC_PLUGIN_CTL_BASE);
+ if(icl == _controller.end() || ((icl->second->id() >> AC_PLUGIN_CTL_BASE_POW) - 1) != idx)
+ continue;
+
+ // We found some controllers with that index. Now iterate the plugin rack...
+ for(int i = idx; i >= 0; i--)
+ {
+ PluginI* p = (*_efxPipe)[i];
+ if(!p)
+ continue;
+
+ // We found a plugin at a rack position. If the rack position is not the same as the controller index...
+ if(i != idx)
+ {
+ (*_efxPipe)[i] = 0;
+ (*_efxPipe)[idx] = p;
+ }
+ p->setID(idx);
+
+ // It is now safe to update the controllers.
+ p->updateControllers();
+
+ break;
+ }
+ }
+
+ // No matter of the outcome of the above - rack position is not too critical -
+ // making sure that each control has a controller is important. Otherwise they
+ // are stuck at zero can't be adjusted.
+ // Muse med files created before the automation patches (before 0.9pre1) may have broken
+ // controller sections, so this will allow more tolerance of them.
+ for(int idx = 0; idx < PipelineDepth; idx++)
+ {
+ PluginI* p = (*_efxPipe)[idx];
+ if(!p)
+ continue;
+
+ if(p->id() != idx)
+ p->setID(idx);
+
+ int j = p->parameters();
+
+ for(int i = 0; i < j; i++)
+ {
+ int id = genACnum(idx, i);
+ CtrlList* l = 0;
+
+ ciCtrlList icl = _controller.find(id);
+ if(icl == _controller.end())
+ {
+ l = new CtrlList(id);
+ addController(l);
+ }
+ else
+ l = icl->second;
+
+ // Force all of these now, even though they may have already been set. With a pre-
+ // 0.9pre1 med file with broken controller sections they may not be set correct.
+ float min, max;
+ p->range(i, &min, &max);
+ CtrlValueType t = p->valueType();
+ l->setRange(min, max);
+ l->setName(QString(p->paramName(i)));
+ l->setValueType(t);
+ LADSPA_PortRangeHint rh = p->range(i);
+ if(LADSPA_IS_HINT_TOGGLED(rh.HintDescriptor))
+ l->setMode(CtrlList::DISCRETE);
+ else
+ l->setMode(CtrlList::INTERPOLATE);
+ l->setCurVal(p->param(i));
+ //l->setDefault(p->defaultValue(i));
+ }
+ }
+
+ // The loop is a safe way to delete while iterating 'non-linear' lists.
+ bool loop;
+ do
+ {
+ loop = false;
+ for(ciCtrlList icl = _controller.begin(); icl != _controller.end(); ++icl)
+ {
+ CtrlList* l = icl->second;
+ int id = l->id();
+ // Ignore volume, pan, mute etc.
+ if(id < AC_PLUGIN_CTL_BASE)
+ continue;
+ int param = id & AC_PLUGIN_CTL_ID_MASK;
+ int idx = (id >> AC_PLUGIN_CTL_BASE_POW) - 1;
+ PluginI* p = (*_efxPipe)[idx];
+ // If there's no plugin at that rack position, or the param is out of range of
+ // the number of controls in the plugin, then it's a stray controller. Delete it.
+ // Future: Leave room for possible bypass controller at AC_PLUGIN_CTL_ID_MASK -1.
+ //if(!p || (param >= p->parameters() && (param != AC_PLUGIN_CTL_ID_MASK -1)))
+ if(!p || (param >= p->parameters()))
+ {
+ _controller.erase(id);
+
+ loop = true;
+ break;
+ }
+ }
+ }
+ while (loop);
+
+
+ // Although this tested OK, and is the 'official' way to erase while iterating,
+ // I don't trust it. I'm weary of this method. The technique didn't work
+ // in Audio::msgRemoveTracks(), see comments there.
+ /*
+
+ // Now delete any stray controllers which don't belong to anything.
+ for(iCtrlList icl = _controller.begin(); icl != _controller.end(); )
+ {
+ CtrlList* l = icl->second;
+ int id = l->id();
+ // Ignore volume, pan, mute etc.
+ if(id < AC_PLUGIN_CTL_BASE)
+ {
+ ++icl;
+ continue;
+ }
+ int param = id & AC_PLUGIN_CTL_ID_MASK;
+ int idx = (id >> AC_PLUGIN_CTL_BASE_POW) - 1;
+ PluginI* p = (*_efxPipe)[idx];
+ // If there's no plugin at that rack position, or the param is out of range of
+ // the number of controls in the plugin, then it's a stray controller. Delete it.
+ // Future: Leave room for possible bypass controller at AC_PLUGIN_CTL_ID_MASK -1.
+ //if(!p || (param >= p->parameters() && (param != AC_PLUGIN_CTL_ID_MASK -1)))
+ if(!p || (param >= p->parameters()))
+ _controller.erase(icl++);
+ else
+ ++icl;
+ }
+ */
+}
+
+/*
+//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void AudioTrack::writeRouting(int level, Xml& xml) const
+{
+ QString n;
+ if (type() == Track::AUDIO_INPUT) {
+ ciJackRouteNameCache circ = jackRouteNameCache.find(this);
+ if(circ != jackRouteNameCache.end())
+ {
+ jackRouteNameMap rm = circ->second;
+ for(ciJackRouteNameMap cirm = rm.begin(); cirm != rm.end(); ++cirm)
+ {
+ n = cirm->second;
+ if(!n.isEmpty())
+ {
+ Route dst(name(), true, cirm->first);
+ xml.tag(level++, "Route");
+ xml.strTag(level, "srcNode", n);
+ xml.strTag(level, "dstNode", dst.name());
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ }
+ if(type() == Track::AUDIO_OUTPUT)
+ {
+ ciJackRouteNameCache circ = jackRouteNameCache.find(this);
+ if(circ != jackRouteNameCache.end())
+ {
+ jackRouteNameMap rm = circ->second;
+ for(ciJackRouteNameMap cirm = rm.begin(); cirm != rm.end(); ++cirm)
+ {
+ n = cirm->second;
+ if(!n.isEmpty())
+ {
+ Route src(name(), false, cirm->first);
+ xml.tag(level++, "Route");
+ xml.strTag(level, "srcNode", src.name());
+ xml.strTag(level, "dstNode", n);
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ }
+ else
+ {
+ const RouteList* rl = &_outRoutes;
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r) {
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+ xml.strTag(level, "srcNode", name());
+ xml.strTag(level, "dstNode", r->name());
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+}
+*/
+
+//---------------------------------------------------------
+// AudioInput
+//---------------------------------------------------------
+
+AudioInput::AudioInput()
+ : AudioTrack(AUDIO_INPUT)
+ {
+ // set Default for Input Ports:
+ _mute = true;
+ //setVolume(1.0);
+ for (int i = 0; i < MAX_CHANNELS; ++i)
+ jackPorts[i] = 0;
+ //_channels = 0;
+ //setChannels(2);
+ }
+
+//AudioInput::AudioInput(const AudioInput& t)
+// : AudioTrack(t)
+AudioInput::AudioInput(const AudioInput& t, bool cloneParts)
+ : AudioTrack(t, cloneParts)
+ {
+ for (int i = 0; i < MAX_CHANNELS; ++i)
+ jackPorts[i] = t.jackPorts[i];
+ }
+
+//---------------------------------------------------------
+// ~AudioInput
+//---------------------------------------------------------
+
+AudioInput::~AudioInput()
+ {
+ if (!checkAudioDevice()) return;
+ for (int i = 0; i < _channels; ++i)
+ if(jackPorts[i])
+ audioDevice->unregisterPort(jackPorts[i]);
+ }
+
+//---------------------------------------------------------
+// write
+//---------------------------------------------------------
+
+void AudioInput::write(int level, Xml& xml) const
+ {
+ xml.tag(level++, "AudioInput");
+ AudioTrack::writeProperties(level, xml);
+ xml.etag(level, "AudioInput");
+ }
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void AudioInput::read(Xml& xml)
+ {
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::TagStart:
+ if (AudioTrack::readProperties(xml, tag))
+ xml.unknown("AudioInput");
+ break;
+ case Xml::Attribut:
+ break;
+ case Xml::TagEnd:
+ if (tag == "AudioInput") {
+ setName(name()); // allocate jack ports
+ mapRackPluginsToControllers();
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// AudioOutput
+//---------------------------------------------------------
+
+AudioOutput::AudioOutput()
+ : AudioTrack(AUDIO_OUTPUT)
+ {
+ for (int i = 0; i < MAX_CHANNELS; ++i)
+ jackPorts[i] = 0;
+ //_channels = 0;
+ //setChannels(2);
+ }
+
+//AudioOutput::AudioOutput(const AudioOutput& t)
+// : AudioTrack(t)
+AudioOutput::AudioOutput(const AudioOutput& t, bool cloneParts)
+ : AudioTrack(t, cloneParts)
+ {
+ for (int i = 0; i < MAX_CHANNELS; ++i)
+ jackPorts[i] = t.jackPorts[i];
+ _nframes = t._nframes;
+ }
+
+//---------------------------------------------------------
+// ~AudioOutput
+//---------------------------------------------------------
+
+AudioOutput::~AudioOutput()
+ {
+ if (!checkAudioDevice()) return;
+ for (int i = 0; i < _channels; ++i)
+ if(jackPorts[i])
+ audioDevice->unregisterPort(jackPorts[i]);
+ }
+
+//---------------------------------------------------------
+// write
+//---------------------------------------------------------
+
+void AudioOutput::write(int level, Xml& xml) const
+ {
+ xml.tag(level++, "AudioOutput");
+ AudioTrack::writeProperties(level, xml);
+ xml.etag(level, "AudioOutput");
+ }
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void AudioOutput::read(Xml& xml)
+ {
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::TagStart:
+ if (AudioTrack::readProperties(xml, tag))
+ xml.unknown("AudioOutput");
+ break;
+ case Xml::Attribut:
+ break;
+ case Xml::TagEnd:
+ if (tag == "AudioOutput") {
+ setName(name()); // allocate jack ports
+ mapRackPluginsToControllers();
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// write
+//---------------------------------------------------------
+
+void AudioGroup::write(int level, Xml& xml) const
+ {
+ xml.tag(level++, "AudioGroup");
+ AudioTrack::writeProperties(level, xml);
+ xml.etag(level, "AudioGroup");
+ }
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void AudioGroup::read(Xml& xml)
+ {
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::TagStart:
+ if (AudioTrack::readProperties(xml, tag))
+ xml.unknown("AudioGroup");
+ break;
+ case Xml::Attribut:
+ break;
+ case Xml::TagEnd:
+ if (tag == "AudioGroup")
+ {
+ mapRackPluginsToControllers();
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// write
+//---------------------------------------------------------
+
+void AudioAux::write(int level, Xml& xml) const
+ {
+ xml.tag(level++, "AudioAux");
+ AudioTrack::writeProperties(level, xml);
+ xml.etag(level, "AudioAux");
+ }
+
+//---------------------------------------------------------
+// AudioAux
+//---------------------------------------------------------
+
+AudioAux::AudioAux()
+ : AudioTrack(AUDIO_AUX)
+{
+ //_channels = 0;
+ //setChannels(2);
+ // Changed by Tim. p3.3.15
+ //for (int i = 0; i < MAX_CHANNELS; ++i)
+ // buffer[i] = (i < channels()) ? new float[segmentSize] : 0;
+ for(int i = 0; i < MAX_CHANNELS; ++i)
+ {
+ if(i < channels())
+ posix_memalign((void**)(buffer + i), 16, sizeof(float) * segmentSize);
+ else
+ buffer[i] = 0;
+ }
+}
+
+//---------------------------------------------------------
+// AudioAux
+//---------------------------------------------------------
+
+AudioAux::~AudioAux()
+ {
+ // Changed by Tim. p3.3.15
+ //for (int i = 0; i < channels(); ++i)
+ // delete[] buffer[i];
+ for (int i = 0; i < MAX_CHANNELS; ++i) {
+ if (buffer[i])
+ free(buffer[i]);
+ }
+ }
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void AudioAux::read(Xml& xml)
+ {
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::TagStart:
+ if (AudioTrack::readProperties(xml, tag))
+ xml.unknown("AudioAux");
+ break;
+ case Xml::Attribut:
+ break;
+ case Xml::TagEnd:
+ if (tag == "AudioAux")
+ {
+ mapRackPluginsToControllers();
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+//---------------------------------------------------------
+// getData
+//---------------------------------------------------------
+
+bool AudioAux::getData(unsigned /*pos*/, int ch, unsigned /*samples*/, float** data)
+ {
+ for (int i = 0; i < ch; ++i)
+ data[i] = buffer[i % channels()];
+ return true;
+ }
+
+//---------------------------------------------------------
+// setChannels
+//---------------------------------------------------------
+
+void AudioAux::setChannels(int n)
+{
+ if(n > channels())
+ {
+ // Changed by Tim. p3.3.15
+ //for (int i = channels(); i < n; ++i)
+ // buffer[i] = new float[segmentSize];
+ for(int i = channels(); i < n; ++i)
+ posix_memalign((void**)(buffer + i), 16, sizeof(float) * segmentSize);
+ }
+ else if(n < channels())
+ {
+ // Changed by Tim. p3.3.15
+ //for (int i = n; i < channels(); ++i)
+ // delete[] buffer[i];
+ for(int i = n; i < channels(); ++i)
+ {
+ if(buffer[i])
+ free(buffer[i]);
+ }
+ }
+ AudioTrack::setChannels(n);
+}
+
+//---------------------------------------------------------
+// setRecordFlag1
+// gui part (executed in gui thread)
+//---------------------------------------------------------
+
+bool AudioTrack::setRecordFlag1(bool f)
+ {
+ if (f == _recordFlag)
+ return true;
+ if (f) {
+ if (_recFile == 0) {
+ //
+ // create soundfile for recording
+ //
+ char buffer[128];
+ QFile fil;
+ for (;;++recFileNumber) {
+ sprintf(buffer, "%s/rec%d.wav",
+ museProject.latin1(),
+ recFileNumber);
+ fil.setName(QString(buffer));
+ if (!fil.exists())
+ break;
+ }
+ _recFile = new SndFile(QString(buffer));
+ _recFile->setFormat(
+ SF_FORMAT_WAV | SF_FORMAT_FLOAT,
+ _channels, sampleRate);
+ }
+ if(_recFile->openWrite())
+ {
+ QMessageBox::critical(NULL, "MusE write error.", "Error creating target wave file\n"
+ "Check your configuration.");
+ return false;
+
+ }
+ if (debugMsg)
+ printf("AudioNode::setRecordFlag1: create internal file %s\n",
+ _recFile->path().latin1());
+ }
+ else {
+ if (_recFile) {
+ // this file has not been processed and can be
+ // deleted
+ // We should only arrive here if going from a 'record-armed' state
+ // to a non record-armed state. Because otherwise after actually
+ // recording, the _recFile pointer is made into an event,
+ // then _recFile is made zero before this function is called.
+ QString s = _recFile->path();
+ // Added by Tim. p3.3.8
+ delete _recFile;
+ setRecFile(0);
+
+ remove(s.latin1());
+ if(debugMsg)
+ printf("AudioNode::setRecordFlag1: remove file %s\n", s.latin1());
+ //_recFile = 0;
+ }
+ }
+ return true;
+ }
+double AudioTrack::auxSend(int idx) const
+ {
+ if (unsigned(idx) >= _auxSend.size()) {
+ printf("%s auxSend: bad index: %d >= %zd\n",
+ name().latin1(), idx, _auxSend.size());
+ return 0.0;
+ }
+ return _auxSend[idx];
+ }
+
+void AudioTrack::setAuxSend(int idx, double v)
+ {
+ if (unsigned(idx) >= _auxSend.size()) {
+ printf("%s setAuxSend: bad index: %d >= %zd\n",
+ name().latin1(), idx, _auxSend.size());
+ return;
+ }
+ _auxSend[idx] = v;
+ }
+