summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog21
-rw-r--r--muse/muse/app.cpp11
-rw-r--r--muse/muse/arranger/arranger.h6
-rw-r--r--muse/muse/arranger/trackinfo.cpp88
-rw-r--r--muse/muse/audio.cpp4
-rw-r--r--muse/muse/audiotrack.cpp62
-rw-r--r--muse/muse/conf.cpp23
-rw-r--r--muse/muse/confmport.cpp389
-rw-r--r--muse/muse/confmport.h4
-rw-r--r--muse/muse/driver/alsamidi.cpp124
-rw-r--r--muse/muse/driver/alsamidi.h5
-rw-r--r--muse/muse/driver/audiodev.h6
-rw-r--r--muse/muse/driver/dummyaudio.cpp24
-rw-r--r--muse/muse/driver/jack.cpp539
-rw-r--r--muse/muse/driver/jackaudio.h9
-rw-r--r--muse/muse/driver/jackmidi.cpp509
-rw-r--r--muse/muse/driver/jackmidi.h62
-rw-r--r--muse/muse/dssihost.cpp39
-rw-r--r--muse/muse/dssihost.h2
-rw-r--r--muse/muse/globaldefs.h3
-rw-r--r--muse/muse/midi.cpp505
-rw-r--r--muse/muse/mididev.cpp73
-rw-r--r--muse/muse/mididev.h59
-rw-r--r--muse/muse/midiseq.cpp7
-rw-r--r--muse/muse/mixer/astrip.cpp1334
-rw-r--r--muse/muse/mixer/mstrip.cpp263
-rw-r--r--muse/muse/mixer/mstrip.h8
-rw-r--r--muse/muse/mixer/routedialog.cpp7
-rw-r--r--muse/muse/node.cpp311
-rw-r--r--muse/muse/route.cpp1445
-rw-r--r--muse/muse/route.h68
-rw-r--r--muse/muse/seqmsg.cpp229
-rw-r--r--muse/muse/song.cpp353
-rw-r--r--muse/muse/song.h2
-rw-r--r--muse/muse/songfile.cpp22
-rw-r--r--muse/muse/sync.cpp28
-rw-r--r--muse/muse/synth.cpp39
-rw-r--r--muse/muse/synth.h6
-rw-r--r--muse/muse/ticksynth.cpp2
-rw-r--r--muse/muse/track.cpp138
-rw-r--r--muse/muse/track.h55
-rw-r--r--muse/muse/vst.cpp12
-rw-r--r--muse/muse/vst.h2
-rw-r--r--muse/muse/wavetrack.cpp33
-rw-r--r--muse/muse/widgets/mtrackinfobase.ui348
45 files changed, 6219 insertions, 1060 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index a9505d58..cdf4928f 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,24 @@
+30.03.2010
+ * Major reworks: Jack midi, routing system, multichannel synth ins/outs, midi strips and trackinfo pane. (T356)
+ - WORK IN PROGRESS. Should be usable for current projects.
+ - ADVISORY: If opening current projects you are advised to "save as" or back up your med files (waves should be OK)
+ until all is deemed to be working OK. It is possible more changes to .med file structure are needed later.
+ - Some .med project file structures have CHANGED (like routing). I have tested opening large existing projects,
+ then re-saving them. OK so far.
+ However, I have not added importing code for the old midi trackinfo panel 'input port' and 'input channel' boxes (gone now).
+ If you want to wait, I am planning to do that, but later... Otherwise you must re-enter them with the new midi input routing.
+ - ** Multichannel synth inputs and outputs: Fairly satisfied with popup menus, hopefully no major reworks...
+ Routing system fully supports multichannel synth mono/stero paths but is NOT COMPLETE yet.
+ When changing a connected track from stereo to mono, there is no coding yet to ensure the existing stereo routes are
+ changed from stereo to mono (just like the audio input and output tracks have always done with Jack routes).
+ Also coding must be added to avoid simultaneous mono and stereo routes - make them mutually exclusive - although
+ there's nothing technically wrong with it, it's just not desirable.
+ - ** Jack midi: You now create your own Jack midi ports. I have not added any means to delete them yet, but I believe
+ if you 'unselect' them in the midi ports list so that they are not used, then the saved .med file will ignore them.
+ - Multi-instances of MusE should work OK now - all ports should hopefully have unique names.
+ - Number of midi ports increased from 32 to 128. It's a bit much for the ports list, was planning "create your own
+ midi port as needed" (like RG). Obstacles seem to have been cleared now, but it would be a big job (lots of places to change).
+ - Along the way various tweaks and fixes when I spotted them.
18.02.2010
* Added: Separate Jack midi client ports per MusE port. (T356)
- For now, you will have to manually add further connections to those ports if desired, each session.
diff --git a/muse/muse/app.cpp b/muse/muse/app.cpp
index 6bc52319..219f59bd 100644
--- a/muse/muse/app.cpp
+++ b/muse/muse/app.cpp
@@ -95,7 +95,8 @@
#include "didyouknow.h"
#include <qtextedit.h>
-extern void cacheJackRouteNames();
+//extern void cacheJackRouteNames();
+
static pthread_t watchdogThread;
//ErrorHandler *error;
static const char* fileOpenText =
@@ -1698,7 +1699,9 @@ bool MusE::save(const QString& name, bool overwriteWarn)
// By T356. Cache the jack in/out route names BEFORE saving.
// Because jack often shuts down during save, causing the routes to be lost in the file.
- cacheJackRouteNames();
+ // Not required any more...
+ //cacheJackRouteNames();
+
if (QFile::exists(name)) {
backupCommand.sprintf("cp \"%s\" \"%s.backup\"", name.latin1(), name.latin1());
}
@@ -2659,7 +2662,9 @@ int main(int argc, char* argv[])
lash_client = lash_init (lash_args, muse_name, lash_flags, LASH_PROTOCOL(2,0));
lash_alsa_client_id (lash_client, snd_seq_client_id (alsaSeq));
if (!noAudio) {
- char *jack_name = ((JackAudioDevice*)audioDevice)->getJackName();
+ // p3.3.38
+ //char *jack_name = ((JackAudioDevice*)audioDevice)->getJackName();
+ const char *jack_name = audioDevice->clientName();
lash_jack_client_name (lash_client, jack_name);
}
}
diff --git a/muse/muse/arranger/arranger.h b/muse/muse/arranger/arranger.h
index 5a402585..c43320cb 100644
--- a/muse/muse/arranger/arranger.h
+++ b/muse/muse/arranger/arranger.h
@@ -132,9 +132,9 @@ class Arranger : public QWidget {
void trackInfoScroll(int);
//void iNameChanged();
- void iInputChannelChanged(const QString&);
+ ///void iInputChannelChanged(const QString&);
void iOutputChannelChanged(int);
- void iInputPortChanged(const QString&);
+ ///void iInputPortChanged(const QString&);
void iOutputPortChanged(int);
void iProgHBankChanged();
void iProgLBankChanged();
@@ -166,6 +166,8 @@ class Arranger : public QWidget {
void panRecClicked();
void recEchoToggled(bool);
void verticalScrollSetYpos(unsigned);
+ void inRoutesPressed();
+ void outRoutesPressed();
signals:
void redirectWheelEvent(QWheelEvent*);
diff --git a/muse/muse/arranger/trackinfo.cpp b/muse/muse/arranger/trackinfo.cpp
index 914d98e6..bc1cf939 100644
--- a/muse/muse/arranger/trackinfo.cpp
+++ b/muse/muse/arranger/trackinfo.cpp
@@ -40,6 +40,7 @@
#include "mixer/astrip.h"
#include "icons.h"
#include "app.h"
+#include "route.h"
//---------------------------------------------------------
@@ -59,9 +60,9 @@ void Arranger::midiTrackInfoHeartBeat()
int outChannel = track->outChannel();
int outPort = track->outPort();
- int ichMask = track->inChannelMask();
+ ///int ichMask = track->inChannelMask();
//int iptMask = track->inPortMask();
- unsigned int iptMask = track->inPortMask();
+ ///unsigned int iptMask = track->inPortMask();
MidiPort* mp = &midiPorts[outPort];
@@ -76,19 +77,36 @@ void Arranger::midiTrackInfoHeartBeat()
// Check for detection of midi general activity on chosen channels...
int mpt = 0;
//int mch = 0;
- for(; mpt < MIDI_PORTS; ++mpt)
+ RouteList* rl = track->inRoutes();
+
+ ciRoute r = rl->begin();
+ //for( ; mpt < MIDI_PORTS; ++mpt)
+ for( ; r != rl->end(); ++r)
{
+ //if(!r->isValid() || ((r->type != Route::ALSA_MIDI_ROUTE) && (r->type != Route::JACK_MIDI_ROUTE)))
+ if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE))
+ continue;
+
+ // NOTE: TODO: Code for channelless events like sysex, ** IF we end up using the 'special channel 17' method.
+ if(r->channel == -1)
+ continue;
+
+ // No port assigned to the device?
+ mpt = r->device->midiPort();
+ if(mpt == -1)
+ continue;
+
//for(; mch < MIDI_CHANNELS; ++mch)
//{
//if(midiPorts[mpt].syncInfo().actDetect(mch) && (iptMask & (1 << mpt)) && (ichMask & (1 << mch)) )
- if((iptMask & bitShiftLU[mpt]) && (midiPorts[mpt].syncInfo().actDetectBits() & ichMask) )
+ //if((iptMask & bitShiftLU[mpt]) && (midiPorts[mpt].syncInfo().actDetectBits() & ichMask) )
+ if(midiPorts[mpt].syncInfo().actDetectBits() & bitShiftLU[r->channel])
{
//if(midiTrackInfo->iChanTextLabel->paletteBackgroundColor() != green)
// midiTrackInfo->iChanTextLabel->setPaletteBackgroundColor(green);
//if(midiTrackInfo->iChanDetectLabel->pixmap() != greendotIcon)
if(!midiTrackInfo->_midiDetect)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting green icon\n");
midiTrackInfo->_midiDetect = true;
@@ -101,14 +119,14 @@ void Arranger::midiTrackInfoHeartBeat()
}
// No activity detected?
//if(mch == MIDI_CHANNELS)
- if(mpt == MIDI_PORTS)
+ //if(mpt == MIDI_PORTS)
+ if(r == rl->end())
{
//if(midiTrackInfo->iChanTextLabel->paletteBackgroundColor() != darkGreen)
// midiTrackInfo->iChanTextLabel->setPaletteBackgroundColor(darkGreen);
//if(midiTrackInfo->iChanDetectLabel->pixmap() != darkgreendotIcon)
if(midiTrackInfo->_midiDetect)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting darkgreen icon\n");
midiTrackInfo->_midiDetect = false;
@@ -122,7 +140,6 @@ void Arranger::midiTrackInfoHeartBeat()
{
if(program != CTRL_VAL_UNKNOWN)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting program to unknown\n");
program = CTRL_VAL_UNKNOWN;
@@ -154,7 +171,6 @@ void Arranger::midiTrackInfoHeartBeat()
//if(strcmp(midiTrackInfo->iPatch->text().latin1(), n) != 0)
if(midiTrackInfo->iPatch->text() != n)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting patch <unknown>\n");
midiTrackInfo->iPatch->setText(n);
@@ -172,7 +188,6 @@ void Arranger::midiTrackInfoHeartBeat()
else
if(strcmp(midiTrackInfo->iPatch->text().latin1(), name) != 0)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting patch name\n");
midiTrackInfo->iPatch->setText(name);
@@ -207,7 +222,6 @@ void Arranger::midiTrackInfoHeartBeat()
pr = 0;
//}
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting program\n");
if(midiTrackInfo->iHBank->value() != hb)
@@ -249,7 +263,6 @@ void Arranger::midiTrackInfoHeartBeat()
volume = v;
if(midiTrackInfo->iLautst->value() != v)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting volume\n");
midiTrackInfo->iLautst->blockSignals(true);
@@ -277,7 +290,6 @@ void Arranger::midiTrackInfoHeartBeat()
pan = v;
if(midiTrackInfo->iPan->value() != v)
{
- // Added by Tim. p3.3.6
//printf("Arranger::midiTrackInfoHeartBeat setting pan\n");
midiTrackInfo->iPan->blockSignals(true);
@@ -405,7 +417,6 @@ void Arranger::switchInfo(int n)
//---------------------------------------------------------
// setTrackInfoLabelText
//---------------------------------------------------------
-// Added by Tim. p3.3.9
void Arranger::setTrackInfoLabelText()
{
@@ -419,7 +430,6 @@ void Arranger::setTrackInfoLabelText()
//---------------------------------------------------------
// setTrackInfoLabelFont
//---------------------------------------------------------
-// Added by Tim. p3.3.9
void Arranger::setTrackInfoLabelFont()
{
@@ -498,6 +508,7 @@ void Arranger::iOutputChannelChanged(int channel)
}
}
+/*
//---------------------------------------------------------
// iKanalChanged
//---------------------------------------------------------
@@ -511,6 +522,7 @@ void Arranger::iInputChannelChanged(const QString& s)
list->redraw();
}
}
+*/
//---------------------------------------------------------
// iOutputPortChanged
@@ -531,6 +543,7 @@ void Arranger::iOutputPortChanged(int index)
list->redraw();
}
+/*
//---------------------------------------------------------
// iInputPortChanged
//---------------------------------------------------------
@@ -547,6 +560,31 @@ void Arranger::iInputPortChanged(const QString& s)
track->setInPortMask(val);
list->redraw();
}
+*/
+
+//---------------------------------------------------------
+// inRoutesPressed
+//---------------------------------------------------------
+
+void Arranger::inRoutesPressed()
+{
+ if(!selected)
+ return;
+
+ song->chooseMidiRoutes(midiTrackInfo->iRButton, (MidiTrack*)selected, false);
+}
+
+//---------------------------------------------------------
+// outRoutesPressed
+//---------------------------------------------------------
+
+void Arranger::outRoutesPressed()
+{
+ if(!selected)
+ return;
+
+ song->chooseMidiRoutes(midiTrackInfo->oRButton, (MidiTrack*)selected, true);
+}
//---------------------------------------------------------
// iProgHBankChanged
@@ -1124,7 +1162,7 @@ void Arranger::genMidiTrackInfo()
//connect(midiTrackInfo->iName, SIGNAL(returnPressed()), SLOT(iNameChanged()));
connect(midiTrackInfo->iOutputChannel, SIGNAL(valueChanged(int)), SLOT(iOutputChannelChanged(int)));
- connect(midiTrackInfo->iInputChannel, SIGNAL(textChanged(const QString&)), SLOT(iInputChannelChanged(const QString&)));
+ ///connect(midiTrackInfo->iInputChannel, SIGNAL(textChanged(const QString&)), SLOT(iInputChannelChanged(const QString&)));
connect(midiTrackInfo->iHBank, SIGNAL(valueChanged(int)), SLOT(iProgHBankChanged()));
connect(midiTrackInfo->iLBank, SIGNAL(valueChanged(int)), SLOT(iProgLBankChanged()));
connect(midiTrackInfo->iProgram, SIGNAL(valueChanged(int)), SLOT(iProgramChanged()));
@@ -1141,12 +1179,17 @@ void Arranger::genMidiTrackInfo()
connect(midiTrackInfo->iPan, SIGNAL(valueChanged(int)), SLOT(iPanChanged(int)));
connect(midiTrackInfo->iPan, SIGNAL(doubleClicked()), SLOT(iPanDoubleClicked()));
connect(midiTrackInfo->iOutput, SIGNAL(activated(int)), SLOT(iOutputPortChanged(int)));
- connect(midiTrackInfo->iInput, SIGNAL(textChanged(const QString&)), SLOT(iInputPortChanged(const QString&)));
+ ///connect(midiTrackInfo->iInput, SIGNAL(textChanged(const QString&)), SLOT(iInputPortChanged(const QString&)));
connect(midiTrackInfo->recordButton, SIGNAL(clicked()), SLOT(recordClicked()));
connect(midiTrackInfo->progRecButton, SIGNAL(clicked()), SLOT(progRecClicked()));
connect(midiTrackInfo->volRecButton, SIGNAL(clicked()), SLOT(volRecClicked()));
connect(midiTrackInfo->panRecButton, SIGNAL(clicked()), SLOT(panRecClicked()));
connect(midiTrackInfo->recEchoButton, SIGNAL(toggled(bool)), SLOT(recEchoToggled(bool)));
+ connect(midiTrackInfo->iRButton, SIGNAL(pressed()), SLOT(inRoutesPressed()));
+
+ // TODO: Works OK, but disabled for now, until we figure out what to do about multiple out routes and display values...
+ midiTrackInfo->oRButton->setEnabled(false);
+ connect(midiTrackInfo->oRButton, SIGNAL(pressed()), SLOT(outRoutesPressed()));
connect(heartBeatTimer, SIGNAL(timeout()), SLOT(midiTrackInfoHeartBeat()));
}
@@ -1169,12 +1212,12 @@ void Arranger::updateMidiTrackInfo(int flags)
//{
int outChannel = track->outChannel();
- int inChannel = track->inChannelMask();
+ ///int inChannel = track->inChannelMask();
int outPort = track->outPort();
//int inPort = track->inPortMask();
- unsigned int inPort = track->inPortMask();
+ ///unsigned int inPort = track->inPortMask();
- midiTrackInfo->iInput->clear();
+ //midiTrackInfo->iInput->clear();
midiTrackInfo->iOutput->clear();
for (int i = 0; i < MIDI_PORTS; ++i) {
@@ -1185,7 +1228,8 @@ void Arranger::updateMidiTrackInfo(int flags)
midiTrackInfo->iOutput->setCurrentItem(i);
}
//midiTrackInfo->iInput->setText(bitmap2String(inPort));
- midiTrackInfo->iInput->setText(u32bitmap2String(inPort));
+ ///midiTrackInfo->iInput->setText(u32bitmap2String(inPort));
+
//midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel));
// Removed by Tim. p3.3.9
@@ -1195,7 +1239,7 @@ void Arranger::updateMidiTrackInfo(int flags)
// }
midiTrackInfo->iOutputChannel->setValue(outChannel+1);
- midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel));
+ ///midiTrackInfo->iInputChannel->setText(bitmap2String(inChannel));
// Set record echo.
if(midiTrackInfo->recEchoButton->isOn() != track->recEcho())
diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp
index d8c12331..5172447e 100644
--- a/muse/muse/audio.cpp
+++ b/muse/muse/audio.cpp
@@ -596,7 +596,9 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)
// Added by Tim. p3.3.13
//printf("Audio::process1 calling track->copyData for track:%s\n", track->name().latin1());
- track->copyData(samplePos, channels, frames, buffer);
+ // p3.3.38
+ //track->copyData(samplePos, channels, frames, buffer);
+ track->copyData(samplePos, channels, -1, -1, frames, buffer);
}
}
}
diff --git a/muse/muse/audiotrack.cpp b/muse/muse/audiotrack.cpp
index ece9bed6..fd6ba76a 100644
--- a/muse/muse/audiotrack.cpp
+++ b/muse/muse/audiotrack.cpp
@@ -22,6 +22,8 @@
// 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;
@@ -54,13 +56,17 @@ void cacheJackRouteNames()
}
}
}
+*/
+
//---------------------------------------------------------
// 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;
@@ -79,8 +85,9 @@ AudioTrack::AudioTrack(TrackType t)
//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);
+ //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.).
@@ -88,6 +95,18 @@ AudioTrack::AudioTrack(TrackType t)
//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);
@@ -98,6 +117,7 @@ AudioTrack::AudioTrack(TrackType 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;
@@ -112,8 +132,18 @@ AudioTrack::AudioTrack(const AudioTrack& t, bool cloneParts)
//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);
+ //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;
}
@@ -124,11 +154,26 @@ AudioTrack::~AudioTrack()
//for (int i = 0; i < MAX_CHANNELS; ++i)
// delete[] outBuffers[i];
//delete[] outBuffers;
- for(int i = 0; i < MAX_CHANNELS; ++i)
+
+ // 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;
+
}
//---------------------------------------------------------
@@ -1109,12 +1154,13 @@ void AudioTrack::mapRackPluginsToControllers()
*/
}
+/*
//---------------------------------------------------------
// writeRouting
//---------------------------------------------------------
void AudioTrack::writeRouting(int level, Xml& xml) const
- {
+{
QString n;
if (type() == Track::AUDIO_INPUT) {
ciJackRouteNameCache circ = jackRouteNameCache.find(this);
@@ -1168,7 +1214,9 @@ void AudioTrack::writeRouting(int level, Xml& xml) const
}
}
}
- }
+}
+*/
+
//---------------------------------------------------------
// AudioInput
//---------------------------------------------------------
diff --git a/muse/muse/conf.cpp b/muse/muse/conf.cpp
index 57d6f4f0..8af9994b 100644
--- a/muse/muse/conf.cpp
+++ b/muse/muse/conf.cpp
@@ -40,6 +40,7 @@
#include "midiport.h"
#include "mididev.h"
#include "driver/audiodev.h"
+#include "driver/jackmidi.h"
#include "xml.h"
#include "waveedit.h"
#include "midi.h"
@@ -216,6 +217,7 @@ static void readConfigMidiPort(Xml& xml)
int openFlags = 1;
bool thruFlag = false;
MidiSyncInfo tmpSi;
+ int type = MidiDevice::ALSA_MIDI;
for (;;) {
Xml::Token token = xml.parse();
@@ -226,6 +228,8 @@ static void readConfigMidiPort(Xml& xml)
case Xml::TagStart:
if (tag == "name")
device = xml.parse1();
+ else if (tag == "type")
+ type = xml.parseInt();
else if (tag == "record") { // old
bool f = xml.parseInt();
if (f)
@@ -262,7 +266,19 @@ static void readConfigMidiPort(Xml& xml)
idx, MIDI_PORTS);
idx = 0;
}
+
MidiDevice* dev = midiDevices.find(device);
+
+ if(debugMsg && !dev)
+ fprintf(stderr, "readConfigMidiPort: device not found %s\n", device.latin1());
+
+ if(!dev && type == MidiDevice::JACK_MIDI)
+ {
+ if(debugMsg)
+ fprintf(stderr, "readConfigMidiPort: creating jack midi device %s\n", device.latin1());
+ dev = MidiJackDevice::createJackMidiDevice(device, openFlags);
+ }
+
MidiPort* mp = &midiPorts[idx];
mp->syncInfo().copyParams(tmpSi);
if (dev) {
@@ -942,6 +958,13 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
xml.strTag(level, "instrument", mport->instrument()->iname());
if (dev) {
xml.strTag(level, "name", dev->name());
+
+ // p3.3.38
+ //if(dynamic_cast<MidiJackDevice*>(dev))
+ if(dev->deviceType() != MidiDevice::ALSA_MIDI)
+ //xml.intTag(level, "type", MidiDevice::JACK_MIDI);
+ xml.intTag(level, "type", dev->deviceType());
+
// Changed by T356. "record" is old and by mistake written as rwFlags here.
// openFlags was read before, but never written here.
//xml.intTag(level, "record", dev->rwFlags() & 0x2 ? 1 : 0);
diff --git a/muse/muse/confmport.cpp b/muse/muse/confmport.cpp
index a3761439..61960910 100644
--- a/muse/muse/confmport.cpp
+++ b/muse/muse/confmport.cpp
@@ -44,11 +44,16 @@
#include "synth.h"
#include "audio.h"
#include "midiseq.h"
+#include "driver/alsamidi.h"
+#include "driver/jackmidi.h"
+#include "audiodev.h"
+#include "menutitleitem.h"
extern std::vector<Synth*> synthis;
enum { DEVCOL_NO = 0, DEVCOL_GUI, DEVCOL_REC, DEVCOL_PLAY, DEVCOL_INSTR, DEVCOL_NAME,
- DEVCOL_STATE };
+ //DEVCOL_STATE };
+ DEVCOL_ROUTES, DEVCOL_STATE };
//---------------------------------------------------------
// rbClicked
@@ -95,36 +100,343 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint&, int col)
dev->setOpenFlags(openFlags);
midiSeq->msgSetMidiDevice(port, dev); // reopen device
break;
- case DEVCOL_NAME:
+ case DEVCOL_ROUTES:
{
- if (popup == 0)
- popup = new QPopupMenu(this);
- popup->clear();
- popup->insertItem(tr("<none>"), 0);
- int id = 1;
- for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) {
- const QString s = (*i)->name();
- popup->insertItem(s, id);
- for (int k = 0; k < MIDI_PORTS; ++k) {
- MidiDevice* dev = midiPorts[k].device();
- if (dev && s == dev->name()) {
- popup->setItemEnabled(id, false);
- break;
- }
- }
- ++id;
+ if(!checkAudioDevice())
+ return;
+
+ if(!dev)
+ return;
+
+ // Only Jack midi devices.
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(dev);
+ //if(!mjd)
+ if(dev->deviceType() != MidiDevice::JACK_MIDI)
+ return;
+
+ if(!dev->rwFlags() & 3)
+ return;
+
+ RouteList* rl = (dev->rwFlags() & 1) ? dev->outRoutes() : dev->inRoutes();
+
+ QPopupMenu* pup = 0;
+ int gid = 0;
+ std::list<QString> sl;
+
+ _redisplay:
+ // Jack input ports if device is writable, and jack output ports if device is readable.
+ sl = (dev->rwFlags() & 1) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases);
+
+ pup = new QPopupMenu(this);
+ pup->setCheckable(true);
+
+ gid = 0;
+ //for (int i = 0; i < channel; ++i)
+ //{
+ //char buffer[128];
+ //snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ //MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ //pup->insertItem(titel);
+
+ pup->insertItem(tr("Show first aliases"), gid);
+ pup->setItemChecked(gid, (_showAliases == 0));
+ ++gid;
+ pup->insertItem(tr("Show second aliases"), gid);
+ pup->setItemChecked(gid, (_showAliases == 1));
+ ++gid;
+ pup->insertSeparator();
+
+ for(std::list<QString>::iterator ip = sl.begin(); ip != sl.end(); ++ip)
+ {
+ //int id = pup->insertItem(*ip, gid);
+ pup->insertItem(*ip, gid);
+ //Route dst(*ip, true, i);
+ Route rt(*ip, (dev->rwFlags() & 1), -1, Route::JACK_ROUTE);
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ if (*ir == rt)
+ {
+ //pup->setItemChecked(id, true);
+ pup->setItemChecked(gid, true);
+ break;
+ }
}
- n = popup->exec(ppt, 0);
- if (n == -1)
- break;
-
- QString s = popup->text(n);
- MidiDevice* dev = 0;
- if (n > 0)
- dev = midiDevices.find(s);
- midiSeq->msgSetMidiDevice(port, dev);
- muse->changeConfig(true); // save configuration file
- song->update();
+ ++gid;
+ }
+ //if (i+1 != channel)
+ // pup->insertSeparator();
+ //}
+
+ n = pup->exec(ppt, 0);
+ if (n != -1)
+ {
+ if(n == 0) // Show first aliases
+ {
+ delete pup;
+ if(_showAliases == 0)
+ _showAliases = -1;
+ else
+ _showAliases = 0;
+ goto _redisplay; // Go back
+ }
+ else
+ if(n == 1) // Show second aliases
+ {
+ delete pup;
+ if(_showAliases == 1)
+ _showAliases = -1;
+ else
+ _showAliases = 1;
+ goto _redisplay; // Go back
+ }
+
+ QString s(pup->text(n));
+
+ if(dev->rwFlags() & 1) // Writable
+ {
+ Route srcRoute(dev, -1);
+ Route dstRoute(s, true, -1, Route::JACK_ROUTE);
+
+ iRoute iir = rl->begin();
+ for(; iir != rl->end(); ++iir)
+ {
+ if(*iir == dstRoute)
+ break;
+ }
+ if(iir != rl->end())
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ else
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ else
+ if(dev->rwFlags() & 2) // Readable
+ {
+ Route srcRoute(s, false, -1, Route::JACK_ROUTE);
+ Route dstRoute(dev, -1);
+
+ iRoute iir = rl->begin();
+ for(; iir != rl->end(); ++iir)
+ {
+ if(*iir == srcRoute)
+ break;
+ }
+ if(iir != rl->end())
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ else
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ //iR->setDown(false); // pup->exec() catches mouse release event
+
+
+
+ }
+ break;
+ case DEVCOL_NAME:
+ {
+ QPopupMenu* pup = new QPopupMenu(this);
+
+ pup->setCheckable(true);
+
+ pup->insertItem(tr("Create") + QT_TR_NOOP(" Jack") + tr(" input"), 0);
+ pup->insertItem(tr("Create") + QT_TR_NOOP(" Jack") + tr(" output"), 1);
+
+ typedef std::map<std::string, int > asmap;
+ typedef std::map<std::string, int >::iterator imap;
+
+ asmap mapALSA;
+ asmap mapJACK;
+ asmap mapSYNTH;
+
+ int aix = 2;
+ int jix = 0x10000000;
+ int six = 0x20000000;
+ for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ //devALSA = dynamic_cast<MidiAlsaDevice*>(*i);
+ //if(devALSA)
+ if((*i)->deviceType() == MidiDevice::ALSA_MIDI)
+ {
+ //mapALSA.insert( std::pair<std::string, int> (std::string(devALSA->name().lower().latin1()), ii) );
+ mapALSA.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), aix) );
+ ++aix;
+ }
+ else
+ if((*i)->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ //devJACK = dynamic_cast<MidiJackDevice*>(*i);
+ //if(devJACK)
+ //mapJACK.insert( std::pair<std::string, int> (std::string(devJACK->name().lower().latin1()), ii) );
+ mapJACK.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), jix) );
+ ++jix;
+ }
+ else
+ if((*i)->deviceType() == MidiDevice::SYNTH_MIDI)
+ {
+ mapSYNTH.insert( std::pair<std::string, int> (std::string((*i)->name().latin1()), six) );
+ ++six;
+ }
+ else
+ printf("MPConfig::rbClicked unknown midi device: %s\n", (*i)->name().latin1());
+ }
+
+ //int sz = midiDevices.size();
+ if(!mapALSA.empty())
+ {
+ pup->insertSeparator();
+ pup->insertItem(new MenuTitleItem(QT_TR_NOOP("ALSA:")));
+
+ for(imap i = mapALSA.begin(); i != mapALSA.end(); ++i)
+ {
+ int idx = i->second;
+ //if(idx > sz) // Sanity check
+ // continue;
+ QString s(i->first.c_str());
+ MidiDevice* md = midiDevices.find(s, MidiDevice::ALSA_MIDI);
+ if(md)
+ {
+ //if(!dynamic_cast<MidiAlsaDevice*>(md))
+ if(md->deviceType() != MidiDevice::ALSA_MIDI)
+ continue;
+
+ //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3);
+ pup->insertItem(QT_TR_NOOP(md->name()), idx);
+
+ //for(int k = 0; k < MIDI_PORTS; ++k)
+ //{
+ //MidiDevice* dev = midiPorts[k].device();
+ //if(dev && s == dev->name())
+ if(md == dev)
+ {
+ //pup->setItemEnabled(idx + 3, false);
+ //pup->setItemChecked(idx + 3, true);
+ pup->setItemChecked(idx, true);
+ //break;
+ }
+ //}
+ }
+ }
+ }
+
+ if(!mapJACK.empty())
+ {
+ pup->insertSeparator();
+ pup->insertItem(new MenuTitleItem(QT_TR_NOOP("JACK:")));
+
+ for(imap i = mapJACK.begin(); i != mapJACK.end(); ++i)
+ {
+ int idx = i->second;
+ //if(idx > sz)
+ // continue;
+ QString s(i->first.c_str());
+ MidiDevice* md = midiDevices.find(s, MidiDevice::JACK_MIDI);
+ if(md)
+ {
+ //if(!dynamic_cast<MidiJackDevice*>(md))
+ if(md->deviceType() != MidiDevice::JACK_MIDI)
+ continue;
+
+ //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3);
+ pup->insertItem(QT_TR_NOOP(md->name()), idx);
+
+ //for(int k = 0; k < MIDI_PORTS; ++k)
+ //{
+ //MidiDevice* dev = midiPorts[k].device();
+ //if(dev && s == dev->name())
+ if(md == dev)
+ {
+ //pup->setItemEnabled(idx + 3, false);
+ //pup->setItemChecked(idx + 3, true);
+ pup->setItemChecked(idx, true);
+ //break;
+ }
+ //}
+ }
+ }
+ }
+
+ if(!mapSYNTH.empty())
+ {
+ pup->insertSeparator();
+ pup->insertItem(new MenuTitleItem(QT_TR_NOOP("SYNTH:")));
+
+ for(imap i = mapSYNTH.begin(); i != mapSYNTH.end(); ++i)
+ {
+ int idx = i->second;
+ //if(idx > sz)
+ // continue;
+ QString s(i->first.c_str());
+ MidiDevice* md = midiDevices.find(s, MidiDevice::SYNTH_MIDI);
+ if(md)
+ {
+ //if(!dynamic_cast<MidiJackDevice*>(md))
+ if(md->deviceType() != MidiDevice::SYNTH_MIDI)
+ continue;
+
+ //pup->insertItem(QT_TR_NOOP(md->name()), idx + 3);
+ pup->insertItem(QT_TR_NOOP(md->name()), idx);
+
+ //for(int k = 0; k < MIDI_PORTS; ++k)
+ //{
+ //MidiDevice* dev = midiPorts[k].device();
+ //if(dev && s == dev->name())
+ if(md == dev)
+ {
+ //pup->setItemEnabled(idx + 3, false);
+ //pup->setItemChecked(idx + 3, true);
+ pup->setItemChecked(idx, true);
+ //break;
+ }
+ //}
+ }
+ }
+ }
+
+ n = pup->exec(ppt, 0);
+ if(n == -1)
+ {
+ delete pup;
+ break;
+ }
+
+ //printf("MPConfig::rbClicked n:%d\n", n);
+
+ MidiDevice* sdev = 0;
+ if(n < 2)
+ {
+ delete pup;
+ if(n == 0)
+ sdev = MidiJackDevice::createJackMidiDevice(QString(), 2); // 2: Readable.
+ else
+ if(n == 1)
+ sdev = MidiJackDevice::createJackMidiDevice(QString(), 1); // 1:Writable.
+ }
+ else
+ {
+ int typ = MidiDevice::ALSA_MIDI;
+ if(n >= 0x10000000)
+ typ = MidiDevice::JACK_MIDI;
+ if(n >= 0x20000000)
+ typ = MidiDevice::SYNTH_MIDI;
+
+ sdev = midiDevices.find(pup->text(n), typ);
+ delete pup;
+ // Is it the current device? Reset it to <none>.
+ if(sdev == dev)
+ sdev = 0;
+ }
+
+ midiSeq->msgSetMidiDevice(port, sdev);
+ muse->changeConfig(true); // save configuration file
+ song->update();
}
break;
@@ -189,6 +501,8 @@ QString MPWhatsThis::text(const QPoint& pos)
" this port number");
case DEVCOL_INSTR:
return QHeader::tr("Instrument connected to port");
+ case DEVCOL_ROUTES:
+ return QHeader::tr("Jack midi ports");
case DEVCOL_STATE:
return QHeader::tr("State: result of opening the device");
default:
@@ -207,7 +521,8 @@ MPConfig::MPConfig(QWidget* parent, char* name)
{
popup = 0;
instrPopup = 0;
-
+ _showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first.
+
mdevView->setSorting(-1);
mdevView->setAllColumnsShowFocus(true);
mdevView->addColumn(tr("Port"));
@@ -216,6 +531,7 @@ MPConfig::MPConfig(QWidget* parent, char* name)
mdevView->addColumn(tr("O"));
mdevView->addColumn(tr("Instrument"), 120);
mdevView->addColumn(tr("Device Name"), 120);
+ mdevView->addColumn(tr("Routing"), 80);
mdevView->addColumn(tr("State"));
mdevView->setFocusPolicy(NoFocus);
@@ -279,6 +595,11 @@ void MPConfig::songChanged(int flags)
item->setText(DEVCOL_INSTR, tr("<unknown>"));
if (dev) {
item->setText(DEVCOL_NAME, dev->name());
+ // Is it a Jack midi device? Allow renaming.
+ //if(dynamic_cast<MidiJackDevice*>(dev))
+ if(dev->deviceType() == MidiDevice::JACK_MIDI)
+ item->setRenameEnabled(DEVCOL_NAME, true);
+
if (dev->rwFlags() & 0x2)
item->setPixmap(DEVCOL_REC, dev->openFlags() & 2 ? *dotIcon : *dothIcon);
else
@@ -303,6 +624,14 @@ void MPConfig::songChanged(int flags)
if (!(dev && dev->isSynti()))
item->setPixmap(DEVCOL_INSTR, *buttondownIcon);
item->setPixmap(DEVCOL_NAME, *buttondownIcon);
+
+ //if(dev && dynamic_cast<MidiJackDevice*>(dev))
+ if(dev && dev->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ item->setPixmap(DEVCOL_ROUTES, *buttondownIcon);
+ item->setText(DEVCOL_ROUTES, tr("routes"));
+ }
+
mdevView->insertItem(item);
}
diff --git a/muse/muse/confmport.h b/muse/muse/confmport.h
index b98a2189..577c0afd 100644
--- a/muse/muse/confmport.h
+++ b/muse/muse/confmport.h
@@ -45,7 +45,9 @@ class MPWhatsThis : public QWhatsThis {
class MPConfig : public SynthConfigBase {
QPopupMenu* popup;
QPopupMenu* instrPopup;
-
+
+ int _showAliases; // -1: None. 0: First aliases. 1: Second aliases etc.
+
Q_OBJECT
private slots:
diff --git a/muse/muse/driver/alsamidi.cpp b/muse/muse/driver/alsamidi.cpp
index c9e14bbc..bcd1bd75 100644
--- a/muse/muse/driver/alsamidi.cpp
+++ b/muse/muse/driver/alsamidi.cpp
@@ -18,6 +18,8 @@
#include "mpevent.h"
//#include "sync.h"
#include "utils.h"
+#include "audiodev.h"
+#include "xml.h"
static int alsaSeqFdi = -1;
static int alsaSeqFdo = -1;
@@ -169,6 +171,101 @@ void MidiAlsaDevice::close()
}
//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void MidiAlsaDevice::writeRouting(int level, Xml& xml) const
+{
+ QString s;
+ /*
+ //if(rwFlags() & 2) // Readable
+ {
+ //RouteList* rl = _inRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
+ {
+ // Since an ALSA midi device supports read + write, this is the only way we can tell if this route is using the device as input.
+ if(r->type == Route::TRACK_ROUTE)
+ continue;
+
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", r->name());
+ xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ //xml.strTag(level, "dstNode", name());
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ */
+
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ //if(r->type != Route::TRACK_ROUTE)
+ //{
+ // printf("MidiAlsaDevice::writeRouting Warning out route is not TRACK_ROUTE type\n");
+ // continue;
+ //}
+
+ if(!r->name().isEmpty())
+ {
+ //xml.tag(level++, "Route");
+
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+ xml.tag(level++, s);
+
+ /*
+ //xml.strTag(level, "srcNode", name());
+ if(r->channel != -1)
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, r->channel, name().latin1());
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, r->channel, name().latin1());
+ else
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ */
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, name().latin1());
+
+ /*
+ //xml.strTag(level, "dstNode", r->name());
+ if(r->channel != -1)
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1());
+ }
+ else
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ }
+ */
+
+ s = QT_TR_NOOP("dest");
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType());
+ else
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ xml.tag(level, s);
+
+ xml.etag(level--, "Route");
+ }
+ }
+}
+
+//---------------------------------------------------------
// putEvent
//---------------------------------------------------------
@@ -418,7 +515,11 @@ bool initMidiAlsa()
}
}
- snd_seq_set_client_name(alsaSeq, "MusE Sequencer");
+
+ // p3.3.38
+ //snd_seq_set_client_name(alsaSeq, "MusE Sequencer");
+ snd_seq_set_client_name(alsaSeq, audioDevice->clientName());
+
int ci = snd_seq_poll_descriptors_count(alsaSeq, POLLIN);
int co = snd_seq_poll_descriptors_count(alsaSeq, POLLOUT);
@@ -721,28 +822,39 @@ void alsaProcessMidiInput()
break;
case SND_SEQ_EVENT_CLOCK:
- midiSeq->realtimeSystemInput(curPort, 0xf8);
+ midiSeq->realtimeSystemInput(curPort, ME_CLOCK);
//mdev->syncInfo().trigMCSyncDetect();
break;
case SND_SEQ_EVENT_START:
- midiSeq->realtimeSystemInput(curPort, 0xfa);
+ midiSeq->realtimeSystemInput(curPort, ME_START);
break;
case SND_SEQ_EVENT_CONTINUE:
- midiSeq->realtimeSystemInput(curPort, 0xfb);
+ midiSeq->realtimeSystemInput(curPort, ME_CONTINUE);
break;
case SND_SEQ_EVENT_STOP:
- midiSeq->realtimeSystemInput(curPort, 0xfc);
+ midiSeq->realtimeSystemInput(curPort, ME_STOP);
break;
case SND_SEQ_EVENT_TICK:
- midiSeq->realtimeSystemInput(curPort, 0xf9);
+ midiSeq->realtimeSystemInput(curPort, ME_TICK);
//mdev->syncInfo().trigTickDetect();
break;
case SND_SEQ_EVENT_SYSEX:
+
+ // TODO: Deal with large sysex, which are broken up into chunks!
+ // For now, do not accept if the first byte is not SYSEX or the last byte is not EOX,
+ // meaning it's a chunk, possibly with more chunks to follow.
+ if((*((unsigned char*)ev->data.ext.ptr) != ME_SYSEX) ||
+ (*(((unsigned char*)ev->data.ext.ptr) + ev->data.ext.len - 1) != ME_SYSEX_END))
+ {
+ printf("MusE: alsaProcessMidiInput sysex chunks not supported!\n");
+ break;
+ }
+
event.setTime(0); // mark as used
event.setType(ME_SYSEX);
event.setData((unsigned char*)(ev->data.ext.ptr)+1,
diff --git a/muse/muse/driver/alsamidi.h b/muse/muse/driver/alsamidi.h
index 48645706..6c19ff0d 100644
--- a/muse/muse/driver/alsamidi.h
+++ b/muse/muse/driver/alsamidi.h
@@ -13,6 +13,8 @@
#include "mididev.h"
+class Xml;
+
//---------------------------------------------------------
// MidiAlsaDevice
//---------------------------------------------------------
@@ -35,6 +37,9 @@ class MidiAlsaDevice : public MidiDevice {
MidiAlsaDevice() {}
MidiAlsaDevice(const snd_seq_addr_t&, const QString& name);
virtual ~MidiAlsaDevice() {}
+ virtual void* clientPort() { return (void*)&adr; }
+ virtual void writeRouting(int, Xml&) const;
+ virtual inline int deviceType() { return ALSA_MIDI; }
};
extern bool initMidiAlsa();
diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h
index f66627b8..b888f6eb 100644
--- a/muse/muse/driver/audiodev.h
+++ b/muse/muse/driver/audiodev.h
@@ -33,11 +33,13 @@ class AudioDevice {
virtual float* getBuffer(void* port, unsigned long nframes) = 0;
- virtual std::list<QString> outputPorts() = 0;
- virtual std::list<QString> inputPorts() = 0;
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1) = 0;
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1) = 0;
virtual void registerClient() = 0;
+ virtual const char* clientName() = 0;
+
//virtual void* registerOutPort(const char* name) = 0;
//virtual void* registerInPort(const char* name) = 0;
virtual void* registerOutPort(const char* /*name*/, bool /*midi*/) = 0;
diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp
index 2695f705..0bca9890 100644
--- a/muse/muse/driver/dummyaudio.cpp
+++ b/muse/muse/driver/dummyaudio.cpp
@@ -88,11 +88,13 @@ class DummyAudioDevice : public AudioDevice {
return buffer;
}
- virtual std::list<QString> outputPorts();
- virtual std::list<QString> inputPorts();
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1);
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);
virtual void registerClient() {}
+ virtual const char* clientName() { return "MusE"; }
+
//virtual void* registerOutPort(const char*) {
virtual void* registerOutPort(const char*, bool) {
return (void*)1;
@@ -214,11 +216,14 @@ bool initDummyAudio()
// outputPorts
//---------------------------------------------------------
-std::list<QString> DummyAudioDevice::outputPorts()
+std::list<QString> DummyAudioDevice::outputPorts(bool midi, int /*aliases*/)
{
std::list<QString> clientList;
- clientList.push_back(QString("output1"));
- clientList.push_back(QString("output2"));
+ if(!midi)
+ {
+ clientList.push_back(QString("output1"));
+ clientList.push_back(QString("output2"));
+ }
return clientList;
}
@@ -226,11 +231,14 @@ std::list<QString> DummyAudioDevice::outputPorts()
// inputPorts
//---------------------------------------------------------
-std::list<QString> DummyAudioDevice::inputPorts()
+std::list<QString> DummyAudioDevice::inputPorts(bool midi, int /*aliases*/)
{
std::list<QString> clientList;
- clientList.push_back(QString("input1"));
- clientList.push_back(QString("input2"));
+ if(!midi)
+ {
+ clientList.push_back(QString("input1"));
+ clientList.push_back(QString("input2"));
+ }
return clientList;
}
diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp
index 3329b73f..2926e281 100644
--- a/muse/muse/driver/jack.cpp
+++ b/muse/muse/driver/jack.cpp
@@ -6,6 +6,8 @@
//=========================================================
#include "config.h"
+#include <string>
+#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
@@ -123,6 +125,7 @@ static void jack_thread_init (void* ) // data
undoSetuid();
}
+/*
//---------------------------------------------------------
// processAudio + Midi
// JACK callback
@@ -137,6 +140,7 @@ print_triplet(unsigned char *data)
memcpy(&c, data+2, 1);
fprintf(stderr, "%x,%x,%x", a, b, c);
}
+*/
/*
void handle_jack_midi_in_events(jack_nframes_t frames)
@@ -430,7 +434,7 @@ static void noJackError(const char* /* s */)
// JackAudioDevice
//---------------------------------------------------------
-JackAudioDevice::JackAudioDevice(jack_client_t* cl, char * name)
+JackAudioDevice::JackAudioDevice(jack_client_t* cl, char* name)
: AudioDevice()
{
_frameCounter = 0;
@@ -496,6 +500,7 @@ int JackAudioDevice::realtimePriority() const
return param.sched_priority;
}
+/*
//---------------------------------------------------------
// getJackName()
//---------------------------------------------------------
@@ -504,6 +509,22 @@ char* JackAudioDevice::getJackName()
{
return jackRegisteredName;
}
+*/
+
+/*
+//---------------------------------------------------------
+// clientName()
+//---------------------------------------------------------
+
+const char* JackAudioDevice::clientName()
+{
+ //if(_client)
+ // return jack_get_client_name(_client);
+ //else
+ // return "MusE";
+ return jackRegisteredName;
+}
+*/
//---------------------------------------------------------
// initJackAudio
@@ -531,25 +552,41 @@ bool initJackAudio()
jack_set_error_function(noJackError);
doSetuid();
- jack_client_t* client = 0;
- int i = 0;
- char jackIdString[8];
- for (i = 0; i < 5; ++i) {
- sprintf(jackIdString, "MusE-%d", i+1);
+ //jack_client_t* client = 0;
+ //int i = 0;
+ //char jackIdString[8];
+ //for (i = 0; i < 5; ++i) {
+ // sprintf(jackIdString, "MusE-%d", i+1);
//client = jack_client_new(jackIdString);
- client = jack_client_open(jackIdString, JackNoStartServer, 0);
- if (client)
- break;
- }
-
- if (i == 5)
+ // client = jack_client_open(jackIdString, JackNoStartServer, 0);
+ // if (client)
+ // break;
+ // }
+ //if (i == 5)
+ // return true;
+ jack_status_t status;
+ jack_client_t* client = jack_client_open("MusE", JackNoStartServer, &status);
+ if (!client) {
+ if (status & JackServerStarted)
+ printf("jack server started...\n");
+ if (status & JackServerFailed)
+ printf("cannot connect to jack server\n");
+ if (status & JackServerError)
+ printf("communication with jack server failed\n");
+ if (status & JackShmFailure)
+ printf("jack cannot access shared memory\n");
+ if (status & JackVersionError)
+ printf("jack server has wrong version\n");
+ printf("cannot create jack client\n");
return true;
+ }
if (debugMsg)
- fprintf(stderr, "initJackAudio(): client %s opened.\n", jackIdString);
+ fprintf(stderr, "initJackAudio(): client %s opened.\n", jack_get_client_name(client));
if (client) {
jack_set_error_function(jackError);
- jackAudio = new JackAudioDevice(client, jackIdString);
+ //jackAudio = new JackAudioDevice(client, jackIdString);
+ jackAudio = new JackAudioDevice(client, jack_get_client_name(client));
if (debugMsg)
fprintf(stderr, "initJackAudio(): registering client...\n");
jackAudio->registerClient();
@@ -648,8 +685,10 @@ void JackAudioDevice::registrationChanged()
if(JACK_DEBUG)
printf("JackAudioDevice::registrationChanged()\n");
+ // Rescan.
+ scanMidiPorts();
// Connect the Jack midi client ports to the device ports.
- connectJackMidiPorts();
+ //connectJackMidiPorts();
}
//---------------------------------------------------------
@@ -661,6 +700,32 @@ void JackAudioDevice::connectJackMidiPorts()
if(JACK_DEBUG)
printf("JackAudioDevice::connectJackMidiPorts()\n");
+ for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i);
+ //if(!mjd)
+ MidiDevice* md = *i;
+ if(md->deviceType() != MidiDevice::JACK_MIDI)
+ continue;
+
+ void* port = md->clientPort();
+ if(md->rwFlags() & 1)
+ {
+ RouteList* rl = md->outRoutes();
+ for (iRoute r = rl->begin(); r != rl->end(); ++r)
+ connect(port, r->jackPort);
+ }
+ else
+ if(md->rwFlags() & 2)
+ {
+ RouteList* rl = md->inRoutes();
+ for (iRoute r = rl->begin(); r != rl->end(); ++r)
+ connect(r->jackPort, port);
+ }
+ }
+
+
+ /*
const char* type = JACK_DEFAULT_MIDI_TYPE;
const char** ports = jack_get_ports(_client, 0, type, 0);
for (const char** p = ports; p && *p; ++p)
@@ -668,6 +733,13 @@ void JackAudioDevice::connectJackMidiPorts()
jack_port_t* port = jack_port_by_name(_client, *p);
if(!port)
continue;
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf(" ignoring own port: %s\n", *p);
+ continue;
+ }
int nsz = jack_port_name_size();
char buffer[nsz];
strncpy(buffer, *p, nsz);
@@ -675,6 +747,9 @@ void JackAudioDevice::connectJackMidiPorts()
//if(strncmp(buffer, "MusE", 4) == 0)
// continue;
+ if(debugMsg)
+ printf(" found port: %s ", buffer);
+
// If there are aliases for this port, use the first one - much better for identifying.
//char a1[nsz];
char a2[nsz];
@@ -688,6 +763,9 @@ void JackAudioDevice::connectJackMidiPorts()
//char* namep = (na >= 1) ? aliases[0] : buffer;
char* namep = aliases[0];
+ if(debugMsg)
+ printf("alias: %s\n", aliases[0]);
+
//int flags = 0;
int pf = jack_port_flags(port);
// If Jack port can send data to us...
@@ -753,6 +831,8 @@ void JackAudioDevice::connectJackMidiPorts()
if(ports)
free(ports);
+
+ */
}
//---------------------------------------------------------
// client_registration_callback
@@ -846,7 +926,8 @@ void JackAudioDevice::graphChanged()
}
if (!found) {
audio->msgRemoveRoute1(
- Route(portName, false, channel),
+ //Route(portName, false, channel),
+ Route(portName, false, channel, Route::JACK_ROUTE),
Route(it, channel)
);
erased = true;
@@ -877,7 +958,8 @@ void JackAudioDevice::graphChanged()
}
if (!found) {
audio->msgAddRoute1(
- Route(*pn, false, channel),
+ //Route(*pn, false, channel),
+ Route(*pn, false, channel, Route::JACK_ROUTE),
Route(it, channel)
);
}
@@ -929,7 +1011,8 @@ void JackAudioDevice::graphChanged()
if (!found) {
audio->msgRemoveRoute1(
Route(it, channel),
- Route(portName, false, channel)
+ //Route(portName, false, channel)
+ Route(portName, false, channel, Route::JACK_ROUTE)
);
erased = true;
break;
@@ -960,7 +1043,8 @@ void JackAudioDevice::graphChanged()
if (!found) {
audio->msgAddRoute1(
Route(it, channel),
- Route(*pn, false, channel)
+ //Route(*pn, false, channel)
+ Route(*pn, false, channel, Route::JACK_ROUTE)
);
}
++pn;
@@ -975,6 +1059,201 @@ void JackAudioDevice::graphChanged()
}
}
+ for (iMidiDevice ii = midiDevices.begin(); ii != midiDevices.end(); ++ii)
+ {
+ MidiDevice* md = *ii;
+ if(md->deviceType() != MidiDevice::JACK_MIDI)
+ continue;
+
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*ii);
+ //if(!mjd)
+ // continue;
+ //for (int channel = 0; channel < channels; ++channel)
+ //{
+ jack_port_t* port = (jack_port_t*)md->clientPort();
+ if (port == 0)
+ continue;
+ const char** ports = jack_port_get_all_connections(_client, port);
+
+ //---------------------------------------
+ // outputs
+ //---------------------------------------
+
+ if(md->rwFlags() & 1) // Writable
+ {
+ RouteList* rl = md->outRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0; i < 20 ; i++)
+ {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ //Route(it, channel),
+ //Route(mjd),
+ Route(md, -1),
+ //Route(portName, false, channel)
+ //Route(portName, false, -1)
+ Route(portName, false, -1, Route::JACK_ROUTE)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports)
+ {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ //Route(it, channel),
+ //Route(mjd),
+ Route(md, -1),
+ //Route(*pn, false, channel)
+ //Route(*pn, false, -1)
+ Route(*pn, false, -1, Route::JACK_ROUTE)
+ );
+ }
+ ++pn;
+ }
+
+ // p3.3.37
+ //delete ports;
+ //free(ports);
+
+ //ports = NULL;
+ }
+ }
+
+
+ //------------------------
+ // Inputs
+ //------------------------
+
+ if(md->rwFlags() & 2) // Readable
+ {
+ RouteList* rl = md->inRoutes();
+
+ //---------------------------------------
+ // check for disconnects
+ //---------------------------------------
+
+ bool erased;
+ // limit set to 20 iterations for disconnects, don't know how to make it go
+ // the "right" amount
+ for (int i = 0; i < 20 ; i++)
+ {
+ erased = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ bool found = false;
+ const char** pn = ports;
+ while (pn && *pn) {
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ ++pn;
+ }
+ if (!found) {
+ audio->msgRemoveRoute1(
+ //Route(portName, false, channel),
+ //Route(portName, false, -1),
+ Route(portName, false, -1, Route::JACK_ROUTE),
+ //Route(it, channel)
+ //Route(mjd)
+ Route(md, -1)
+ );
+ erased = true;
+ break;
+ }
+ }
+ if (!erased)
+ break;
+ }
+
+ //---------------------------------------
+ // check for connects
+ //---------------------------------------
+
+ if (ports)
+ {
+ const char** pn = ports;
+ while (*pn) {
+ bool found = false;
+ for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) {
+ //if (irl->channel != channel)
+ // continue;
+ QString name = irl->name();
+ const char* portName = name.latin1();
+ if (strcmp(*pn, portName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ audio->msgAddRoute1(
+ //Route(*pn, false, channel),
+ //Route(*pn, false, -1),
+ Route(*pn, false, -1, Route::JACK_ROUTE),
+ //Route(it, channel)
+ //Route(mjd)
+ Route(md, -1)
+ );
+ }
+ ++pn;
+ }
+ }
+ }
+ if(ports)
+ // Done with ports. Free them.
+ //delete ports;
+ free(ports);
+
+ ports = NULL;
+ }
}
//static int xrun_callback(void*)
@@ -1279,24 +1558,67 @@ int JackAudioDevice::frameDelay() const
// outputPorts
//---------------------------------------------------------
-std::list<QString> JackAudioDevice::outputPorts()
+std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)
{
if (JACK_DEBUG)
printf("JackAudioDevice::outputPorts()\n");
std::list<QString> clientList;
if(!checkJackClient(_client)) return clientList;
- const char** ports = jack_get_ports(_client, 0, JACK_DEFAULT_AUDIO_TYPE, 0);
+ QString qname;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput);
for (const char** p = ports; p && *p; ++p) {
jack_port_t* port = jack_port_by_name(_client, *p);
- int flags = jack_port_flags(port);
- if (!(flags & JackPortIsOutput))
- continue;
- char buffer[128];
- strncpy(buffer, *p, 128);
- if (strncmp(buffer, "MusE", 4) == 0)
- continue;
- clientList.push_back(QString(buffer));
+ //int flags = jack_port_flags(port);
+ //if (!(flags & JackPortIsOutput))
+ // continue;
+ //char buffer[128];
+
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+
+ strncpy(buffer, *p, nsz);
+ //if (strncmp(buffer, "MusE", 4) == 0)
+ //{
+ // if(debugMsg)
+ // printf("JackAudioDevice::outputPorts ignoring own MusE port: %s\n", *p);
+ // continue;
+ //}
+
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf("JackAudioDevice::outputPorts ignoring own port: %s\n", *p);
+ continue;
}
+
+ // p3.3.38
+ if((aliases == 0) || (aliases == 1))
+ {
+ //char a1[nsz];
+ char a2[nsz];
+ char* al[2];
+ //aliases[0] = a1;
+ al[0] = buffer;
+ al[1] = a2;
+ int na = jack_port_get_aliases(port, al);
+ int a = aliases;
+ if(a >= na)
+ {
+ a = na;
+ if(a > 0)
+ a--;
+ }
+ qname = QString(al[a]);
+ }
+ else
+ qname = QString(buffer);
+
+ //clientList.push_back(QString(buffer));
+ clientList.push_back(qname);
+ }
+
// p3.3.37
if(ports)
free(ports);
@@ -1308,24 +1630,67 @@ std::list<QString> JackAudioDevice::outputPorts()
// inputPorts
//---------------------------------------------------------
-std::list<QString> JackAudioDevice::inputPorts()
+std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)
{
if (JACK_DEBUG)
printf("JackAudioDevice::inputPorts()\n");
std::list<QString> clientList;
if(!checkJackClient(_client)) return clientList;
- const char** ports = jack_get_ports(_client, 0, JACK_DEFAULT_AUDIO_TYPE, 0);
+ QString qname;
+ const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;
+ const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput);
for (const char** p = ports; p && *p; ++p) {
jack_port_t* port = jack_port_by_name(_client, *p);
- int flags = jack_port_flags(port);
- if (!(flags & JackPortIsInput))
- continue;
- char buffer[128];
- strncpy(buffer, *p, 128);
- if (strncmp(buffer, "MusE", 4) == 0)
- continue;
- clientList.push_back(QString(buffer));
+ //int flags = jack_port_flags(port);
+ //if (!(flags & JackPortIsInput))
+ // continue;
+ //char buffer[128];
+
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+
+ strncpy(buffer, *p, nsz);
+ //if (strncmp(buffer, "MusE", 4) == 0)
+ //{
+ // if(debugMsg)
+ // printf("JackAudioDevice::inputPorts ignoring own MusE port: %s\n", *p);
+ // continue;
+ //}
+
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf("JackAudioDevice::inputPorts ignoring own port: %s\n", *p);
+ continue;
+ }
+
+ // p3.3.38
+ if((aliases == 0) || (aliases == 1))
+ {
+ //char a1[nsz];
+ char a2[nsz];
+ char* al[2];
+ //aliases[0] = a1;
+ al[0] = buffer;
+ al[1] = a2;
+ int na = jack_port_get_aliases(port, al);
+ int a = aliases;
+ if(a >= na)
+ {
+ a = na;
+ if(a > 0)
+ a--;
+ }
+ qname = QString(al[a]);
+ }
+ else
+ qname = QString(buffer);
+
+ //clientList.push_back(QString(buffer));
+ clientList.push_back(qname);
}
+
// p3.3.37
if(ports)
free(ports);
@@ -1678,22 +2043,34 @@ void JackAudioDevice::scanMidiPorts()
{
if(debugMsg)
printf("JackAudioDevice::scanMidiPorts:\n");
+
+/*
const char* type = JACK_DEFAULT_MIDI_TYPE;
const char** ports = jack_get_ports(_client, 0, type, 0);
+
+ std::set<std::string> names;
for (const char** p = ports; p && *p; ++p)
{
jack_port_t* port = jack_port_by_name(_client, *p);
if(!port)
continue;
+ // Ignore our own client ports.
+ if(jack_port_is_mine(_client, port))
+ {
+ if(debugMsg)
+ printf(" ignoring own port: %s\n", *p);
+ continue;
+ }
+
int nsz = jack_port_name_size();
char buffer[nsz];
strncpy(buffer, *p, nsz);
// Ignore the MusE Jack port.
- if(strncmp(buffer, "MusE", 4) == 0)
- continue;
+ //if(strncmp(buffer, "MusE", 4) == 0)
+ // continue;
if(debugMsg)
- printf(" found port:%s\n", buffer);
+ printf(" found port: %s ", buffer);
// If there are aliases for this port, use the first one - much better for identifying.
//char a1[nsz];
@@ -1706,8 +2083,75 @@ void JackAudioDevice::scanMidiPorts()
jack_port_get_aliases(port, aliases);
//int na = jack_port_get_aliases(port, aliases);
//char* namep = (na >= 1) ? aliases[0] : buffer;
- char* namep = aliases[0];
+ //char* namep = aliases[0];
+ //names.insert(std::string(*p));
+ if(debugMsg)
+ printf("alias: %s\n", aliases[0]);
+
+ names.insert(std::string(aliases[0]));
+ }
+ if(ports)
+ free(ports);
+ std::list<MidiDevice*> to_del;
+ for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
+ {
+ // Only Jack midi devices.
+ if(dynamic_cast<MidiJackDevice*>(*imd) == 0)
+ continue;
+ if(names.find(std::string((*imd)->name().latin1())) == names.end())
+ to_del.push_back(*imd);
+ }
+
+ for(std::list<MidiDevice*>::iterator imd = to_del.begin(); imd != to_del.end(); ++imd)
+ {
+ if(debugMsg)
+ printf(" removing port device:%s\n", (*imd)->name().latin1());
+ midiDevices.remove(*imd);
+ // This will close (and unregister) the client port.
+ delete (*imd);
+ }
+
+ //for (const char** p = ports; p && *p; ++p)
+ for(std::set<std::string>::iterator is = names.begin(); is != names.end(); ++is)
+ {
+ //jack_port_t* port = jack_port_by_name(_client, *p);
+ jack_port_t* port = jack_port_by_name(_client, is->c_str());
+ if(!port)
+ continue;
+*/
+
+ /*
+ int nsz = jack_port_name_size();
+ char buffer[nsz];
+ //strncpy(buffer, *p, nsz);
+ strncpy(buffer, is->c_str(), nsz);
+ // Ignore the MusE Jack port.
+ //if(strncmp(buffer, "MusE", 4) == 0)
+ // continue;
+
+ // If there are aliases for this port, use the first one - much better for identifying.
+ //char a1[nsz];
+ char a2[nsz];
+ char* aliases[2];
+ //aliases[0] = a1;
+ aliases[0] = buffer;
+ aliases[1] = a2;
+ // To disable aliases, just rem this line.
+ jack_port_get_aliases(port, aliases);
+ //int na = jack_port_get_aliases(port, aliases);
+ //char* namep = (na >= 1) ? aliases[0] : buffer;
+ char* namep = aliases[0];
+ QString qname(namep);
+ */
+
+/*
+ QString qname(is->c_str());
+
+ // Port already exists?
+ if(midiDevices.find(qname))
+ continue;
+
int flags = 0;
int pf = jack_port_flags(port);
// If Jack port can send data to us...
@@ -1722,12 +2166,13 @@ void JackAudioDevice::scanMidiPorts()
//JackPort jp(0, QString(buffer), flags);
//portList.append(jp);
- MidiJackDevice* dev = new MidiJackDevice(0, QString(namep));
+ if(debugMsg)
+ printf(" adding port device:%s\n", qname.latin1());
+
+ MidiJackDevice* dev = new MidiJackDevice(0, qname);
dev->setrwFlags(flags);
midiDevices.add(dev);
}
- // p3.3.37
- if(ports)
- free(ports);
+*/
}
diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h
index 086e36db..242e762d 100644
--- a/muse/muse/driver/jackaudio.h
+++ b/muse/muse/driver/jackaudio.h
@@ -25,7 +25,7 @@ class JackAudioDevice : public AudioDevice {
int samplePos;
jack_transport_state_t transportState;
jack_position_t pos;
- char jackRegisteredName[8];
+ char jackRegisteredName[16];
int dummyState;
int dummyPos;
// Free-running frame counter incremented always in process.
@@ -52,17 +52,18 @@ class JackAudioDevice : public AudioDevice {
return (float*)jack_port_get_buffer((jack_port_t*)port, nframes);
}
- virtual std::list<QString> outputPorts();
- virtual std::list<QString> inputPorts();
+ virtual std::list<QString> outputPorts(bool midi = false, int aliases = -1);
+ virtual std::list<QString> inputPorts(bool midi = false, int aliases = -1);
virtual void registerClient();
+ virtual const char* clientName() { return jackRegisteredName; }
//virtual void* registerOutPort(const char* name);
//virtual void* registerInPort(const char* name);
virtual void* registerOutPort(const char* /*name*/, bool /*midi*/);
virtual void* registerInPort(const char* /*name*/, bool /*midi*/);
- virtual char* getJackName();
+ //virtual char* getJackName();
virtual void unregisterPort(void*);
virtual void connect(void*, void*);
diff --git a/muse/muse/driver/jackmidi.cpp b/muse/muse/driver/jackmidi.cpp
index efc70602..d27d83d6 100644
--- a/muse/muse/driver/jackmidi.cpp
+++ b/muse/muse/driver/jackmidi.cpp
@@ -5,6 +5,7 @@
// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
//=========================================================
+#include <qt.h>
#include <qstring.h>
#include <stdio.h>
@@ -25,6 +26,9 @@
#include "audiodev.h"
#include "../mplugins/midiitransform.h"
#include "../mplugins/mitplugin.h"
+#include "xml.h"
+
+extern unsigned int volatile lastExtMidiSyncTick;
// Turn on debug messages.
//#define JACK_MIDI_DEBUG
@@ -42,28 +46,115 @@
///int* jackSeq;
//static snd_seq_addr_t musePort;
-int MidiJackDevice::_nextOutIdNum = 0;
-int MidiJackDevice::_nextInIdNum = 0;
+//int MidiJackDevice::_nextOutIdNum = 0;
+//int MidiJackDevice::_nextInIdNum = 0;
+
+//int JackMidiPortList::_nextOutIdNum = 0;
+//int JackMidiPortList::_nextInIdNum = 0;
+
+//JackMidiPortList jackMidiClientPorts;
+
+/*
//---------------------------------------------------------
-// MidiAlsaDevice
+// JackMidiPortList
//---------------------------------------------------------
-MidiJackDevice::MidiJackDevice(const int& a, const QString& n)
+JackMidiPortList::JackMidiPortList()
+{
+
+}
+
+JackMidiPortList::~JackMidiPortList()
+{
+
+}
+
+iJackMidiPort JackMidiPortList::createClientPort(int flags) // 1 = writable, 2 = readable - do not mix
+{
+ if(flags & 1)
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
+ jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-out\n");
+ //return QString("Could not register jack-midi-out client port");
+ return end();
+ }
+ else
+ {
+ JackMidiPort jmp(_client_jackport, QString(buf), flags);
+ _nextOutIdNum++;
+ return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
+ }
+ }
+ else
+ if(flags & 2)
+ {
+ char buf[80];
+ snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
+ jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
+ if(_client_jackport == NULL)
+ {
+ fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-in\n");
+ return end();
+ }
+ else
+ {
+ JackMidiPort jmp(_client_jackport, QString(buf), flags);
+ _nextInIdNum++;
+ return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
+ }
+ }
+ return end();
+}
+
+// Return true if removed.
+bool JackMidiPortList::removeClientPort(jack_port_t* port)
+{
+ iJackMidiPort ijp = find(port);
+ if(ijp == end())
+ return false;
+
+ // Is output?
+ if(ijp->second._flags & 1)
+ _nextOutIdNum--;
+ // Is input?
+ if(ijp->second._flags & 2)
+ _nextInIdNum--;
+
+ erase(ijp);
+
+ audioDevice->unregisterPort(port);
+
+ return true;
+}
+*/
+
+//---------------------------------------------------------
+// MidiJackDevice
+//---------------------------------------------------------
+
+//MidiJackDevice::MidiJackDevice(const int& a, const QString& n)
+MidiJackDevice::MidiJackDevice(jack_port_t* jack_port, const QString& n)
: MidiDevice(n)
{
- _client_jackport = 0;
- adr = a;
+ //_client_jackport = 0;
+ _client_jackport = jack_port;
+ //adr = a;
init();
}
MidiJackDevice::~MidiJackDevice()
{
- #ifdef JACK_MIDI_USE_MULTIPLE_CLIENT_PORTS
+ #ifdef JACK_MIDI_DEBUG
+ printf("MidiJackDevice::~MidiJackDevice()\n");
+ #endif
if(_client_jackport)
- //audioDevice->unregisterPort(_client_jackport);
- close();
- #endif
+ audioDevice->unregisterPort(_client_jackport);
+ //close();
}
/*
@@ -83,6 +174,181 @@ int MidiJackDevice::selectWfd()
*/
//---------------------------------------------------------
+// createJackMidiDevice
+// If name parameter is blank, creates a new (locally) unique one.
+//---------------------------------------------------------
+
+//QString MidiJackDevice::createJackMidiDevice(int rwflags) // 1:Writable 2: Readable. Do not mix.
+MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable. Do not mix.
+{
+/// _openFlags &= _rwFlags; // restrict to available bits
+
+/// #ifdef JACK_MIDI_DEBUG
+/// printf("MidiJackDevice::open %s\n", name.latin1());
+/// #endif
+
+ //jack_port_t* jp = jack_port_by_name(_client, name().latin1());
+/// jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
+
+/// if(!jp)
+/// {
+/// printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().latin1());
+/// _writeEnable = false;
+/// _readEnable = false;
+/// return QString("Jack midi port not found");
+/// }
+
+/// int pf = jack_port_flags(jp);
+
+ //if(!name.isEmpty())
+ //{
+ // Does not work.
+ // if(audioDevice->findPort(name.latin1()))
+ // {
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Given port name %s already exists!\n", name.latin1());
+ // return 0;
+ // }
+ //}
+
+ jack_port_t* client_jackport = NULL;
+ //char buf[80];
+
+ // If Jack port can receive data from us and we actually want to...
+ //if((pf & JackPortIsInput) && (_openFlags & 1))
+ if(rwflags & 1)
+ {
+ if(name.isEmpty())
+ {
+ //snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
+ for(int i = 0; ; ++i)
+ {
+ //snprintf(buf, 80, "midi-out-%d", i);
+ name.sprintf("midi-out-%d", i);
+
+ // Does not work.
+ //if(!audioDevice->findPort(buf))
+ // break;
+ //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(client_jackport)
+ break;
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
+ return 0;
+ }
+ }
+ //name = QString(buf);
+ }
+ else
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.latin1());
+ return 0;
+ }
+ }
+ /*
+ else
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ for(int i = 0; ; ++i)
+ {
+ snprintf(buf, 80, "midi-out-%d", i);
+ // Does not work!
+ //if(!audioDevice->findPort(buf))
+ // break;
+ client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
+ if(client_jackport)
+ break;
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
+ return 0;
+ }
+ }
+ name = QString(buf);
+ }
+ }
+ */
+
+ //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.latin1(), true);
+ //if(client_jackport == NULL)
+ //{
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client output port %s\n", name.latin1());
+ // return 0;
+ //}
+ //else
+ // _nextOutIdNum++;
+
+ }
+ else // Note docs say it can't be both input and output.
+ // If Jack port can send data to us and we actually want it...
+ //if((pf & JackPortIsOutput) && (_openFlags & 2))
+ if(rwflags & 2)
+ {
+ if(name.isEmpty())
+ {
+ //snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
+ for(int i = 0; ; ++i)
+ {
+ //snprintf(buf, 80, "midi-in-%d", i);
+ name.sprintf("midi-in-%d", i);
+
+ // Does not work.
+ //if(!audioDevice->findPort(buf))
+ // break;
+ //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
+ client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+ if(client_jackport)
+ break;
+
+ if(i == 65535)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused input port name!\n");
+ return 0;
+ }
+ }
+ //name = QString(buf);
+ }
+ else
+ {
+ client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+ if(!client_jackport)
+ {
+ fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.latin1());
+ return 0;
+ }
+ }
+
+ //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.latin1(), true);
+
+ //if(client_jackport == NULL)
+ //{
+ // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client input port %s\n", name.latin1());
+ //_readEnable = false;
+ //return QString("Could not register jack-midi-in client port");
+ // return 0;
+ //}
+ //else
+ // _nextInIdNum++;
+
+ }
+ if(client_jackport == NULL)
+ return 0;
+
+ MidiJackDevice* dev = new MidiJackDevice(client_jackport, name);
+ dev->setrwFlags(rwflags);
+ midiDevices.add(dev);
+ return dev;
+}
+
+//---------------------------------------------------------
// open
//---------------------------------------------------------
@@ -91,9 +357,10 @@ QString MidiJackDevice::open()
_openFlags &= _rwFlags; // restrict to available bits
#ifdef JACK_MIDI_DEBUG
- printf("MidiJackDevice::open %s\n", name.latin1());
+ printf("MidiJackDevice::open %s\n", name().latin1());
#endif
+ /*
//jack_port_t* jp = jack_port_by_name(_client, name().latin1());
jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
@@ -147,6 +414,11 @@ QString MidiJackDevice::open()
_readEnable = true;
}
}
+ */
+
+ _writeEnable = bool(_openFlags & 1);
+ _readEnable = bool(_openFlags & 2);
+
return QString("OK");
}
@@ -157,9 +429,10 @@ QString MidiJackDevice::open()
void MidiJackDevice::close()
{
#ifdef JACK_MIDI_DEBUG
- printf("MidiJackDevice::close %s\n", name.latin1());
+ printf("MidiJackDevice::close %s\n", name().latin1());
#endif
+ /*
if(_client_jackport)
{
int pf = jack_port_flags(_client_jackport);
@@ -175,7 +448,11 @@ void MidiJackDevice::close()
_readEnable = false;
return;
}
+ */
+ _writeEnable = false;
+ _readEnable = false;
+
/*
//jack_port_t* jp = jack_port_by_name(_client, name().latin1());
jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().latin1());
@@ -210,6 +487,124 @@ void MidiJackDevice::close()
}
//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void MidiJackDevice::writeRouting(int level, Xml& xml) const
+{
+ QString s;
+ if(rwFlags() & 2) // Readable
+ {
+ //RouteList* rl = _inRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", r->name());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ s = QT_TR_NOOP("source");
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ xml.tag(level, s);
+
+ //xml.strTag(level, "dstNode", name());
+ //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+
+ //xml.tag(level++, "Route");
+ xml.tag(level++, s);
+
+ /*
+ //xml.strTag(level, "srcNode", name());
+ if(r->channel != -1)
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, r->channel, name().latin1());
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().latin1());
+ xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, r->channel, name().latin1());
+ else
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().latin1());
+ */
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().latin1());
+
+ /*
+ //xml.strTag(level, "dstNode", r->name());
+ if(r->channel != -1)
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1());
+ }
+ else
+ {
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1());
+ else
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ }
+ */
+
+ s = QT_TR_NOOP("dest");
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType());
+ else
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ xml.tag(level, s);
+
+
+ xml.etag(level--, "Route");
+ }
+ }
+
+ /*
+ else
+ if(rwFlags() & 1) // Writable
+ {
+ //RouteList* rl = _outRoutes;
+ //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ xml.tag(level++, "Route");
+
+ //xml.strTag(level, "srcNode", name());
+ //if(r->channel != -1)
+ // xml.tag(level, "srcNode type=\"%d\" channel=\"%d\" name=\"%s\"", Route::JACK_MIDI_ROUTE, r->channel, name().latin1());
+ //else
+ xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().latin1());
+
+ //xml.strTag(level, "dstNode", r->name());
+ xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+ */
+}
+
+//---------------------------------------------------------
// putEvent
//---------------------------------------------------------
@@ -310,12 +705,12 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
event.dump();
}
+ int typ = event.type();
+
if(_port != -1)
{
int idin = midiPorts[_port].syncInfo().idIn();
- int typ = event.type();
-
//---------------------------------------------------
// filter some SYSEX events
//---------------------------------------------------
@@ -370,13 +765,24 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
// transfer noteOn events to gui for step recording and keyboard
// remote control
//
- if (event.type() == ME_NOTEON) {
+ if (typ == ME_NOTEON) {
int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
song->putEvent(pv);
}
- if(_recordFifo.put(MidiPlayEvent(event)))
- printf("MidiJackDevice::recordEvent: fifo overflow\n");
+ //if(_recordFifo.put(MidiPlayEvent(event)))
+ // printf("MidiJackDevice::recordEvent: fifo overflow\n");
+
+ // p3.3.38
+ // Do not bother recording if it is NOT actually being used by a port.
+ // Because from this point on, process handles things, by selected port.
+ if(_port == -1)
+ return;
+
+ // Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
+ unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel();
+ if(_recordFifo[ch].put(MidiPlayEvent(event)))
+ printf("MidiJackDevice::recordEvent: fifo channel %d overflow\n", ch);
}
//---------------------------------------------------------
@@ -403,7 +809,9 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
// unsigned curFrame = st->lastFrameTime;
//int frameOffset = audio->getFrameOffset();
unsigned pos = audio->pos().frame();
- event.setTime(pos + ev->time);
+
+ //event.setTime(pos + ev->time);
+ event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time));
event.setChannel(*(ev->buffer) & 0xf);
int type = *(ev->buffer) & 0xf0;
@@ -428,23 +836,56 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
case ME_SYSEX:
{
- int type = *(ev->buffer) & 0xff;
- switch(type) {
- case ME_SYSEX:
- event.setTime(0); // mark as used
- event.setType(ME_SYSEX);
- event.setData((unsigned char*)(ev->buffer + 1),
- ev->size - 2);
- break;
- case ME_CLOCK:
- case ME_SENSE:
- break;
- default:
- printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type);
- return;
- }
+ int type = *(ev->buffer) & 0xff;
+ switch(type)
+ {
+ case ME_SYSEX:
+
+ // TODO: Deal with large sysex, which are broken up into chunks!
+ // For now, do not accept if the last byte is not EOX, meaning it's a chunk with more chunks to follow.
+ if(*(((unsigned char*)ev->buffer) + ev->size - 1) != ME_SYSEX_END)
+ {
+ printf("MidiJackDevice::eventReceived sysex chunks not supported!\n");
+ return;
+ }
+
+ //event.setTime(0); // mark as used
+ event.setType(ME_SYSEX);
+ event.setData((unsigned char*)(ev->buffer + 1), ev->size - 2);
+ break;
+ case ME_MTC_QUARTER:
+ if(_port != -1)
+ midiSeq->mtcInputQuarter(_port, *(ev->buffer + 1));
+ return;
+ case ME_SONGPOS:
+ if(_port != -1)
+ midiSeq->setSongPosition(_port, *(ev->buffer + 1) | (*(ev->buffer + 2) >> 2 )); // LSB then MSB
+ return;
+ //case ME_SONGSEL:
+ //case ME_TUNE_REQ:
+ //case ME_SENSE:
+ case ME_CLOCK:
+ case ME_TICK:
+ case ME_START:
+ case ME_CONTINUE:
+ case ME_STOP:
+ if(_port != -1)
+ midiSeq->realtimeSystemInput(_port, type);
+ return;
+ //case ME_SYSEX_END:
+ //break;
+ // return;
+ default:
+ printf("MidiJackDevice::eventReceived unsupported system event 0x%02x\n", type);
+ return;
+ }
}
- return;
+ //return;
+ break;
+ default:
+ printf("MidiJackDevice::eventReceived unknown event 0x%02x\n", type);
+ //printf("MidiJackDevice::eventReceived unknown event 0x%02x size:%d buf:0x%02x 0x%02x 0x%02x ...0x%02x\n", type, ev->size, *(ev->buffer), *(ev->buffer + 1), *(ev->buffer + 2), *(ev->buffer + (ev->size - 1)));
+ return;
}
if (midiInputTrace) {
diff --git a/muse/muse/driver/jackmidi.h b/muse/muse/driver/jackmidi.h
index d260163c..a143b7ff 100644
--- a/muse/muse/driver/jackmidi.h
+++ b/muse/muse/driver/jackmidi.h
@@ -10,15 +10,20 @@
//#include <config.h>
+#include <map>
+
#include <jack/jack.h>
#include <jack/midiport.h>
#include "mididev.h"
+#include "route.h"
class QString;
class MidiFifo;
class MidiRecordEvent;
class MidiPlayEvent;
+//class RouteList;
+class Xml;
// Turn on to show multiple devices, work in progress,
// not working fully yet, can't seem to connect...
@@ -44,23 +49,57 @@ typedef struct {
} muse_jack_midi_buffer;
*/
+/*
+struct JackMidiPort
+{
+ jack_port_t* _jackPort;
+ QString _name;
+ int _flags; // 1 = writable, 2 = readable - do not mix
+ JackMidiPort(jack_port_t* jp, const QString& s, int f)
+ {
+ _jackPort = jp;
+ _name = QString(s);
+ _flags = f;
+ }
+};
+
+typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::iterator iJackMidiPort;
+typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::const_iterator ciJackMidiPort;
+
+class JackMidiPortList : public std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >
+{
+ private:
+ static int _nextOutIdNum;
+ static int _nextInIdNum;
+
+ public:
+ JackMidiPortList();
+ ~JackMidiPortList();
+ iJackMidiPort createClientPort(int flags);
+ bool removeClientPort(jack_port_t* port);
+};
+
+extern JackMidiPortList jackMidiClientPorts;
+*/
+
//---------------------------------------------------------
// MidiJackDevice
//---------------------------------------------------------
class MidiJackDevice : public MidiDevice {
public:
- int adr;
+ //int adr;
private:
// fifo for midi events sent from gui
// direct to midi port:
MidiFifo eventFifo;
- static int _nextOutIdNum;
- static int _nextInIdNum;
+ //static int _nextOutIdNum;
+ //static int _nextInIdNum;
jack_port_t* _client_jackport;
+ //RouteList _routes;
virtual QString open();
virtual void close();
@@ -77,8 +116,14 @@ class MidiJackDevice : public MidiDevice {
public:
MidiJackDevice() {}
- MidiJackDevice(const int&, const QString& name);
- void processMidi();
+ //MidiJackDevice(const int&, const QString& name);
+ MidiJackDevice(jack_port_t* jack_port, const QString& name);
+
+ static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix.
+
+ virtual inline int deviceType() { return JACK_MIDI; }
+
+ virtual void processMidi();
virtual ~MidiJackDevice();
//virtual int selectRfd();
//virtual int selectWfd();
@@ -90,7 +135,12 @@ class MidiJackDevice : public MidiDevice {
virtual void collectMidiEvents();
//virtual jack_port_t* jackPort() { return _jackport; }
- virtual jack_port_t* clientJackPort() { return _client_jackport; }
+ //virtual jack_port_t* clientJackPort() { return _client_jackport; }
+ virtual void* clientPort() { return (void*)_client_jackport; }
+
+ //RouteList* routes() { return &_routes; }
+ //bool noRoute() const { return _routes.empty(); }
+ virtual void writeRouting(int, Xml&) const;
};
extern bool initMidiJack();
diff --git a/muse/muse/dssihost.cpp b/muse/muse/dssihost.cpp
index b9825a83..eb07b1d1 100644
--- a/muse/muse/dssihost.cpp
+++ b/muse/muse/dssihost.cpp
@@ -360,6 +360,28 @@ static void scanDSSILib(const QFileInfo& fi)
//DssiSynth* s = new DssiSynth(fi, label);
DssiSynth* s = new DssiSynth(fi, label, QString(descr->LADSPA_Plugin->Name), QString(descr->LADSPA_Plugin->Maker), QString());
+ if(debugMsg)
+ {
+ fprintf(stderr, "scanDSSILib: name:%s listname:%s lib:%s listlib:%s\n", label.ascii(), s->name().ascii(), fi.baseName(true).ascii(), s->baseName().ascii());
+ int ai = 0, ao = 0, ci = 0, co = 0;
+ for(int pt = 0; pt < descr->LADSPA_Plugin->PortCount; ++pt)
+ {
+ LADSPA_PortDescriptor pd = descr->LADSPA_Plugin->PortDescriptors[pt];
+ if(LADSPA_IS_PORT_INPUT(pd) && LADSPA_IS_PORT_AUDIO(pd))
+ ai++;
+ else
+ if(LADSPA_IS_PORT_OUTPUT(pd) && LADSPA_IS_PORT_AUDIO(pd))
+ ao++;
+ else
+ if(LADSPA_IS_PORT_INPUT(pd) && LADSPA_IS_PORT_CONTROL(pd))
+ ci++;
+ else
+ if(LADSPA_IS_PORT_OUTPUT(pd) && LADSPA_IS_PORT_CONTROL(pd))
+ co++;
+ }
+ fprintf(stderr, "audio ins:%d outs:%d control ins:%d outs:%d\n", ai, ao, ci, co);
+ }
+
synthis.push_back(s);
}
else
@@ -545,7 +567,8 @@ bool DssiSynthIF::init(DssiSynth* s)
for(int k = 0; k < inports; ++k)
{
//audioInBuffers[k] = new LADSPA_Data[segmentSize];
- posix_memalign((void**)(audioInBuffers + k), 16, sizeof(float) * segmentSize);
+ //posix_memalign((void**)(audioInBuffers + k), 16, sizeof(float) * segmentSize);
+ posix_memalign((void**)&audioInBuffers[k], 16, sizeof(float) * segmentSize);
memset(audioInBuffers[k], 0, sizeof(float) * segmentSize);
ld->connect_port(handle, synth->iIdx[k], audioInBuffers[k]);
}
@@ -558,9 +581,11 @@ bool DssiSynthIF::init(DssiSynth* s)
for(int k = 0; k < outports; ++k)
{
//audioOutBuffers[k] = new LADSPA_Data[segmentSize];
- posix_memalign((void**)(audioOutBuffers + k), 16, sizeof(float) * segmentSize);
+ //posix_memalign((void**)(audioOutBuffers + k), 16, sizeof(float) * segmentSize);
+ posix_memalign((void**)&audioOutBuffers[k], 16, sizeof(float) * segmentSize);
memset(audioOutBuffers[k], 0, sizeof(float) * segmentSize);
ld->connect_port(handle, synth->oIdx[k], audioOutBuffers[k]);
+ //printf("DssiSynthIF::init output port name: %s\n", ld->PortNames[synth->oIdx[k]]); // out1, out2, out3 etc
}
}
@@ -1995,6 +2020,16 @@ int DssiSynthIF::channels() const
return synth->_outports > MAX_CHANNELS ? MAX_CHANNELS : synth->_outports;
}
+int DssiSynthIF::totalOutChannels() const
+{
+ return synth->_outports;
+}
+
+int DssiSynthIF::totalInChannels() const
+{
+ return synth->_inports;
+}
+
#else //DSSI_SUPPORT
void initDSSI() {}
#endif
diff --git a/muse/muse/dssihost.h b/muse/muse/dssihost.h
index f2609dca..eb3637f0 100644
--- a/muse/muse/dssihost.h
+++ b/muse/muse/dssihost.h
@@ -139,6 +139,8 @@ class DssiSynthIF : public SynthIF
//virtual int channels() const { return synth->_outports; }
virtual int channels() const;
+ virtual int totalOutChannels() const;
+ virtual int totalInChannels() const;
virtual void deactivate3() {}
diff --git a/muse/muse/globaldefs.h b/muse/muse/globaldefs.h
index d842a3f0..06661771 100644
--- a/muse/muse/globaldefs.h
+++ b/muse/muse/globaldefs.h
@@ -23,7 +23,8 @@ enum AutomationType {
const int MAX_CHANNELS = 2; // max audio channels
const int MAX_PLUGINS = 4; // plugins in mixer rack
-const int MIDI_PORTS = 32; // max Number of Midi Ports
+//const int MIDI_PORTS = 32; // max Number of Midi Ports
+const int MIDI_PORTS = 128; // max Number of Midi Ports
#ifndef MIDI_CHANNELS
#define MIDI_CHANNELS 16 // Channels per Port
diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp
index 04f802be..5f919a45 100644
--- a/muse/muse/midi.cpp
+++ b/muse/muse/midi.cpp
@@ -955,10 +955,11 @@ void Audio::processMidi()
}
}
- // Is it a Jack midi device?
- MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
- if(mjd)
- mjd->collectMidiEvents();
+ // Is it a Jack midi device?
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
+ //if(mjd)
+ // mjd->collectMidiEvents();
+ md->collectMidiEvents();
// Take snapshots of the current sizes of the recording fifos,
// because they may change while here in process, asynchronously.
@@ -1004,220 +1005,314 @@ void Audio::processMidi()
if (track->recordFlag())
{
//int portMask = track->inPortMask();
- unsigned int portMask = track->inPortMask();
- int channelMask = track->inChannelMask();
+ // p3.3.38 Removed
+ //unsigned int portMask = track->inPortMask();
+ //int channelMask = track->inChannelMask();
+
MPEventList* rl = track->mpevents();
MidiPort* tport = &midiPorts[port];
- for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
+ // p3.3.38
+ //for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
+ //{
+ RouteList* irl = track->inRoutes();
+ for(ciRoute r = irl->begin(); r != irl->end(); ++r)
{
- MidiDevice* dev = *id;
-
+ //if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE))
+ if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE))
+ continue;
+
+ //MidiDevice* dev = *id;
+ MidiDevice* dev = r->device;
+ int channel = r->channel;
+
+ // NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **.
+ // This would mean having a separate 'System' channel listed in the routing popups.
+ // The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it,
+ // this does not require a 'System' channel listed in the routing popups.
+ // But that requires more code below... Not added yet...
+ if(channel == -1)
+ //channel = MIDI_CHANNELS; // Special channel '17'
+ continue;
+
int devport = dev->midiPort();
// record only from ports marked in portMask:
- if (devport == -1 || !(portMask & (1 << devport)))
+ //if (devport == -1 || !(portMask & (1 << devport)))
+ if (devport == -1)
continue;
//MREventList* el = dev->recordEvents();
- MidiFifo& rf = dev->recordEvents();
+ //MidiFifo& rf = dev->recordEvents();
+
+
+ if(!dev->sysexFIFOProcessed())
+ {
+ // Set to the sysex fifo at first.
+ MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
+ // Get the frozen snapshot of the size.
+ int count = dev->tmpRecordCount(MIDI_CHANNELS);
+
+ for(int i = 0; i < count; ++i)
+ {
+ MidiPlayEvent event(rf.peek(i));
+
+ //unsigned time = event.time() + segmentSize*(segmentCount-1);
+ //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
+ //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
+ //event.setTime(time);
+ //if(!extsync)
+ // event.setTime(event.time() + segmentSize*(segmentCount-1));
+
+ event.setPort(port);
+
+ // dont't echo controller changes back to software
+ // synthesizer:
+ if(!dev->isSynti() && md && track->recEcho())
+ playEvents->add(event);
+
+ // If syncing externally the event time is already in units of ticks, set above.
+ if(!extsync)
+ {
+ //time = tempomap.frame2tick(event.time());
+ //event.setTime(time); // set tick time
+ event.setTime(tempomap.frame2tick(event.time())); // set tick time
+ }
+
+ if(recording)
+ rl->add(event);
+ }
+
+ dev->setSysexFIFOProcessed(true);
+ }
+
+ // Set to the sysex fifo at first.
+ ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
// Get the frozen snapshot of the size.
- int count = dev->tmpRecordCount();
+ ///int count = dev->tmpRecordCount(MIDI_CHANNELS);
- //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
- for(int i = 0; i < count; ++i)
+ // Iterate once for sysex fifo (if needed), once for channel fifos.
+ ///for(int sei = 0; sei < 2; ++sei)
{
- MidiPlayEvent event(rf.peek(i));
-
- //int channel = ie->channel();
- int channel = event.channel();
- int defaultPort = devport;
- if (!(channelMask & (1 << channel)))
- {
- continue;
- }
-
- //MidiPlayEvent event(*ie);
- int drumRecPitch=0; //prevent compiler warning: variable used without initialization
- MidiController *mc = 0;
- int ctl = 0;
-
- //Hmmm, hehhh...
- // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
- // But not before 0.7 (ml)
-
- int prePitch = 0, preVelo = 0;
-
- event.setChannel(track->outChannel());
-
- if (event.isNote() || event.isNoteOff())
- {
- //
- // apply track values
- //
-
- //Apply drum inkey:
- if (track->type() == Track::DRUM)
- {
- int pitch = event.dataA();
- //Map note that is played according to drumInmap
- drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote;
- devport = drumMap[(unsigned int)drumInmap[pitch]].port;
- event.setPort(devport);
- channel = drumMap[(unsigned int)drumInmap[pitch]].channel;
- event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote);
- event.setChannel(channel);
- }
- else
- { //Track transpose if non-drum
- prePitch = event.dataA();
- int pitch = prePitch + track->transposition;
- if (pitch > 127)
- pitch = 127;
- if (pitch < 0)
- pitch = 0;
- event.setA(pitch);
- }
-
- if (!event.isNoteOff())
- {
- preVelo = event.dataB();
- int velo = preVelo + track->velocity;
- velo = (velo * track->compression) / 100;
- if (velo > 127)
- velo = 127;
- if (velo < 1)
- velo = 1;
- event.setB(velo);
- }
- }
- // Added by T356.
- else
- if(event.type() == ME_CONTROLLER)
- {
- if(track->type() == Track::DRUM)
+ // If on first pass, do sysex fifo.
+ /*
+ if(sei == 0)
+ {
+ // Ignore any further channel routes on this device if already done here.
+ if(dev->sysexFIFOProcessed())
+ continue;
+ // Go ahead and set this now.
+ dev->setSysexFIFOProcessed(true);
+ // Allow it to fall through with the sysex fifo and count...
+ }
+ else
+ {
+ // We're on the second pass, do channel fifos.
+ rf = dev->recordEvents(channel);
+ // Get the frozen snapshot of the size.
+ count = dev->tmpRecordCount(channel);
+ }
+ */
+
+ MidiFifo& rf = dev->recordEvents(channel);
+ int count = dev->tmpRecordCount(channel);
+
+ //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
+ for(int i = 0; i < count; ++i)
+ {
+ MidiPlayEvent event(rf.peek(i));
+
+ //int channel = ie->channel();
+ ///int channel = event.channel();
+
+ int defaultPort = devport;
+ ///if (!(channelMask & (1 << channel)))
+ ///{
+ /// continue;
+ ///}
+
+ //MidiPlayEvent event(*ie);
+ int drumRecPitch=0; //prevent compiler warning: variable used without initialization
+ MidiController *mc = 0;
+ int ctl = 0;
+
+ //Hmmm, hehhh...
+ // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
+ // But not before 0.7 (ml)
+
+ int prePitch = 0, preVelo = 0;
+
+ event.setChannel(track->outChannel());
+
+ if (event.isNote() || event.isNoteOff())
{
- ctl = event.dataA();
- // Regardless of what port the event came from, is it a drum controller event
- // according to the track port's instrument?
- mc = tport->drumController(ctl);
- if(mc)
- {
- int pitch = ctl & 0x7f;
- ctl &= ~0xff;
- int dmindex = drumInmap[pitch] & 0x7f;
- //Map note that is played according to drumInmap
- drumRecPitch = drumMap[dmindex].enote;
- devport = drumMap[dmindex].port;
- event.setPort(devport);
- channel = drumMap[dmindex].channel;
- event.setA(ctl | drumMap[dmindex].anote);
- event.setChannel(channel);
- }
- }
- }
-
- // p3.3.25
- // MusE uses a fixed clocks per quarternote of 24.
- // At standard 384 ticks per quarternote for example,
- // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks').
- // That is what we'll use if syncing externally.
- //unsigned time = event.time() + segmentSize*(segmentCount-1);
- //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
- // p3.3.34
- // Oops, use the current tick.
- //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
- //event.setTime(time);
- // p3.3.35
- // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent().
- // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
- // p3.3.36
- //if(!extsync)
- // event.setTime(event.time() + segmentSize*(segmentCount-1));
-
- // dont't echo controller changes back to software
- // synthesizer:
-
- if (!dev->isSynti())
- {
- //Check if we're outputting to another port than default:
- if (devport == defaultPort) {
- event.setPort(port);
- if(md && track->recEcho())
- playEvents->add(event);
+ //
+ // apply track values
+ //
+
+ //Apply drum inkey:
+ if (track->type() == Track::DRUM)
+ {
+ int pitch = event.dataA();
+ //Map note that is played according to drumInmap
+ drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote;
+ devport = drumMap[(unsigned int)drumInmap[pitch]].port;
+ event.setPort(devport);
+ channel = drumMap[(unsigned int)drumInmap[pitch]].channel;
+ event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote);
+ event.setChannel(channel);
}
- else {
- // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
- MidiDevice* mdAlt = midiPorts[devport].device();
- if(mdAlt && track->recEcho())
- mdAlt->playEvents()->add(event);
+ else
+ { //Track transpose if non-drum
+ prePitch = event.dataA();
+ int pitch = prePitch + track->transposition;
+ if (pitch > 127)
+ pitch = 127;
+ if (pitch < 0)
+ pitch = 0;
+ event.setA(pitch);
}
- // Shall we activate meters even while rec echo is off? Sure, why not...
- if(event.isNote() && event.dataB() > track->activity())
- track->setActivity(event.dataB());
- }
-
- // p3.3.25
- // If syncing externally the event time is already in units of ticks, set above.
- if(!extsync)
- {
- // p3.3.35
- //time = tempomap.frame2tick(event.time());
- //event.setTime(time); // set tick time
- event.setTime(tempomap.frame2tick(event.time())); // set tick time
- }
-
- // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
- if (recording)
- {
- // In these next steps, it is essential to set the recorded event's port
- // to the track port so buildMidiEventList will accept it. Even though
- // the port may have no device "<none>".
- //
- if (track->type() == Track::DRUM)
+
+ if (!event.isNoteOff())
+ {
+ preVelo = event.dataB();
+ int velo = preVelo + track->velocity;
+ velo = (velo * track->compression) / 100;
+ if (velo > 127)
+ velo = 127;
+ if (velo < 1)
+ velo = 1;
+ event.setB(velo);
+ }
+ }
+ // Added by T356.
+ else
+ if(event.type() == ME_CONTROLLER)
+ {
+ if(track->type() == Track::DRUM)
+ {
+ ctl = event.dataA();
+ // Regardless of what port the event came from, is it a drum controller event
+ // according to the track port's instrument?
+ mc = tport->drumController(ctl);
+ if(mc)
{
- // Is it a drum controller event?
- if(mc)
- {
- MidiPlayEvent drumRecEvent = event;
- drumRecEvent.setA(ctl | drumRecPitch);
- // In this case, preVelo is simply the controller value.
- drumRecEvent.setB(preVelo);
- drumRecEvent.setPort(port); //rec-event to current port
- drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
- rl->add(drumRecEvent);
+ int pitch = ctl & 0x7f;
+ ctl &= ~0xff;
+ int dmindex = drumInmap[pitch] & 0x7f;
+ //Map note that is played according to drumInmap
+ drumRecPitch = drumMap[dmindex].enote;
+ devport = drumMap[dmindex].port;
+ event.setPort(devport);
+ channel = drumMap[dmindex].channel;
+ event.setA(ctl | drumMap[dmindex].anote);
+ event.setChannel(channel);
+ }
+ }
+ }
+
+ // p3.3.25
+ // MusE uses a fixed clocks per quarternote of 24.
+ // At standard 384 ticks per quarternote for example,
+ // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks').
+ // That is what we'll use if syncing externally.
+ //unsigned time = event.time() + segmentSize*(segmentCount-1);
+ //unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));
+ // p3.3.34
+ // Oops, use the current tick.
+ //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
+ //event.setTime(time);
+ // p3.3.35
+ // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent().
+ // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
+ // p3.3.36
+ //if(!extsync)
+ // event.setTime(event.time() + segmentSize*(segmentCount-1));
+
+ // dont't echo controller changes back to software
+ // synthesizer:
+
+ if (!dev->isSynti())
+ {
+ //Check if we're outputting to another port than default:
+ if (devport == defaultPort) {
+ event.setPort(port);
+ if(md && track->recEcho())
+ playEvents->add(event);
+ }
+ else {
+ // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
+ MidiDevice* mdAlt = midiPorts[devport].device();
+ if(mdAlt && track->recEcho())
+ mdAlt->playEvents()->add(event);
+ }
+ // Shall we activate meters even while rec echo is off? Sure, why not...
+ if(event.isNote() && event.dataB() > track->activity())
+ track->setActivity(event.dataB());
+ }
+
+ // p3.3.25
+ // If syncing externally the event time is already in units of ticks, set above.
+ if(!extsync)
+ {
+ // p3.3.35
+ //time = tempomap.frame2tick(event.time());
+ //event.setTime(time); // set tick time
+ event.setTime(tempomap.frame2tick(event.time())); // set tick time
+ }
+
+ // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
+ if (recording)
+ {
+ // In these next steps, it is essential to set the recorded event's port
+ // to the track port so buildMidiEventList will accept it. Even though
+ // the port may have no device "<none>".
+ //
+ if (track->type() == Track::DRUM)
+ {
+ // Is it a drum controller event?
+ if(mc)
+ {
+ MidiPlayEvent drumRecEvent = event;
+ drumRecEvent.setA(ctl | drumRecPitch);
+ // In this case, preVelo is simply the controller value.
+ drumRecEvent.setB(preVelo);
+ drumRecEvent.setPort(port); //rec-event to current port
+ drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
+ rl->add(drumRecEvent);
+ }
+ else
+ {
+
+ MidiPlayEvent drumRecEvent = event;
+ drumRecEvent.setA(drumRecPitch);
+ drumRecEvent.setB(preVelo);
+ // Changed by T356.
+ // Tested: Events were not being recorded for a drum map entry pointing to a
+ // different port. This must have been wrong - buildMidiEventList would ignore this.
+ //drumRecEvent.setPort(devport);
+ drumRecEvent.setPort(port); //rec-event to current port
+
+ drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
+ rl->add(drumRecEvent);
+ }
}
- else
+ else
{
-
- MidiPlayEvent drumRecEvent = event;
- drumRecEvent.setA(drumRecPitch);
- drumRecEvent.setB(preVelo);
- // Changed by T356.
- // Tested: Events were not being recorded for a drum map entry pointing to a
- // different port. This must have been wrong - buildMidiEventList would ignore this.
- //drumRecEvent.setPort(devport);
- drumRecEvent.setPort(port); //rec-event to current port
-
- drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
- rl->add(drumRecEvent);
- }
- }
- else
- {
- // Restore record-pitch to non-transposed value since we don't want the note transposed twice next
- MidiPlayEvent recEvent = event;
- if (prePitch)
- recEvent.setA(prePitch);
- if (preVelo)
- recEvent.setB(preVelo);
- recEvent.setPort(port);
- recEvent.setChannel(track->outChannel());
-
- rl->add(recEvent);
- }
- }
- }
+ // Restore record-pitch to non-transposed value since we don't want the note transposed twice next
+ MidiPlayEvent recEvent = event;
+ if (prePitch)
+ recEvent.setA(prePitch);
+ if (preVelo)
+ recEvent.setB(preVelo);
+ recEvent.setPort(port);
+ recEvent.setChannel(track->outChannel());
+
+ rl->add(recEvent);
+ }
+ }
+ }
+ }
}
}
// Added by Tim. p3.3.8
@@ -1382,13 +1477,13 @@ void Audio::processMidi()
//
for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
{
- MidiDevice* md = *id;
+ //MidiDevice* md = *id;
// Is it a Jack midi device?
- MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
- if(!mjd)
- continue;
-
- mjd->processMidi();
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
+ //if(!mjd)
+ // continue;
+ //mjd->processMidi();
+ (*id)->processMidi();
/*
int port = md->midiPort();
diff --git a/muse/muse/mididev.cpp b/muse/muse/mididev.cpp
index 28acd541..7f52fc2e 100644
--- a/muse/muse/mididev.cpp
+++ b/muse/muse/mididev.cpp
@@ -83,7 +83,14 @@ void MidiDevice::init()
MidiDevice::MidiDevice()
{
///_recBufFlipped = false;
- _tmpRecordCount = 0;
+ //_tmpRecordCount = 0;
+ for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i)
+ _tmpRecordCount[i] = 0;
+
+ _sysexFIFOProcessed = false;
+ //_sysexWritingChunks = false;
+ _sysexReadingChunks = false;
+
init();
}
@@ -91,7 +98,14 @@ MidiDevice::MidiDevice(const QString& n)
: _name(n)
{
///_recBufFlipped = false;
- _tmpRecordCount = 0;
+ //_tmpRecordCount = 0;
+ for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i)
+ _tmpRecordCount[i] = 0;
+
+ _sysexFIFOProcessed = false;
+ //_sysexWritingChunks = false;
+ _sysexReadingChunks = false;
+
init();
}
@@ -151,10 +165,16 @@ bool filterEvent(const MEvent& event, int type, bool thru)
//---------------------------------------------------------
void MidiDevice::afterProcess()
- {
- while (_tmpRecordCount--)
- _recordFifo.remove();
- }
+{
+ //while (_tmpRecordCount--)
+ // _recordFifo.remove();
+
+ for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i)
+ {
+ while (_tmpRecordCount[i]--)
+ _recordFifo[i].remove();
+ }
+}
//---------------------------------------------------------
// beforeProcess
@@ -162,11 +182,17 @@ void MidiDevice::afterProcess()
//---------------------------------------------------------
void MidiDevice::beforeProcess()
- {
- //if (!jackPort(0).isZero())
- // audioDriver->collectMidiEvents(this, jackPort(0));
- _tmpRecordCount = _recordFifo.getSize();
- }
+{
+ //if (!jackPort(0).isZero())
+ // audioDriver->collectMidiEvents(this, jackPort(0));
+
+ //_tmpRecordCount = _recordFifo.getSize();
+ for(unsigned int i = 0; i < MIDI_CHANNELS + 1; ++i)
+ _tmpRecordCount[i] = _recordFifo[i].getSize();
+
+ // Reset this.
+ _sysexFIFOProcessed = false;
+}
/*
//---------------------------------------------------------
@@ -230,13 +256,14 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
event.dump();
}
+ int typ = event.type();
+
if(_port != -1)
{
int idin = midiPorts[_port].syncInfo().idIn();
// p3.3.26 1/23/10 Section was disabled, enabled by Tim.
//#if 0
- int typ = event.type();
//---------------------------------------------------
// filter some SYSEX events
@@ -296,7 +323,7 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
// transfer noteOn events to gui for step recording and keyboard
// remote control
//
- if (event.type() == ME_NOTEON) {
+ if (typ == ME_NOTEON) {
int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
song->putEvent(pv);
}
@@ -305,18 +332,30 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
/// _recordEvents2.add(event); // add event to secondary list of recorded events
///else
/// _recordEvents.add(event); // add event to primary list of recorded events
- if(_recordFifo.put(MidiPlayEvent(event)))
- printf("MidiDevice::recordEvent: fifo overflow\n");
+
+ //if(_recordFifo.put(MidiPlayEvent(event)))
+ // printf("MidiDevice::recordEvent: fifo overflow\n");
+
+ // p3.3.38
+ // Do not bother recording if it is NOT actually being used by a port.
+ // Because from this point on, process handles things, by selected port.
+ if(_port == -1)
+ return;
+
+ // Split the events up into channel fifos. Special 'channel' number 17 for sysex events.
+ unsigned int ch = (typ == ME_SYSEX)? MIDI_CHANNELS : event.channel();
+ if(_recordFifo[ch].put(MidiPlayEvent(event)))
+ printf("MidiDevice::recordEvent: fifo channel %d overflow\n", ch);
}
//---------------------------------------------------------
// find
//---------------------------------------------------------
-MidiDevice* MidiDeviceList::find(const QString& s)
+MidiDevice* MidiDeviceList::find(const QString& s, int typeHint)
{
for (iMidiDevice i = begin(); i != end(); ++i)
- if ((*i)->name() == s)
+ if( (typeHint == -1 || typeHint == (*i)->deviceType()) && ((*i)->name() == s) )
return *i;
return 0;
}
diff --git a/muse/muse/mididev.h b/muse/muse/mididev.h
index a0744923..36b33c27 100644
--- a/muse/muse/mididev.h
+++ b/muse/muse/mididev.h
@@ -14,6 +14,11 @@
#include "mpevent.h"
//#include "sync.h"
+#include "route.h"
+#include "globaldefs.h"
+
+//class RouteList;
+class Xml;
//---------------------------------------------------------
// MidiDevice
@@ -26,8 +31,10 @@ class MidiDevice {
///MREventList _recordEvents;
///MREventList _recordEvents2;
- // Used for multiple reads of fifo during process.
- int _tmpRecordCount;
+ // Used for multiple reads of fifos during process.
+ //int _tmpRecordCount;
+ int _tmpRecordCount[MIDI_CHANNELS + 1];
+ bool _sysexFIFOProcessed;
///bool _recBufFlipped;
// Holds sync settings and detection monitors.
@@ -40,22 +47,43 @@ class MidiDevice {
int _openFlags; // configured open flags
bool _readEnable; // set when opened/closed.
bool _writeEnable; //
+ //int _sysexWriteChunk;
+ //int _sysexReadChunk;
+ //bool _sysexWritingChunks;
+ bool _sysexReadingChunks;
+
// Recording fifo.
- MidiFifo _recordFifo;
+ //MidiFifo _recordFifo;
+ // Recording fifos. To speed up processing, one per channel plus one special system 'channel' for channel-less events like sysex.
+ MidiFifo _recordFifo[MIDI_CHANNELS + 1];
+
+ RouteList _inRoutes, _outRoutes;
+
void init();
virtual bool putMidiEvent(const MidiPlayEvent&) = 0;
public:
+ enum { ALSA_MIDI=0, JACK_MIDI=1, SYNTH_MIDI=2 };
+
MidiDevice();
MidiDevice(const QString& name);
virtual ~MidiDevice() {}
+ virtual int deviceType() = 0;
+
+ virtual void* clientPort() { return 0; }
virtual QString open() = 0;
virtual void close() = 0;
+ virtual void writeRouting(int, Xml&) const { };
+ RouteList* inRoutes() { return &_inRoutes; }
+ RouteList* outRoutes() { return &_outRoutes; }
+ bool noInRoute() const { return _inRoutes.empty(); }
+ bool noOutRoute() const { return _outRoutes.empty(); }
+
const QString& name() const { return _name; }
void setName(const QString& s) { _name = s; }
-
+
int midiPort() const { return _port; }
void setPort(int p) { _port = p; }
@@ -76,6 +104,10 @@ class MidiDevice {
virtual void recordEvent(MidiRecordEvent&);
virtual bool putEvent(const MidiPlayEvent&);
+
+ // For Jack-based devices - called in Jack audio process callback
+ virtual void collectMidiEvents() {}
+ virtual void processMidi() {}
MPEventList* stuckNotes() { return &_stuckNotes; }
MPEventList* playEvents() { return &_playEvents; }
@@ -85,8 +117,16 @@ class MidiDevice {
///bool recBufFlipped() { return _recBufFlipped; }
void beforeProcess();
void afterProcess();
- int tmpRecordCount() { return _tmpRecordCount; }
- MidiFifo& recordEvents() { return _recordFifo; }
+ //int tmpRecordCount() { return _tmpRecordCount; }
+ int tmpRecordCount(const unsigned int ch) { return _tmpRecordCount[ch]; }
+ //MidiFifo& recordEvents() { return _recordFifo; }
+ MidiFifo& recordEvents(const unsigned int ch) { return _recordFifo[ch]; }
+ bool sysexFIFOProcessed() { return _sysexFIFOProcessed; }
+ void setSysexFIFOProcessed(bool v) { _sysexFIFOProcessed = v; }
+ //bool sysexWritingChunks() { return _sysexWritingChunks; }
+ //void setSysexWritingChunks(bool v) { _sysexWritingChunks = v; }
+ bool sysexReadingChunks() { return _sysexReadingChunks; }
+ void setSysexReadingChunks(bool v) { _sysexReadingChunks = v; }
//virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MPEventList* /*dst*/);
iMPEvent nextPlayEvent() { return _nextPlayEvent; }
@@ -100,13 +140,14 @@ class MidiDevice {
typedef std::list<MidiDevice*>::iterator iMidiDevice;
-class MidiDeviceList : public std::list<MidiDevice*> {
+class MidiDeviceList : public std::list<MidiDevice*>
+{
public:
void add(MidiDevice* dev);
void remove(MidiDevice* dev);
- MidiDevice* find(const QString& name);
+ MidiDevice* find(const QString& name, int typeHint = -1);
iMidiDevice find(const MidiDevice* dev);
- };
+};
extern MidiDeviceList midiDevices;
extern void initMidiDevices();
diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp
index bd079c5a..e5692a6a 100644
--- a/muse/muse/midiseq.cpp
+++ b/muse/muse/midiseq.cpp
@@ -685,10 +685,11 @@ void MidiSeq::processTimerTick()
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
MidiDevice* md = *id;
// Is it a Jack midi device? p3.3.36
- MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
- if(mjd)
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
+ //if(mjd)
+ if(md->deviceType() == MidiDevice::JACK_MIDI)
continue;
- if (md->isSynti()) // syntis are handled by audio thread
+ if(md->isSynti()) // syntis are handled by audio thread
continue;
int port = md->midiPort();
MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
diff --git a/muse/muse/mixer/astrip.cpp b/muse/muse/mixer/astrip.cpp
index 6a31bc82..da06ad63 100644
--- a/muse/muse/mixer/astrip.cpp
+++ b/muse/muse/mixer/astrip.cpp
@@ -21,6 +21,7 @@
#include <qcursor.h>
#include <qmenudata.h>
#include <qpainter.h>
+#include <qstring.h>
#include "globals.h"
#include "audio.h"
@@ -122,9 +123,6 @@ void AudioStrip::heartBeat()
void AudioStrip::configChanged()
{
- // Added by Tim. p3.3.6
- //printf("AudioStrip::configChanged\n");
-
songChanged(SC_CONFIG);
}
@@ -962,137 +960,1399 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)
}
//---------------------------------------------------------
+// addMenuItem
+//---------------------------------------------------------
+
+static int addMenuItem(QButton* /*parent*/, AudioTrack* track, Track* route_track, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+{
+ // totalInChannels is only used by syntis.
+ //int channels = (!isOutput || route_track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)route_track)->totalOutChannels() : ((AudioTrack*)route_track)->totalInChannels();
+ //int channels = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels();
+ int toch = ((AudioTrack*)track)->totalOutChannels();
+ // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
+ if(track->channels() == 1)
+ toch = 1;
+
+ // totalInChannels is only used by syntis.
+ int chans = (isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels();
+
+ // Don't add the last stray mono route if the track is stereo.
+ //if(route_track->channels() > 1 && (channel+1 == chans))
+ // return id;
+
+ RouteList* rl = isOutput ? track->outRoutes() : track->inRoutes();
+
+ QString s(route_track->name());
+ //int trackchans = track->channels();
+ //QString ns;
+
+ //if(track->channels() > 1 && (channel+1 < channels))
+ //if(track->channels() > 1)
+ //if(route_track->type() == Track::AUDIO_SOFTSYNTH && channels > 2 && track->channels() > 1)
+ ///if(track->type() == Track::AUDIO_SOFTSYNTH && chans > 2 && route_track->channels() > 1)
+ /// s += QString(" < [%1,%2]").arg(channel+1).arg(channel+2);
+
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
+
+ int ach = channel;
+ int bch = -1;
+
+ Route r(route_track, isOutput ? ach : bch, channels);
+ //Route r(route_track, channel);
+
+ r.remoteChannel = isOutput ? bch : ach;
+
+ mm.insert( pRouteMenuMap(id, r) );
+
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if (ir->type == 0 && ir->track == track) {
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channels == channels)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track &&
+ // (channel != -1 && ir->channel == channel) && (channels != -1 && ir->channels == channels))
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel)
+ //printf("addMenuItem: ir->type:%d ir->track:%s track:%s ir->channel:%d channel:%d ir->channels:%d channels:%d\n",
+ // ir->type, ir->track->name().latin1(), track->name().latin1(), ir->channel, channel, ir->channels, channels);
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == channel && ir->remoteChannel == r.remoteChannel)
+ //if(*ir == r)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == channel && ir->channels == channels && ir->remoteChannel == r.remoteChannel)
+
+ if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->remoteChannel == r.remoteChannel)
+ {
+ int tcompch = r.channel;
+ if(tcompch == -1)
+ tcompch = 0;
+ int tcompchs = r.channels;
+ if(tcompchs == -1)
+ tcompchs = isOutput ? track->channels() : route_track->channels();
+
+ int compch = ir->channel;
+ if(compch == -1)
+ compch = 0;
+ int compchs = ir->channels;
+ if(compchs == -1)
+ compchs = isOutput ? track->channels() : ir->track->channels();
+
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == route_track && ir->channel == r.channel && ir->channels == r.channels && ir->remoteChannel == r.remoteChannel)
+ if(compch == tcompch && compchs == tcompchs)
+ {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ return ++id;
+}
+
+//---------------------------------------------------------
// addAuxPorts
//---------------------------------------------------------
-static void addAuxPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addAuxPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addAuxPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
AuxList* al = song->auxs();
for (iAudioAux i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
+ id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
}
+ return id;
}
//---------------------------------------------------------
// addInPorts
//---------------------------------------------------------
-static void addInPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addInPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addInPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
InputList* al = song->inputs();
for (iAudioInput i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
+ id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
}
+ return id;
}
//---------------------------------------------------------
// addOutPorts
//---------------------------------------------------------
-static void addOutPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addOutPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addOutPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
OutputList* al = song->outputs();
for (iAudioOutput i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
+ id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
}
+ return id;
}
//---------------------------------------------------------
// addGroupPorts
//---------------------------------------------------------
-static void addGroupPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addGroupPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addGroupPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
GroupList* al = song->groups();
for (iAudioGroup i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
+ id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
}
+ return id;
}
//---------------------------------------------------------
// addWavePorts
//---------------------------------------------------------
-static void addWavePorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addWavePorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addWavePorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
WaveTrackList* al = song->waves();
for (iWaveTrack i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
+ id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
}
+ return id;
}
//---------------------------------------------------------
// addSyntiPorts
//---------------------------------------------------------
-static void addSyntiPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+//static void addSyntiPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
+static int addSyntiPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+{
+ RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
+
+ SynthIList* al = song->syntis();
+ for (iSynthI i = al->begin(); i != al->end(); ++i)
+ {
+ Track* track = *i;
+ if (t == track)
+ continue;
+ //id = addMenuItem(parent, track, lb, r, id, mm, channel, channels);
+
+ /*
+ QString s(track->name());
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
+ for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
+ break;
+ }
+ }
+ ++id;
+ */
+
+ //SynthI* synti = (SynthI*)track;
+
+ int toch = ((AudioTrack*)track)->totalOutChannels();
+ // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
+ if(track->channels() == 1)
+ toch = 1;
+
+ //int chans = synti->totalOutChannels();
+ //int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels();
+ // totalInChannels is only used by syntis.
+ int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels();
+
+ //int schans = synti->channels();
+ //if(schans < chans)
+ // chans = schans;
+ int tchans = (channels != -1) ? channels: t->channels();
+ if(tchans == 2)
+ {
+ // Ignore odd numbered left-over mono channel.
+ //chans = chans & ~1;
+ //if(chans != 0)
+ chans -= 1;
+ }
+
+ if(chans > 0)
+ {
+ QPopupMenu* chpup = new QPopupMenu(parent);
+ chpup->setCheckable(true);
+ for(int ch = 0; ch < chans; ++ch)
+ {
+ char buffer[128];
+ if(tchans == 2)
+ snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2);
+ else
+ snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1);
+ chpup->insertItem(QString(buffer), id);
+
+ int ach = (channel == -1) ? ch : channel;
+ int bch = (channel == -1) ? -1 : ch;
+
+ Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans);
+ //Route rt(track, ch);
+ //rt.remoteChannel = -1;
+ rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach;
+
+ mm.insert( pRouteMenuMap(id, rt) );
+
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if (ir->type == 0 && ir->track == track) {
+ //if(ir->type == 0 && ir->track == track && ir->channels == channels)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&
+ // ir->channels == channels && ir->remoteChannel == r.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&
+ // ir->remoteChannel == rt.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&
+ // ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)
+
+ if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel)
+ {
+ int tcompch = rt.channel;
+ if(tcompch == -1)
+ tcompch = 0;
+ int tcompchs = rt.channels;
+ if(tcompchs == -1)
+ tcompchs = isOutput ? t->channels() : track->channels();
+
+ int compch = ir->channel;
+ if(compch == -1)
+ compch = 0;
+ int compchs = ir->channels;
+ if(compchs == -1)
+ compchs = isOutput ? t->channels() : ir->track->channels();
+
+ if(compch == tcompch && compchs == tcompchs)
+ {
+ chpup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ ++id;
+ }
+
+ lb->insertItem(track->name(), chpup);
+ }
+ }
+ return id;
+}
+
+//---------------------------------------------------------
+// addMultiChannelOutPorts
+//---------------------------------------------------------
+
+static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup, int id, RouteMenuMap& mm, bool isOutput)
+{
+ int toch = t->totalOutChannels();
+ // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
+ if(t->channels() == 1)
+ toch = 1;
+
+ // Number of allocated buffers is always MAX_CHANNELS or more, even if _totalOutChannels is less.
+ //int chans = t->totalOutChannels();
+ // totalInChannels is only used by syntis.
+ //int chans = isOutput ? t->totalOutChannels() : t->totalInChannels();
+ //int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? t->totalOutChannels() : t->totalInChannels();
+ int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? toch : t->totalInChannels();
+
+ // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
+ //if(t->channels() == 1)
+ // chans = 1;
+
+ if(chans > 1)
+ {
+ pup->insertItem(new MenuTitleItem("<Mono>"));
+ //pup->insertSeparator();
+ }
+
+ //
+ // If it's more than one channel, create a sub-menu. If it's just one channel, don't bother with a sub-menu...
+ //
+
+ QPopupMenu* chpup = pup;
+
+ for(int ch = 0; ch < chans; ++ch)
+ {
+ // If more than one channel, create the sub-menu.
+ if(chans > 1)
+ {
+ chpup = new QPopupMenu(parent);
+ chpup->setCheckable(true);
+ }
+
+ if(isOutput)
+ {
+ switch(t->type())
+ {
+
+ case Track::AUDIO_INPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_SOFTSYNTH:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ break;
+ case Track::AUDIO_AUX:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ break;
+ default:
+ break;
+
+ /*
+ case Track::AUDIO_INPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_SOFTSYNTH:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput);
+ break;
+ case Track::AUDIO_AUX:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, isOutput);
+ break;
+ default:
+ break;
+ */
+ }
+ }
+ else
+ {
+ switch(t->type())
+ {
+
+ case Track::AUDIO_OUTPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addAuxPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ break;
+ case Track::WAVE:
+ id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ case Track::AUDIO_GROUP:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ break;
+ default:
+ break;
+
+ /*
+ case Track::AUDIO_OUTPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addAuxPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput);
+ break;
+ case Track::WAVE:
+ id = addInPorts(parent, t, chpup, id, mm, ch, isOutput);
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ case Track::AUDIO_GROUP:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, isOutput);
+ break;
+ default:
+ break;
+ */
+ }
+ }
+
+ // If more than one channel, add the created sub-menu.
+ if(chans > 1)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", pup->tr("Channel").latin1(), ch+1);
+ pup->insertItem(QString(buffer), chpup);
+ }
+ }
+
+ // For stereo listing, ignore odd numbered left-over channels.
+ chans -= 1;
+ if(chans > 0)
+ {
+ // Ignore odd numbered left-over channels.
+ //int schans = (chans & ~1) - 1;
+
+ pup->insertSeparator();
+ pup->insertItem(new MenuTitleItem("<Stereo>"));
+ //pup->insertSeparator();
+
+ //
+ // If it's more than two channels, create a sub-menu. If it's just two channels, don't bother with a sub-menu...
+ //
+
+ //QPopupMenu* chpup = pup;
+ chpup = pup;
+ if(chans <= 2)
+ // Just do one iteration.
+ chans = 1;
+
+ //for(int ch = 0; ch < schans; ++ch)
+ for(int ch = 0; ch < chans; ++ch)
+ {
+ // If more than two channels, create the sub-menu.
+ if(chans > 2)
{
+ chpup = new QPopupMenu(parent);
+ chpup->setCheckable(true);
+ }
+
+ if(isOutput)
+ {
+ switch(t->type())
+ {
+ case Track::AUDIO_INPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_SOFTSYNTH:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ break;
+ case Track::AUDIO_AUX:
+ id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch(t->type())
+ {
+ case Track::AUDIO_OUTPUT:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addAuxPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ break;
+ case Track::WAVE:
+ id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ break;
+ case Track::AUDIO_SOFTSYNTH:
+ case Track::AUDIO_GROUP:
+ id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // If more than two channels, add the created sub-menu.
+ if(chans > 2)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d,%d", pup->tr("Channel").latin1(), ch+1, ch+2);
+ pup->insertItem(QString(buffer), chpup);
+ }
+ }
+ }
+
+ return id;
+}
+
+//---------------------------------------------------------
+// nonSyntiTrackAddSyntis
+//---------------------------------------------------------
+
+//static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, bool isOutput)
+{
+ RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
+
SynthIList* al = song->syntis();
- for (iSynthI i = al->begin(); i != al->end(); ++i) {
+ for (iSynthI i = al->begin(); i != al->end(); ++i)
+ {
Track* track = *i;
if (t == track)
continue;
+ //id = addMenuItem(parent, track, lb, r, id, mm, channel, channels);
+
+ /*
QString s(track->name());
- int it = lb->insertItem(s);
+ //int it = lb->insertItem(s);
+ lb->insertItem(s, id);
for (iRoute ir = r->begin(); ir != r->end(); ++ir) {
- if (ir->type == 0 && ir->track == track) {
- lb->setItemChecked(it, true);
+ //if (ir->type == 0 && ir->track == track) {
+ if (ir->type == 0 && ir->track == track && ir->channels == channels) {
+ //lb->setItemChecked(it, true);
+ lb->setItemChecked(id, true);
break;
}
}
+ ++id;
+ */
+
+ //SynthI* synti = (SynthI*)track;
+
+ int toch = ((AudioTrack*)track)->totalOutChannels();
+ // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
+ if(track->channels() == 1)
+ toch = 1;
+
+ //int chans = synti->totalOutChannels();
+ //int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)track)->totalOutChannels() : ((AudioTrack*)track)->totalInChannels();
+ // totalInChannels is only used by syntis.
+ int chans = (!isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels();
+
+ //int schans = synti->channels();
+ //if(schans < chans)
+ // chans = schans;
+// int tchans = (channels != -1) ? channels: t->channels();
+// if(tchans == 2)
+// {
+ // Ignore odd numbered left-over mono channel.
+ //chans = chans & ~1;
+ //if(chans != 0)
+// chans -= 1;
+// }
+ //int tchans = (channels != -1) ? channels: t->channels();
+
+ if(chans > 0)
+ {
+ QPopupMenu* chpup = new QPopupMenu(parent);
+ chpup->setCheckable(true);
+
+ if(chans > 1)
+ {
+ chpup->insertItem(new MenuTitleItem("<Mono>"));
+ //pup->insertSeparator();
+ }
+
+ for(int ch = 0; ch < chans; ++ch)
+ {
+ char buffer[128];
+ //if(tchans == 2)
+ // snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2);
+ //else
+ snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1);
+ chpup->insertItem(QString(buffer), id);
+
+ //int ach = (channel == -1) ? ch : channel;
+ //int bch = (channel == -1) ? -1 : ch;
+ int ach = ch;
+ int bch = -1;
+
+ //Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans);
+ Route rt(track, isOutput ? bch : ach, 1);
+ //Route rt(track, ch);
+
+ //rt.remoteChannel = -1;
+ //rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach;
+ rt.remoteChannel = isOutput ? ach : bch;
+
+ mm.insert( pRouteMenuMap(id, rt) );
+
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if (ir->type == 0 && ir->track == track) {
+ //if(ir->type == 0 && ir->track == track && ir->channels == channels)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&
+ // ir->channels == channels && ir->remoteChannel == r.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&
+ // ir->remoteChannel == rt.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&
+ // ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)
+
+ if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel)
+ {
+ int tcompch = rt.channel;
+ if(tcompch == -1)
+ tcompch = 0;
+ int tcompchs = rt.channels;
+ if(tcompchs == -1)
+ tcompchs = isOutput ? t->channels() : track->channels();
+
+ int compch = ir->channel;
+ if(compch == -1)
+ compch = 0;
+ int compchs = ir->channels;
+ if(compchs == -1)
+ compchs = isOutput ? t->channels() : ir->track->channels();
+
+ if(compch == tcompch && compchs == tcompchs)
+ {
+ chpup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ ++id;
+ }
+
+ chans -= 1;
+ if(chans > 0)
+ {
+ // Ignore odd numbered left-over channels.
+ //int schans = (chans & ~1) - 1;
+
+ chpup->insertSeparator();
+ chpup->insertItem(new MenuTitleItem("<Stereo>"));
+ //pup->insertSeparator();
+
+ for(int ch = 0; ch < chans; ++ch)
+ {
+ char buffer[128];
+ //if(tchans == 2)
+ snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").latin1(), ch+1, ch+2);
+ //else
+ // snprintf(buffer, 128, "%s %d", chpup->tr("Channel").latin1(), ch+1);
+ chpup->insertItem(QString(buffer), id);
+
+ //int ach = (channel == -1) ? ch : channel;
+ //int bch = (channel == -1) ? -1 : ch;
+ int ach = ch;
+ int bch = -1;
+
+ //Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans);
+ Route rt(track, isOutput ? bch : ach, 2);
+ //Route rt(track, ch);
+
+ //rt.remoteChannel = -1;
+ //rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach;
+ rt.remoteChannel = isOutput ? ach : bch;
+
+ mm.insert( pRouteMenuMap(id, rt) );
+
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if (ir->type == 0 && ir->track == track) {
+ //if(ir->type == 0 && ir->track == track && ir->channels == channels)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == channel &&
+ // ir->channels == channels && ir->remoteChannel == r.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == ch &&
+ // ir->remoteChannel == rt.remoteChannel)
+ //if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->channel == rt.channel &&
+ // ir->channels == rt.channels && ir->remoteChannel == rt.remoteChannel)
+
+
+ if(ir->type == Route::TRACK_ROUTE && ir->track == track && ir->remoteChannel == rt.remoteChannel)
+ {
+ int tcompch = rt.channel;
+ if(tcompch == -1)
+ tcompch = 0;
+ int tcompchs = rt.channels;
+ if(tcompchs == -1)
+ tcompchs = isOutput ? t->channels() : track->channels();
+
+ int compch = ir->channel;
+ if(compch == -1)
+ compch = 0;
+ int compchs = ir->channels;
+ if(compchs == -1)
+ compchs = isOutput ? t->channels() : ir->track->channels();
+
+ if(compch == tcompch && compchs == tcompchs)
+ {
+ chpup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ ++id;
+ }
+ }
+
+ lb->insertItem(track->name(), chpup);
+ }
+ }
+ return id;
+}
+
+//---------------------------------------------------------
+// iRoutePressed
+//---------------------------------------------------------
+
+void AudioStrip::iRoutePressed()
+ {
+ //if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH))
+ if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX))
+ return;
+
+ QPopupMenu* pup = new QPopupMenu(iR);
+ //pup->setCheckable(true);
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* irl = t->inRoutes();
+
+ int gid = 0;
+ RouteMenuMap mm;
+
+ switch(track->type())
+ {
+ case Track::AUDIO_INPUT:
+ {
+ pup->setCheckable(true);
+ //int gid = 0;
+ for(int i = 0; i < channel; ++i)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if(!checkAudioDevice())
+ {
+ delete pup;
+ return;
+ }
+ std::list<QString> ol = audioDevice->outputPorts();
+ for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+ {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
+ ++gid;
+ for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)
+ {
+ if(*ir == dst)
+ {
+ pup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ if(i+1 != channel)
+ pup->insertSeparator();
+ }
+ }
+ break;
+ /*
+ case Track::AUDIO_OUTPUT:
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ */
+
+ case Track::AUDIO_OUTPUT:
+ gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false);
+ gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
+ gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false);
+ gid = addAuxPorts( iR, t, pup, gid, mm, -1, -1, false);
+ //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false);
+ gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false);
+ break;
+ case Track::WAVE:
+ gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
+ break;
+ case Track::AUDIO_GROUP:
+ gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false);
+ gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
+ gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false);
+ //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false);
+ gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false);
+ break;
+
+ case Track::AUDIO_SOFTSYNTH:
+ gid = addMultiChannelPorts(iR, t, pup, gid, mm, false);
+ break;
+ default:
+ delete pup;
+ return;
+ }
+
+ if(pup->count() == 0)
+ {
+ delete pup;
+ return;
+ }
+
+ int n = pup->exec(QCursor::pos());
+ if(n != -1)
+ {
+ QString s(pup->text(n));
+
+ if(track->type() == Track::AUDIO_INPUT)
+ {
+ delete pup;
+ int chan = n & 0xf;
+
+ Route srcRoute(s, false, -1, Route::JACK_ROUTE);
+ Route dstRoute(t, chan);
+
+ srcRoute.channel = chan;
+
+ iRoute iir = irl->begin();
+ for(; iir != irl->end(); ++iir)
+ {
+ if(*iir == srcRoute)
+ break;
+ }
+ if(iir != irl->end())
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ else
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ iRouteMenuMap imm = mm.find(n);
+ if(imm == mm.end())
+ {
+ delete pup;
+ iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
+
+ //Route srcRoute(s, false, -1);
+ //Route srcRoute(s, false, -1, Route::TRACK_ROUTE);
+ Route &srcRoute = imm->second;
+
+ //Route dstRoute(t, -1);
+ //Route dstRoute(t, chan, chans);
+ Route dstRoute(t, imm->second.channel, imm->second.channels);
+ //Route dstRoute(t, imm->second.channel);
+ dstRoute.remoteChannel = imm->second.remoteChannel;
+
+ iRoute iir = irl->begin();
+ for (; iir != irl->end(); ++iir) {
+ if (*iir == srcRoute)
+ break;
+ }
+ if (iir != irl->end()) {
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ iR->setDown(false); // pup->exec() catches mouse release event
+ }
+
+//---------------------------------------------------------
+// oRoutePressed
+//---------------------------------------------------------
+
+void AudioStrip::oRoutePressed()
+{
+ if(track->isMidiTrack())
+ return;
+
+ QPopupMenu* pup = new QPopupMenu(oR);
+ //pup->setCheckable(true);
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* orl = t->outRoutes();
+
+ int gid = 0;
+ RouteMenuMap mm;
+
+ switch(track->type())
+ {
+ case Track::AUDIO_OUTPUT:
+ {
+ pup->setCheckable(true);
+ //int gid = 0;
+ for(int i = 0; i < channel; ++i)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if(!checkAudioDevice())
+ {
+ delete pup;
+ return;
+ }
+ std::list<QString> ol = audioDevice->inputPorts();
+ for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+ {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
+ ++gid;
+ for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)
+ {
+ if(*ir == dst)
+ {
+ pup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ if(i+1 != channel)
+ pup->insertSeparator();
+ }
+ }
+ break;
+ /*
+ case Track::AUDIO_INPUT:
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_AUX:
+ */
+
+ case Track::AUDIO_SOFTSYNTH:
+ //addOutPorts(t, pup, orl);
+ //addGroupPorts(t, pup, orl);
+ gid = addMultiChannelPorts(oR, t, pup, gid, mm, true);
+ break;
+
+ case Track::AUDIO_INPUT:
+ gid = addWavePorts( oR, t, pup, gid, mm, -1, -1, true);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ //case Track::AUDIO_SOFTSYNTH:
+ gid = addOutPorts( oR, t, pup, gid, mm, -1, -1, true);
+ gid = addGroupPorts( oR, t, pup, gid, mm, -1, -1, true);
+ //gid = addSyntiPorts( oR, t, pup, gid, mm, -1, -1, true);
+ gid = nonSyntiTrackAddSyntis(oR, t, pup, gid, mm, true);
+ break;
+ case Track::AUDIO_AUX:
+ gid = addOutPorts( oR, t, pup, gid, mm, -1, -1, true);
+ break;
+
+ default:
+ delete pup;
+ return;
+ }
+
+ if(pup->count() == 0)
+ {
+ delete pup;
+ return;
+ }
+
+ int n = pup->exec(QCursor::pos());
+ if (n != -1) {
+ QString s(pup->text(n));
+
+ if(track->type() == Track::AUDIO_OUTPUT)
+ {
+ delete pup;
+ int chan = n & 0xf;
+
+ //Route srcRoute(t, -1);
+ //Route srcRoute(t, chan, chans);
+ //Route srcRoute(t, chan, 1);
+ Route srcRoute(t, chan);
+
+ //Route dstRoute(s, true, -1);
+ Route dstRoute(s, true, -1, Route::JACK_ROUTE);
+ //Route dstRoute(s, true, 0, Route::JACK_ROUTE);
+
+ //srcRoute.channel = dstRoute.channel = chan;
+ dstRoute.channel = chan;
+ //dstRoute.channels = 1;
+
+ // check if route src->dst exists:
+ iRoute iorl = orl->begin();
+ for (; iorl != orl->end(); ++iorl) {
+ if (*iorl == dstRoute)
+ break;
+ }
+ if (iorl != orl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ oR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ iRouteMenuMap imm = mm.find(n);
+ if(imm == mm.end())
+ {
+ delete pup;
+ oR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
+
+ //Route srcRoute(t, -1);
+ //srcRoute.remoteChannel = chan;
+ //Route srcRoute(t, chan, chans);
+ Route srcRoute(t, imm->second.channel, imm->second.channels);
+ //Route srcRoute(t, imm->second.channel);
+ srcRoute.remoteChannel = imm->second.remoteChannel;
+
+ //Route dstRoute(s, true, -1);
+ //Route dstRoute(s, true, -1, Route::TRACK_ROUTE);
+ Route &dstRoute = imm->second;
+
+ // check if route src->dst exists:
+ iRoute iorl = orl->begin();
+ for (; iorl != orl->end(); ++iorl) {
+ if (*iorl == dstRoute)
+ break;
+ }
+ if (iorl != orl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ oR->setDown(false); // pup->exec() catches mouse release event
+}
+
+/*
+//---------------------------------------------------------
+// iRoutePressed
+//---------------------------------------------------------
+
+void AudioStrip::iRoutePressed()
+ {
+ if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH))
+ return;
+
+ QPopupMenu* pup = new QPopupMenu(iR);
+ //pup->setCheckable(true);
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* irl = t->inRoutes();
+
+ RouteMenuMap mm;
+
+ if(track->type() == Track::AUDIO_INPUT)
+ {
+ pup->setCheckable(true);
+ int gid = 0;
+ for(int i = 0; i < channel; ++i)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if(!checkAudioDevice())
+ {
+ delete pup;
+ return;
+ }
+ std::list<QString> ol = audioDevice->outputPorts();
+ for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+ {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
+ ++gid;
+ for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)
+ {
+ if(*ir == dst)
+ {
+ pup->setItemChecked(id, true);
+ break;
+ }
}
+ }
+ if(i+1 != channel)
+ pup->insertSeparator();
+ }
}
+ else
+ addMultiChannelOutPorts(iR, t, pup, irl, mm, false);
+
+ int n = pup->exec(QCursor::pos());
+ if (n != -1) {
+ QString s(pup->text(n));
+
+ //Route srcRoute(s, false, -1);
+ Route srcRoute(s, false, -1, (track->type() == Track::AUDIO_INPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);
+ Route dstRoute(t, -1);
+
+ if (track->type() == Track::AUDIO_INPUT)
+ srcRoute.channel = dstRoute.channel = n & 0xf;
+ iRoute iir = irl->begin();
+ for (; iir != irl->end(); ++iir) {
+ if (*iir == srcRoute)
+ break;
+ }
+ if (iir != irl->end()) {
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ iR->setDown(false); // pup->exec() catches mouse release event
+ }
+*/
+/*
+//---------------------------------------------------------
+// oRoutePressed
+//---------------------------------------------------------
+
+void AudioStrip::oRoutePressed()
+{
+ if(track->isMidiTrack())
+ return;
+
+ QPopupMenu* pup = new QPopupMenu(oR);
+ //pup->setCheckable(true);
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* orl = t->outRoutes();
+
+ RouteMenuMap mm;
+
+ if(track->type() == Track::AUDIO_OUTPUT)
+ {
+ pup->setCheckable(true);
+ int gid = 0;
+ for(int i = 0; i < channel; ++i)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if(!checkAudioDevice())
+ {
+ delete pup;
+ return;
+ }
+ std::list<QString> ol = audioDevice->inputPorts();
+ for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+ {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
+ ++gid;
+ for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)
+ {
+ if(*ir == dst)
+ {
+ pup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ if(i+1 != channel)
+ pup->insertSeparator();
+ }
+ }
+ else
+ addMultiChannelOutPorts(oR, t, pup, orl, mm, true);
+
+ int n = pup->exec(QCursor::pos());
+ if (n != -1) {
+ QString s(pup->text(n));
+
+ if(track->type() == Track::AUDIO_OUTPUT)
+ {
+ delete pup;
+ int chan = n & 0xf;
+
+ //Route srcRoute(t, -1);
+ //Route srcRoute(t, chan, chans);
+ Route srcRoute(t, chan, 1);
+
+ //Route dstRoute(s, true, -1);
+ Route dstRoute(s, true, -1, Route::JACK_ROUTE);
+ //Route dstRoute(s, true, 0, Route::JACK_ROUTE);
+
+ //srcRoute.channel = dstRoute.channel = chan;
+ dstRoute.channel = chan;
+ dstRoute.channels = 1;
+
+ // check if route src->dst exists:
+ iRoute iorl = orl->begin();
+ for (; iorl != orl->end(); ++iorl) {
+ if (*iorl == dstRoute)
+ break;
+ }
+ if (iorl != orl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ oR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ iRouteMenuMap imm = mm.find(n);
+ if(imm == mm.end())
+ {
+ delete pup;
+ oR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ int chan = imm->second.channel;
+ int chans = imm->second.channels;
+
+ //Route srcRoute(t, -1);
+ Route srcRoute(t, chan, chans);
+
+ //Route dstRoute(s, true, -1);
+ Route dstRoute(s, true, -1, Route::TRACK_ROUTE);
+
+ // check if route src->dst exists:
+ iRoute iorl = orl->begin();
+ for (; iorl != orl->end(); ++iorl) {
+ if (*iorl == dstRoute)
+ break;
+ }
+ if (iorl != orl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ oR->setDown(false); // pup->exec() catches mouse release event
+}
+*/
+
+/*
//---------------------------------------------------------
// iRoutePressed
//---------------------------------------------------------
@@ -1124,7 +2384,8 @@ void AudioStrip::iRoutePressed()
std::list<QString> ol = audioDevice->outputPorts();
for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {
int id = pup->insertItem(*ip, (gid * 16) + i);
- Route dst(*ip, true, i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
++gid;
for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) {
if (*ir == dst) {
@@ -1138,7 +2399,6 @@ void AudioStrip::iRoutePressed()
}
}
break;
- break;
case Track::AUDIO_OUTPUT:
addWavePorts(t, pup, irl);
addInPorts(t, pup, irl);
@@ -1159,7 +2419,9 @@ void AudioStrip::iRoutePressed()
int n = pup->exec(QCursor::pos());
if (n != -1) {
QString s(pup->text(n));
- Route srcRoute(s, false, -1);
+
+ //Route srcRoute(s, false, -1);
+ Route srcRoute(s, false, -1, (track->type() == Track::AUDIO_INPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);
Route dstRoute(t, -1);
if (track->type() == Track::AUDIO_INPUT)
@@ -1183,7 +2445,9 @@ void AudioStrip::iRoutePressed()
delete pup;
iR->setDown(false); // pup->exec() catches mouse release event
}
+*/
+/*
//---------------------------------------------------------
// oRoutePressed
//---------------------------------------------------------
@@ -1213,7 +2477,8 @@ void AudioStrip::oRoutePressed()
std::list<QString> ol = audioDevice->inputPorts();
for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {
int id = pup->insertItem(*ip, (gid * 16) + i);
- Route dst(*ip, true, i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
++gid;
for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) {
if (*ir == dst) {
@@ -1243,7 +2508,8 @@ void AudioStrip::oRoutePressed()
if (n != -1) {
QString s(pup->text(n));
Route srcRoute(t, -1);
- Route dstRoute(s, true, -1);
+ //Route dstRoute(s, true, -1);
+ Route dstRoute(s, true, -1, (track->type() == Track::AUDIO_OUTPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);
if (track->type() == Track::AUDIO_OUTPUT)
srcRoute.channel = dstRoute.channel = n & 0xf;
@@ -1268,4 +2534,4 @@ void AudioStrip::oRoutePressed()
delete pup;
oR->setDown(false); // pup->exec() catches mouse release event
}
-
+*/
diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp
index cd9cea86..a2cd26dd 100644
--- a/muse/muse/mixer/mstrip.cpp
+++ b/muse/muse/mixer/mstrip.cpp
@@ -17,11 +17,14 @@
#include <qcombobox.h>
#include <qtooltip.h>
#include <qtimer.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
#include <math.h>
#include "midi.h"
#include "midictrl.h"
#include "mstrip.h"
+#include "midiport.h"
#include "globals.h"
#include "audio.h"
#include "song.h"
@@ -343,7 +346,7 @@ MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t)
dev_ch_label->setFont(config.fonts[1]);
// Dealing with a horizontally constrained label. Ignore vertical. Use a minimum readable point size.
//autoAdjustFontSize(dev_ch_label, dev_ch_label->text(), false, true, config.fonts[6].pointSize(), 5);
- QToolTip::add(dev_ch_label, tr("output: device - channel"));
+ QToolTip::add(dev_ch_label, tr("output port and channel"));
smBox1->addWidget(dev_ch_label);
smBox1->addWidget(record);
@@ -351,15 +354,36 @@ MidiStrip::MidiStrip(QWidget* parent, MidiTrack* t)
layout->addLayout(smBox2);
//---------------------------------------------------
- // output routing
+ // routing
//---------------------------------------------------
- route = new QToolButton(this);
- route->setFont(config.fonts[1]);
- route->setFixedWidth(STRIP_WIDTH);
- route->setText(tr("Route"));
- QToolTip::add(route, tr("set routing"));
- layout->addWidget(route);
+ // p3.3.38
+ //route = new QToolButton(this);
+ //route->setFont(config.fonts[1]);
+ //route->setFixedWidth(STRIP_WIDTH);
+ //route->setText(tr("Route"));
+ //QToolTip::add(route, tr("set routing"));
+ //layout->addWidget(route);
+ QHBoxLayout* rBox = new QHBoxLayout(0);
+ iR = new QToolButton(this);
+ iR->setFont(config.fonts[1]);
+ iR->setFixedWidth((STRIP_WIDTH-4)/2);
+ iR->setText(tr("iR"));
+ iR->setToggleButton(false);
+ QToolTip::add(iR, tr("input routing"));
+ rBox->addWidget(iR);
+ connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed()));
+ oR = new QToolButton(this);
+ oR->setFont(config.fonts[1]);
+ oR->setFixedWidth((STRIP_WIDTH-4)/2);
+ oR->setText(tr("oR"));
+ oR->setToggleButton(false);
+ // TODO: Works OK, but disabled for now, until we figure out what to do about multiple out routes and display values...
+ oR->setEnabled(false);
+ QToolTip::add(oR, tr("output routing"));
+ rBox->addWidget(oR);
+ connect(oR, SIGNAL(pressed()), SLOT(oRoutePressed()));
+ layout->addLayout(rBox);
//---------------------------------------------------
// automation mode
@@ -518,6 +542,7 @@ void MidiStrip::labelDoubleClicked(int idx)
}
+/*
//---------------------------------------------------------
// routeClicked
//---------------------------------------------------------
@@ -525,6 +550,7 @@ void MidiStrip::labelDoubleClicked(int idx)
void MidiStrip::routeClicked()
{
}
+*/
//---------------------------------------------------------
// heartBeat
@@ -929,3 +955,224 @@ void MidiStrip::updateOffState() // Ripped from AudioStrip, hehh(mg)
if (mute)
mute->setEnabled(val);
}
+
+//---------------------------------------------------------
+// iRoutePressed
+//---------------------------------------------------------
+
+void MidiStrip::iRoutePressed()
+{
+ if(!track->isMidiTrack())
+ return;
+
+ song->chooseMidiRoutes(iR, (MidiTrack*)track, false);
+
+ /*
+ RouteList* irl = track->inRoutes();
+ //Route dst(track, -1);
+
+ QPopupMenu* pup = new QPopupMenu(iR);
+ pup->setCheckable(true);
+
+ int gid = 0;
+
+ //MidiInPortList* tl = song->midiInPorts();
+ //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ //MidiInPort* track = *i;
+ // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports.
+ MidiPort* mp = &midiPorts[i];
+ MidiDevice* md = mp->device();
+ if(!md)
+ continue;
+
+ if(!(md->rwFlags() & 2))
+ continue;
+
+ //printf("MidiStrip::iRoutePressed adding submenu portnum:%d\n", i);
+
+ //QMenu* m = menu->addMenu(track->name());
+ QPopupMenu* subp = new QPopupMenu(iR);
+
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ //QAction* a = m->addAction(QString("Channel %1").arg(ch+1));
+ //subp->insertItem(QT_TR_NOOP(QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch);
+ gid = i * MIDI_CHANNELS + ch;
+
+ //printf("MidiStrip::iRoutePressed inserting gid:%d\n", gid);
+
+ subp->insertItem(QString("Channel %1").arg(ch+1), gid);
+ //a->setCheckable(true);
+ //Route src(track, ch, RouteNode::TRACK);
+ //Route src(md, ch);
+ //Route r = Route(src, dst);
+ //a->setData(QVariant::fromValue(r));
+ //a->setChecked(rl->indexOf(r) != -1);
+ Route srcRoute(md, ch);
+ for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)
+ {
+ //if(*ir == dst)
+ if(*ir == srcRoute)
+ {
+ subp->setItemChecked(gid, true);
+ break;
+ }
+ }
+ }
+ pup->insertItem(QT_TR_NOOP(md->name()), subp);
+ }
+
+ int n = pup->exec(QCursor::pos());
+ delete pup;
+ if (n != -1)
+ {
+ int mdidx = n / MIDI_CHANNELS;
+ int ch = n % MIDI_CHANNELS;
+
+ //if(debugMsg)
+ printf("MidiStrip::iRoutePressed mdidx:%d ch:%d\n", mdidx, ch);
+
+ MidiPort* mp = &midiPorts[mdidx];
+ MidiDevice* md = mp->device();
+ if(!md)
+ return;
+
+ if(!(md->rwFlags() & 2))
+ return;
+
+
+ //QString s(pup->text(n));
+ //QT_TR_NOOP(md->name())
+
+ //Route srcRoute(s, false, -1);
+ Route srcRoute(md, ch);
+ //Route srcRoute(md, -1);
+ //Route dstRoute(track, -1);
+ Route dstRoute(track, ch);
+
+ //if (track->type() == Track::AUDIO_INPUT)
+ // srcRoute.channel = dstRoute.channel = n & 0xf;
+ iRoute iir = irl->begin();
+ for (; iir != irl->end(); ++iir) {
+ if (*iir == srcRoute)
+ break;
+ }
+ if (iir != irl->end()) {
+ // disconnect
+ printf("MidiStrip::iRoutePressed removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect
+ printf("MidiStrip::iRoutePressed adding route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ printf("MidiStrip::iRoutePressed calling msgUpdateSoloStates\n");
+ audio->msgUpdateSoloStates();
+ printf("MidiStrip::iRoutePressed calling song->update\n");
+ song->update(SC_ROUTE);
+ }
+ //delete pup;
+ iR->setDown(false); // pup->exec() catches mouse release event
+ printf("MidiStrip::iRoutePressed end\n");
+ */
+
+}
+
+//---------------------------------------------------------
+// oRoutePressed
+//---------------------------------------------------------
+
+void MidiStrip::oRoutePressed()
+ {
+ if(!track->isMidiTrack())
+ return;
+
+ song->chooseMidiRoutes(oR, (MidiTrack*)track, true);
+
+ /*
+ QPopupMenu* pup = new QPopupMenu(oR);
+ pup->setCheckable(true);
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* orl = t->outRoutes();
+
+ switch(track->type()) {
+ case Track::MIDI:
+ case Track::DRUM:
+ delete pup;
+ return;
+ case Track::AUDIO_OUTPUT:
+ {
+ int gid = 0;
+ for (int i = 0; i < channel; ++i) {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if (!checkAudioDevice()) return;
+ std::list<QString> ol = audioDevice->inputPorts();
+ for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ Route dst(*ip, true, i);
+ ++gid;
+ for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) {
+ if (*ir == dst) {
+ pup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ if (i+1 != channel)
+ pup->insertSeparator();
+ }
+ }
+ break;
+ case Track::AUDIO_INPUT:
+ addWavePorts(t, pup, orl);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ case Track::AUDIO_SOFTSYNTH:
+ addOutPorts(t, pup, orl);
+ addGroupPorts(t, pup, orl);
+ break;
+ case Track::AUDIO_AUX:
+ addOutPorts(t, pup, orl);
+ break;
+ }
+ int n = pup->exec(QCursor::pos());
+ if (n != -1) {
+ QString s(pup->text(n));
+ Route srcRoute(t, -1);
+ Route dstRoute(s, true, -1);
+
+ if (track->type() == Track::AUDIO_OUTPUT)
+ srcRoute.channel = dstRoute.channel = n & 0xf;
+
+ // check if route src->dst exists:
+ iRoute iorl = orl->begin();
+ for (; iorl != orl->end(); ++iorl) {
+ if (*iorl == dstRoute)
+ break;
+ }
+ if (iorl != orl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ }
+ delete pup;
+ oR->setDown(false); // pup->exec() catches mouse release event
+ */
+
+
+ }
+
+
diff --git a/muse/muse/mixer/mstrip.h b/muse/muse/mixer/mstrip.h
index e32b4310..460a7d65 100644
--- a/muse/muse/mixer/mstrip.h
+++ b/muse/muse/mixer/mstrip.h
@@ -28,7 +28,9 @@ class MidiStrip : public Strip {
Slider* slider;
DoubleLabel* sl;
- QToolButton* route;
+ //QToolButton* route;
+ QToolButton* iR;
+ QToolButton* oR;
struct KNOB {
Knob* knob;
@@ -49,7 +51,9 @@ class MidiStrip : public Strip {
void updateOffState();
private slots:
- void routeClicked();
+ //void routeClicked();
+ void iRoutePressed();
+ void oRoutePressed();
void setVolume(double);
void setPan(double);
void setChorusSend(double);
diff --git a/muse/muse/mixer/routedialog.cpp b/muse/muse/mixer/routedialog.cpp
index 595305c0..e3b1f211 100644
--- a/muse/muse/mixer/routedialog.cpp
+++ b/muse/muse/mixer/routedialog.cpp
@@ -49,13 +49,16 @@ void RouteDialog::routingChanged()
for (ciTrack i = tl->begin(); i != tl->end(); ++i) {
if ((*i)->isMidiTrack())
continue;
- WaveTrack* track = (WaveTrack*)(*i);
+ // p3.3.38
+ //WaveTrack* track = (WaveTrack*)(*i);
+ AudioTrack* track = (AudioTrack*)(*i);
if (track->type() == Track::AUDIO_INPUT) {
for (int channel = 0; channel < track->channels(); ++channel)
newDstList->insertItem(Route(track, channel).name());
const RouteList* rl = track->inRoutes();
for (ciRoute r = rl->begin(); r != rl->end(); ++r) {
- Route dst(track->name(), true, r->channel);
+ //Route dst(track->name(), true, r->channel);
+ Route dst(track->name(), true, r->channel, Route::TRACK_ROUTE);
new QListViewItem(routeList, r->name(), dst.name());
}
}
diff --git a/muse/muse/node.cpp b/muse/muse/node.cpp
index 4928420f..178c87cc 100644
--- a/muse/muse/node.cpp
+++ b/muse/muse/node.cpp
@@ -177,7 +177,7 @@ void AudioTrack::updateInternalSoloStates()
const RouteList* rl = inRoutes();
for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
{
- if(ir->type == TRACK_ROUTE)
+ if(ir->type == Route::TRACK_ROUTE)
ir->track->updateInternalSoloStates();
}
}
@@ -186,7 +186,7 @@ void AudioTrack::updateInternalSoloStates()
const RouteList* rl = outRoutes();
for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
{
- if(ir->type == TRACK_ROUTE)
+ if(ir->type == Route::TRACK_ROUTE)
ir->track->updateInternalSoloStates();
}
}
@@ -243,7 +243,7 @@ void AudioTrack::updateSoloStates(bool noDec)
const RouteList* rl = inRoutes();
for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
{
- if(ir->type == TRACK_ROUTE)
+ if(ir->type == Route::TRACK_ROUTE)
ir->track->updateInternalSoloStates();
}
}
@@ -252,7 +252,7 @@ void AudioTrack::updateSoloStates(bool noDec)
const RouteList* rl = outRoutes();
for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir)
{
- if(ir->type == TRACK_ROUTE)
+ if(ir->type == Route::TRACK_ROUTE)
ir->track->updateInternalSoloStates();
}
}
@@ -280,7 +280,8 @@ void Track::setOff(bool val)
// copyData
//---------------------------------------------------------
-void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
+//void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
+void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)
{
//Changed by T356. 12/12/09.
// Overhaul and streamline to eliminate multiple processing during one process loop.
@@ -288,9 +289,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing.
// Previously only WaveTrack used them. (Changed WaveTrack as well).
- int srcChannels = channels();
+ if(srcStartChan == -1)
+ srcStartChan = 0;
+
+ int srcChans = (srcChannels == -1) ? channels() : srcChannels;
+ int srcTotalOutChans = totalOutChannels();
+ if(channels() == 1)
+ srcTotalOutChans = 1;
- //Added by Tim. p3.3.16
#ifdef NODE_DEBUG
printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().latin1(), processed());
#endif
@@ -304,7 +310,11 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
int i;
- float* buffer[srcChannels];
+ // p3.3.38
+ //float* buffer[srcChannels];
+ float* buffer[srcTotalOutChans];
+
+
//float data[nframes * srcChannels];
//for(i = 0; i < srcChannels; ++i)
// buffer[i] = data + i * nframes;
@@ -315,7 +325,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
double _pan = pan();
vol[0] = _volume * (1.0 - _pan);
vol[1] = _volume * (1.0 + _pan);
- float meter[srcChannels];
+ float meter[srcChans];
// Have we been here already during this process cycle?
if(processed())
@@ -330,7 +340,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
if(_haveData)
{
// Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after.
- for(i = 0; i < srcChannels; ++i)
+ //for(i = 0; i < srcChannels; ++i)
+ // buffer[i] = outBuffers[i];
+ // p3.3.38
+ for(i = 0; i < srcTotalOutChans; ++i)
buffer[i] = outBuffers[i];
}
else
@@ -354,8 +367,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// First time here during this process cycle.
// Point the input buffers at a temporary stack buffer.
- float data[nframes * srcChannels];
- for(i = 0; i < srcChannels; ++i)
+ //float data[nframes * srcChannels];
+ //for(i = 0; i < srcChannels; ++i)
+ // buffer[i] = data + i * nframes;
+ // p3.3.38
+ float data[nframes * srcTotalOutChans];
+ 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.
@@ -363,9 +380,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// p3.3.29 1/27/10 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, srcChannels, nframes, buffer) || off() || (isMute() && !_prefader))
- if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader))
+ //if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader))
+ // p3.3.38
+ if(off() || !getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader))
{
- //Added by Tim. p3.3.16
#ifdef NODE_DEBUG
printf("MusE: AudioTrack::copyData name:%s dstChannels:%d zeroing buffers\n", name().latin1(), dstChannels);
#endif
@@ -383,7 +401,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
memset(dstBuffer[i], 0, sizeof(float) * nframes);
}
- for(i = 0; i < srcChannels; ++i)
+ for(i = 0; i < srcChans; ++i)
{
//_meter[i] = 0;
_meter[i] = 0.0;
@@ -411,7 +429,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// apply plugin chain
//---------------------------------------------------
- _efxPipe->apply(srcChannels, nframes, buffer);
+ _efxPipe->apply(srcChans, nframes, buffer);
//---------------------------------------------------
// aux sends
@@ -429,9 +447,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
AudioAux* a = (AudioAux*)((*al)[k]);
float** dst = a->sendBuffer();
int auxChannels = a->channels();
- if((srcChannels ==1 && auxChannels==1) || srcChannels == 2)
+ if((srcChans ==1 && auxChannels==1) || srcChans == 2)
{
- for(int ch = 0; ch < srcChannels; ++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];
@@ -439,7 +457,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
*db++ += (*sb++ * m * vol[ch]); // add to mix
}
}
- else if(srcChannels==1 && auxChannels==2) // copy mono to both channels
+ else if(srcChans==1 && auxChannels==2) // copy mono to both channels
{
for(int ch = 0; ch < auxChannels; ++ch)
{
@@ -458,7 +476,7 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
if(_prefader)
{
- for(i = 0; i < srcChannels; ++i)
+ for(i = 0; i < srcChans; ++i)
{
float* p = buffer[i];
meter[i] = 0.0;
@@ -514,7 +532,10 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// 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.
if(!usedirectbuf)
{
- for(i = 0; i < srcChannels; ++i)
+ //for(i = 0; i < srcChannels; ++i)
+ // AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
+ // p3.3.38
+ for(i = 0; i < srcTotalOutChans; ++i)
AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
}
@@ -522,18 +543,43 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
_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(config.useDenormalBias)
+ {
+ for(q = 0; q < nframes; q++)
+ dstBuffer[i][q] = denormalBias;
+ }
+ else
+ memset(dstBuffer[i], 0, sizeof(float) * nframes);
+ }
+ _processed = true;
+ return;
+ }
+ // Force a source range to fit actual available total out channels.
+ if((srcStartChan + srcChans) > srcTotalOutChans)
+ srcChans = srcTotalOutChans - srcStartChan;
+
//---------------------------------------------------
// apply volume
// postfader metering
//---------------------------------------------------
- if(srcChannels == dstChannels)
+
+ if(srcChans == dstChannels)
{
if(_prefader)
{
for(int c = 0; c < dstChannels; ++c)
{
- float* sp = buffer[c];
+ // p3.3.38
+ //float* sp = buffer[c];
+ float* sp = buffer[c + srcStartChan];
+
float* dp = dstBuffer[c];
for(unsigned k = 0; k < nframes; ++k)
*dp++ = (*sp++ * vol[c]);
@@ -544,7 +590,11 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
for(int c = 0; c < dstChannels; ++c)
{
meter[c] = 0.0;
- float* sp = buffer[c];
+
+ // p3.3.38
+ //float* sp = buffer[c];
+ float* sp = buffer[c + srcStartChan];
+
float* dp = dstBuffer[c];
//printf("2 dstBuffer[c]=%d\n",long(dstBuffer[c]));
for(unsigned k = 0; k < nframes; ++k)
@@ -562,9 +612,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
}
}
}
- else if(srcChannels == 1 && dstChannels == 2)
+ else if(srcChans == 1 && dstChannels == 2)
{
- float* sp = buffer[0];
+ // p3.3.38
+ //float* sp = buffer[0];
+ float* sp = buffer[srcStartChan];
+
if(_prefader)
{
for(int c = 0; c < dstChannels; ++c)
@@ -592,10 +645,14 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
_peak[0] = _meter[0];
}
}
- else if(srcChannels == 2 && dstChannels == 1)
+ else if(srcChans == 2 && dstChannels == 1)
{
- float* sp1 = buffer[0];
- float* sp2 = buffer[1];
+ // p3.3.38
+ //float* sp1 = buffer[0];
+ //float* sp2 = buffer[1];
+ float* sp1 = buffer[srcStartChan];
+ float* sp2 = buffer[srcStartChan + 1];
+
if(_prefader)
{
float* dp = dstBuffer[0];
@@ -637,7 +694,8 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float
// addData
//---------------------------------------------------------
-void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
+//void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)
+void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)
{
//Changed by T356. 12/12/09.
// Overhaul and streamline to eliminate multiple processing during one process loop.
@@ -656,7 +714,13 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
return;
}
- int srcChannels = channels();
+ if(srcStartChan == -1)
+ srcStartChan = 0;
+
+ int srcChans = (srcChannels == -1) ? channels() : srcChannels;
+ int srcTotalOutChans = totalOutChannels();
+ if(channels() == 1)
+ srcTotalOutChans = 1;
// 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 !
@@ -666,7 +730,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
int i;
- float* buffer[srcChannels];
+ // p3.3.38
+ //float* buffer[srcChannels];
+ float* buffer[srcTotalOutChans];
+
//float data[nframes * srcChannels];
//for (i = 0; i < srcChannels; ++i)
// buffer[i] = data + i * nframes;
@@ -677,7 +744,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
double _pan = pan();
vol[0] = _volume * (1.0 - _pan);
vol[1] = _volume * (1.0 + _pan);
- float meter[srcChannels];
+ float meter[srcChans];
// Have we been here already during this process cycle?
if(processed())
@@ -692,7 +759,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
if(_haveData)
{
// Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after.
- for(i = 0; i < srcChannels; ++i)
+ //for(i = 0; i < srcChannels; ++i)
+ // buffer[i] = outBuffers[i];
+ // p3.3.38
+ for(i = 0; i < srcTotalOutChans; ++i)
buffer[i] = outBuffers[i];
}
else
@@ -704,16 +774,23 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
// First time here during this process cycle.
// Point the input buffers at a temporary stack buffer.
- float data[nframes * srcChannels];
- for(i = 0; i < srcChannels; ++i)
- buffer[i] = data + i * nframes;
+ //float data[nframes * srcChannels];
+ //for(i = 0; i < srcChannels; ++i)
+ // buffer[i] = data + i * nframes;
+ // p3.3.38
+ float data[nframes * srcTotalOutChans];
+ 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.
- if(!getData(pos, srcChannels, nframes, buffer))
+ //if(!getData(pos, srcChannels, nframes, buffer))
+ // p3.3.38
+ if(!getData(pos, srcTotalOutChans, nframes, buffer))
{
// No data was available. Nothing to add, but zero our local buffers and the meters.
- for(i = 0; i < srcChannels; ++i)
+ for(i = 0; i < srcChans; ++i)
{
// If we're using local buffers, we must zero them so that the next thing requiring them
// during this process cycle will see zeros.
@@ -743,7 +820,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
// apply plugin chain
//---------------------------------------------------
- _efxPipe->apply(srcChannels, nframes, buffer);
+ _efxPipe->apply(srcChans, nframes, buffer);
//---------------------------------------------------
// aux sends
@@ -761,9 +838,9 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
AudioAux* a = (AudioAux*)((*al)[k]);
float** dst = a->sendBuffer();
int auxChannels = a->channels();
- if((srcChannels ==1 && auxChannels==1) || srcChannels==2)
+ if((srcChans ==1 && auxChannels==1) || srcChans==2)
{
- for(int ch = 0; ch < srcChannels; ++ch)
+ for(int ch = 0; ch < srcChans; ++ch)
{
float* db = dst[ch % a->channels()];
float* sb = buffer[ch];
@@ -771,7 +848,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
*db++ += (*sb++ * m * vol[ch]); // add to mix
}
}
- else if(srcChannels == 1 && auxChannels == 2)
+ else if(srcChans == 1 && auxChannels == 2)
{
for(int ch = 0; ch < auxChannels; ++ch)
{
@@ -790,7 +867,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
if(_prefader)
{
- for(i = 0; i < srcChannels; ++i)
+ for(i = 0; i < srcChans; ++i)
{
float* p = buffer[i];
meter[i] = 0.0;
@@ -835,7 +912,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
// 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.
if(!usedirectbuf)
{
- for(i = 0; i < srcChannels; ++i)
+ //for(i = 0; i < srcChannels; ++i)
+ // AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
+ // p3.3.38
+ for(i = 0; i < srcTotalOutChans; ++i)
AL::dsp->cpy(outBuffers[i], buffer[i], nframes);
}
@@ -843,18 +923,42 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
_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(config.useDenormalBias)
+ {
+ for(q = 0; q < nframes; q++)
+ dstBuffer[i][q] = denormalBias;
+ }
+ else
+ memset(dstBuffer[i], 0, sizeof(float) * nframes);
+ }
+ _processed = true;
+ return;
+ }
+ // Force a source range to fit actual available total out channels.
+ if((srcStartChan + srcChans) > srcTotalOutChans)
+ srcChans = srcTotalOutChans - srcStartChan;
+
//---------------------------------------------------
// apply volume
// postfader metering
//---------------------------------------------------
- if(srcChannels == dstChannels)
+ if(srcChans == dstChannels)
{
if(_prefader)
{
for(int c = 0; c < dstChannels; ++c)
{
- float* sp = buffer[c];
+ // p3.3.38
+ //float* sp = buffer[c];
+ float* sp = buffer[c + srcStartChan];
+
float* dp = dstBuffer[c];
for(unsigned k = 0; k < nframes; ++k)
*dp++ += (*sp++ * vol[c]);
@@ -865,7 +969,10 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
for(int c = 0; c < dstChannels; ++c)
{
meter[c] = 0.0;
- float* sp = buffer[c];
+ // p3.3.38
+ //float* sp = buffer[c];
+ float* sp = buffer[c + srcStartChan];
+
float* dp = dstBuffer[c];
for(unsigned k = 0; k < nframes; ++k)
{
@@ -882,21 +989,24 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
}
}
}
- else if(srcChannels == 1 && dstChannels == 2)
+ else if(srcChans == 1 && dstChannels == 2)
{
+ // p3.3.38
+ float* sp = buffer[srcStartChan];
+
if(_prefader)
{
for(int c = 0; c < dstChannels; ++c)
{
float* dp = dstBuffer[c];
- float* sp = buffer[0];
+ //float* sp = buffer[0];
for(unsigned k = 0; k < nframes; ++k)
*dp++ += (*sp++ * vol[c]);
}
}
else
{
- float* sp = buffer[0];
+ //float* sp = buffer[0];
meter[0] = 0.0;
for(unsigned k = 0; k < nframes; ++k)
{
@@ -913,10 +1023,14 @@ void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float*
_peak[0] = _meter[0];
}
}
- else if(srcChannels == 2 && dstChannels == 1)
+ else if(srcChans == 2 && dstChannels == 1)
{
- float* sp1 = buffer[0];
- float* sp2 = buffer[1];
+ // p3.3.38
+ //float* sp1 = buffer[0];
+ //float* sp2 = buffer[1];
+ float* sp1 = buffer[srcStartChan];
+ float* sp2 = buffer[srcStartChan + 1];
+
if(_prefader)
{
float* dp = dstBuffer[0];
@@ -1096,7 +1210,6 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b
RouteList* rl = inRoutes();
- // Added by Tim. p3.3.16
#ifdef NODE_DEBUG
printf("AudioTrack::getData name:%s inRoutes:%d\n", name().latin1(), rl->size());
#endif
@@ -1105,20 +1218,37 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b
if (ir == rl->end())
return false;
- // Added by Tim. p3.3.16
+ if(ir->track->isMidiTrack())
+ return false;
+
#ifdef NODE_DEBUG
printf(" calling copyData on %s...\n", ir->track->name().latin1());
#endif
- ir->track->copyData(pos, channels, nframes, buffer);
+ // p3.3.38
+ //((AudioTrack*)ir->track)->copyData(pos, channels, nframes, buffer);
+ ((AudioTrack*)ir->track)->copyData(pos, channels,
+ //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0,
+ ir->channel,
+ ir->channels,
+ nframes, buffer);
+
++ir;
for (; ir != rl->end(); ++ir) {
- // Added by Tim. p3.3.16
#ifdef NODE_DEBUG
printf(" calling addData on %s...\n", ir->track->name().latin1());
#endif
- ir->track->addData(pos, channels, nframes, buffer);
+ if(ir->track->isMidiTrack())
+ continue;
+
+ // p3.3.38
+ //((AudioTrack*)ir->track)->addData(pos, channels, nframes, buffer);
+ ((AudioTrack*)ir->track)->addData(pos, channels,
+ //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0,
+ ir->channel,
+ ir->channels,
+ nframes, buffer);
}
return true;
}
@@ -1368,7 +1498,7 @@ void AudioOutput::processInit(unsigned nframes)
//---------------------------------------------------------
void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)
- {
+{
//Added by Tim. p3.3.16
#ifdef NODE_DEBUG
printf("MusE: AudioOutput::process name:%s processed:%d\n", name().latin1(), processed());
@@ -1377,8 +1507,11 @@ void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)
for (int i = 0; i < _channels; ++i) {
buffer1[i] = buffer[i] + offset;
}
- copyData(pos, _channels, n, buffer1);
- }
+
+ // p3.3.38
+ //copyData(pos, _channels, n, buffer1);
+ copyData(pos, _channels, -1, -1, n, buffer1);
+}
//---------------------------------------------------------
// silence
@@ -1427,7 +1560,9 @@ void AudioOutput::processWrite()
printf("MusE: AudioOutput::processWrite Calling metronome->addData frame:%u channels:%d frames:%lu\n", audio->pos().frame(), _channels, _nframes);
#endif
- metronome->addData(audio->pos().frame(), _channels, _nframes, buffer);
+ // p3.3.38
+ //metronome->addData(audio->pos().frame(), _channels, _nframes, buffer);
+ metronome->addData(audio->pos().frame(), _channels, -1, -1, _nframes, buffer);
}
}
//---------------------------------------------------------
@@ -1606,3 +1741,53 @@ void AudioTrack::setChannels(int n)
_efxPipe->setChannels(n);
}
+//---------------------------------------------------------
+// setTotalOutChannels
+//---------------------------------------------------------
+
+void AudioTrack::setTotalOutChannels(int num)
+{
+ if(num == _totalOutChannels)
+ return;
+
+ 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;
+
+ _totalOutChannels = num;
+ chans = num;
+ // 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);
+
+ chans = num;
+ // Limit the actual track (meters, copying etc, all 'normal' operation) to two-channel stereo.
+ if(chans > MAX_CHANNELS)
+ chans = MAX_CHANNELS;
+
+ setChannels(chans);
+}
+
+//---------------------------------------------------------
+// setTotalInChannels
+//---------------------------------------------------------
+
+void AudioTrack::setTotalInChannels(int num)
+{
+ if(num == _totalInChannels)
+ return;
+
+ _totalInChannels = num;
+}
+
diff --git a/muse/muse/route.cpp b/muse/muse/route.cpp
index ace53252..0b45fdf2 100644
--- a/muse/muse/route.cpp
+++ b/muse/muse/route.cpp
@@ -16,6 +16,10 @@
#include "synth.h"
#include "audiodev.h"
#include "xml.h"
+#include "driver/jackmidi.h"
+#include "driver/alsamidi.h"
+
+//#define ROUTE_DEBUG
//---------------------------------------------------------
// Route
@@ -25,34 +29,79 @@ Route::Route(void* t, int ch)
{
jackPort = t;
channel = ch;
+ channels = -1;
+ remoteChannel = -1;
type = JACK_ROUTE;
}
-Route::Route(AudioTrack* t, int ch)
+//Route::Route(AudioTrack* t, int ch)
+Route::Route(Track* t, int ch, int chans)
+//Route::Route(Track* t, int ch)
{
- channel = ch;
- track = t;
- type = TRACK_ROUTE;
+ track = t;
+ channel = ch;
+ channels = chans;
+ remoteChannel = -1;
+ type = TRACK_ROUTE;
}
-Route::Route(const QString& s, bool dst, int ch)
+//Route::Route(MidiJackDevice* d)
+Route::Route(MidiDevice* d, int ch)
+{
+ device = d;
+ channel = ch;
+ channels = -1;
+ remoteChannel = -1;
+ /*
+ //if(dynamic_cast<MidiJackDevice*>(d))
+ if(d->deviceType() == MidiDevice::JACK_MIDI)
+ type = JACK_MIDI_ROUTE;
+ else
+ //if(dynamic_cast<MidiAlsaDevice*>(d))
+ if(d->deviceType() == MidiDevice::ALSA_MIDI)
+ type = ALSA_MIDI_ROUTE;
+ */
+ type = MIDI_DEVICE_ROUTE;
+}
+
+//Route::Route(const QString& s, bool dst, int ch)
+Route::Route(const QString& s, bool dst, int ch, int rtype)
{
- Route node(name2route(s, dst));
- channel = node.channel;
- if (channel == -1)
- channel = ch;
+ //Route node(name2route(s, dst));
+ Route node(name2route(s, dst, rtype));
+ channel = node.channel;
+ if(channel == -1)
+ channel = ch;
+ //if(channels == -1)
+ // channels = chans;
+ channels = node.channels;
+ remoteChannel = node.remoteChannel;
type = node.type;
- if (type == TRACK_ROUTE)
- track = node.track;
+ if(type == TRACK_ROUTE)
+ track = node.track;
+ else
+ if(type == JACK_ROUTE)
+ jackPort = node.jackPort;
+ /*
+ else
+ if (type == JACK_MIDI_ROUTE)
+ device = node.device;
else
- jackPort = node.jackPort;
+ if (type == ALSA_MIDI_ROUTE)
+ device = node.device;
+ */
+ else
+ if (type == MIDI_DEVICE_ROUTE)
+ device = node.device;
}
Route::Route()
{
- track = 0;
- channel = -1;
- type = TRACK_ROUTE;
+ track = 0;
+ channel = -1;
+ channels = -1;
+ remoteChannel = -1;
+ type = TRACK_ROUTE;
}
//---------------------------------------------------------
@@ -60,58 +109,306 @@ Route::Route()
//---------------------------------------------------------
void addRoute(Route src, Route dst)
- {
+{
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute:\n");
+ #endif
+
if (!src.isValid() || !dst.isValid())
+ {
+ if(!src.isValid())
+ fprintf(stderr, "addRoute: invalid src\n");
+ if(!dst.isValid())
+ fprintf(stderr, "addRoute: invalid dst\n");
return;
-
+ }
+
// printf("addRoute %d.%d:<%s> %d.%d:<%s>\n",
// src.type, src.channel, src.name().latin1(),
// dst.type, dst.channel, dst.name().latin1());
- if (src.type == JACK_ROUTE) {
- if (dst.type != TRACK_ROUTE) {
- fprintf(stderr, "addRoute: bad route 1\n");
+ if (src.type == Route::JACK_ROUTE)
+ {
+ //if (dst.type != TRACK_ROUTE)
+ //{
+ // fprintf(stderr, "addRoute: bad route 1\n");
// exit(-1);
+ // return;
+ //}
+
+ if (dst.type == Route::TRACK_ROUTE)
+ {
+ if (dst.track->type() != Track::AUDIO_INPUT)
+ {
+ fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().latin1());
+ //exit(-1);
return;
- }
- if (dst.track->type() != Track::AUDIO_INPUT) {
- fprintf(stderr, "addRoute: bad route 2\n");
- exit(-1);
- }
- src.channel = dst.channel;
- RouteList* inRoutes = dst.track->inRoutes();
- for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) {
+ }
+ //src.channel = src.dstChannel = dst.channel;
+ src.channel = dst.channel;
+ //src.channels = dst.channels = 1;
+ RouteList* inRoutes = dst.track->inRoutes();
+ for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)
+ {
+ if (*i == src) // route already there
+ {
+ //#ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src track route already exists.\n");
+ //#endif
+ return;
+ }
+ }
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src Jack dst track name: %s pushing source route\n", dst.track->name().latin1());
+ #endif
+ inRoutes->push_back(src);
+ }
+ else
+ //if (dst.type == Route::JACK_MIDI_ROUTE)
+ if (dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ if(dst.device->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ src.channel = dst.channel;
+ //src.channel = -1;
+ //src.channel = 0;
+ //src.channel = src.dstChannel = dst.channel;
+ //src.channels = dst.channels = 1;
+ //dst.channel = -1;
+
+ RouteList* routes = dst.device->inRoutes();
+ for (iRoute i = routes->begin(); i != routes->end(); ++i)
+ {
if (*i == src) // route already there
- return;
- }
- inRoutes->push_back(src);
+ {
+ //#ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src Jack midi route already exists.\n");
+ //#endif
+ return;
+ }
+ }
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src Jack dst Jack midi name: %s pushing source route\n", dst.device->name().latin1());
+ #endif
+ routes->push_back(src);
+ }
+ else
+ {
+ fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType());
+ // exit(-1);
+ return;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type);
+ // exit(-1);
+ return;
}
- else if (dst.type == JACK_ROUTE) {
- if (src.type != TRACK_ROUTE) {
- fprintf(stderr, "addRoute: bad route 3\n");
- // exit(-1);
- return;
- }
- if (src.track->type() != Track::AUDIO_OUTPUT) {
- fprintf(stderr, "addRoute: bad route 4\n");
+ }
+ else if (dst.type == Route::JACK_ROUTE)
+ {
+ //if (src.type != TRACK_ROUTE)
+ //{
+ // fprintf(stderr, "addRoute: bad route 3\n");
// exit(-1);
- return;
- }
- RouteList* outRoutes = src.track->outRoutes();
- dst.channel = src.channel;
- for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) {
+ // return;
+ //}
+
+ if (src.type == Route::TRACK_ROUTE)
+ {
+ if (src.track->type() != Track::AUDIO_OUTPUT)
+ {
+ fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n");
+ // exit(-1);
+ return;
+ }
+ RouteList* outRoutes = src.track->outRoutes();
+ //dst.channel = dst.dstChannel = src.channel;
+ dst.channel = src.channel;
+ //dst.channels = src.channels = 1;
+
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) // route already there
+ {
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: dst track route already exists.\n");
+ #endif
+ return;
+ }
+ }
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: dst Jack src track name: %s pushing destination route\n", src.track->name().latin1());
+ #endif
+ outRoutes->push_back(dst);
+ }
+ else
+ //if (src.type == Route::JACK_MIDI_ROUTE)
+ if (src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ if(src.device->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ dst.channel = src.channel;
+ //dst.channel = -1;
+ //src.channel = -1;
+ //dst.channel = dst.dstChannel = src.channel;
+ //dst.channels = src.channels = 1;
+
+ RouteList* routes = src.device->outRoutes();
+ for (iRoute i = routes->begin(); i != routes->end(); ++i)
+ {
if (*i == dst) // route already there
- return;
- }
- outRoutes->push_back(dst);
+ {
+ //#ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: dst Jack midi route already exists.\n");
+ //#endif
+ return;
+ }
+ }
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: dst Jack src Jack midi name: %s pushing destination route\n", src.device->name().latin1());
+ #endif
+ routes->push_back(dst);
+ }
+ else
+ {
+ fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType());
+ // exit(-1);
+ return;
+ }
}
- else {
- RouteList* outRoutes = src.track->outRoutes();
- for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) {
+ else
+ {
+ fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type);
+ // exit(-1);
+ return;
+ }
+ }
+ else
+ {
+ //if ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE))
+ if(src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //src.channel = src.dstChannel = dst.dstChannel = dst.channel;
+ src.channel = dst.channel;
+ //src.channels = dst.channels = 1;
+ RouteList* outRoutes = src.device->outRoutes();
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src name: %s looking for existing dest in out routes...\n", src.device->name().latin1());
+ #endif
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
if (*i == dst) // route already there
+ {
+ //#ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src Jack or ALSA midi route already exists.\n");
+ //#endif
return;
- }
+ }
+ }
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src midi dst name: %s pushing destination and source routes\n", dst.track->name().latin1());
+ #endif
+
outRoutes->push_back(dst);
RouteList* inRoutes = dst.track->inRoutes();
+ inRoutes->push_back(src);
+ }
+ else
+ {
+ if(dst.type == Route::MIDI_DEVICE_ROUTE)
+ //{
+ dst.channel = src.channel;
+ //src.channel = src.dstChannel = dst.dstChannel = dst.channel;
+ //src.channels = dst.channels = 1;
+ //}
+ //else
+ //{
+ //src.channel = src.dstChannel = dst.dstChannel = dst.channel;
+ //src.channels = dst.channels = 1;
+ //}
+
+ RouteList* outRoutes = src.track->outRoutes();
+
+ //
+ // Must enforce to ensure channel and channels are valid if defaults of -1 passed.
+ //
+ if(src.track->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ if(src.channel == -1)
+ src.channel = 0;
+ if(src.channels == -1)
+ src.channels = src.track->channels();
+ if(dst.type == Route::TRACK_ROUTE)
+ {
+ //if(dst.channel == -1)
+ // dst.channel = 0;
+ //if(dst.channels == -1)
+ // Yes, that's correct: dst channels = src track channels.
+ // dst.channels = src.track->channels();
+ dst.channel = src.channel;
+ dst.channels = src.channels;
+ dst.remoteChannel = src.remoteChannel;
+ }
+ }
+ /*
+ if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH)
+ {
+ if(dst.channel == -1)
+ dst.channel = 0;
+ if(dst.channels == -1)
+ // Yes, that's correct: dst channels = src track channels.
+ dst.channels = src.track->channels();
+ }
+ */
+
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) // route already there
+ // TODO:
+ //if (i->type == dst.type && i->channel == dst.channel)
+ {
+ //if(i->type == Route::TRACK_ROUTE)
+ {
+ //if(i->track == dst.track)
+ {
+ //if(i->channels == dst.channels)
+ {
+ //#ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src track route already exists.\n");
+ //#endif
+ return;
+ }
+ //else
+ //{
+
+ //}
+ }
+ }
+ }
+ }
+ outRoutes->push_back(dst);
+ RouteList* inRoutes;
+ //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE))
+ if(dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ #ifdef ROUTE_DEBUG
+ fprintf(stderr, "addRoute: src track dst midi name: %s pushing destination and source routes\n", dst.device->name().latin1());
+ #endif
+ inRoutes = dst.device->inRoutes();
+ }
+ else
+ {
+ #ifdef ROUTE_DEBUG
+ //fprintf(stderr, "addRoute: src track ch:%d chs:%d dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().latin1());
+ fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n",
+ src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().latin1());
+ //fprintf(stderr, "addRoute: src track ch:%d dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().latin1());
+ #endif
+ inRoutes = dst.track->inRoutes();
+ }
+
+
//
// make sure AUDIO_AUX is processed last
//
@@ -119,76 +416,198 @@ void addRoute(Route src, Route dst)
inRoutes->push_back(src);
else
inRoutes->insert(inRoutes->begin(), src);
- }
+ }
}
+}
//---------------------------------------------------------
// removeRoute
//---------------------------------------------------------
void removeRoute(Route src, Route dst)
- {
+{
//printf("removeRoute %d.%d:<%s> %d.%d:<%s>\n",
// src.type, src.channel, src.name().latin1(),
// dst.type, dst.channel, dst.name().latin1());
- if (src.type == JACK_ROUTE) {
- if (dst.type != TRACK_ROUTE) {
- fprintf(stderr, "removeRoute: bad route 1\n");
+ if (src.type == Route::JACK_ROUTE)
+ {
+ //if (dst.type != TRACK_ROUTE)
+ //{
+ // fprintf(stderr, "removeRoute: bad route 1\n");
// exit(-1);
- return;
- }
- if (dst.track->type() != Track::AUDIO_INPUT) {
- fprintf(stderr, "removeRoute: bad route 2\n");
+ // return;
+ //}
+ if(!dst.isValid())
+ {
+ printf("removeRoute: source is jack, invalid destination\n");
+ return;
+ }
+
+ if (dst.type == Route::TRACK_ROUTE)
+ {
+ if (dst.track->type() != Track::AUDIO_INPUT)
+ {
+ fprintf(stderr, "removeRoute: source is jack, destination is track but not audio input\n");
+ // exit(-1);
+ return;
+ }
+ RouteList* inRoutes = dst.track->inRoutes();
+ iRoute i;
+ for (i = inRoutes->begin(); i != inRoutes->end(); ++i)
+ {
+ if (*i == src)
+ {
+ inRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ //if (dst.type == Route::JACK_MIDI_ROUTE)
+ if (dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ RouteList* routes = dst.device->inRoutes();
+ iRoute i;
+ for (i = routes->begin(); i != routes->end(); ++i)
+ {
+ if (*i == src)
+ {
+ routes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "removeRoute: source is jack, destination unknown\n");
// exit(-1);
return;
- }
- RouteList* inRoutes = dst.track->inRoutes();
- iRoute i;
- for (i = inRoutes->begin(); i != inRoutes->end(); ++i) {
- if (*i == src) {
- inRoutes->erase(i);
- break;
- }
- }
}
- else if (dst.type == JACK_ROUTE) {
- if (src.type != TRACK_ROUTE) {
- fprintf(stderr, "removeRoute: bad route 3\n");
+ }
+ else if (dst.type == Route::JACK_ROUTE)
+ {
+ //if (src.type != TRACK_ROUTE)
+ //{
+ // fprintf(stderr, "removeRoute: bad route 3\n");
// exit(-1);
- return;
- }
- if (src.track->type() != Track::AUDIO_OUTPUT) {
- fprintf(stderr, "removeRoute: bad route 4\n");
+ // return;
+ //}
+ if(!src.isValid())
+ {
+ printf("removeRoute: destination is jack, invalid source\n");
+ return;
+ }
+
+ if (src.type == Route::TRACK_ROUTE)
+ {
+ if (src.track->type() != Track::AUDIO_OUTPUT)
+ {
+ fprintf(stderr, "removeRoute: destination is jack, source is track but not audio output\n");
+ // exit(-1);
+ return;
+ }
+ RouteList* outRoutes = src.track->outRoutes();
+ iRoute i;
+ for (i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) {
+ outRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ //if (src.type == Route::JACK_MIDI_ROUTE)
+ if (src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ RouteList* routes = src.device->outRoutes();
+ iRoute i;
+ for (i = routes->begin(); i != routes->end(); ++i)
+ {
+ if (*i == dst) {
+ routes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "removeRoute: destination is jack, source unknown\n");
// exit(-1);
return;
- }
- RouteList* outRoutes = src.track->outRoutes();
- iRoute i;
- for (i = outRoutes->begin(); i != outRoutes->end(); ++i) {
- if (*i == dst) {
- outRoutes->erase(i);
- break;
- }
- }
}
- else {
- RouteList* outRoutes = src.track->outRoutes();
- for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) {
- if (*i == dst) {
- outRoutes->erase(i);
- break;
- }
- }
- RouteList* inRoutes = dst.track->inRoutes();
- for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) {
- if (*i == src) {
- inRoutes->erase(i);
- break;
- }
- }
+ }
+ else
+ {
+ //if((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE))
+ if(src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ if(src.isValid())
+ {
+ RouteList* outRoutes = src.device->outRoutes();
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) {
+ outRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ printf("removeRoute: source is midi but invalid\n");
+
+ if(dst.isValid())
+ {
+ RouteList* inRoutes = dst.track->inRoutes();
+ for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)
+ {
+ if (*i == src) {
+ inRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ printf("removeRoute: source is midi but destination invalid\n");
}
+ else
+ {
+ if(src.isValid())
+ {
+ RouteList* outRoutes = src.track->outRoutes();
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) {
+ outRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ printf("removeRoute: source is track but invalid\n");
+
+ if(dst.isValid())
+ {
+ RouteList* inRoutes;
+ //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE))
+ if (dst.type == Route::MIDI_DEVICE_ROUTE)
+ inRoutes = dst.device->inRoutes();
+ else
+ inRoutes = dst.track->inRoutes();
+ for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)
+ {
+ if (*i == src) {
+ inRoutes->erase(i);
+ break;
+ }
+ }
+ }
+ else
+ printf("removeRoute: source is track but destination invalid\n");
+ }
}
+}
//---------------------------------------------------------
// track2name
@@ -208,7 +627,9 @@ static QString track2name(const Track* n)
//---------------------------------------------------------
QString Route::name() const
- {
+{
+ // p3.3.38 Removed
+ /*
QString s;
if ((type == TRACK_ROUTE) && (channel != -1)) {
// if (channel != -1) {
@@ -216,58 +637,333 @@ QString Route::name() const
c.setNum(channel+1);
s = c + ":";
}
- if (type == JACK_ROUTE) {
- if (!checkAudioDevice()) return "";
- return s + audioDevice->portName(jackPort);
+ */
+
+ /*
+ if (type == ALSA_MIDI_ROUTE)
+ {
+ if(device)
+ // TODO
+ //snd_seq_addr_t
+ return device->name();
+ else
+ return QWidget::tr("None");
+ }
+ else
+ if (type == JACK_MIDI_ROUTE)
+ {
+ if(device)
+ {
+ return audioDevice->portName(device->clientPort());
+ //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(device);
+ //if(jmd)
+ // return audioDevice->portName(jmd->clientJackPort());
+ //else
+ //{
+ // fprintf(stderr, "Route::name Route is Jack midi but device is not a MidiJackDevice\n");
+ // return QWidget::tr("None");
+ //}
}
+ else
+ return QWidget::tr("None");
+ }
+ */
+
+ if(type == MIDI_DEVICE_ROUTE)
+ {
+ if(device)
+ {
+ if(device->deviceType() == MidiDevice::JACK_MIDI)
+ return audioDevice->portName(device->clientPort());
+ else
+ //if(device->deviceType() == MidiDevice::ALSA_MIDI)
+ return device->name();
+ }
+ return QWidget::tr("None");
+ }
else
- return s + track2name(track);
+ if(type == JACK_ROUTE)
+ {
+ if (!checkAudioDevice()) return "";
+ //return s + audioDevice->portName(jackPort);
+ return audioDevice->portName(jackPort);
}
+ else
+ //return s + track2name(track);
+ return track2name(track);
+}
//---------------------------------------------------------
// name2route
//---------------------------------------------------------
-Route name2route(const QString& rn, bool dst)
- {
+//Route name2route(const QString& rn, bool dst)
+Route name2route(const QString& rn, bool /*dst*/, int rtype)
+{
// printf("name2route %s\n", rn.latin1());
- int channel = -1;
- QString s(rn);
- if (rn[0].isNumber() && rn[1]==':') {
- channel = rn[0] - '1';
- s = rn.mid(2);
- }
- if (dst) {
- TrackList* tl = song->tracks();
- for (iTrack i = tl->begin(); i != tl->end(); ++i) {
- if ((*i)->isMidiTrack())
- continue;
- AudioTrack* track = (AudioTrack*)*i;
- if (track->name() == s)
- return Route(track, channel);
- }
- if (!checkAudioDevice()) return Route((AudioTrack*)NULL,0);
- void* p = audioDevice->findPort(s.latin1());
- if (p)
- return Route(p, channel);
- }
- else {
- if (!checkAudioDevice()) return Route((AudioTrack*)NULL,0);
- void* p = audioDevice->findPort(s.latin1());
- if (p)
- return Route(p, channel);
- TrackList* tl = song->tracks();
- for (iTrack i = tl->begin(); i != tl->end(); ++i) {
- if ((*i)->isMidiTrack())
- continue;
- AudioTrack* track = (AudioTrack*)*i;
- if (track->name() == s)
- return Route(track, channel);
- }
- }
- printf(" name2route: <%s> not found\n", rn.latin1());
- return Route((Track*) 0, channel);
+ int channel = -1;
+ //int channel = 0;
+ QString s(rn);
+ // Support old route style in med files. Obsolete.
+ if (rn[0].isNumber() && rn[1]==':')
+ {
+ channel = rn[0] - '1';
+ s = rn.mid(2);
+ }
+
+ if(rtype == -1)
+ {
+ //if(dst)
+ //{
+ if(checkAudioDevice())
+ {
+ void* p = audioDevice->findPort(s.latin1());
+ if(p)
+ return Route(p, channel);
+ }
+
+ TrackList* tl = song->tracks();
+ for(iTrack i = tl->begin(); i != tl->end(); ++i)
+ {
+ if((*i)->isMidiTrack())
+ {
+ MidiTrack* track = (MidiTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ //return Route(track, channel, 1);
+ }
+ else
+ {
+ AudioTrack* track = (AudioTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ //return Route(track, channel, 1);
+ //return Route(track, channel, track->channels());
+ }
}
+
+ for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ if((*i)->name() == s)
+ //if (jmd->name() == rn)
+ return Route(*i, channel);
+
+ /*
+ MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i);
+ if(jmd)
+ {
+ if(jmd->name() == s)
+ //if (jmd->name() == rn)
+ return Route(jmd);
+ }
+ MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i);
+ if(amd)
+ {
+ // TODO
+ if(amd->name() == s)
+ //if (amd->name() == rn)
+ return Route(amd);
+ }
+ */
+ }
+
+
+/*
+ }
+ else
+ {
+ if(checkAudioDevice())
+ {
+ void* p = audioDevice->findPort(s.latin1());
+ if(p)
+ return Route(p, channel);
+ }
+
+ TrackList* tl = song->tracks();
+ for(iTrack i = tl->begin(); i != tl->end(); ++i)
+ {
+ if((*i)->isMidiTrack())
+ {
+ MidiTrack* track = (MidiTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ }
+ else
+ {
+ AudioTrack* track = (AudioTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ }
+ }
+
+ for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ if((*i)->name() == s)
+ //if (jmd->name() == rn)
+ return Route(*i, channel);
+*/
+
+ /*
+ MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i);
+ if(jmd)
+ {
+ if(jmd->name() == s)
+ //if (jmd->name() == rn)
+ return Route(jmd);
+ }
+ MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i);
+ if(amd)
+ {
+ // TODO
+ if(amd->name() == s)
+ //if (amd->name() == rn)
+ return Route(amd);
+ }
+ */
+// }
+// }
+
+ }
+ else
+ {
+ //if(dst)
+ //{
+ if(rtype == Route::TRACK_ROUTE)
+ {
+ TrackList* tl = song->tracks();
+ for(iTrack i = tl->begin(); i != tl->end(); ++i)
+ {
+ if((*i)->isMidiTrack())
+ {
+ MidiTrack* track = (MidiTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ }
+ else
+ {
+ AudioTrack* track = (AudioTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ //return Route(track, channel, 1);
+ //return Route(track, channel, track->channels());
+ }
+ }
+ }
+ else
+ //if((rtype == Route::JACK_MIDI_ROUTE) || (rtype == Route::ALSA_MIDI_ROUTE))
+ // TODO Distinguish the device types
+ if(rtype == Route::MIDI_DEVICE_ROUTE)
+ {
+ for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ if((*i)->name() == s)
+ //if (jmd->name() == rn)
+ return Route(*i, channel);
+
+ /*
+ MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i);
+ if(jmd)
+ {
+ if(jmd->name() == s)
+ //if (jmd->name() == rn)
+ return Route(jmd);
+ }
+ MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i);
+ if(amd)
+ {
+ // TODO
+ if(amd->name() == s)
+ //if (amd->name() == rn)
+ return Route(amd);
+ }
+ */
+ }
+ }
+ else
+ if(rtype == Route::JACK_ROUTE)
+ {
+ if(checkAudioDevice())
+ {
+ void* p = audioDevice->findPort(s.latin1());
+ if(p)
+ return Route(p, channel);
+ }
+ }
+
+
+/*
+ }
+ else
+ {
+ if(rtype == Route::TRACK_ROUTE)
+ {
+ TrackList* tl = song->tracks();
+ for(iTrack i = tl->begin(); i != tl->end(); ++i)
+ {
+ if((*i)->isMidiTrack())
+ {
+ MidiTrack* track = (MidiTrack*)*i;
+ if (track->name() == s)
+ return Route(track, channel);
+ }
+ else
+ {
+ AudioTrack* track = (AudioTrack*)*i;
+ if(track->name() == s)
+ return Route(track, channel);
+ }
+ }
+ }
+ else
+ if((rtype == Route::JACK_MIDI_ROUTE) || (rtype == Route::ALSA_MIDI_ROUTE))
+ {
+ for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
+ {
+ if((*i)->name() == s)
+ //if (jmd->name() == rn)
+ return Route(*i, channel);
+*/
+
+ /*
+ MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(*i);
+ if(jmd)
+ {
+ if(jmd->name() == s)
+ //if (jmd->name() == rn)
+ return Route(jmd);
+ }
+ MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(*i);
+ if(amd)
+ {
+ // TODO
+ if(amd->name() == s)
+ //if (amd->name() == rn)
+ return Route(amd);
+ }
+ */
+
+/*
+ }
+ }
+ else
+ if(rtype == JACK_ROUTE)
+ {
+ if(checkAudioDevice())
+ {
+ void* p = audioDevice->findPort(s.latin1());
+ if(p)
+ return Route(p, channel);
+ }
+ }
+ }
+*/
+
+ }
+
+ printf(" name2route: <%s> not found\n", rn.latin1());
+ return Route((Track*) 0, channel);
+ //return Route((Track*) 0, channel, 1);
+}
//---------------------------------------------------------
// checkRoute
@@ -281,44 +977,95 @@ bool checkRoute(const QString& s, const QString& d)
if (!(src.isValid() && dst.isValid()) || (src == dst))
return false;
- if (src.type == JACK_ROUTE) {
- if (dst.type != TRACK_ROUTE) {
- return false;
- }
- if (dst.track->type() != Track::AUDIO_INPUT) {
- return false;
- }
- src.channel = dst.channel;
- RouteList* inRoutes = dst.track->inRoutes();
- for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) {
- if (*i == src) { // route already there
- return false;
- }
- }
+ if (src.type == Route::JACK_ROUTE)
+ {
+ //if (dst.type != TRACK_ROUTE) {
+ // return false;
+ // }
+
+ if (dst.type == Route::TRACK_ROUTE)
+ {
+ if (dst.track->type() != Track::AUDIO_INPUT) {
+ return false;
+ }
+ src.channel = dst.channel;
+ RouteList* inRoutes = dst.track->inRoutes();
+ for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)
+ {
+ if (*i == src) { // route already there
+ return false;
+ }
+ }
}
- else if (dst.type == JACK_ROUTE) {
- if (src.type != TRACK_ROUTE) {
- return false;
- }
- if (src.track->type() != Track::AUDIO_OUTPUT) {
- return false;
- }
- RouteList* outRoutes = src.track->outRoutes();
- dst.channel = src.channel;
- for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) {
- if (*i == dst) { // route already there
- return false;
- }
- }
+ else
+ //if (dst.type == Route::JACK_MIDI_ROUTE)
+ if (dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //src.channel = dst.channel;
+ src.channel = -1;
+ //dst.channel = -1;
+ RouteList* routes = dst.device->inRoutes();
+ for (iRoute i = routes->begin(); i != routes->end(); ++i)
+ {
+ if (*i == src) { // route already there
+ return false;
+ }
+ }
}
- else {
- RouteList* outRoutes = src.track->outRoutes();
- for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) {
+ else
+ return false;
+ }
+ else if (dst.type == Route::JACK_ROUTE)
+ {
+ //if (src.type != TRACK_ROUTE) {
+ // return false;
+ // }
+
+ if (src.type == Route::TRACK_ROUTE)
+ {
+ if (src.track->type() != Track::AUDIO_OUTPUT) {
+ return false;
+ }
+ RouteList* outRoutes = src.track->outRoutes();
+ dst.channel = src.channel;
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
+ if (*i == dst) { // route already there
+ return false;
+ }
+ }
+ }
+ else
+ //if (src.type == Route::JACK_MIDI_ROUTE)
+ if (src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ RouteList* routes = src.device->outRoutes();
+ //dst.channel = src.channel;
+ dst.channel = -1;
+ //src.channel = -1;
+ for (iRoute i = routes->begin(); i != routes->end(); ++i)
+ {
+ if (*i == dst) { // route already there
+ return false;
+ }
+ }
+ }
+ else
+ return false;
+ }
+ else
+ {
+ //RouteList* outRoutes = ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) ?
+ // src.device->outRoutes() : src.track->outRoutes();
+ RouteList* outRoutes = (src.type == Route::MIDI_DEVICE_ROUTE) ? src.device->outRoutes() : src.track->outRoutes();
+
+ for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)
+ {
if (*i == dst) { // route already there
return false;
}
- }
}
+ }
return true;
}
@@ -326,47 +1073,201 @@ bool checkRoute(const QString& s, const QString& d)
// read
//---------------------------------------------------------
-void Song::readRoute(Xml& xml)
+void Route::read(Xml& xml)
+{
+ QString s;
+ int dtype = MidiDevice::ALSA_MIDI;
+
+ //channel = -1;
+ //channels = -1;
+ //remoteChannel = -1;
+ type = Route::TRACK_ROUTE;
+ track = 0;
+
+ for (;;)
{
+ const QString& tag = xml.s1();
+ Xml::Token token = xml.parse();
+ switch (token)
+ {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ //case Xml::TagStart:
+ // xml.unknown("Route");
+ // break;
+ case Xml::Attribut:
+ #ifdef ROUTE_DEBUG
+ printf("Route::read(): attribute:%s\n", tag.latin1());
+ #endif
+ if(tag == "type")
+ type = xml.s2().toInt();
+ else
+ if(tag == "devtype")
+ {
+ dtype = xml.s2().toInt();
+ type = Route::MIDI_DEVICE_ROUTE;
+ }
+ //else
+ //if(tag == "channel")
+ // channel = xml.s2().toInt();
+ //else
+ //if(tag == "channels")
+ // channels = xml.s2().toInt();
+ //else
+ //if(tag == "remch")
+ // remoteChannel = xml.s2().toInt();
+ else
+ if(tag == "name")
+ s = xml.s2();
+ else
+ printf("Route::read(): unknown attribute:%s\n", tag.latin1());
+ break;
+ case Xml::TagEnd:
+ #ifdef ROUTE_DEBUG
+ printf("Route::read(): tag end type:%d channel:%d name:%s\n", type, channel, s.latin1());
+ #endif
+ if(!s.isEmpty())
+ {
+ if(type == TRACK_ROUTE)
+ {
+ track = 0;
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i)
+ {
+ Track* t = *i;
+ if (t->name() == s)
+ {
+ track = t;
+ break;
+ }
+ }
+ if(track == 0)
+ printf("Route::read(): track <%s> not found\n", s.latin1());
+ }
+ else
+ if(type == JACK_ROUTE)
+ {
+ jackPort = audioDevice->findPort(s);
+ if(jackPort == 0)
+ printf("Route::read(): jack port <%s> not found\n", s.latin1());
+ }
+ else
+ //if((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE))
+ if(type == MIDI_DEVICE_ROUTE)
+ {
+ device = 0;
+ for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
+ {
+ MidiDevice* md = *imd;
+ //if(md->name() == s)
+ if(md->name() == s && md->deviceType() == dtype)
+ {
+ device = md;
+ break;
+ }
+ }
+ if(device == 0)
+ printf("Route::read(): midi device <%s> not found\n", s.latin1());
+ }
+ }
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void Song::readRoute(Xml& xml)
+{
QString src;
QString dst;
+ int ch = -1;
+ int chs = -1;
+ int remch = -1;
- for (;;) {
+ Route sroute, droute;
+
+ for (;;)
+ {
const QString& tag = xml.s1();
Xml::Token token = xml.parse();
- switch (token) {
+ switch (token)
+ {
case Xml::Error:
case Xml::End:
return;
case Xml::TagStart:
+ // p3.3.38 2010/02/03 Support old routes in med files. Now obsolete!
if (tag == "srcNode")
src = xml.parse1();
else if (tag == "dstNode")
dst = xml.parse1();
+ // Support new routes.
+ else if (tag == "source")
+ {
+ sroute.read(xml);
+ sroute.channel = ch;
+ sroute.channels = chs;
+ sroute.remoteChannel = remch;
+ }
+ else if (tag == "dest")
+ {
+ droute.read(xml);
+ droute.channel = ch;
+ droute.channels = chs;
+ droute.remoteChannel = remch;
+ }
else
xml.unknown("readRoute");
break;
+ case Xml::Attribut:
+ #ifdef ROUTE_DEBUG
+ printf("Song::readRoute(): attribute:%s\n", tag.latin1());
+ #endif
+ if(tag == "channel")
+ ch = xml.s2().toInt();
+ else
+ if(tag == "channels")
+ chs = xml.s2().toInt();
+ else
+ if(tag == "remch")
+ remch = xml.s2().toInt();
+ else
+ printf("Song::readRoute(): unknown attribute:%s\n", tag.latin1());
+ break;
case Xml::TagEnd:
- if (xml.s1() == "Route") {
-
- if(!src.isEmpty() && !dst.isEmpty())
- {
-
- Route s = name2route(src, false);
- Route d = name2route(dst, true);
- addRoute(s, d);
-
- }
- else
- printf(" Warning - route name missing. Ignoring route!\n");
-
- return;
- }
+ if (xml.s1() == "Route")
+ {
+ // Support old routes in med files. Now obsolete!
+ if(!src.isEmpty() && !dst.isEmpty())
+ {
+ Route s = name2route(src, false);
+ Route d = name2route(dst, true);
+ addRoute(s, d);
+ }
+ else
+ // Support new routes.
+ if(sroute.isValid() && droute.isValid())
+ {
+ //printf("adding new route...\n");
+ addRoute(sroute, droute);
+ }
+ else
+ printf(" Warning - route invalid. Ignoring route!\n");
+
+ return;
+ }
default:
break;
- }
- }
+ }
}
+}
//---------------------------------------------------------
// removeRoute
@@ -388,30 +1289,156 @@ void RouteList::removeRoute(const Route& r)
//---------------------------------------------------------
void Route::dump() const
+{
+ if (type == TRACK_ROUTE)
+ {
+ if(track)
+ printf("Route dump: track <%s> channel %d channels %d\n", track->name().latin1(), channel, channels);
+ //printf("Route dump: track <%s> channel %d\n", track->name().latin1(), channel);
+ //else
+ // printf("Route dump: invalid track, channel %d\n", channel);
+ }
+ else
+ if (type == JACK_ROUTE)
+ {
+ if(checkAudioDevice())
+ printf("Route dump: jack audio port <%s> channel %d\n", audioDevice->portName(jackPort).latin1(), channel);
+ }
+ else
+ if (type == MIDI_DEVICE_ROUTE)
+ {
+ printf("Route dump: ");
+ if(device)
+ {
+ if(device->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ if(checkAudioDevice())
+ printf("jack midi port device <%s> ", audioDevice->portName(device->clientPort()).latin1());
+ }
+ else
+ if(device->deviceType() == MidiDevice::ALSA_MIDI)
+ printf("alsa midi device <%s> ", device->name().latin1());
+ else
+ if(device->deviceType() == MidiDevice::SYNTH_MIDI)
+ printf("synth midi device <%s> ", device->name().latin1());
+ else
+ printf("is midi but unknown device type:%d, ", device->deviceType());
+ }
+ else
+ printf("is midi but invalid device, ");
+
+ printf("channel:%d\n", channel);
+ }
+ /*
+ else
+ if (type == JACK_MIDI_ROUTE)
{
- if (type == 0)
- printf("Route dump: track <%s> channel %d\n", track->name().latin1(), channel);
- else {
if (!checkAudioDevice()) return;
- printf("Route dump: jPort <%s> channel %d\n",
- audioDevice->portName(jackPort).latin1(), channel);
- }
+ printf("Route dump: jMidiPort <%s>\n",
+ audioDevice->portName(device->clientPort()).latin1());
}
+ else
+ if (type == ALSA_MIDI_ROUTE)
+ {
+ // TODO
+ //if (!checkAudioDevice()) return;
+ //printf("Route dump: aMidiPort <%s>\n",
+ // audioDevice->portName(device->clientJackPort()).latin1());
+ printf("Route dump: aMidiPort\n");
+ }
+ */
+ else
+ printf("Route dump: unknown route type:%d\n", type);
+}
//---------------------------------------------------------
// operator==
//---------------------------------------------------------
bool Route::operator==(const Route& a) const
+{
+ if ((type == a.type) && (channel == a.channel))
+ //if (type == a.type)
{
- if ((type == a.type) && (channel == a.channel)) {
- if (type == 0)
- return track == a.track;
- else {
- if (!checkAudioDevice()) return false;
- return audioDevice->portName(jackPort) == audioDevice->portName(a.jackPort);
- }
+ if (type == TRACK_ROUTE)
+ {
+ //return track == a.track;
+ //return track == a.track && remoteChannel == a.remoteChannel;
+ return track == a.track && channels == a.channels && remoteChannel == a.remoteChannel;
+
+ /*
+ if(a.track == track && a.remoteChannel == remoteChannel)
+ {
+ int tcompch = rt.channel;
+ if(tcompch == -1)
+ tcompch = 0;
+ int tcompchs = rt.channels;
+ if(tcompchs == -1)
+ tcompchs = isOutput ? t->channels() : track->channels();
+
+ int compch = ir->channel;
+ if(compch == -1)
+ compch = 0;
+ int compchs = ir->channels;
+ if(compchs == -1)
+ compchs = isOutput ? t->channels() : ir->track->channels();
+
+ if(compch == tcompch && compchs == tcompchs)
+ {
+ chpup->setItemChecked(id, true);
+ break;
+ }
+ }
+ */
+
}
- return false;
+ else
+ if(channel == a.channel)
+ {
+ if (type == JACK_ROUTE)
+ {
+ if (!checkAudioDevice()) return false;
+ return audioDevice->portName(jackPort) == audioDevice->portName(a.jackPort);
+ }
+ else
+ if (type == MIDI_DEVICE_ROUTE)
+ {
+ //if(device)
+ if(device && a.device && device->deviceType() == a.device->deviceType())
+ {
+ if(device->deviceType() == MidiDevice::JACK_MIDI)
+ {
+ if (!checkAudioDevice()) return false;
+ return audioDevice->portName(device->clientPort()) == audioDevice->portName(a.device->clientPort());
+ }
+ else
+ if(device->deviceType() == MidiDevice::ALSA_MIDI)
+ // TODO: OK ??
+ return device->clientPort() == a.device->clientPort() && (channel == a.channel);
+ else
+ if(device->deviceType() == MidiDevice::SYNTH_MIDI)
+ return device->name() == a.device->name();
+ }
+ }
+
+ /*
+ if (type == JACK_MIDI_ROUTE)
+ {
+ if (!checkAudioDevice()) return false;
+ return audioDevice->portName(device->clientPort()) == audioDevice->portName(a.device->clientPort());
+ }
+ else
+ if (type == ALSA_MIDI_ROUTE)
+ {
+ // TODO
+ //if (!checkAudioDevice()) return false;
+ //return audioDevice->portName(device->clientJackPort()) == audioDevice->portName(a.device->clientJackPort());
+ //return device->name() == a.device->name();
+ return device->clientPort() == a.device->clientPort() && (channel == a.channel);
+ }
+ */
+ }
}
+ return false;
+}
diff --git a/muse/muse/route.h b/muse/muse/route.h
index ba40bb06..d8217207 100644
--- a/muse/muse/route.h
+++ b/muse/muse/route.h
@@ -9,34 +9,69 @@
#ifndef __ROUTE_H__
#define __ROUTE_H__
+//#include <alsa/asoundlib.h>
#include <vector>
+#include <map>
class QString;
-class AudioTrack;
+//class AudioTrack;
+class Track;
+//class MidiJackDevice;
+class MidiDevice;
+class Xml;
//---------------------------------------------------------
// Route
//---------------------------------------------------------
-enum { TRACK_ROUTE=0, JACK_ROUTE=1 };
+//enum { TRACK_ROUTE=0, JACK_ROUTE=1 };
struct Route {
+ //enum { TRACK_ROUTE=0, JACK_ROUTE=1, JACK_MIDI_ROUTE=2, ALSA_MIDI_ROUTE=3 };
+ enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2 };
+
union {
- AudioTrack* track;
+ //AudioTrack* track;
+ Track* track;
+ //MidiJackDevice* device;
+ MidiDevice* device;
void* jackPort;
};
+
+ //snd_seq_addr_t alsaAdr;
+
+ // Starting source channel (of the owner of this route). Normally zero for mono or stereo tracks, higher for multi-channel tracks.
int channel;
- unsigned char type; // 0 - track, 1 - jackPort
+ // Number of channels being routed.
+ int channels;
+
+ // Allow for multi-channel syntis to feed to/from regular tracks, and to feed one to another.
+ // If a synti is feeding to/from a regular track, remoteChannel is the 'starting' channel of this multi-channel synti.
+ // If a synti is feeding to/from another synti, this is not used and individual channels are routed using channel instead.
+ int remoteChannel;
+
+ unsigned char type; // 0 - track, 1 - jackPort, 2 - jack midi device, 3 - alsa midi device
Route(void* t, int ch=-1);
- Route(AudioTrack* t, int ch);
- Route(const QString&, bool dst, int ch);
+ //Route(AudioTrack* t, int ch);
+ //Route(Track* t, int ch);
+ Route(Track* t, int ch = -1, int chans = -1);
+ //Route(Track* t, int ch = -1);
+
+ //Route(MidiJackDevice* d);
+ Route(MidiDevice* d, int ch);
+ //Route(const QString&, bool dst, int ch);
+ Route(const QString&, bool dst, int ch, int rtype = -1);
Route();
QString name() const;
bool operator==(const Route& a) const;
bool isValid() const {
- return ((type == 0) && (track != 0)) || ((type == 1) && (jackPort != 0));
+ //return ((type == 0) && (track != 0)) || ((type == 1) && (jackPort != 0));
+ return ((type == TRACK_ROUTE) && (track != 0)) || ((type == JACK_ROUTE) && (jackPort != 0)) ||
+ //(((type == JACK_MIDI_ROUTE) || (type == ALSA_MIDI_ROUTE)) && (device != 0));
+ ((type == MIDI_DEVICE_ROUTE) && (device != 0));
}
+ void read(Xml& xml);
void dump() const;
};
@@ -54,8 +89,25 @@ typedef RouteList::const_iterator ciRoute;
extern void addRoute(Route, Route);
extern void removeRoute(Route, Route);
-extern Route name2route(const QString&, bool dst);
+//extern Route name2route(const QString&, bool dst);
+extern Route name2route(const QString&, bool dst, int rtype = -1);
extern bool checkRoute(const QString&, const QString&);
+//---------------------------------------------------------
+// RouteMenuMap
+//---------------------------------------------------------
+
+//struct TRouteMenuMap{
+// Route r;
+// };
+//typedef std::map<int, TRouteMenuMap, std::less<int> >::iterator iRouteMenuMap;
+//typedef std::map<int, TRouteMenuMap, std::less<int> >::const_iterator ciRouteMenuMap;
+//typedef std::map<int, TRouteMenuMap, std::less<int> > RouteMenuMap;
+typedef std::map<int, Route, std::less<int> >::iterator iRouteMenuMap;
+typedef std::map<int, Route, std::less<int> >::const_iterator ciRouteMenuMap;
+typedef std::map<int, Route, std::less<int> > RouteMenuMap;
+typedef std::pair<int, Route> pRouteMenuMap;
+typedef std::pair<iRouteMenuMap, bool > rpRouteMenuMap;
+
#endif
diff --git a/muse/muse/seqmsg.cpp b/muse/muse/seqmsg.cpp
index 42227305..02fbdf01 100644
--- a/muse/muse/seqmsg.cpp
+++ b/muse/muse/seqmsg.cpp
@@ -21,6 +21,7 @@
#include "alsamidi.h"
#include "audio.h"
#include "arranger.h"
+#include "driver/jackmidi.h"
//---------------------------------------------------------
// sendMsg
@@ -72,14 +73,58 @@ bool Audio::sendMessage(AudioMsg* m, bool doUndo)
//---------------------------------------------------------
void Audio::msgRemoveRoute(Route src, Route dst)
- {
+{
msgRemoveRoute1(src, dst);
- if (!checkAudioDevice()) return;
- if (src.type == JACK_ROUTE)
+ //if (!checkAudioDevice()) return;
+ if (src.type == Route::JACK_ROUTE)
+ {
+ if (!checkAudioDevice()) return;
+
+ //if(dst.type == Route::JACK_MIDI_ROUTE)
+ if(dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(dst.device);
+ //if(jmd)
+ if(dst.device)
+ {
+ if(dst.device->deviceType() == MidiDevice::JACK_MIDI)
+ audioDevice->disconnect(src.jackPort, dst.device->clientPort());
+ //else
+ //{
+ // TODO...
+ //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(dst.device);
+ //if(amd)
+ //}
+ }
+ }
+ else
audioDevice->disconnect(src.jackPort, ((AudioInput*)dst.track)->jackPort(dst.channel));
- else if (dst.type == JACK_ROUTE)
+ }
+ else if (dst.type == Route::JACK_ROUTE)
+ {
+ if (!checkAudioDevice()) return;
+
+ //if(src.type == Route::JACK_MIDI_ROUTE)
+ if(src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(src.device);
+ //if(jmd)
+ if(src.device)
+ {
+ if(src.device->deviceType() == MidiDevice::JACK_MIDI)
+ audioDevice->disconnect(src.device->clientPort(), dst.jackPort);
+ //else
+ //{
+ // TODO...
+ //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(src.device);
+ //if(amd)
+ //}
+ }
+ }
+ else
audioDevice->disconnect(((AudioOutput*)src.track)->jackPort(src.channel), dst.jackPort);
}
+}
//---------------------------------------------------------
// msgRemoveRoute1
@@ -100,16 +145,58 @@ void Audio::msgRemoveRoute1(Route src, Route dst)
void Audio::msgAddRoute(Route src, Route dst)
{
- if (src.type == JACK_ROUTE) {
+ if (src.type == Route::JACK_ROUTE)
+ {
if (!checkAudioDevice()) return;
if (isRunning())
+ {
+ //if(dst.type == Route::JACK_MIDI_ROUTE)
+ if(dst.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(dst.device);
+ //if(jmd)
+ if(dst.device)
+ {
+ if(dst.device->deviceType() == MidiDevice::JACK_MIDI)
+ audioDevice->connect(src.jackPort, dst.device->clientPort());
+ //else
+ //{
+ // TODO...
+ //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(dst.device);
+ //if(amd)
+ //}
+ }
+ }
+ else
audioDevice->connect(src.jackPort, ((AudioInput*)dst.track)->jackPort(dst.channel));
- }
- else if (dst.type == JACK_ROUTE) {
+ }
+ }
+ else if (dst.type == Route::JACK_ROUTE)
+ {
if (!checkAudioDevice()) return;
if (audio->isRunning())
+ {
+ //if(src.type == Route::JACK_MIDI_ROUTE)
+ if(src.type == Route::MIDI_DEVICE_ROUTE)
+ {
+ //MidiJackDevice* jmd = dynamic_cast<MidiJackDevice*>(src.device);
+ //if(jmd)
+ if(src.device)
+ {
+ if(src.device->deviceType() == MidiDevice::JACK_MIDI)
+ audioDevice->connect(src.device->clientPort(), dst.jackPort);
+ //else
+ //{
+ // TODO...
+ //MidiAlsaDevice* amd = dynamic_cast<MidiAlsaDevice*>(src.device);
+ //if(amd)
+ //}
+ }
+ }
+ else
audioDevice->connect(((AudioOutput*)src.track)->jackPort(dst.channel), dst.jackPort);
- }
+ }
+ }
msgAddRoute1(src, dst);
}
@@ -203,57 +290,117 @@ void Audio::msgSetChannels(AudioTrack* node, int n)
QString name = node->name();
int mc = std::max(n, node->channels());
- if (!name.isEmpty()) {
- if (node->type() == Track::AUDIO_INPUT) {
- if (!checkAudioDevice()) return;
- AudioInput* ai = (AudioInput*)node;
- for (int i = 0; i < mc; ++i) {
- if (i < n && ai->jackPort(i) == 0) {
- char buffer[128];
- snprintf(buffer, 128, "%s-%d", name.latin1(), i);
- //ai->setJackPort(i, audioDevice->registerInPort(buffer));
- ai->setJackPort(i, audioDevice->registerInPort(buffer, false));
- }
- else if ((i >= n) && ai->jackPort(i)) {
- RouteList* ir = node->inRoutes();
- for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) {
- Route r = *ii;
- if ((r.type == JACK_ROUTE) && (r.channel == i)) {
- msgRemoveRoute(r, Route(node,i));
- break;
- }
- }
- audioDevice->unregisterPort(ai->jackPort(i));
- ai->setJackPort(i, 0);
- }
- }
+ if (!name.isEmpty())
+ {
+ if (node->type() == Track::AUDIO_INPUT)
+ {
+ if (!checkAudioDevice()) return;
+ AudioInput* ai = (AudioInput*)node;
+ for (int i = 0; i < mc; ++i)
+ {
+ if (i < n && ai->jackPort(i) == 0)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s-%d", name.latin1(), i);
+ //ai->setJackPort(i, audioDevice->registerInPort(buffer));
+ ai->setJackPort(i, audioDevice->registerInPort(buffer, false));
+ }
+ else if ((i >= n) && ai->jackPort(i))
+ {
+ RouteList* ir = node->inRoutes();
+ for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)
+ {
+ Route r = *ii;
+ if ((r.type == Route::JACK_ROUTE) && (r.channel == i))
+ {
+ msgRemoveRoute(r, Route(node,i));
+ break;
+ }
}
- else if (node->type() == Track::AUDIO_OUTPUT) {
+ audioDevice->unregisterPort(ai->jackPort(i));
+ ai->setJackPort(i, 0);
+ }
+ }
+ }
+ else if (node->type() == Track::AUDIO_OUTPUT)
+ {
if (!checkAudioDevice()) return;
AudioOutput* ao = (AudioOutput*)node;
- for (int i = 0; i < mc; ++i) {
+ for (int i = 0; i < mc; ++i)
+ {
void* jp = ao->jackPort(i);
- if (i < n && jp == 0) {
+ if (i < n && jp == 0)
+ {
char buffer[128];
snprintf(buffer, 128, "%s-%d", name.latin1(), i);
//ao->setJackPort(i, audioDevice->registerOutPort(buffer));
ao->setJackPort(i, audioDevice->registerOutPort(buffer, false));
- }
- else if (i >= n && jp) {
+ }
+ else if (i >= n && jp)
+ {
RouteList* ir = node->outRoutes();
- for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) {
+ for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)
+ {
Route r = *ii;
- if ((r.type == JACK_ROUTE) && (r.channel == i)) {
+ if ((r.type == Route::JACK_ROUTE) && (r.channel == i))
+ {
msgRemoveRoute(Route(node,i), r);
break;
- }
}
+ }
audioDevice->unregisterPort(jp);
ao->setJackPort(i, 0);
- }
}
}
}
+ }
+
+ /* TODO TODO: Change all stereo routes to mono.
+ // If we are going from stereo to mono we need to disconnect any stray synti 'mono last channel'...
+ if(n == 1 && node->channels() > 1)
+ {
+ // This should always happen - syntis are fixed channels, user cannot change them. But to be safe...
+ if(node->type() != Track::AUDIO_SOFTSYNTH)
+ {
+ if(node->type() != Track::AUDIO_INPUT)
+ {
+ RouteList* rl = node->inRoutes();
+ for(iRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ // Only interested in synth tracks.
+ if(r->type != Route::TRACK_ROUTE || r->track->type() != Track::AUDIO_SOFTSYNTH)
+ continue;
+ // If it's the last channel...
+ if(r->channel + 1 == ((AudioTrack*)r->track)->totalOutChannels())
+ {
+ msgRemoveRoute(*r, Route(node, r->channel));
+ //msgRemoveRoute(r, Route(node, r->remoteChannel));
+ break;
+ }
+ }
+ }
+
+ if(node->type() != Track::AUDIO_OUTPUT)
+ {
+ RouteList* rl = node->outRoutes();
+ for(iRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ // Only interested in synth tracks.
+ if(r->type != Route::TRACK_ROUTE || r->track->type() != Track::AUDIO_SOFTSYNTH)
+ continue;
+ // If it's the last channel...
+ if(r->channel + 1 == ((AudioTrack*)r->track)->totalOutChannels())
+ {
+ msgRemoveRoute(Route(node, r->channel), *r);
+ //msgRemoveRoute(Route(node, r->remoteChannel), r);
+ break;
+ }
+ }
+ }
+ }
+ }
+ */
+
AudioMsg msg;
msg.id = AUDIO_SET_CHANNELS;
msg.snode = node;
diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp
index 7b1e46bb..fa08f27f 100644
--- a/muse/muse/song.cpp
+++ b/muse/muse/song.cpp
@@ -14,6 +14,8 @@
#include <qpopupmenu.h>
#include <qdir.h>
#include <qaction.h>
+#include <qcursor.h>
+#include <qbutton.h>
#include "app.h"
#include "song.h"
@@ -42,6 +44,26 @@ extern void clearMidiTransforms();
extern void clearMidiInputTransforms();
Song* song;
+/*
+//---------------------------------------------------------
+// RoutingMenuItem
+//---------------------------------------------------------
+
+class RoutingMenuItem : public QCustomMenuItem
+{
+ Route route;
+ //virtual QSize sizeHint() { return QSize(80, h); }
+ virtual void paint(QPainter* p, const QColorGroup&, bool, bool, int x, int y, int w, int h)
+ {
+ p->fillRect(x, y, w, h, QBrush(lightGray));
+ p->drawText(x, y, w, h, AlignCenter, route.name());
+ }
+
+ public:
+ RoutingMenuItem(const Route& r) : route(r) { }
+};
+*/
+
//---------------------------------------------------------
// Song
//---------------------------------------------------------
@@ -235,10 +257,16 @@ Track* Song::addTrack(int t)
case Track::AUDIO_GROUP:
case Track::AUDIO_AUX:
case Track::AUDIO_INPUT:
- case Track::AUDIO_SOFTSYNTH:
+ // p3.3.38
+ //case Track::AUDIO_SOFTSYNTH:
audio->msgAddRoute(Route((AudioTrack*)track, -1), Route(ao, -1));
updateFlags |= SC_ROUTE;
break;
+ // p3.3.38 It should actually never get here now, but just in case.
+ case Track::AUDIO_SOFTSYNTH:
+ audio->msgAddRoute(Route((AudioTrack*)track, 0, ((AudioTrack*)track)->channels()), Route(ao, 0, ((AudioTrack*)track)->channels()));
+ updateFlags |= SC_ROUTE;
+ break;
}
}
audio->msgUpdateSoloStates();
@@ -853,7 +881,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start
}
newPart->setLenTick(endTick); // endTick - part->tick()
- // Added by Tim. p3.3.6
//printf("Song::cmdAddRecordedEvents before changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());
// Change the part.
@@ -866,7 +893,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start
// Now add all of the new part's port controller values, and do all clone parts.
addPortCtrlEvents(newPart, true);
- // Added by Tim. p3.3.6
//printf("Song::cmdAddRecordedEvents after changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());
//undoOp(UndoOp::ModifyPart, part, newPart);
@@ -877,7 +903,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start
//part->events()->incARef(-1);
updateFlags |= SC_PART_MODIFIED;
- // Added by Tim. p3.3.6
//printf("Song::cmdAddRecordedEvents final part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount());
*/
@@ -1123,7 +1148,7 @@ void Song::setPlay(bool f)
{
if (extSyncFlag.value()) {
if (debugMsg)
- printf("not allowed while using external sync");
+ printf("not allowed while using external sync");
return;
}
// only allow the user to set the button "on"
@@ -1137,7 +1162,7 @@ void Song::setStop(bool f)
{
if (extSyncFlag.value()) {
if (debugMsg)
- printf("not allowed while using external sync");
+ printf("not allowed while using external sync");
return;
}
// only allow the user to set the button "on"
@@ -1857,7 +1882,6 @@ void Song::cmdRemovePart(Part* part)
//void Song::cmdChangePart(Part* oldPart, Part* newPart)
void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClones)
{
- // Added by Tim. p3.3.6
//printf("Song::cmdChangePart before changePart oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());
if(doCtrls)
@@ -1875,7 +1899,6 @@ void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClon
//oldPart->replaceClone(newPart);
- // Added by Tim. p3.3.6
//printf("Song::cmdChangePart before repl/unchClone oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());
replaceClone(oldPart, newPart);
@@ -1883,7 +1906,6 @@ void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClon
if(doCtrls)
addPortCtrlEvents(newPart, doClones);
- // Added by Tim. p3.3.6
//printf("Song::cmdChangePart after repl/unchClone oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn());
updateFlags = SC_PART_MODIFIED;
@@ -2028,6 +2050,20 @@ void Song::cleanupForQuit()
// Remove the controllers and the values.
midiPorts[i].controller()->clearDelete(true);
+ // Can't do this here. Jack isn't running.
+ /*
+ if(debugMsg)
+ printf("deleting midi devices\n");
+ for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
+ {
+ // Since Syntis are midi devices, there's no need to delete them below.
+ if((*imd)->isSynti())
+ continue;
+ delete (*imd);
+ }
+ midiDevices.clear(); // midi devices
+ */
+
if(debugMsg)
printf("deleting synths\n");
// Delete all synths.
@@ -2385,7 +2421,6 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo
dctl |= drumMap[note].anote;
}
- // Added by Tim. p3.3.6
//printf("Song::execMidiAutomationCtlPopup ctlnum:%d dctl:%d anote:%d\n", ctlnum, dctl, drumMap[ctlnum & 0x7f].anote);
unsigned tick = cpos();
@@ -2428,7 +2463,6 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo
ev = i->second;
if(ev.type() == Controller)
{
- // Added by Tim. p3.3.6
//printf("Song::execMidiAutomationCtlPopup ev.dataA:%d\n", ev.dataA());
//if(ev.dataA() == dctl)
@@ -2651,7 +2685,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)
for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)
{
Route r = *ii;
- if ((r.type == JACK_ROUTE) && (r.channel == ch))
+ if ((r.type == Route::JACK_ROUTE) && (r.channel == ch))
{
if(disconnect)
audioDevice->disconnect(ao->jackPort(ch), r.jackPort);
@@ -2684,7 +2718,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)
for (iRoute ii = ir->begin(); ii != ir->end(); ++ii)
{
Route r = *ii;
- if ((r.type == JACK_ROUTE) && (r.channel == ch))
+ if ((r.type == Route::JACK_ROUTE) && (r.channel == ch))
{
if(disconnect)
audioDevice->disconnect(r.jackPort, ai->jackPort(ch));
@@ -2708,6 +2742,199 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)
}
//---------------------------------------------------------
+// chooseMidiRoutes
+//---------------------------------------------------------
+
+void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
+{
+ if(!track)
+ return;
+
+ //if(!track->isMidiTrack())
+ // return;
+
+ //if(dst)
+ //{
+ // TODO
+
+ //}
+ //else
+ //{
+ RouteList* rl = dst ? track->outRoutes() : track->inRoutes();
+ //Route dst(track, -1);
+
+ QPopupMenu* pup = new QPopupMenu(parent);
+ pup->setCheckable(true);
+
+ int gid = 0;
+
+ //MidiInPortList* tl = song->midiInPorts();
+ //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ //MidiInPort* track = *i;
+ // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports.
+ MidiPort* mp = &midiPorts[i];
+ MidiDevice* md = mp->device();
+ if(!md)
+ continue;
+
+ if(!(md->rwFlags() & (dst ? 1 : 2)))
+ continue;
+
+ //printf("MidiStrip::iRoutePressed adding submenu portnum:%d\n", i);
+
+ //QMenu* m = menu->addMenu(track->name());
+ QPopupMenu* subp = new QPopupMenu(parent);
+
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ //QAction* a = m->addAction(QString("Channel %1").arg(ch+1));
+ //subp->insertItem(QT_TR_NOOP(QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch);
+ gid = i * MIDI_CHANNELS + ch;
+
+ //printf("MidiStrip::iRoutePressed inserting gid:%d\n", gid);
+
+ subp->insertItem(QString("Channel %1").arg(ch+1), gid);
+ //a->setCheckable(true);
+ //Route src(track, ch, RouteNode::TRACK);
+ //Route src(md, ch);
+ //Route r = Route(src, dst);
+ //a->setData(QVariant::fromValue(r));
+ //a->setChecked(rl->indexOf(r) != -1);
+ Route srcRoute(md, ch);
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if(*ir == dst)
+ if(*ir == srcRoute)
+ {
+ subp->setItemChecked(gid, true);
+ break;
+ }
+ }
+ }
+ pup->insertItem(QT_TR_NOOP(md->name()), subp);
+ }
+
+ /*
+ QPopupMenu* pup = new QPopupMenu(iR);
+ pup->setCheckable(true);
+ //MidiTrack* t = (MidiTrack*)track;
+ RouteList* irl = track->inRoutes();
+
+ MidiTrack* t = (MidiTrack*)track;
+ int gid = 0;
+ for (int i = 0; i < channel; ++i)
+ {
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if (!checkAudioDevice()) return;
+ std::list<QString> ol = audioDevice->outputPorts();
+ for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ Route dst(*ip, true, i);
+ ++gid;
+ for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) {
+ if (*ir == dst) {
+ pup->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ if (i+1 != channel)
+ pup->insertSeparator();
+ }
+ */
+
+ if(pup->count() == 0)
+ {
+ delete pup;
+ return;
+ }
+
+ int n = pup->exec(QCursor::pos());
+ delete pup;
+ if (n != -1)
+ {
+ int mdidx = n / MIDI_CHANNELS;
+ int ch = n % MIDI_CHANNELS;
+
+ //if(debugMsg)
+ //printf("Song::chooseMidiRoutes mdidx:%d ch:%d\n", mdidx, ch);
+
+ MidiPort* mp = &midiPorts[mdidx];
+ MidiDevice* md = mp->device();
+ if(!md)
+ return;
+
+ //if(!(md->rwFlags() & 2))
+ if(!(md->rwFlags() & (dst ? 1 : 2)))
+ return;
+
+
+ //QString s(pup->text(n));
+ //QT_TR_NOOP(md->name())
+
+ //Route srcRoute(s, false, -1);
+ Route aRoute(md, ch);
+ //Route srcRoute(md, -1);
+ //Route dstRoute(track, -1);
+ Route bRoute(track, ch);
+
+ //if (track->type() == Track::AUDIO_INPUT)
+ // srcRoute.channel = dstRoute.channel = n & 0xf;
+ iRoute iir = rl->begin();
+ for (; iir != rl->end(); ++iir)
+ {
+ //if(*iir == (dst ? bRoute : aRoute))
+ if(*iir == aRoute)
+ break;
+ }
+ if (iir != rl->end())
+ {
+ // disconnect
+ if(dst)
+ {
+ //printf("Song::chooseMidiRoutes removing route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
+ audio->msgRemoveRoute(bRoute, aRoute);
+ }
+ else
+ {
+ //printf("Song::chooseMidiRoutes removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgRemoveRoute(aRoute, bRoute);
+ }
+ }
+ else
+ {
+ // connect
+ if(dst)
+ {
+ //printf("Song::chooseMidiRoutes adding route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
+ audio->msgAddRoute(bRoute, aRoute);
+ }
+ else
+ {
+ //printf("Song::chooseMidiRoutes adding route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgAddRoute(aRoute, bRoute);
+ }
+ }
+
+ //printf("Song::chooseMidiRoutes calling msgUpdateSoloStates\n");
+ audio->msgUpdateSoloStates();
+ //printf("Song::chooseMidiRoutes calling song->update\n");
+ song->update(SC_ROUTE);
+ }
+ //delete pup;
+ parent->setDown(false); // pup->exec() catches mouse release event
+ //printf("Song::chooseMidiRoutes end\n");
+
+ //}
+}
+
+//---------------------------------------------------------
// insertTrack0
//---------------------------------------------------------
@@ -2725,7 +2952,6 @@ void Song::insertTrack0(Track* track, int idx)
void Song::insertTrack1(Track* track, int /*idx*/)
{
- // Added by Tim. p3.3.13
//printf("Song::insertTrack1 track:%lx\n", track);
switch(track->type()) {
@@ -2742,7 +2968,6 @@ void Song::insertTrack1(Track* track, int /*idx*/)
break;
}
- // Added by Tim. p3.3.13
//printf("Song::insertTrack1 end of function\n");
}
@@ -2753,8 +2978,7 @@ void Song::insertTrack1(Track* track, int /*idx*/)
//---------------------------------------------------------
void Song::insertTrack2(Track* track, int idx)
- {
- // Added by Tim. p3.3.13
+{
//printf("Song::insertTrack2 track:%lx\n", track);
int n;
@@ -2805,11 +3029,9 @@ void Song::insertTrack2(Track* track, int idx)
// initialize missing aux send
//
iTrack i = _tracks.index2iterator(idx);
- // Added by Tim. p3.3.13
//printf("Song::insertTrack2 inserting into _tracks...\n");
_tracks.insert(i, track);
- // Added by Tim. p3.3.13
//printf("Song::insertTrack2 inserted\n");
n = _auxs.size();
@@ -2822,6 +3044,7 @@ void Song::insertTrack2(Track* track, int idx)
}
}
+ /*
//
// add routes
//
@@ -2848,11 +3071,51 @@ void Song::insertTrack2(Track* track, int idx)
for (ciRoute r = rl->begin(); r != rl->end(); ++r)
r->track->inRoutes()->push_back(src);
}
+ */
- // Added by Tim. p3.3.13
- //printf("Song::insertTrack2 end of function\n");
+ // p3.3.38
+ //
+ // add routes
+ //
+
+ if (track->type() == Track::AUDIO_OUTPUT)
+ {
+ const RouteList* rl = track->inRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->outRoutes()->push_back(*r);
+ }
+ }
+ else if (track->type() == Track::AUDIO_INPUT)
+ {
+ const RouteList* rl = track->outRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->inRoutes()->push_back(*r);
+ }
}
+ else
+ {
+ const RouteList* rl = track->inRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->outRoutes()->push_back(*r);
+ }
+ rl = track->outRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->inRoutes()->push_back(*r);
+ }
+ }
+
+ //printf("Song::insertTrack2 end of function\n");
+
+}
//---------------------------------------------------------
// insertTrack3
@@ -2861,7 +3124,6 @@ void Song::insertTrack2(Track* track, int idx)
void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning: unused parameter
{
- // Added by Tim. p3.3.13
//printf("Song::insertTrack3\n");
/*
@@ -2932,7 +3194,7 @@ void Song::removeTrack1(Track* track)
//---------------------------------------------------------
void Song::removeTrack2(Track* track)
- {
+{
switch(track->type()) {
case Track::MIDI:
case Track::DRUM:
@@ -2970,6 +3232,9 @@ void Song::removeTrack2(Track* track)
break;
}
_tracks.erase(track);
+
+
+ /*
if (track->isMidiTrack())
return;
//
@@ -2996,7 +3261,49 @@ void Song::removeTrack2(Track* track)
for (ciRoute r = rl->begin(); r != rl->end(); ++r)
r->track->inRoutes()->removeRoute(src);
}
+ */
+
+ // p3.3.38
+
+ //
+ // remove routes
+ //
+
+ if (track->type() == Track::AUDIO_OUTPUT)
+ {
+ const RouteList* rl = track->inRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->outRoutes()->removeRoute(*r);
+ }
}
+ else if (track->type() == Track::AUDIO_INPUT)
+ {
+ const RouteList* rl = track->outRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->inRoutes()->removeRoute(*r);
+ }
+ }
+ else
+ {
+ const RouteList* rl = track->inRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->outRoutes()->removeRoute(*r);
+ }
+ rl = track->outRoutes();
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(r->track == track)
+ r->track->inRoutes()->removeRoute(*r);
+ }
+ }
+
+}
//---------------------------------------------------------
// removeTrack3
diff --git a/muse/muse/song.h b/muse/muse/song.h
index 0e08d8ab..6c76362b 100644
--- a/muse/muse/song.h
+++ b/muse/muse/song.h
@@ -36,6 +36,7 @@ class MarkerList;
class Marker;
class SNode;
class QPopupMenu;
+class QButton;
class MidiPort;
class MidiDevice;
@@ -301,6 +302,7 @@ class Song : public QObject {
int execMidiAutomationCtlPopup(MidiTrack*, MidiPart*, const QPoint&, int);
void connectJackRoutes(AudioTrack* track, bool disconnect);
void updateSoloStates();
+ void chooseMidiRoutes(QButton* /*parent*/, MidiTrack* /*track*/, bool /*dst*/);
//-----------------------------------------
// undo, redo
diff --git a/muse/muse/songfile.cpp b/muse/muse/songfile.cpp
index 2e4a5395..07bf1e31 100644
--- a/muse/muse/songfile.cpp
+++ b/muse/muse/songfile.cpp
@@ -29,6 +29,7 @@
#include "midictrl.h"
#include "amixer.h"
#include "conf.h"
+#include "driver/jackmidi.h"
//struct ClonePart {
//const EventList* el;
@@ -1428,12 +1429,25 @@ void Song::write(int level, Xml& xml) const
// write routing
for (ciTrack i = _tracks.begin(); i != _tracks.end(); ++i) {
- if ((*i)->isMidiTrack())
- continue;
- WaveTrack* track = (WaveTrack*)(*i);
- track->writeRouting(level, xml);
+
+ // p3.3.38 Changed
+ //if ((*i)->isMidiTrack())
+ // continue;
+ //WaveTrack* track = (WaveTrack*)(*i);
+ //track->writeRouting(level, xml);
+
+ (*i)->writeRouting(level, xml);
}
+ // Write Jack midi routing.
+ for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) {
+ //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(*i);
+ //if (!mjd)
+ // continue;
+ //mjd->writeRouting(level, xml);
+ (*i)->writeRouting(level, xml);
+ }
+
tempomap.write(level, xml);
sigmap.write(level, xml);
_markerList->write(level, xml);
diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp
index 6b8e959c..0fbfa144 100644
--- a/muse/muse/sync.cpp
+++ b/muse/muse/sync.cpp
@@ -18,6 +18,7 @@
#include "audiodev.h"
#include "gconfig.h"
#include "xml.h"
+#include "midi.h"
//int rxSyncPort = -1; // receive from all ports
//int txSyncPort = 1;
@@ -26,7 +27,7 @@
//MidiSyncPort midiSyncPorts[MIDI_PORTS];
int volatile curMidiSyncInPort = -1;
-bool debugSync = false;
+bool debugSync = true;
int mtcType = 1;
MTC mtcOffset;
@@ -880,10 +881,10 @@ void MidiSeq::realtimeSystemInput(int port, int c)
MidiPort* mp = &midiPorts[port];
// Trigger on any tick, clock, or realtime command.
- if(c == 0xf9) // Tick
+ if(c == ME_TICK) // Tick
mp->syncInfo().trigTickDetect();
else
- if(c == 0xf8) // Clock
+ if(c == ME_CLOCK) // Clock
mp->syncInfo().trigMCSyncDetect();
else
mp->syncInfo().trigMRTDetect(); // Other
@@ -891,7 +892,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
// External sync not on? Clock in not turned on? Otherwise realtime in not turned on?
if(!extSyncFlag.value())
return;
- if(c == 0xf8)
+ if(c == ME_CLOCK)
{
if(!mp->syncInfo().MCIn())
return;
@@ -902,7 +903,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
switch(c) {
- case 0xf8: // midi clock (24 ticks / quarter note)
+ case ME_CLOCK: // midi clock (24 ticks / quarter note)
{
// Not for the current in port? Forget it.
if(port != curMidiSyncInPort)
@@ -1194,7 +1195,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
}
break;
- case 0xf9: // midi tick (every 10 msec)
+ case ME_TICK: // midi tick (every 10 msec)
// FIXME: Unfinished? mcStartTick is uninitialized and Song::setPos doesn't set it either. Dangerous to allow this.
//if (mcStart) {
// song->setPos(0, mcStartTick);
@@ -1202,7 +1203,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
// return;
// }
break;
- case 0xfa: // start
+ case ME_START: // start
// Re-transmit start to other devices if clock out turned on.
for(int p = 0; p < MIDI_PORTS; ++p)
//if(p != port && midiPorts[p].syncInfo().MCOut())
@@ -1259,7 +1260,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
playStateExt = true;
}
break;
- case 0xfb: // continue
+ case ME_CONTINUE: // continue
// Re-transmit continue to other devices if clock out turned on.
for(int p = 0; p < MIDI_PORTS; ++p)
//if(p != port && midiPorts[p].syncInfo().MCOut())
@@ -1286,7 +1287,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)
playStateExt = true;
}
break;
- case 0xfc: // stop
+ case ME_STOP: // stop
{
// p3.3.35
// Stop the increment right away.
@@ -1326,10 +1327,11 @@ void MidiSeq::realtimeSystemInput(int port, int c)
}
break;
- case 0xfd: // unknown
- case 0xfe: // active sensing
- case 0xff: // system reset
- break;
+ //case 0xfd: // unknown
+ //case ME_SENSE: // active sensing
+ //case ME_META: // system reset (reset is 0xff same enumeration as file meta event)
+ default:
+ break;
}
}
diff --git a/muse/muse/synth.cpp b/muse/muse/synth.cpp
index e3bf1582..24780a52 100644
--- a/muse/muse/synth.cpp
+++ b/muse/muse/synth.cpp
@@ -126,12 +126,12 @@ static Synth* findSynth(const QString& sclass, const QString& label)
}
//---------------------------------------------------------
-// createSynthI
+// createSynthInstance
// create a synthesizer instance of class "label"
//---------------------------------------------------------
//static SynthI* createSynthI(const QString& sclass)
-static SynthI* createSynthI(const QString& sclass, const QString& label)
+static SynthI* createSynthInstance(const QString& sclass, const QString& label)
{
//Synth* s = findSynth(sclass);
Synth* s = findSynth(sclass, label);
@@ -149,7 +149,7 @@ static SynthI* createSynthI(const QString& sclass, const QString& label)
}
}
else
- printf("synthi class:%s label:%s not found\n", sclass.latin1(), label.latin1());
+ printf("createSynthInstance: synthi class:%s label:%s not found\n", sclass.latin1(), label.latin1());
return si;
}
@@ -300,6 +300,16 @@ int MessSynthIF::channels() const
return _mess->channels();
}
+int MessSynthIF::totalOutChannels() const
+ {
+ return _mess->channels();
+ }
+
+int MessSynthIF::totalInChannels() const
+ {
+ return 0;
+ }
+
//SynthIF* MessSynth::createSIF() const
SynthIF* MessSynth::createSIF(SynthI* si)
{
@@ -327,8 +337,11 @@ bool SynthI::initInstance(Synth* s, const QString& instanceName)
setIName(instanceName); // set instrument name
_sif = s->createSIF(this);
- AudioTrack::setChannels(_sif->channels());
-
+ // p3.3.38
+ //AudioTrack::setChannels(_sif->channels());
+ AudioTrack::setTotalOutChannels(_sif->totalOutChannels());
+ AudioTrack::setTotalInChannels(_sif->totalInChannels());
+
//---------------------------------------------------
// read available controller from synti
//---------------------------------------------------
@@ -531,36 +544,38 @@ void initMidiSynth()
//SynthI* Song::createSynthI(const QString& sclass)
SynthI* Song::createSynthI(const QString& sclass, const QString& label)
{
- // Added by Tim. p3.3.13
//printf("Song::createSynthI calling ::createSynthI class:%s\n", sclass.latin1());
//SynthI* si = ::createSynthI(sclass);
- SynthI* si = ::createSynthI(sclass, label);
+ //SynthI* si = ::createSynthI(sclass, label);
+ SynthI* si = createSynthInstance(sclass, label);
if(!si)
return 0;
- // Added by Tim. p3.3.13
//printf("Song::createSynthI created SynthI. Before insertTrack1...\n");
insertTrack1(si, -1);
- // Added by Tim. p3.3.13
//printf("Song::createSynthI after insertTrack1. Before msgInsertTrack...\n");
msgInsertTrack(si, -1, true); // add to instance list
- // Added by Tim. p3.3.13
//printf("Song::createSynthI after msgInsertTrack. Before insertTrack3...\n");
insertTrack3(si, -1);
- // Added by Tim. p3.3.13
//printf("Song::createSynthI after insertTrack3. Adding default routes...\n");
OutputList* ol = song->outputs();
// add default route to master (first audio output)
if (!ol->empty()) {
AudioOutput* ao = ol->front();
- audio->msgAddRoute(Route(si, -1), Route(ao, -1));
+ // p3.3.38
+ //audio->msgAddRoute(Route(si, -1), Route(ao, -1));
+ //audio->msgAddRoute(Route((AudioTrack*)si, -1), Route(ao, -1));
+ // Make sure the route channel and channels are valid.
+ audio->msgAddRoute(Route((AudioTrack*)si, 0, ((AudioTrack*)si)->channels()), Route(ao, 0, ((AudioTrack*)si)->channels()));
+
audio->msgUpdateSoloStates();
}
+
return si;
}
diff --git a/muse/muse/synth.h b/muse/muse/synth.h
index 7132e227..87584a53 100644
--- a/muse/muse/synth.h
+++ b/muse/muse/synth.h
@@ -118,6 +118,8 @@ class SynthIF {
//virtual bool init(Synth* s) = 0;
virtual int channels() const = 0;
+ virtual int totalOutChannels() const = 0;
+ virtual int totalInChannels() const = 0;
virtual void deactivate3() = 0;
virtual const char* getPatchName(int, int, int, bool) const = 0;
virtual const char* getPatchName(int, int, MType, bool) = 0;
@@ -169,6 +171,8 @@ class SynthI : public AudioTrack, public MidiDevice,
//SynthI* clone() const { return new SynthI(*this); }
SynthI* clone(bool /*cloneParts*/) const { return new SynthI(*this); }
+ virtual inline int deviceType() { return SYNTH_MIDI; }
+
SynthIF* sif() const { return _sif; }
bool initInstance(Synth* s, const QString& instanceName);
@@ -237,6 +241,8 @@ class MessSynthIF : public SynthIF {
bool init(Synth* s, SynthI* si);
virtual int channels() const;
+ virtual int totalOutChannels() const;
+ virtual int totalInChannels() const;
virtual void deactivate3();
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool);
diff --git a/muse/muse/ticksynth.cpp b/muse/muse/ticksynth.cpp
index acbdfb3e..2cd0ae82 100644
--- a/muse/muse/ticksynth.cpp
+++ b/muse/muse/ticksynth.cpp
@@ -74,6 +74,8 @@ class MetronomeSynthIF : public SynthIF
//virtual bool init(Synth*) { return true; }
virtual int channels() const { return 1; }
+ virtual int totalOutChannels() const { return 1; }
+ virtual int totalInChannels() const { return 0; }
virtual void deactivate3() {}
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp
index 1580f180..6f6f11a8 100644
--- a/muse/muse/track.cpp
+++ b/muse/muse/track.cpp
@@ -6,6 +6,9 @@
// (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
//=========================================================
+#include <qt.h>
+#include <qstring.h>
+
#include "track.h"
#include "event.h"
#include "mididev.h"
@@ -367,8 +370,8 @@ MidiTrack::MidiTrack(const MidiTrack& mt, bool cloneParts)
{
_outPort = mt.outPort();
_outChannel = mt.outChannel();
- _inPortMask = mt.inPortMask();
- _inChannelMask = mt.inChannelMask();
+ ///_inPortMask = mt.inPortMask();
+ ///_inChannelMask = mt.inChannelMask();
_events = new EventList;
_mpevents = new MPEventList;
transposition = mt.transposition;
@@ -395,9 +398,9 @@ void MidiTrack::init()
_outChannel = 0;
// Changed by Tim. p3.3.8
//_inPortMask = 0xffff;
- _inPortMask = 0xffffffff;
+ ///_inPortMask = 0xffffffff;
- _inChannelMask = 0xffff; // "ALL"
+ ///_inChannelMask = 0xffff; // "ALL"
transposition = 0;
velocity = 0;
delay = 0;
@@ -648,6 +651,123 @@ bool Track::readProperties(Xml& xml, const QString& tag)
}
//---------------------------------------------------------
+// writeRouting
+//---------------------------------------------------------
+
+void Track::writeRouting(int level, Xml& xml) const
+{
+ QString s;
+
+ if (type() == Track::AUDIO_INPUT)
+ {
+ const RouteList* rl = &_inRoutes;
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+
+ ///Route dst(name(), true, r->channel);
+ //xml.tag(level++, "Route");
+ xml.tag(level++, s);
+
+ // p3.3.38 New routing scheme.
+ ///xml.strTag(level, "srcNode", r->name());
+ //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+ s = QT_TR_NOOP("source");
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ xml.tag(level, s);
+
+ ///xml.strTag(level, "dstNode", dst.name());
+
+ //if(r->channel != -1)
+ // xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1());
+ //else
+ // xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, name().latin1());
+ xml.tag(level, "dest name=\"%s\"/", name().latin1());
+
+ xml.etag(level--, "Route");
+ }
+ }
+ }
+
+ const RouteList* rl = &_outRoutes;
+ for (ciRoute r = rl->begin(); r != rl->end(); ++r)
+ {
+ if(!r->name().isEmpty())
+ {
+ ///QString src(name());
+ ///if (type() == Track::AUDIO_OUTPUT)
+ ///{
+ ///Route s(src, false, r->channel);
+ ///src = s.name();
+ ///}
+
+ s = QT_TR_NOOP("Route");
+ if(r->channel != -1)
+ s += QString(QT_TR_NOOP(" channel=\"%1\"")).arg(r->channel);
+ if(r->channels != -1)
+ s += QString(QT_TR_NOOP(" channels=\"%1\"")).arg(r->channels);
+ if(r->remoteChannel != -1)
+ s += QString(QT_TR_NOOP(" remch=\"%1\"")).arg(r->remoteChannel);
+
+ //xml.tag(level++, "Route");
+ xml.tag(level++, s);
+
+ ///xml.strTag(level, "srcNode", src);
+ //if(r->channel != -1)
+
+ // Allow for a regular mono or stereo track to feed a multi-channel synti.
+ // thisChannel is the 'starting' channel of this source if feeding a regular track.
+ //if(r->type == Route::TRACK_ROUTE && r->track->isSynti() && r->channel != -1)
+ //if(isSynti() && r->thisChannel != -1)
+ //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1());
+ // xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->thisChannel, name().latin1());
+ //else
+
+ //if(r->channel != -1)
+ // xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, r->channel, name().latin1());
+ //else
+ // xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::TRACK_ROUTE, name().latin1());
+ xml.tag(level, "source name=\"%s\"/", name().latin1());
+
+ ///xml.strTag(level, "dstNode", r->name());
+ //if(r->channel != -1)
+ // xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().latin1());
+ //else
+ // xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ // Allow for a regular mono or stereo track to feed a multi-channel synti.
+ // Channel is the 'starting' channel of the destination.
+ //if(r->type == Route::TRACK_ROUTE && r->track->isSynti() && r->channel != -1)
+
+ //if(r->type == Route::TRACK_ROUTE && r->track->type() == Track::AUDIO_SOFTSYNTH && r->remoteChannel != -1)
+ // xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->remoteChannel, r->name().latin1());
+ //else
+ //if(r->type == Route::MIDI_DEVICE_ROUTE)
+ // xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().latin1());
+ //else
+ // xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().latin1());
+
+ s = QT_TR_NOOP("dest");
+ if(r->type == Route::MIDI_DEVICE_ROUTE)
+ s += QString(QT_TR_NOOP(" devtype=\"%1\"")).arg(r->device->deviceType());
+ else
+ if(r->type != Route::TRACK_ROUTE)
+ s += QString(QT_TR_NOOP(" type=\"%1\"")).arg(r->type);
+ s += QString(QT_TR_NOOP(" name=\"%1\"/")).arg(r->name());
+ xml.tag(level, s);
+
+ xml.etag(level--, "Route");
+ }
+ }
+}
+
+//---------------------------------------------------------
// MidiTrack::write
//---------------------------------------------------------
@@ -665,8 +785,8 @@ void MidiTrack::write(int level, Xml& xml) const
xml.intTag(level, "device", outPort());
xml.intTag(level, "channel", outChannel());
//xml.intTag(level, "inportMap", inPortMask());
- xml.uintTag(level, "inportMap", inPortMask());
- xml.intTag(level, "inchannelMap", inChannelMask());
+ ///xml.uintTag(level, "inportMap", inPortMask()); // Obsolete
+ ///xml.intTag(level, "inchannelMap", inChannelMask()); // Obsolete
xml.intTag(level, "locked", _locked);
xml.intTag(level, "echo", _recEcho);
@@ -721,9 +841,11 @@ void MidiTrack::read(Xml& xml)
setOutChannel(xml.parseInt());
else if (tag == "inportMap")
//setInPortMask(xml.parseInt());
- setInPortMask(xml.parseUInt());
+ ///setInPortMask(xml.parseUInt());
+ xml.skip(tag); // Obsolete
else if (tag == "inchannelMap")
- setInChannelMask(xml.parseInt());
+ ///setInChannelMask(xml.parseInt());
+ xml.skip(tag); // Obsolete
else if (tag == "locked")
_locked = xml.parseInt();
else if (tag == "echo")
diff --git a/muse/muse/track.h b/muse/muse/track.h
index 6f06c923..9449fd1b 100644
--- a/muse/muse/track.h
+++ b/muse/muse/track.h
@@ -51,6 +51,9 @@ class Track {
static bool _tmpSoloChainDoIns;
static bool _tmpSoloChainNoDec;
+ // p3.3.38
+ RouteList _inRoutes;
+ RouteList _outRoutes;
QString _name;
bool _recordFlag;
@@ -115,6 +118,13 @@ class Track {
TrackType type() const { return _type; }
void setType(TrackType t) { _type = t; }
+ // routing
+ RouteList* inRoutes() { return &_inRoutes; }
+ RouteList* outRoutes() { return &_outRoutes; }
+ bool noInRoute() const { return _inRoutes.empty(); }
+ bool noOutRoute() const { return _outRoutes.empty(); }
+ void writeRouting(int, Xml&) const;
+
PartList* parts() { return &_parts; }
const PartList* cparts() const { return &_parts; }
Part* findPart(unsigned tick);
@@ -184,8 +194,8 @@ class MidiTrack : public Track {
int _outPort;
int _outChannel;
//int _inPortMask;
- unsigned int _inPortMask; // bitmask of accepted record ports
- int _inChannelMask; // bitmask of accepted record channels
+ ///unsigned int _inPortMask; // bitmask of accepted record ports
+ ///int _inChannelMask; // bitmask of accepted record channels
bool _recEcho; // For midi (and audio). Whether to echo incoming record events to output device.
EventList* _events; // tmp Events during midi import
@@ -227,14 +237,14 @@ class MidiTrack : public Track {
void setOutChanAndUpdate(int i);
void setOutPortAndUpdate(int i);
//void setInPortMask(int i) { _inPortMask = i; }
- void setInPortMask(unsigned int i) { _inPortMask = i; }
- void setInChannelMask(int i) { _inChannelMask = i; }
+ ///void setInPortMask(unsigned int i) { _inPortMask = i; }
+ ///void setInChannelMask(int i) { _inChannelMask = i; }
void setRecEcho(bool b) { _recEcho = b; }
int outPort() const { return _outPort; }
//int inPortMask() const { return _inPortMask; }
- unsigned int inPortMask() const { return _inPortMask; }
+ ///unsigned int inPortMask() const { return _inPortMask; }
int outChannel() const { return _outChannel; }
- int inChannelMask() const { return _inChannelMask; }
+ ///int inChannelMask() const { return _inChannelMask; }
bool recEcho() const { return _recEcho; }
virtual bool isMute() const;
@@ -269,8 +279,8 @@ class AudioTrack : public Track {
AutomationType _automationType;
- RouteList _inRoutes;
- RouteList _outRoutes;
+ //RouteList _inRoutes;
+ //RouteList _outRoutes;
bool _sendMetronome;
@@ -278,8 +288,11 @@ class AudioTrack : public Track {
void readAuxSend(Xml& xml);
protected:
- //float** outBuffers;
- float* outBuffers[MAX_CHANNELS];
+ float** outBuffers;
+ //float* outBuffers[MAX_CHANNELS];
+ int _totalOutChannels;
+ int _totalInChannels;
+
unsigned bufferPos;
virtual bool getData(unsigned, int, unsigned, float**);
SndFile* _recFile;
@@ -288,6 +301,8 @@ class AudioTrack : public Track {
public:
AudioTrack(TrackType t);
+ //AudioTrack(TrackType t, int num_out_bufs = MAX_CHANNELS);
+
//AudioTrack(const AudioTrack&);
AudioTrack(const AudioTrack&, bool cloneParts);
virtual ~AudioTrack();
@@ -317,6 +332,10 @@ class AudioTrack : public Track {
CtrlListList* controller() { return &_controller; }
virtual void setChannels(int n);
+ virtual void setTotalOutChannels(int num);
+ virtual int totalOutChannels() { return _totalOutChannels; }
+ virtual void setTotalInChannels(int num);
+ virtual int totalInChannels() { return _totalInChannels; }
virtual bool isMute() const;
virtual void setSolo(bool val);
@@ -355,19 +374,19 @@ class AudioTrack : public Track {
void setPluginCtrlVal(int param, double val);
void readVolume(Xml& xml);
- void writeRouting(int, Xml&) const;
+ //void writeRouting(int, Xml&) const;
// routing
- RouteList* inRoutes() { return &_inRoutes; }
- RouteList* outRoutes() { return &_outRoutes; }
- bool noInRoute() const { return _inRoutes.empty(); }
- bool noOutRoute() const { return _outRoutes.empty(); }
+ //RouteList* inRoutes() { return &_inRoutes; }
+ //RouteList* outRoutes() { return &_outRoutes; }
+ //bool noInRoute() const { return _inRoutes.empty(); }
+ //bool noOutRoute() const { return _outRoutes.empty(); }
virtual void preProcessAlways() { _processed = false; }
- virtual void addData(unsigned, int, unsigned, float**);
- virtual void copyData(unsigned, int, unsigned, float**);
+ virtual void addData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/);
+ virtual void copyData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/);
virtual bool hasAuxSend() const { return false; }
-
+
// automation
virtual AutomationType automationType() const { return _automationType; }
virtual void setAutomationType(AutomationType t);
diff --git a/muse/muse/vst.cpp b/muse/muse/vst.cpp
index 945bc2e9..194e1993 100644
--- a/muse/muse/vst.cpp
+++ b/muse/muse/vst.cpp
@@ -473,6 +473,18 @@ int VstSynthIF::channels() const
return plugin->numOutputs;
}
+int VstSynthIF::totalOutChannels() const
+ {
+ AEffect* plugin = _fst->plugin;
+ return plugin->numOutputs;
+ }
+
+int VstSynthIF::totalInChannels() const
+ {
+ AEffect* plugin = _fst->plugin;
+ return plugin->numInputs;
+ }
+
//---------------------------------------------------------
// createSIF
//---------------------------------------------------------
diff --git a/muse/muse/vst.h b/muse/muse/vst.h
index 1caef0fc..33eaaab3 100644
--- a/muse/muse/vst.h
+++ b/muse/muse/vst.h
@@ -61,6 +61,8 @@ class VstSynthIF : public SynthIF
virtual int eventsPending() const { return 0; }
virtual bool init(Synth*);
virtual int channels() const;
+ virtual int totalOutChannels() const;
+ virtual int totalInChannels() const;
virtual void deactivate3();
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
diff --git a/muse/muse/wavetrack.cpp b/muse/muse/wavetrack.cpp
index fbf7b965..c4fe7071 100644
--- a/muse/muse/wavetrack.cpp
+++ b/muse/muse/wavetrack.cpp
@@ -197,10 +197,39 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float*
if ((song->bounceTrack != this) && !noInRoute()) {
RouteList* irl = inRoutes();
iRoute i = irl->begin();
- i->track->copyData(framePos, channels, nframe, bp);
+ if(i->track->isMidiTrack())
+ {
+ if(debugMsg)
+ printf("WaveTrack::getData: Error: First route is a midi track route!\n");
+ return false;
+ }
+ // p3.3.38
+ //((AudioTrack*)i->track)->copyData(framePos, channels, nframe, bp);
+ ((AudioTrack*)i->track)->copyData(framePos, channels,
+ //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,
+ i->channel,
+ i->channels,
+ nframe, bp);
+
++i;
for (; i != irl->end(); ++i)
- i->track->addData(framePos, channels, nframe, bp);
+ {
+ if(i->track->isMidiTrack())
+ {
+ if(debugMsg)
+ printf("WaveTrack::getData: Error: Route is a midi track route!\n");
+ //return false;
+ continue;
+ }
+ // p3.3.38
+ //((AudioTrack*)i->track)->addData(framePos, channels, nframe, bp);
+ ((AudioTrack*)i->track)->addData(framePos, channels,
+ //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,
+ i->channel,
+ i->channels,
+ nframe, bp);
+
+ }
if (recordFlag()) {
if (audio->isRecording() && recFile()) {
if (audio->freewheel()) {
diff --git a/muse/muse/widgets/mtrackinfobase.ui b/muse/muse/widgets/mtrackinfobase.ui
index cf753252..3d2b274a 100644
--- a/muse/muse/widgets/mtrackinfobase.ui
+++ b/muse/muse/widgets/mtrackinfobase.ui
@@ -95,7 +95,7 @@
<set>AlignCenter | WordBreak</set>
</property>
</widget>
- <widget class="SpinBox" row="8" column="0">
+ <widget class="SpinBox" row="7" column="0">
<property name="name">
<cstring>iLen</cstring>
</property>
@@ -136,81 +136,29 @@
<string>output port</string>
</property>
</widget>
- <widget class="QLayoutWidget" row="2" column="1">
+ <widget class="QLabel" row="2" column="1">
<property name="name">
- <cstring>oPortsLayout</cstring>
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="indent">
+ <number>1</number>
+ </property>
+ <property name="text">
+ <string>Out ch</string>
</property>
- <hbox>
- <widget class="QLabel">
- <property name="name">
- <cstring>TextLabel2</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <property name="indent">
- <number>1</number>
- </property>
- <property name="text">
- <string>OCh</string>
- </property>
- </widget>
- <widget class="QToolButton">
- <property name="name">
- <cstring>recEchoButton</cstring>
- </property>
- <property name="maximumSize">
- <size>
- <width>14</width>
- <height>32767</height>
- </size>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>1</hsizetype>
- <vsizetype>1</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="toggleButton">
- <string>true</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string>Echo recording events to output.</string>
- </property>
- <property name="toolTip" stdset="0">
- <string>Echo</string>
- </property>
- </widget>
- <spacer>
- <property name="name">
- <cstring>recEchoSpacer</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Minimum</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>2</width>
- <height>2</height>
- </size>
- </property>
- </spacer>
- </hbox>
</widget>
- <widget class="SpinBox" row="7" column="0">
+ <widget class="SpinBox" row="6" column="0">
<property name="name">
<cstring>iVerz</cstring>
</property>
@@ -232,7 +180,7 @@
<number>-1000</number>
</property>
</widget>
- <widget class="SpinBox" row="9" column="0">
+ <widget class="SpinBox" row="8" column="0">
<property name="name">
<cstring>iAnschl</cstring>
</property>
@@ -254,7 +202,7 @@
<number>0</number>
</property>
</widget>
- <widget class="SpinBox" row="10" column="0">
+ <widget class="SpinBox" row="9" column="0">
<property name="name">
<cstring>iKompr</cstring>
</property>
@@ -282,7 +230,7 @@
<number>100</number>
</property>
</widget>
- <widget class="SpinBox" row="6" column="0">
+ <widget class="SpinBox" row="5" column="0">
<property name="name">
<cstring>iTransp</cstring>
</property>
@@ -307,7 +255,7 @@
<number>1</number>
</property>
</widget>
- <widget class="QLabel" row="6" column="1">
+ <widget class="QLabel" row="5" column="1">
<property name="name">
<cstring>TextLabel9</cstring>
</property>
@@ -326,7 +274,7 @@
<number>2</number>
</property>
</widget>
- <widget class="QLabel" row="7" column="1">
+ <widget class="QLabel" row="6" column="1">
<property name="name">
<cstring>TextLabel10</cstring>
</property>
@@ -345,7 +293,7 @@
<number>2</number>
</property>
</widget>
- <widget class="QLabel" row="10" column="1">
+ <widget class="QLabel" row="9" column="1">
<property name="name">
<cstring>TextLabel13</cstring>
</property>
@@ -364,7 +312,7 @@
<number>2</number>
</property>
</widget>
- <widget class="QLabel" row="9" column="1">
+ <widget class="QLabel" row="8" column="1">
<property name="name">
<cstring>TextLabel12</cstring>
</property>
@@ -383,7 +331,7 @@
<number>0</number>
</property>
</widget>
- <widget class="QLabel" row="8" column="1">
+ <widget class="QLabel" row="7" column="1">
<property name="name">
<cstring>TextLabel11</cstring>
</property>
@@ -402,135 +350,131 @@
<number>2</number>
</property>
</widget>
- <widget class="QLineEdit" row="3" column="0">
+ <widget class="QLayoutWidget" row="3" column="0">
<property name="name">
- <cstring>iInput</cstring>
+ <cstring>routingLayout</cstring>
</property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>0</vsizetype>
+ <hbox>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>iRButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="whatsThis" stdset="0">
- <string>Events from all configured ports are
-recorded to this track.
-You can specify more than one port for
-recording:
- 1 2 3 record from port 1 2 and 3
- 1-3 same
- 1-3 5 record from port 1 2 3 and 5</string>
- </property>
- <property name="toolTip" stdset="0">
- <string>input ports</string>
- </property>
- </widget>
- <widget class="QLabel" row="3" column="1">
- <property name="name">
- <cstring>iPortsTextLabel</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>0</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <property name="indent">
- <number>2</number>
- </property>
- <property name="text">
- <string>IPorts</string>
- </property>
- </widget>
- <widget class="QLayoutWidget" row="4" column="1">
- <property name="name">
- <cstring>iChLayout</cstring>
- </property>
- <hbox>
- <widget class="QLabel">
- <property name="name">
- <cstring>iChanTextLabel</cstring>
- </property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>0</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <property name="indent">
- <number>2</number>
- </property>
- <property name="text">
- <string>ICh</string>
- </property>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>iR</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>input routing</string>
+ </property>
</widget>
- <widget class="QLabel">
+ <widget class="QToolButton">
<property name="name">
- <cstring>iChanDetectLabel</cstring>
+ <cstring>oRButton</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>0</vsizetype>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
- <string>W</string>
- </property>
- <property name="alignment">
- <set>AlignCenter</set>
+ <string>oR</string>
</property>
<property name="toolTip" stdset="0">
- <string>input detect</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string>Input detect indicator. Detects all note on-off, controller, aftertouch,
- program change, and pitchbend (but not sysex or realtime) events
- on the selected channels, on the selected midi ports.</string>
+ <string>output routing</string>
</property>
</widget>
</hbox>
</widget>
- <widget class="QLineEdit" row="4" column="0">
- <property name="name">
- <cstring>iInputChannel</cstring>
- </property>
- <property name="sizePolicy">
+ <widget class="QLayoutWidget" row="3" column="1">
+ <property name="name">
+ <cstring>routingLayout2</cstring>
+ </property>
+ <hbox>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>iChanDetectLabel</cstring>
+ </property>
+ <property name="sizePolicy">
<sizepolicy>
- <hsizetype>5</hsizetype>
- <vsizetype>0</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
</sizepolicy>
- </property>
- <property name="toolTip" stdset="0">
- <string>input channels</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string>Events from all configured channels are
-recorded to this track.
-You can specify more than one channel for
-recording:
- 1 2 3 record from channel 1 2 and 3
- 1-3 same
- 1-3 5 record from channel 1 2 3 and 5</string>
- </property>
+ </property>
+ <property name="text">
+ <string>W</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>input detect</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Input detect indicator. Detects all note on-off, controller, aftertouch,
+ program change, and pitchbend (but not sysex or realtime) events
+ on the selected channels, on the selected midi ports.</string>
+ </property>
+ </widget>
+ <widget class="QToolButton">
+ <property name="name">
+ <cstring>recEchoButton</cstring>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>14</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toggleButton">
+ <string>true</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Echo recording events to output.</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Echo</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>echoSpacer</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Maximum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>4</width>
+ <height>2</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
</widget>
- <widget class="QLabel" row="11" column="0" rowspan="1" colspan="2">
+ <widget class="QLabel" row="10" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>TextLabel1_2</cstring>
</property>
@@ -561,7 +505,7 @@ recording:
<set>AlignCenter</set>
</property>
</widget>
- <widget class="QPushButton" row="12" column="0" rowspan="1" colspan="2">
+ <widget class="QPushButton" row="11" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>iPatch</cstring>
</property>
@@ -580,7 +524,7 @@ recording:
<string>Select instrument patch</string>
</property>
</widget>
- <widget class="QLabel" row="13" column="0">
+ <widget class="QLabel" row="12" column="0">
<property name="name">
<cstring>textLabel1</cstring>
</property>
@@ -599,7 +543,7 @@ recording:
<set>AlignVCenter|AlignRight</set>
</property>
</widget>
- <widget class="QLayoutWidget" row="13" column="1">
+ <widget class="QLayoutWidget" row="12" column="1">
<property name="name">
<cstring>recLayout</cstring>
</property>
@@ -662,7 +606,7 @@ recording:
</spacer>
</hbox>
</widget>
- <widget class="SpinBox" row="14" column="0">
+ <widget class="SpinBox" row="13" column="0">
<property name="name">
<cstring>iHBank</cstring>
</property>
@@ -690,7 +634,7 @@ recording:
<string>Bank Select MSB. Double-click on/off.</string>
</property>
</widget>
- <widget class="QLabel" row="14" column="1">
+ <widget class="QLabel" row="13" column="1">
<property name="name">
<cstring>TextLabel4</cstring>
</property>
@@ -715,7 +659,7 @@ recording:
<number>2</number>
</property>
</widget>
- <widget class="SpinBox" row="15" column="0">
+ <widget class="SpinBox" row="14" column="0">
<property name="name">
<cstring>iLBank</cstring>
</property>
@@ -743,7 +687,7 @@ recording:
<string>Bank Select LSB. Double-click on/off.</string>
</property>
</widget>
- <widget class="QLabel" row="15" column="1">
+ <widget class="QLabel" row="14" column="1">
<property name="name">
<cstring>TextLabel5</cstring>
</property>
@@ -768,7 +712,7 @@ recording:
<number>2</number>
</property>
</widget>
- <widget class="SpinBox" row="16" column="0">
+ <widget class="SpinBox" row="15" column="0">
<property name="name">
<cstring>iProgram</cstring>
</property>
@@ -796,7 +740,7 @@ recording:
<string>Program. Double-click on/off.</string>
</property>
</widget>
- <widget class="QLayoutWidget" row="16" column="1">
+ <widget class="QLayoutWidget" row="15" column="1">
<property name="name">
<cstring>progLayout</cstring>
</property>
@@ -865,7 +809,7 @@ recording:
</spacer>
</hbox>
</widget>
- <widget class="SpinBox" row="17" column="0">
+ <widget class="SpinBox" row="16" column="0">
<property name="name">
<cstring>iLautst</cstring>
</property>
@@ -893,7 +837,7 @@ recording:
<string>Volume. Double-click on/off.</string>
</property>
</widget>
- <widget class="QLayoutWidget" row="17" column="1">
+ <widget class="QLayoutWidget" row="16" column="1">
<property name="name">
<cstring>volLayout</cstring>
</property>
@@ -962,7 +906,7 @@ recording:
</spacer>
</hbox>
</widget>
- <widget class="SpinBox" row="18" column="0">
+ <widget class="SpinBox" row="17" column="0">
<property name="name">
<cstring>iPan</cstring>
</property>
@@ -993,7 +937,7 @@ recording:
<string>Change stereo position. Double-click on/off.</string>
</property>
</widget>
- <widget class="QLayoutWidget" row="18" column="1">
+ <widget class="QLayoutWidget" row="17" column="1">
<property name="name">
<cstring>panLayout</cstring>
</property>
@@ -1062,7 +1006,7 @@ recording:
</spacer>
</hbox>
</widget>
- <spacer row="19" column="0" rowspan="1" colspan="2">
+ <spacer row="18" column="0" rowspan="1" colspan="2">
<property name="name">
<cstring>spacer5</cstring>
</property>
@@ -1107,8 +1051,6 @@ recording:
<tabstops>
<tabstop>iOutput</tabstop>
<tabstop>iOutputChannel</tabstop>
- <tabstop>iInput</tabstop>
- <tabstop>iInputChannel</tabstop>
<tabstop>iTransp</tabstop>
<tabstop>iVerz</tabstop>
<tabstop>iLen</tabstop>