From e8612708161b71b43d56ef47eede6cc58b035967 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Thu, 26 May 2011 00:18:47 +0000 Subject: Moved all routing popup menu stuff from app, astrip, mstrip, mtrackinfo into new class RoutePopupMenu, *massively* cleaning up those 4 files. Used new Route QVariant type as action data instead of integers. Moved MenuTitleItem definitions from astrip.cpp into it's own menutitleitem.cpp Added to settings: "Make popup menus stay open. Otherwise hold Ctrl." --- muse2/ChangeLog | 7 + muse2/muse/app.cpp | 796 +--------------- muse2/muse/app.h | 27 +- muse2/muse/audiotrack.cpp | 1 + muse2/muse/conf.cpp | 40 +- muse2/muse/confmport.cpp | 6 +- muse2/muse/driver/jack.cpp | 24 +- muse2/muse/gconfig.cpp | 3 +- muse2/muse/gconfig.h | 1 + muse2/muse/globals.cpp | 4 - muse2/muse/globals.h | 10 - muse2/muse/mixer/astrip.cpp | 1058 +-------------------- muse2/muse/mixer/astrip.h | 6 +- muse2/muse/mixer/mstrip.cpp | 52 +- muse2/muse/mixer/mstrip.h | 5 - muse2/muse/node.cpp | 2 +- muse2/muse/route.cpp | 22 +- muse2/muse/route.h | 15 +- muse2/muse/seqmsg.cpp | 4 +- muse2/muse/song.cpp | 4 +- muse2/muse/wavetrack.cpp | 2 +- muse2/muse/widgets/CMakeLists.txt | 4 + muse2/muse/widgets/genset.cpp | 3 + muse2/muse/widgets/gensetbase.ui | 23 +- muse2/muse/widgets/menutitleitem.cpp | 48 + muse2/muse/widgets/mtrackinfo.cpp | 98 +- muse2/muse/widgets/mtrackinfo.h | 2 - muse2/muse/widgets/musewidgetsplug.cpp | 5 +- muse2/muse/widgets/popupmenu.cpp | 91 +- muse2/muse/widgets/popupmenu.h | 3 +- muse2/muse/widgets/routepopup.cpp | 1416 +++++++++++++++++++++++++++++ muse2/muse/widgets/routepopup.h | 73 ++ muse2/synti/deicsonze/deicsonzeplugin.cpp | 8 +- 33 files changed, 1720 insertions(+), 2143 deletions(-) create mode 100644 muse2/muse/widgets/menutitleitem.cpp create mode 100644 muse2/muse/widgets/routepopup.cpp create mode 100644 muse2/muse/widgets/routepopup.h diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 24545b76..613cecc1 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -3,6 +3,13 @@ - Added step-rec-support for drum edit and score edit (flo93) - put step-rec-stuff into its own class (flo93) - moved clefTypes out of scoreedit.h to prevent compile-horror (flo93) + - Declared struct Route as QMetaType to make it a QVariant type. (Tim) + - Moved: All routing popup menu stuff from app, astrip, mstrip, mtrackinfo into + new class RoutePopupMenu, *massively* cleaning up those 4 files. + Used the new Route QVariant type as action data instead of integers. + - Moved MenuTitleItem definitions from astrip.cpp into it's own menutitleitem.cpp (Tim) + - Added to settings: "Make popup menus stay open. Otherwise hold Ctrl." (Tim) + To avoid showing new users non-standard behaviour, the default is off! 24.05.2011: - Awl::PitchEdit now can be set with the musical keyboard (flo93) - fixed y-stretch (flo93) diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index 62871b18..72cdad6a 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -43,7 +43,7 @@ #include "mixdowndialog.h" #include "pianoroll.h" #include "scoreedit.h" -#include "popupmenu.h" +#include "routepopup.h" #include "shortcutconfig.h" #include "songinfo.h" #include "ticksynth.h" @@ -93,7 +93,6 @@ static QString* projectList[PROJECT_LIST_LEN]; extern void initMidiSynth(); extern void exitJackAudio(); extern void exitDummyAudio(); -// p3.3.39 extern void exitOSC(); #ifdef HAVE_LASH @@ -809,7 +808,6 @@ MusE::MusE(int argc, char** argv) : QMainWindow() editInstrument = 0; routingPopupMenu = 0; progress = 0; - //routingPopupView = 0; appName = QString("MusE"); setWindowTitle(appName); @@ -1658,7 +1656,6 @@ void MusE::initMidiDevices() audio->msgInitMidiDevices(); - // Added by T356 //audio->msgIdle(false); } @@ -2080,7 +2077,7 @@ bool MusE::save(const QString& name, bool overwriteWarn) if (ferror(f)) { QString s = "Write File\n" + name + "\nfailed: " //+ strerror(errno); - + QString(strerror(errno)); // p4.0.0 + + QString(strerror(errno)); QMessageBox::critical(this, tr("MusE: Write File failed"), s); popenFlag? pclose(f) : fclose(f); @@ -2172,10 +2169,10 @@ void MusE::closeEvent(QCloseEvent* event) printf("MusE: Exiting Metronome\n"); exitMetronome(); - // p3.3.47 - // Make sure to clear the menu, which deletes any sub menus. + // Make sure to delete the menu. ~routingPopupMenu() will NOT be called automatically. + // Even though it is a child of MusE, it just passes MusE onto the underlying PopupMenus. p4.0.26 if(routingPopupMenu) - routingPopupMenu->clear(); + delete routingPopupMenu; #if 0 if(routingPopupView) { @@ -2201,10 +2198,8 @@ void MusE::closeEvent(QCloseEvent* event) d.remove(f.completeBaseName() + ".wca"); } - // Added by Tim. p3.3.14 - #ifdef HAVE_LASH - // Disconnect gracefully from LASH. + // Disconnect gracefully from LASH. Tim. p3.3.14 if(lash_client) { if(debugMsg) @@ -2292,788 +2287,17 @@ void MusE::showTransport(bool flag) //--------------------------------------------------------- // getRoutingPopupMenu +// Get the special common routing popup menu. Used (so far) +// by audio strip, midi strip, and midi trackinfo. //--------------------------------------------------------- -PopupMenu* MusE::getRoutingPopupMenu() +RoutePopupMenu* MusE::getRoutingPopupMenu() { if(!routingPopupMenu) - routingPopupMenu = new PopupMenu(this, true); + routingPopupMenu = new RoutePopupMenu(this); return routingPopupMenu; } -//--------------------------------------------------------- -// updateRouteMenus -//--------------------------------------------------------- - -void MusE::updateRouteMenus(Track* track, QObject* master) -{ - // NOTE: The purpose of this routine is to make sure the items actually reflect - // the routing status. - // In case for some reason a route could not be added (or removed). - // Then the item will be properly un-checked (or checked) here. - - //if(!track || track != gRoutingPopupMenuMaster || track->type() == Track::AUDIO_AUX) - //if(!track || track->type() == Track::AUDIO_AUX) - if(!track || gRoutingPopupMenuMaster != master) // p3.3.50 - return; - - PopupMenu* pup = getRoutingPopupMenu(); - - if(pup->actions().isEmpty()) - return; - - if(!pup->isVisible()) - return; - - //AudioTrack* t = (AudioTrack*)track; - RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes(); - - iRouteMenuMap imm = gRoutingMenuMap.begin(); - for(; imm != gRoutingMenuMap.end(); ++imm) - { - // p3.3.50 Ignore the 'toggle' items. - if(imm->second.type == Route::MIDI_PORT_ROUTE && - //imm->first >= (MIDI_PORTS * MIDI_CHANNELS) && imm->first < (MIDI_PORTS * MIDI_CHANNELS + MIDI_PORTS)) - imm->second.channel == (1 << MIDI_CHANNELS) - 1) // p4.0.14 See if all channels are set, rather than using ID. - continue; - - - // p4.0.14 TODO FIXME Couldn't quite figure out the logic yet. It should be possible (I hope). - // But not really required for now, as per above note. - if(gIsOutRoutingPopupMenu && track->isMidiTrack() && - imm->second.type == Route::TRACK_ROUTE && imm->second.track->type() == Track::AUDIO_INPUT) - return; - #if 0 - printf("imm route:\n"); - imm->second.dump(); - if(track->isMidiTrack()) - { - if(imm->second.type == Route::TRACK_ROUTE && imm->second.track->type() == Track::AUDIO_INPUT) - { - Route &aRoute = imm->second; - int chbit = aRoute.channel; - ///Route bRoute(track, chbit); - ///int mdidx = bRoute.midiPort; - int port = ((MidiTrack*)track)->outPort(); - if(port < 0 || port >= MIDI_PORTS) - continue; - int tchbit = 1 << ((MidiTrack*)track)->outChannel(); - - MidiPort* mp = &midiPorts[port]; - - ///Route bRoute(port, chbit); - - //int chmask = 0; - bool found = false; - RouteList* mprl = gIsOutRoutingPopupMenu ? mp->outRoutes() : mp->inRoutes(); - iRoute ir = mprl->begin(); - for(; ir != mprl->end(); ++ir) - { - printf("mp route:\n"); - ir->dump(); - ///if(aRoute.type == Route::TRACK_ROUTE) // Is the map route a track route? - { - if(ir->type == Route::TRACK_ROUTE && ir->track == aRoute.track) // Is the track route a midi port route? - //&& (ir->channel & chbit) == chbit) - //&& (ir->channel & tchbit)) // Is the exact channel mask bit(s) set? - { - printf("track matches\n"); - if(ir->channel & tchbit) - { - found = true; - printf("found: bit matches\n"); - } - break; - } - } - ///else - ///if(*ir == aRoute) - ///{ - //found = true; - /// break; - ///} - } - //pup->setItemChecked(imm->first, found); - //printf("MusE::updateRouteMenus setItemChecked\n"); - // TODO: MusE-2: Convert this, fastest way is to change the routing map, otherwise this requires a lookup. - //if(pup->isItemChecked(imm->first) != (irl != rl->end())) - // pup->setItemChecked(imm->first, irl != rl->end()); - QAction* act = pup->findActionFromData(imm->first); - //printf("set act checked to:%d\n", ir != mprl->end()); - //if(act && act->isChecked() != (ir != mprl->end())) - // act->setChecked(ir != mprl->end()); - printf("set act checked to:%d\n", found); - if(act && act->isChecked() != found) - act->setChecked(found); - - //return; - } - } - #endif - - //bool found = false; - iRoute irl = rl->begin(); - for(; irl != rl->end(); ++irl) - { - if(imm->second.type == Route::MIDI_PORT_ROUTE) // p3.3.50 Is the map route a midi port route? - { - if(irl->type == Route::MIDI_PORT_ROUTE && irl->midiPort == imm->second.midiPort // Is the track route a midi port route? - && (irl->channel & imm->second.channel) == imm->second.channel) // Is the exact channel mask bit(s) set? - { - //found = true; - break; - } - } - else - if(*irl == imm->second) - { - //found = true; - break; - } - } - //pup->setItemChecked(imm->first, found); - //printf("MusE::updateRouteMenus setItemChecked\n"); - // TODO: MusE-2: Convert this, fastest way is to change the routing map, otherwise this requires a lookup. - //if(pup->isItemChecked(imm->first) != (irl != rl->end())) - // pup->setItemChecked(imm->first, irl != rl->end()); - QAction* act = pup->findActionFromData(imm->first); - if(act && act->isChecked() != (irl != rl->end())) - act->setChecked(irl != rl->end()); - } -} - -//--------------------------------------------------------- -// routingPopupMenuActivated -//--------------------------------------------------------- - -void MusE::routingPopupMenuActivated(Track* track, int n) -{ - //if(!track || (track != gRoutingPopupMenuMaster)) - if(!track) - return; - - if(track->isMidiTrack()) - { - PopupMenu* pup = getRoutingPopupMenu(); - - if(pup->actions().isEmpty()) - return; - - //MidiTrack* t = (MidiTrack*)track; - RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes(); - - if(n == -1) - return; - - if(!gIsOutRoutingPopupMenu && n == 0) // p4.0.17 - { - muse->configMidiPorts(); - return; - } - - iRouteMenuMap imm = gRoutingMenuMap.find(n); - if(imm == gRoutingMenuMap.end()) - return; - - // Support Midi Port to Audio Input track routes. p4.0.14 Tim. - if(imm->second.type == Route::TRACK_ROUTE) - { - //if(gIsOutRoutingPopupMenu) // Try to avoid splitting like this. - { - Route &aRoute = imm->second; - int chbit = aRoute.channel; - int port = ((MidiTrack*)track)->outPort(); - if(port < 0 || port >= MIDI_PORTS) - return; - - MidiPort* mp = &midiPorts[port]; - ///MidiDevice* md = mp->device(); - - // This is desirable, but could lead to 'hidden' routes unless we add more support - // such as removing the existing routes when user changes flags. - // So for now, just list all valid ports whether read or write. - ///if(!md) - /// return; - ///if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) - /// return; - - //int channel = ((MidiTrack*)track->outChannel(); - Route bRoute(port, chbit); - - int chmask = 0; - RouteList* mprl = gIsOutRoutingPopupMenu ? mp->outRoutes() : mp->inRoutes(); - iRoute ir = mprl->begin(); - for (; ir != mprl->end(); ++ir) - { - if(ir->type == Route::TRACK_ROUTE && ir->track == aRoute.track) // Is there already a route to this port? - { - chmask = ir->channel; // Grab the channel mask. - break; - } - } - //if (iir != rl->end()) - if ((chmask & chbit) == chbit) // Is the channel's bit(s) set? - { - // disconnect - if(gIsOutRoutingPopupMenu) - audio->msgRemoveRoute(bRoute, aRoute); - else - audio->msgRemoveRoute(aRoute, bRoute); - } - else - { - // connect - if(gIsOutRoutingPopupMenu) - audio->msgAddRoute(bRoute, aRoute); - else - audio->msgAddRoute(aRoute, bRoute); - } - - audio->msgUpdateSoloStates(); - song->update(SC_ROUTE); - - } - return; - } - - - if(imm->second.type != Route::MIDI_PORT_ROUTE) - return; - Route &aRoute = imm->second; - int chbit = aRoute.channel; - Route bRoute(track, chbit); - int mdidx = aRoute.midiPort; - - MidiPort* mp = &midiPorts[mdidx]; - MidiDevice* md = mp->device(); - //if(!md) // Removed p4.0.17 Allow connections to ports with no device. - // return; - - //if(!(md->rwFlags() & 2)) - //if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) - if(md && !(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) // p4.0.17 - return; - - int chmask = 0; - iRoute iir = rl->begin(); - for (; iir != rl->end(); ++iir) - { - //if(*iir == (dst ? bRoute : aRoute)) - //if(*iir == aRoute) - if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx) // p3.3.50 Is there already a route to this port? - { - chmask = iir->channel; // p3.3.50 Grab the channel mask. - break; - } - } - //if (iir != rl->end()) - if ((chmask & chbit) == chbit) // p3.3.50 Is the channel's bit(s) set? - { - // disconnect - if(gIsOutRoutingPopupMenu) - audio->msgRemoveRoute(bRoute, aRoute); - else - audio->msgRemoveRoute(aRoute, bRoute); - } - else - { - // connect - if(gIsOutRoutingPopupMenu) - audio->msgAddRoute(bRoute, aRoute); - else - audio->msgAddRoute(aRoute, bRoute); - } - - audio->msgUpdateSoloStates(); - song->update(SC_ROUTE); - } - else - { - // TODO: Try to move code from AudioStrip::routingPopupMenuActivated into here. - - /* - PopupMenu* pup = getRoutingPopupMenu(); - - printf("MusE::routingPopupMenuActivated audio n:%d count:%d\n", n, pup->count()); - - if(pup->count() == 0) - return; - - AudioTrack* t = (AudioTrack*)track; - RouteList* rl = gIsOutRoutingPopupMenu ? t->outRoutes() : t->inRoutes(); - - //QPoint ppt = QCursor::pos(); - - if(n == -1) - { - //printf("MusE::routingPopupMenuActivated audio n = -1 deleting popup...\n"); - printf("MusE::routingPopupMenuActivated audio n = -1\n"); - ///delete pup; - ///pup = 0; - return; - } - else - //if(n == 0) - //{ - //printf("MusE::routingPopupMenuActivated audio n = 0 = tearOffHandle\n"); - //oR->setDown(false); - // return; - //} - //else - { - if(gIsOutRoutingPopupMenu) - { - QString s(pup->text(n)); - - //printf("AudioStrip::routingPopupMenuActivated audio text:%s\n", s.toLatin1().constData()); - - if(track->type() == Track::AUDIO_OUTPUT) - { - ///delete orpup; - - 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 irl = rl->begin(); - for (; irl != rl->end(); ++irl) { - if (*irl == dstRoute) - break; - } - if (irl != rl->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); - - // p3.3.47 - //pup->popup(ppt, 0); - - //oR->setDown(false); - return; - - // p3.3.46 - ///goto _redisplay; - } - - iRouteMenuMap imm = gRoutingMenuMap.find(n); - if(imm == gRoutingMenuMap.end()) - { - ///delete orpup; - //oR->setDown(false); // orpup->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 irl = rl->begin(); - for (; irl != rl->end(); ++irl) { - if (*irl == dstRoute) - break; - } - if (irl != rl->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); - - // p3.3.46 - //oR->setDown(false); - ///goto _redisplay; - - // p3.3.47 - //pup->popup(ppt, 0); - } - else - { - 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 irl = rl->begin(); - for(; irl != rl->end(); ++irl) - { - if(*irl == srcRoute) - break; - } - if(irl != rl->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; - - // p3.3.46 - ///goto _redisplay; - } - - iRouteMenuMap imm = gRoutingMenuMap.find(n); - if(imm == gRoutingMenuMap.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 irl = rl->begin(); - for (; irl != rl->end(); ++irl) { - if (*irl == srcRoute) - break; - } - if (irl != rl->end()) { - // disconnect - audio->msgRemoveRoute(srcRoute, dstRoute); - } - else { - // connect - audio->msgAddRoute(srcRoute, dstRoute); - } - audio->msgUpdateSoloStates(); - song->update(SC_ROUTE); - - // p3.3.46 - //iR->setDown(false); - ///goto _redisplay; - - - - - } - - } - */ - - } - //else - //{ - //} -} - -//--------------------------------------------------------- -// routingPopupMenuAboutToHide -//--------------------------------------------------------- - -void MusE::routingPopupMenuAboutToHide() -{ - // Hmm, can't do this? Sub-menus stay open with this. Re-arranged, testing... Nope. - //PopupMenu* pup = muse->getRoutingPopupMenu(); - //pup->disconnect(); - //pup->clear(); - - gRoutingMenuMap.clear(); - gRoutingPopupMenuMaster = 0; -} - -//--------------------------------------------------------- -// prepareRoutingPopupMenu -//--------------------------------------------------------- - -PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst) -{ - if(!track) - return 0; - - if(track->isMidiTrack()) - { - RouteList* rl = dst ? track->outRoutes() : track->inRoutes(); - //Route dst(track, -1); - - PopupMenu* pup = getRoutingPopupMenu(); - pup->disconnect(); - //connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int))); - //connect(pup, SIGNAL(aboutToHide()), SLOT(routingPopupMenuAboutToHide())); - - pup->clear(); - gRoutingMenuMap.clear(); - - int gid = 0; - QAction* act = 0; - - if(dst) - { - // Support Midi Port to Audio Input track routes. p4.0.14 Tim. - int port = ((MidiTrack*)track)->outPort(); - if(port >= 0 && port < MIDI_PORTS) - { - MidiPort* mp = &midiPorts[port]; - - // p4.0.17 Do not list synth devices! Requiring valid device is desirable, - // but could lead to 'hidden' routes unless we add more support - // such as removing the existing routes when user changes flags. - // So for now, just list all valid ports whether read or write. - if(mp->device() && !mp->device()->isSynti()) - { - RouteList* mprl = mp->outRoutes(); - int chbits = 1 << ((MidiTrack*)track)->outChannel(); - //MidiDevice* md = mp->device(); - //if(!md) - // continue; - - pup->addSeparator(); - pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup)); - PopupMenu* subp = new PopupMenu(pup, true); - subp->setTitle(tr("Audio returns")); - pup->addMenu(subp); - - InputList* al = song->inputs(); - for (iAudioInput i = al->begin(); i != al->end(); ++i) - { - Track* t = *i; - QString s(t->name()); - - act = subp->addAction(s); - act->setData(gid); - act->setCheckable(true); - - Route r(t, chbits); - - gRoutingMenuMap.insert( pRouteMenuMap(gid, r) ); - - for(iRoute ir = mprl->begin(); ir != mprl->end(); ++ir) - { - if(ir->type == Route::TRACK_ROUTE && ir->track == t && (ir->channel & chbits)) - { - act->setChecked(true); - break; - } - } - ++gid; - } - } - } - } - else - { - // Warn if no devices available. Add an item to open midi config. p4.0.17 - int pi = 0; - for( ; pi < MIDI_PORTS; ++pi) - { - MidiDevice* md = midiPorts[pi].device(); - if(md && !md->isSynti() && (md->rwFlags() & 2)) - break; - } - if(pi == MIDI_PORTS) - { - act = pup->addAction(tr("Warning: No midi input devices!")); - act->setCheckable(false); - act->setData(-1); - pup->addSeparator(); - } - act = pup->addAction(QIcon(*settings_midiport_softsynthsIcon), tr("Open midi config...")); - act->setCheckable(false); - act->setData(gid); - pup->addSeparator(); - ++gid; - - pup->addAction(new MenuTitleItem("Midi input ports", pup)); - - for(int i = 0; i < MIDI_PORTS; ++i) - { - // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick with ports. - MidiPort* mp = &midiPorts[i]; - MidiDevice* md = mp->device(); - //if(!md) - // continue; - - // p4.0.17 Do not list synth devices! - if(md && md->isSynti()) - continue; - - if(md && !(md->rwFlags() & 2)) - continue; - - //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i); - - // MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers! - //connect(subp, SIGNAL(triggered(QAction*)), pup, SIGNAL(triggered(QAction*))); - //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide())); - - int chanmask = 0; - // p3.3.50 To reduce number of routes required, from one per channel to just one containing a channel mask. - // Look for the first route to this midi port. There should always be only a single route for each midi port, now. - iRoute ir = rl->begin(); - for( ; ir != rl->end(); ++ir) - { - if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) - { - // We have a route to the midi port. Grab the channel mask. - chanmask = ir->channel; - break; - } - } - // p4.0.17 List ports with no device, but with routes to this track, in the main popup. - if(!md && ir == rl->end()) - continue; - - PopupMenu* subp = new PopupMenu(pup, true); - subp->setTitle(QString("%1:").arg(i+1) + (md ? md->name() : tr(""))); - - for(int ch = 0; ch < MIDI_CHANNELS; ++ch) - { - act = subp->addAction(QString("Channel %1").arg(ch+1)); - act->setCheckable(true); - act->setData(gid); - - int chbit = 1 << ch; - Route srcRoute(i, chbit); // p3.3.50 In accordance with new channel mask, use the bit position. - - gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) ); - - if(chanmask & chbit) // p3.3.50 Is the channel already set? Show item check mark. - act->setChecked(true); - - ++gid; - } - //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. - act = subp->addAction(tr("Toggle all")); - //act->setCheckable(true); - act->setData(gid); - Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. - gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) ); - ++gid; - pup->addMenu(subp); - } - - #if 0 - // p4.0.17 List ports with no device and no in routes, in a separate popup. - PopupMenu* morep = new PopupMenu(pup, true); - morep->setTitle(tr("More...")); - for(int i = 0; i < MIDI_PORTS; ++i) - { - MidiPort* mp = &midiPorts[i]; - if(mp->device()) - continue; - - PopupMenu* subp = new PopupMenu(morep, true); - subp->setTitle(QString("%1:").arg(i) + tr("")); - - // MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers! - //connect(subp, SIGNAL(triggered(QAction*)), pup, SIGNAL(triggered(QAction*))); - //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide())); - - iRoute ir = rl->begin(); - for( ; ir != rl->end(); ++ir) - { - if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) - break; - } - if(ir != rl->end()) - continue; - - for(int ch = 0; ch < MIDI_CHANNELS; ++ch) - { - act = subp->addAction(QString("Channel %1").arg(ch+1)); - act->setCheckable(true); - act->setData(gid); - - int chbit = 1 << ch; - Route srcRoute(i, chbit); // In accordance with new channel mask, use the bit position. - - gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) ); - - //if(chanmask & chbit) // Is the channel already set? Show item check mark. - // act->setChecked(true); - - ++gid; - } - //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. - act = subp->addAction(QString("Toggle all")); - //act->setCheckable(true); - act->setData(gid); - Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. - gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) ); - ++gid; - morep->addMenu(subp); - } - pup->addMenu(morep); - #endif - - } - - if(pup->actions().isEmpty()) - { - gRoutingPopupMenuMaster = 0; - //pup->clear(); - //pup->disconnect(); - gRoutingMenuMap.clear(); - //oR->setDown(false); - return 0; - } - - gIsOutRoutingPopupMenu = dst; - return pup; - } - - return 0; -} - //--------------------------------------------------------- // saveAs //--------------------------------------------------------- diff --git a/muse2/muse/app.h b/muse2/muse/app.h index c194b603..256154e2 100644 --- a/muse2/muse/app.h +++ b/muse2/muse/app.h @@ -36,8 +36,7 @@ class Transport; class BigTime; class Arranger; class Instrument; -class PopupMenu; -class PopupView; +class RoutePopupMenu; class Track; class PrinterConfig; class MidiSyncConfig; @@ -69,8 +68,6 @@ class ScoreEdit; #define MENU_ADD_SYNTH_ID_BASE 0x1000 - - //--------------------------------------------------------- // MusE //--------------------------------------------------------- @@ -164,10 +161,8 @@ class MusE : public QMainWindow QMenu* menu_functions, *menuScriptPlugins; QMenu* select, *master, *midiEdit, *addTrack; - // Special 'stay-open' menu for routes. - PopupMenu* routingPopupMenu; - //PopupView* routingPopupView; - + // Special common menu for routes. Used (so far) by audio and midi strip, and midi trackinfo. + RoutePopupMenu* routingPopupMenu; QMenu* follow; QMenu* midiInputPlugins; @@ -337,7 +332,6 @@ class MusE : public QMainWindow private: void adjustGlobalLists(int startPos, int diff); - public slots: bool saveAs(); void bounceToFile(AudioOutput* ao = 0); @@ -358,8 +352,6 @@ class MusE : public QMainWindow void setUsedTool(int); void showDidYouKnowDialog(); void startEditInstrument(); - - void routingPopupMenuAboutToHide(); void configMidiPorts(); public: @@ -371,7 +363,6 @@ class MusE : public QMainWindow bool importMidi(const QString name, bool merge); void kbAccel(int); void changeConfig(bool writeFlag); - void seqStop(); bool seqStart(); void setHeartBeat(); @@ -384,18 +375,8 @@ class MusE : public QMainWindow QWidget* bigtimeWindow(); bool importWaveToTrack(QString& name, unsigned tick=0, Track* track=NULL); void importPartToTrack(QString& filename, unsigned tick, Track* track); - void showTransport(bool flag); - - // Special 'stay-open' menu for routes. - PopupMenu* getRoutingPopupMenu(); - PopupMenu* prepareRoutingPopupMenu(Track* /*track*/, bool /*dst*/); - void routingPopupMenuActivated(Track* /*track*/, int /*id*/); - void updateRouteMenus(Track* /*track*/, QObject* /*master*/); - // Testing... - //PopupView* getRoutingPopupView(); - //PopupView* prepareRoutingPopupView(Track* /*track*/, bool /*dst*/); - //void routingPopupViewActivated(Track* /*track*/, int /*id*/); + RoutePopupMenu* getRoutingPopupMenu(); #ifdef HAVE_LASH void lash_idle_cb (); diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp index c427a55c..b004638f 100644 --- a/muse2/muse/audiotrack.cpp +++ b/muse2/muse/audiotrack.cpp @@ -34,6 +34,7 @@ bool WaveTrack::_isVisible=true; // 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. +// Keep this around for now. It may come in handy if we want to preserve route names with dummy audio driver! /* typedef std::multimap jackRouteNameMap; std::map jackRouteNameCache; diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp index 56cbc321..89cdd04d 100644 --- a/muse2/muse/conf.cpp +++ b/muse2/muse/conf.cpp @@ -948,6 +948,9 @@ void readConfiguration(Xml& xml, bool readOnlySequencer) config.projectStoreInFolder = xml.parseInt(); else if (tag == "useProjectSaveDialog") config.useProjectSaveDialog = xml.parseInt(); + else if (tag == "popupsDefaultStayOpen") + config.popupsDefaultStayOpen = xml.parseInt(); + else xml.unknown("configuration"); break; @@ -1217,7 +1220,6 @@ void MusE::writeGlobalConfiguration(int level, Xml& xml) const xml.intTag(level, "midiFilterCtrl2", midiFilterCtrl2); xml.intTag(level, "midiFilterCtrl3", midiFilterCtrl3); xml.intTag(level, "midiFilterCtrl4", midiFilterCtrl4); - // Removed by Tim. p3.3.6 //xml.intTag(level, "txDeviceId", txDeviceId); //xml.intTag(level, "rxDeviceId", rxDeviceId); @@ -1226,7 +1228,8 @@ void MusE::writeGlobalConfiguration(int level, Xml& xml) const xml.strTag(level, "externalWavEditor", config.externalWavEditor); xml.intTag(level, "useOldStyleStopShortCut", config.useOldStyleStopShortCut); xml.intTag(level, "moveArmedCheckBox", config.moveArmedCheckBox); - + xml.intTag(level, "popupsDefaultStayOpen", config.popupsDefaultStayOpen); + //for (int i = 0; i < 6; ++i) { for (int i = 0; i < NUM_FONTS; ++i) { char buffer[32]; @@ -1279,39 +1282,8 @@ void MusE::writeGlobalConfiguration(int level, Xml& xml) const xml.colorTag(level, "auxTrackBg", config.auxTrackBg); xml.colorTag(level, "synthTrackBg", config.synthTrackBg); - // Changed by Tim. p3.3.6 - + // Removed by Tim. p3.3.6 //xml.intTag(level, "txSyncPort", txSyncPort); - /* - // To keep old muse versions happy... - bool mcsync = mmc = mtc = false; - for(int sp = 0; sp < MIDI_PORTS; ++sp) - { - MidiSyncTxPort* txPort = &midiSyncTxPorts[sp]; - if(txPort->doMCSync() || txPort->doMMC() || txPort->doMTC()) - { - if(txPort->doMCSync()) - mcsync = true; - if(txPort->doMMC()) - mmc = true; - if(txPort->doMTC()) - mtc = true; - xml.intTag(level, "txSyncPort", sp); - break; - } - } - */ - - // Added by Tim. p3.3.6 - - //xml.tag(level++, "midiSyncInfo"); - //for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) - //{ - // MidiDevice* md = *id; - // (*id)->syncInfo().write(level, xml, md); - //} - //xml.etag(level, "midiSyncInfo"); - //xml.intTag(level, "rxSyncPort", rxSyncPort); xml.intTag(level, "mtctype", mtcType); xml.nput(level, "%02d:%02d:%02d:%02d:%02d\n", diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp index fc005923..8b323fc1 100644 --- a/muse2/muse/confmport.cpp +++ b/muse2/muse/confmport.cpp @@ -507,7 +507,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) //Route dst(*ip, true, i); //Route rt(*ip, (dev->rwFlags() & 1), -1, Route::JACK_ROUTE); Route rt(*ip, (col == DEVCOL_OUTROUTES), -1, Route::JACK_ROUTE); - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) { if (*ir == rt) { @@ -553,7 +553,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) Route srcRoute(dev, -1); Route dstRoute(s, true, -1, Route::JACK_ROUTE); - iRoute iir = rl->begin(); + ciRoute iir = rl->begin(); for(; iir != rl->end(); ++iir) { if(*iir == dstRoute) @@ -573,7 +573,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) Route srcRoute(s, false, -1, Route::JACK_ROUTE); Route dstRoute(dev, -1); - iRoute iir = rl->begin(); + ciRoute iir = rl->begin(); for(; iir != rl->end(); ++iir) { if(*iir == srcRoute) diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index f70cf3d3..c4d7a8ca 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -711,7 +711,7 @@ void JackAudioDevice::connectJackMidiPorts() if(port) // { RouteList* rl = md->outRoutes(); - for (iRoute r = rl->begin(); r != rl->end(); ++r) + for (ciRoute r = rl->begin(); r != rl->end(); ++r) connect(port, r->jackPort); } } @@ -724,7 +724,7 @@ void JackAudioDevice::connectJackMidiPorts() if(port) // { RouteList* rl = md->inRoutes(); - for (iRoute r = rl->begin(); r != rl->end(); ++r) + for (ciRoute r = rl->begin(); r != rl->end(); ++r) connect(r->jackPort, port); } } @@ -915,7 +915,7 @@ void JackAudioDevice::graphChanged() // the "right" amount for (int i = 0;i < 20;i++) { erased = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { if (irl->channel != channel) continue; QString name = irl->name(); @@ -953,7 +953,7 @@ void JackAudioDevice::graphChanged() const char** pn = ports; while (*pn) { bool found = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { if (irl->channel != channel) continue; QString name = irl->name(); @@ -1002,7 +1002,7 @@ void JackAudioDevice::graphChanged() // the "right" amount for (int i = 0; i < 20 ; i++) { erased = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { if (irl->channel != channel) continue; QString name = irl->name(); @@ -1039,7 +1039,7 @@ void JackAudioDevice::graphChanged() const char** pn = ports; while (*pn) { bool found = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { if (irl->channel != channel) continue; QString name = irl->name(); @@ -1113,7 +1113,7 @@ void JackAudioDevice::graphChanged() for (int i = 0; i < 20 ; i++) { erased = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1155,7 +1155,7 @@ void JackAudioDevice::graphChanged() const char** pn = ports; while (*pn) { bool found = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1212,7 +1212,7 @@ void JackAudioDevice::graphChanged() for (int i = 0; i < 20 ; i++) { erased = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1253,7 +1253,7 @@ void JackAudioDevice::graphChanged() const char** pn = ports; while (*pn) { bool found = false; - for (iRoute irl = rl->begin(); irl != rl->end(); ++irl) { + for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1473,7 +1473,7 @@ void JackAudioDevice::start(int /*priority*/) for (int ch = 0; ch < channel; ++ch) { RouteList* rl = ai->inRoutes(); void* port = ai->jackPort(ch); - for (iRoute ir = rl->begin(); ir != rl->end(); ++ir) { + for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) { if (ir->channel == ch) connect(ir->jackPort, port); } @@ -1486,7 +1486,7 @@ void JackAudioDevice::start(int /*priority*/) for (int ch = 0; ch < channel; ++ch) { RouteList* rl = ai->outRoutes(); void* port = ai->jackPort(ch); - for (iRoute r = rl->begin(); r != rl->end(); ++r) { + for (ciRoute r = rl->begin(); r != rl->end(); ++r) { if (r->channel == ch) { connect(port, r->jackPort); } diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp index 4d22ad4c..49a6d572 100644 --- a/muse2/muse/gconfig.cpp +++ b/muse2/muse/gconfig.cpp @@ -168,6 +168,7 @@ GlobalConfigValues config = { QString("./"), // projectBaseFolder true, // projectStoreInFolder true, // useProjectSaveDialog - 64 // minControlProcessPeriod + 64, // minControlProcessPeriod + false // popupsDefaultStayOpen }; diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h index cd236b36..acf39782 100644 --- a/muse2/muse/gconfig.h +++ b/muse2/muse/gconfig.h @@ -143,6 +143,7 @@ struct GlobalConfigValues { bool projectStoreInFolder; bool useProjectSaveDialog; unsigned long minControlProcessPeriod; + bool popupsDefaultStayOpen; }; extern GlobalConfigValues config; diff --git a/muse2/muse/globals.cpp b/muse2/muse/globals.cpp index 00c0f0a9..7f346f87 100644 --- a/muse2/muse/globals.cpp +++ b/muse2/muse/globals.cpp @@ -350,10 +350,6 @@ unsigned char rcPlayNote = 29; unsigned char rcSteprecNote = 36; bool automation = true; -QObject* gRoutingPopupMenuMaster = 0; -RouteMenuMap gRoutingMenuMap; -bool gIsOutRoutingPopupMenu = false; - uid_t euid, ruid; // effective user id, real user id bool midiSeqRunning = false; diff --git a/muse2/muse/globals.h b/muse2/muse/globals.h index 984571e2..cee5e815 100644 --- a/muse2/muse/globals.h +++ b/muse2/muse/globals.h @@ -13,7 +13,6 @@ #include "value.h" #include "mtc.h" -#include "route.h" #include @@ -172,15 +171,6 @@ extern unsigned char rcSteprecNote; extern bool midiSeqRunning; extern bool automation; -class QObject; -// Which audio strip, midi strip, or midi track info strip -// was responsible for popping up the routing menu. -extern QObject* gRoutingPopupMenuMaster; -// Map of routing popup menu item IDs to Routes. -extern RouteMenuMap gRoutingMenuMap; -// Whether the routes popup was shown by clicking the output routes button, or input routes button. -extern bool gIsOutRoutingPopupMenu; - // p3.3.55 #define JACK_MIDI_OUT_PORT_SUFFIX "_out" #define JACK_MIDI_IN_PORT_SUFFIX "_in" diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index c1e92e59..5644e6eb 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -48,33 +48,8 @@ #include "gconfig.h" #include "ttoolbutton.h" #include "menutitleitem.h" -#include "popupmenu.h" - -//--------------------------------------------------------- -// MenuTitleItem -//--------------------------------------------------------- - -MenuTitleItem::MenuTitleItem(const QString& ss, QWidget* parent) - : QWidgetAction(parent) - { - s = ss; - // Don't allow to click on it. - setEnabled(false); - // Just to be safe, set to -1 instead of default 0. - setData(-1); - } - -QWidget* MenuTitleItem::createWidget(QWidget *parent) -{ - QLabel* l = new QLabel(s, parent); - l->setAlignment(Qt::AlignCenter); - l->setAutoFillBackground(true); - //QPalette palette; - //palette.setColor(label->backgroundRole(), c); - //l->setPalette(palette); - l->setBackgroundRole(QPalette::Dark); - return l; -} +//#include "popupmenu.h" +#include "routepopup.h" /* //--------------------------------------------------------- @@ -145,14 +120,6 @@ void AudioStrip::songChanged(int val) if (val & SC_CHANNELS) updateChannels(); - // p3.3.47 - // Update the routing popup menu if anything relevant changed. - if (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) - { - //updateRouteMenus(); - muse->updateRouteMenus(track, this); // p3.3.50 Use this handy shared routine. - } - // Catch when label font, or configuration min slider and meter values change. if (val & SC_CONFIG) { @@ -215,7 +182,6 @@ void AudioStrip::songChanged(int val) if (val & SC_TRACK_MODIFIED) { setLabelText(); - // Added by Tim. p3.3.9 setLabelFont(); } @@ -1006,899 +972,15 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at) connect(heartBeatTimer, SIGNAL(timeout()), SLOT(heartBeat())); } -//--------------------------------------------------------- -// addMenuItem -//--------------------------------------------------------- - -static int addMenuItem(AudioTrack* track, Track* route_track, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput) -{ - // totalInChannels is only used by syntis. - 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; - - // 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(); - - QAction* act; - - QString s(route_track->name()); - - act = lb->addAction(s); - act->setData(id); - act->setCheckable(true); - - int ach = channel; - int bch = -1; - - Route r(route_track, isOutput ? ach : bch, channels); - - r.remoteChannel = isOutput ? bch : ach; - - mm.insert( pRouteMenuMap(id, r) ); - - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - 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(compch == tcompch && compchs == tcompchs) - { - act->setChecked(true); - break; - } - } - } - return ++id; -} - -//--------------------------------------------------------- -// addAuxPorts -//--------------------------------------------------------- - -static int addAuxPorts(AudioTrack* t, PopupMenu* 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(t, track, lb, id, mm, channel, channels, isOutput); - } - return id; - } - -//--------------------------------------------------------- -// addInPorts -//--------------------------------------------------------- - -static int addInPorts(AudioTrack* t, PopupMenu* 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(t, track, lb, id, mm, channel, channels, isOutput); - } - return id; - } - -//--------------------------------------------------------- -// addOutPorts -//--------------------------------------------------------- - -static int addOutPorts(AudioTrack* t, PopupMenu* 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(t, track, lb, id, mm, channel, channels, isOutput); - } - return id; - } - -//--------------------------------------------------------- -// addGroupPorts -//--------------------------------------------------------- - -static int addGroupPorts(AudioTrack* t, PopupMenu* 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(t, track, lb, id, mm, channel, channels, isOutput); - } - return id; - } - -//--------------------------------------------------------- -// addWavePorts -//--------------------------------------------------------- - -static int addWavePorts(AudioTrack* t, PopupMenu* 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(t, track, lb, id, mm, channel, channels, isOutput); - } - return id; - } - -//--------------------------------------------------------- -// addSyntiPorts -//--------------------------------------------------------- - -static int addSyntiPorts(AudioTrack* t, PopupMenu* lb, int id, - RouteMenuMap& mm, int channel, int channels, bool isOutput) -{ - RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); - - QAction* act; - - SynthIList* al = song->syntis(); - for (iSynthI i = al->begin(); i != al->end(); ++i) - { - Track* track = *i; - if (t == track) - continue; - 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(); - - 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) - { - PopupMenu* chpup = new PopupMenu(lb, true); - chpup->setTitle(track->name()); - for(int ch = 0; ch < chans; ++ch) - { - char buffer[128]; - if(tchans == 2) - snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").toLatin1().constData(), ch+1, ch+2); - else - snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); - act = chpup->addAction(QString(buffer)); - act->setData(id); - act->setCheckable(true); - - 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 == 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) - { - act->setChecked(true); - break; - } - } - } - ++id; - } - - lb->addMenu(chpup); - } - } - return id; -} - -//--------------------------------------------------------- -// addMultiChannelOutPorts -//--------------------------------------------------------- - -static int addMultiChannelPorts(AudioTrack* t, PopupMenu* 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. - // totalInChannels is only used by syntis. - int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? toch : t->totalInChannels(); - - if(chans > 1) - pup->addAction(new MenuTitleItem("", pup)); - - // - // If it's more than one channel, create a sub-menu. If it's just one channel, don't bother with a sub-menu... - // - - PopupMenu* chpup = pup; - - for(int ch = 0; ch < chans; ++ch) - { - // If more than one channel, create the sub-menu. - if(chans > 1) - chpup = new PopupMenu(pup, true); - - if(isOutput) - { - switch(t->type()) - { - - case Track::AUDIO_INPUT: - //id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput); // Rem p4.0.20 - case Track::WAVE: - case Track::AUDIO_GROUP: - case Track::AUDIO_SOFTSYNTH: - case Track::AUDIO_AUX: // p4.0.20 - id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput); - id = addOutPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addSyntiPorts(t, chpup, id, mm, ch, 1, isOutput); - //break; // Rem p4.0.20 - //case Track::AUDIO_AUX: // - //id = addOutPorts(t, chpup, id, mm, ch, 1, isOutput); // - break; - default: - break; - } - } - else - { - switch(t->type()) - { - - case Track::AUDIO_OUTPUT: - id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput); - id = addInPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addAuxPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addSyntiPorts(t, chpup, id, mm, ch, 1, isOutput); - break; - case Track::WAVE: - //id = addInPorts(t, chpup, id, mm, ch, 1, isOutput); // Rem p4.0.20 - //break; - case Track::AUDIO_SOFTSYNTH: - case Track::AUDIO_GROUP: - id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput); - id = addInPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput); - id = addAuxPorts(t, chpup, id, mm, ch, 1, isOutput); // p4.0.20 - id = addSyntiPorts(t, chpup, id, mm, ch, 1, 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").toLatin1().constData(), ch+1); - chpup->setTitle(QString(buffer)); - pup->addMenu(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->addSeparator(); - pup->addAction(new MenuTitleItem("", pup)); - - // - // If it's more than two channels, create a sub-menu. If it's just two channels, don't bother with a sub-menu... - // - - chpup = pup; - if(chans <= 2) - // Just do one iteration. - chans = 1; - - for(int ch = 0; ch < chans; ++ch) - { - // If more than two channels, create the sub-menu. - if(chans > 2) - chpup = new PopupMenu(pup, true); - - if(isOutput) - { - switch(t->type()) - { - case Track::AUDIO_INPUT: - //id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput); // Rem p4.0.20 - case Track::WAVE: - case Track::AUDIO_GROUP: - case Track::AUDIO_SOFTSYNTH: - case Track::AUDIO_AUX: // p4.0.20 - id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput); // p4.0.20 - id = addOutPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addSyntiPorts(t, chpup, id, mm, ch, 2, isOutput); - break; - //case Track::AUDIO_AUX: // Rem p4.0.20 - // id = addOutPorts(t, chpup, id, mm, ch, 2, isOutput); - // break; - default: - break; - } - } - else - { - switch(t->type()) - { - case Track::AUDIO_OUTPUT: - id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput); - id = addInPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addAuxPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addSyntiPorts(t, chpup, id, mm, ch, 2, isOutput); - break; - case Track::WAVE: - //id = addInPorts(t, chpup, id, mm, ch, 2, isOutput); // Rem p4.0.20 - //break; - case Track::AUDIO_SOFTSYNTH: - case Track::AUDIO_GROUP: - id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput); - id = addInPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput); - id = addAuxPorts(t, chpup, id, mm, ch, 2, isOutput); // p4.0.20 - id = addSyntiPorts(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").toLatin1().constData(), ch+1, ch+2); - chpup->setTitle(QString(buffer)); - pup->addMenu(chpup); - } - } - } - - return id; -} - -//--------------------------------------------------------- -// nonSyntiTrackAddSyntis -//--------------------------------------------------------- - -static int nonSyntiTrackAddSyntis(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, bool isOutput) -{ - RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); - - QAction* act; - SynthIList* al = song->syntis(); - for (iSynthI i = al->begin(); i != al->end(); ++i) - { - Track* track = *i; - if (t == track) - continue; - - 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(); - - //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) - { - PopupMenu* chpup = new PopupMenu(lb, true); - chpup->setTitle(track->name()); - if(chans > 1) - chpup->addAction(new MenuTitleItem("", chpup)); - - for(int ch = 0; ch < chans; ++ch) - { - char buffer[128]; - snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); - act = chpup->addAction(QString(buffer)); - act->setData(id); - act->setCheckable(true); - - int ach = ch; - int bch = -1; - - Route rt(track, isOutput ? bch : ach, 1); - - rt.remoteChannel = isOutput ? ach : bch; - - mm.insert( pRouteMenuMap(id, rt) ); - - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - 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) - { - act->setChecked(true); - break; - } - } - } - ++id; - } - - chans -= 1; - if(chans > 0) - { - // Ignore odd numbered left-over channels. - //int schans = (chans & ~1) - 1; - - chpup->addSeparator(); - chpup->addAction(new MenuTitleItem("", chpup)); - - for(int ch = 0; ch < chans; ++ch) - { - char buffer[128]; - snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").toLatin1().constData(), ch+1, ch+2); - act = chpup->addAction(QString(buffer)); - act->setData(id); - act->setCheckable(true); - - int ach = ch; - int bch = -1; - - Route rt(track, isOutput ? bch : ach, 2); - - rt.remoteChannel = isOutput ? ach : bch; - - mm.insert( pRouteMenuMap(id, rt) ); - - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - 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) - { - act->setChecked(true); - break; - } - } - } - ++id; - } - } - - lb->addMenu(chpup); - } - } - return id; -} - -//--------------------------------------------------------- -// addMidiPorts -//--------------------------------------------------------- - -static int addMidiPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenuMap& mm, bool isOutput) -{ - QAction* act; - for(int i = 0; i < MIDI_PORTS; ++i) - { - MidiPort* mp = &midiPorts[i]; - MidiDevice* md = mp->device(); - - // This is desirable, but could lead to 'hidden' routes unless we add more support - // such as removing the existing routes when user changes flags. - // So for now, just list all valid ports whether read or write. - if(!md) - continue; - //if(!(md->rwFlags() & (isOutput ? 1 : 2))) - // continue; - - // p4.0.17 Do not list synth devices! - if(md->isSynti()) - continue; - - RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); - - PopupMenu* subp = new PopupMenu(pup, true); - subp->setTitle(md->name()); - - int chanmask = 0; - // To reduce number of routes required, from one per channel to just one containing a channel mask. - // Look for the first route to this midi port. There should always be only a single route for each midi port, now. - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) - { - // We have a route to the midi port. Grab the channel mask. - chanmask = ir->channel; - break; - } - } - - for(int ch = 0; ch < MIDI_CHANNELS; ++ch) - { - act = subp->addAction(QString("Channel %1").arg(ch+1)); - act->setCheckable(true); - act->setData(id); - - int chbit = 1 << ch; - Route srcRoute(i, chbit); // In accordance with new channel mask, use the bit position. - - mm.insert( pRouteMenuMap(id, srcRoute) ); - - if(chanmask & chbit) // Is the channel already set? Show item check mark. - act->setChecked(true); - - ++id; - } - - //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. - act = subp->addAction(QString("Toggle all")); - //act->setCheckable(true); - act->setData(id); - Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. - mm.insert( pRouteMenuMap(id, togRoute) ); - ++id; - - pup->addMenu(subp); - } - return id; -} - -//--------------------------------------------------------- -// routingPopupMenuActivated -//--------------------------------------------------------- - -void AudioStrip::routingPopupMenuActivated(QAction* act) -{ - if(!track || gRoutingPopupMenuMaster != this || track->isMidiTrack()) - return; - - PopupMenu* pup = muse->getRoutingPopupMenu(); - - if(pup->actions().isEmpty()) - return; - - AudioTrack* t = (AudioTrack*)track; - RouteList* rl = gIsOutRoutingPopupMenu ? t->outRoutes() : t->inRoutes(); - - int n = act->data().toInt(); - if (n == -1) - return; - - iRouteMenuMap imm = gRoutingMenuMap.find(n); - if(imm == gRoutingMenuMap.end()) - return; - - if(gIsOutRoutingPopupMenu) - { - Route srcRoute(t, imm->second.channel, imm->second.channels); - srcRoute.remoteChannel = imm->second.remoteChannel; - - Route &dstRoute = imm->second; - - // check if route src->dst exists: - iRoute irl = rl->begin(); - for (; irl != rl->end(); ++irl) { - if (*irl == dstRoute) - break; - } - if (irl != rl->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); - } - else - { - Route &srcRoute = imm->second; - - // Support Midi Port to Audio Input routes. p4.0.14 Tim. - if(track->type() == Track::AUDIO_INPUT && srcRoute.type == Route::MIDI_PORT_ROUTE) - { - int chbit = srcRoute.channel; - Route dstRoute(t, chbit); - int mdidx = srcRoute.midiPort; - int chmask = 0; - iRoute iir = rl->begin(); - for (; iir != rl->end(); ++iir) - { - if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx) // Is there already a route to this port? - { - chmask = iir->channel; // Grab the channel mask. - break; - } - } - - if ((chmask & chbit) == chbit) // Is the channel's bit(s) set? - { - //printf("astrip: removing src route ch:%d dst route ch:%d\n", srcRoute.channel, dstRoute.channel); - audio->msgRemoveRoute(srcRoute, dstRoute); - } - else - { - //printf("astrip: adding src route ch:%d dst route ch:%d\n", srcRoute.channel, dstRoute.channel); - audio->msgAddRoute(srcRoute, dstRoute); - } - - audio->msgUpdateSoloStates(); - song->update(SC_ROUTE); - return; - } - - Route dstRoute(t, imm->second.channel, imm->second.channels); - dstRoute.remoteChannel = imm->second.remoteChannel; - - iRoute irl = rl->begin(); - for (; irl != rl->end(); ++irl) { - if (*irl == srcRoute) - break; - } - if (irl != rl->end()) { - // disconnect - audio->msgRemoveRoute(srcRoute, dstRoute); - } - else { - // connect - audio->msgAddRoute(srcRoute, dstRoute); - } - audio->msgUpdateSoloStates(); - song->update(SC_ROUTE); - } -} - //--------------------------------------------------------- // iRoutePressed //--------------------------------------------------------- void AudioStrip::iRoutePressed() { - //if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH)) - if(!track || track->isMidiTrack() || track->type() == Track::AUDIO_AUX) - { - gRoutingPopupMenuMaster = 0; - return; - } - - QPoint ppt = QCursor::pos(); - - PopupMenu* pup = muse->getRoutingPopupMenu(); - pup->disconnect(); - - AudioTrack* t = (AudioTrack*)track; - RouteList* irl = t->inRoutes(); - - QAction* act = 0; - int gid = 0; - //int id = 0; - - pup->clear(); - gRoutingMenuMap.clear(); - gid = 0; - - switch(track->type()) - { - case Track::AUDIO_INPUT: - { - for(int i = 0; i < channel; ++i) - { - char buffer[128]; - snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); - MenuTitleItem* titel = new MenuTitleItem(QString(buffer), pup); - pup->addAction(titel); - - if(!checkAudioDevice()) - { - gRoutingPopupMenuMaster = 0; - pup->clear(); - gRoutingMenuMap.clear(); - iR->setDown(false); - return; - } - std::list ol = audioDevice->outputPorts(); - for(std::list::iterator ip = ol.begin(); ip != ol.end(); ++ip) - { - //id = gid * 16 + i; // IDs removed p4.0.14 Tim. - act = pup->addAction(*ip); - //act->setData(id); - act->setData(gid); - act->setCheckable(true); - - Route dst(*ip, true, i, Route::JACK_ROUTE); - //gRoutingMenuMap.insert( pRouteMenuMap(id, dst) ); - gRoutingMenuMap.insert( pRouteMenuMap(gid, dst) ); - ++gid; - for(iRoute ir = irl->begin(); ir != irl->end(); ++ir) - { - if(*ir == dst) - { - act->setChecked(true); - break; - } - } - } - if(i+1 != channel) - pup->addSeparator(); - } - - // p4.0.14 - // - // Display using separate menus for midi ports and audio outputs: - // - pup->addSeparator(); - pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup)); - PopupMenu* subp = new PopupMenu(pup, true); - subp->setTitle(tr("Audio sends")); - pup->addMenu(subp); - gid = addOutPorts(t, subp, gid, gRoutingMenuMap, -1, -1, false); - subp = new PopupMenu(pup, true); - subp->setTitle(tr("Midi port sends")); - pup->addMenu(subp); - addMidiPorts(t, subp, gid, gRoutingMenuMap, false); - // - // Display all in the same menu: - // - //pup->addAction(new MenuTitleItem(tr("Audio sends"), pup)); - //gid = addOutPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false); - //pup->addSeparator(); - //pup->addAction(new MenuTitleItem(tr("Midi sends"), pup)); - //addMidiPorts(t, pup, gid, gRoutingMenuMap, false); - } - break; - //case Track::AUDIO_OUTPUT: - //case Track::WAVE: - //case Track::AUDIO_GROUP: - - case Track::AUDIO_OUTPUT: - gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addGroupPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addAuxPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, false); - break; - case Track::WAVE: - gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); // p4.0.20 - gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addGroupPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false); // - gid = addAuxPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); // - gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, false); // - break; - case Track::AUDIO_GROUP: - gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addGroupPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false); - gid = addAuxPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false); // p4.0.20 - gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, false); - break; - - case Track::AUDIO_SOFTSYNTH: - gid = addMultiChannelPorts(t, pup, gid, gRoutingMenuMap, false); - break; - default: - gRoutingPopupMenuMaster = 0; - pup->clear(); - gRoutingMenuMap.clear(); - iR->setDown(false); - return; - } - - if(pup->actions().isEmpty()) - { - gRoutingPopupMenuMaster = 0; - gRoutingMenuMap.clear(); - iR->setDown(false); - return; - } - - gIsOutRoutingPopupMenu = false; - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - pup->popup(ppt); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); iR->setDown(false); + pup->exec(QCursor::pos(), track, false); } //--------------------------------------------------------- @@ -1907,136 +989,8 @@ void AudioStrip::iRoutePressed() void AudioStrip::oRoutePressed() { - if(!track || track->isMidiTrack()) - { - gRoutingPopupMenuMaster = 0; - return; - } - - QPoint ppt = QCursor::pos(); - - PopupMenu* pup = muse->getRoutingPopupMenu(); - pup->disconnect(); - - AudioTrack* t = (AudioTrack*)track; - RouteList* orl = t->outRoutes(); - - QAction* act = 0; - int gid = 0; - //int id = 0; - - pup->clear(); - gRoutingMenuMap.clear(); - gid = 0; - - switch(track->type()) - { - case Track::AUDIO_OUTPUT: - { - for(int i = 0; i < channel; ++i) - { - char buffer[128]; - snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); - MenuTitleItem* titel = new MenuTitleItem(QString(buffer), pup); - pup->addAction(titel); - - if(!checkAudioDevice()) - { - gRoutingPopupMenuMaster = 0; - pup->clear(); - gRoutingMenuMap.clear(); - oR->setDown(false); - return; - } - std::list ol = audioDevice->inputPorts(); - for(std::list::iterator ip = ol.begin(); ip != ol.end(); ++ip) - { - //id = gid * 16 + i; // IDs removed p4.0.14 Tim. - act = pup->addAction(*ip); - //act->setData(id); - act->setData(gid); - act->setCheckable(true); - - Route dst(*ip, true, i, Route::JACK_ROUTE); - //gRoutingMenuMap.insert( pRouteMenuMap(id, dst) ); - gRoutingMenuMap.insert( pRouteMenuMap(gid, dst) ); - ++gid; - for(iRoute ir = orl->begin(); ir != orl->end(); ++ir) - { - if(*ir == dst) - { - act->setChecked(true); - break; - } - } - } - if(i+1 != channel) - pup->addSeparator(); - } - - // p4.0.14 - // - // Display using separate menu for audio inputs: - // - pup->addSeparator(); - pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup)); - PopupMenu* subp = new PopupMenu(pup, true); - subp->setTitle(tr("Audio returns")); - pup->addMenu(subp); - gid = addInPorts(t, subp, gid, gRoutingMenuMap, -1, -1, true); - // - // Display all in the same menu: - // - //pup->addSeparator(); - //MenuTitleItem* title = new MenuTitleItem(tr("Audio returns"), pup); - //pup->addAction(title); - //gid = addInPorts(t, pup, gid, gRoutingMenuMap, -1, -1, true); - } - break; - //case Track::AUDIO_INPUT: - //case Track::WAVE: - //case Track::AUDIO_GROUP: - - case Track::AUDIO_SOFTSYNTH: - gid = addMultiChannelPorts(t, pup, gid, gRoutingMenuMap, true); - break; - - case Track::AUDIO_INPUT: - //gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, true); // Rem p4.0.20 - case Track::WAVE: - case Track::AUDIO_GROUP: - case Track::AUDIO_AUX: - //case Track::AUDIO_SOFTSYNTH: - gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, true); // p4.0.20 - gid = addOutPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true); - gid = addGroupPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true); - gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, true); - break; - //case Track::AUDIO_AUX: - // gid = addOutPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true); - //break; - - default: - gRoutingPopupMenuMaster = 0; - pup->clear(); - gRoutingMenuMap.clear(); - oR->setDown(false); - return; - } - - if(pup->actions().isEmpty()) - { - gRoutingPopupMenuMaster = 0; - gRoutingMenuMap.clear(); - oR->setDown(false); - return; - } - - gIsOutRoutingPopupMenu = true; - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - pup->popup(ppt); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); oR->setDown(false); + pup->exec(QCursor::pos(), track, true); } diff --git a/muse2/muse/mixer/astrip.h b/muse2/muse/mixer/astrip.h index 10d75305..92867033 100644 --- a/muse2/muse/mixer/astrip.h +++ b/muse2/muse/mixer/astrip.h @@ -12,7 +12,7 @@ #include #include "strip.h" -#include "route.h" +//#include "route.h" class Slider; class Knob; @@ -20,7 +20,7 @@ class Knob; class QToolButton; //class QAction; //class QPopupMenu; -class PopupMenu; +//class PopupMenu; class QButton; class TransparentToolButton; class AudioTrack; @@ -61,7 +61,6 @@ class AudioStrip : public Strip { void updateVolume(); void updatePan(); void updateChannels(); - //void updateRouteMenus(); private slots: void stereoToggled(bool); @@ -69,7 +68,6 @@ class AudioStrip : public Strip { void offToggled(bool); void iRoutePressed(); void oRoutePressed(); - void routingPopupMenuActivated(QAction*); void auxChanged(double, int); void volumeChanged(double); void volumePressed(); diff --git a/muse2/muse/mixer/mstrip.cpp b/muse2/muse/mixer/mstrip.cpp index 427f9ed6..d773708a 100644 --- a/muse2/muse/mixer/mstrip.cpp +++ b/muse2/muse/mixer/mstrip.cpp @@ -43,7 +43,8 @@ #include "gconfig.h" #include "ttoolbutton.h" //#include "utils.h" -#include "popupmenu.h" +//#include "popupmenu.h" +#include "routepopup.h" enum { KNOB_PAN, KNOB_VAR_SEND, KNOB_REV_SEND, KNOB_CHO_SEND }; @@ -503,26 +504,17 @@ void MidiStrip::songChanged(int val) if (val & SC_TRACK_MODIFIED) { setLabelText(); - // Added by Tim. p3.3.9 setLabelFont(); } - // Added by Tim. p3.3.9 - // Catch when label font changes. + // Catch when label font changes. Tim. p3.3.9 if (val & SC_CONFIG) { // Set the strip label's font. //label->setFont(config.fonts[1]); setLabelFont(); } - - // p3.3.47 Update the routing popup menu if anything relevant changes. - //if(gRoutingPopupMenuMaster == this && track && (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) - if(val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) // p3.3.50 - // Use this handy shared routine. - //muse->updateRouteMenus(track); - muse->updateRouteMenus(track, this); // p3.3.50 } //--------------------------------------------------------- @@ -1006,36 +998,15 @@ void MidiStrip::setReverbSend(double val) ctrlChanged(CTRL_REVERB_SEND, lrint(val)); } -//--------------------------------------------------------- -// routingPopupMenuActivated -//--------------------------------------------------------- - -void MidiStrip::routingPopupMenuActivated(QAction* act) -{ - if(gRoutingPopupMenuMaster != this || !track || !track->isMidiTrack()) - return; - - muse->routingPopupMenuActivated(track, act->data().toInt()); -} - //--------------------------------------------------------- // iRoutePressed //--------------------------------------------------------- void MidiStrip::iRoutePressed() { - if(!track || !track->isMidiTrack()) - return; - - PopupMenu* pup = muse->prepareRoutingPopupMenu(track, false); - if(!pup) - return; - - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - pup->popup(QCursor::pos()); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); iR->setDown(false); + pup->exec(QCursor::pos(), track, false); } //--------------------------------------------------------- @@ -1044,18 +1015,9 @@ void MidiStrip::iRoutePressed() void MidiStrip::oRoutePressed() { - if(!track || !track->isMidiTrack()) - return; - - PopupMenu* pup = muse->prepareRoutingPopupMenu(track, true); - if(!pup) - return; - - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - pup->popup(QCursor::pos()); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); oR->setDown(false); + pup->exec(QCursor::pos(), track, true); } diff --git a/muse2/muse/mixer/mstrip.h b/muse2/muse/mixer/mstrip.h index 920cca99..39b55d21 100644 --- a/muse2/muse/mixer/mstrip.h +++ b/muse2/muse/mixer/mstrip.h @@ -32,9 +32,6 @@ class MidiStrip : public Strip { Slider* slider; DoubleLabel* sl; TransparentToolButton* off; - //QToolButton* route; - //QToolButton* iR; - //QToolButton* oR; struct KNOB { Knob* knob; @@ -55,11 +52,9 @@ class MidiStrip : public Strip { void updateOffState(); private slots: - //void routeClicked(); void offToggled(bool); void iRoutePressed(); void oRoutePressed(); - void routingPopupMenuActivated(QAction*); void setVolume(double); void setPan(double); void setChorusSend(double); diff --git a/muse2/muse/node.cpp b/muse2/muse/node.cpp index 114b03d3..06dbbc8d 100644 --- a/muse2/muse/node.cpp +++ b/muse2/muse/node.cpp @@ -1264,7 +1264,7 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b printf("AudioTrack::getData name:%s inRoutes:%d\n", name().toLatin1().constData(), rl->size()); #endif - iRoute ir = rl->begin(); + ciRoute ir = rl->begin(); if (ir == rl->end()) return false; diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp index 6f42c1f2..9425f056 100644 --- a/muse2/muse/route.cpp +++ b/muse2/muse/route.cpp @@ -187,7 +187,7 @@ void addRoute(Route src, Route dst) src.channel = dst.channel; //src.channels = dst.channels = 1; RouteList* inRoutes = dst.track->inRoutes(); - for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) + for (ciRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (*i == src) // route already there { @@ -226,7 +226,7 @@ void addRoute(Route src, Route dst) //dst.channel = -1; RouteList* routes = dst.device->inRoutes(); - for (iRoute i = routes->begin(); i != routes->end(); ++i) + for (ciRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == src) // route already there { @@ -284,7 +284,7 @@ void addRoute(Route src, Route dst) dst.channel = src.channel; //dst.channels = src.channels = 1; - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) // route already there { @@ -312,7 +312,7 @@ void addRoute(Route src, Route dst) //dst.channels = src.channels = 1; RouteList* routes = src.device->outRoutes(); - for (iRoute i = routes->begin(); i != routes->end(); ++i) + for (ciRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) // route already there { @@ -616,7 +616,7 @@ void addRoute(Route src, Route dst) // dst.channels = src.track->channels(); //} - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) // route already there // TODO: @@ -1248,7 +1248,7 @@ bool checkRoute(const QString& s, const QString& d) } src.channel = dst.channel; RouteList* inRoutes = dst.track->inRoutes(); - for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) + for (ciRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { if (*i == src) { // route already there return false; @@ -1263,7 +1263,7 @@ bool checkRoute(const QString& s, const QString& d) src.channel = -1; //dst.channel = -1; RouteList* routes = dst.device->inRoutes(); - for (iRoute i = routes->begin(); i != routes->end(); ++i) + for (ciRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == src) { // route already there return false; @@ -1286,7 +1286,7 @@ bool checkRoute(const QString& s, const QString& d) } RouteList* outRoutes = src.track->outRoutes(); dst.channel = src.channel; - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; @@ -1301,7 +1301,7 @@ bool checkRoute(const QString& s, const QString& d) //dst.channel = src.channel; dst.channel = -1; //src.channel = -1; - for (iRoute i = routes->begin(); i != routes->end(); ++i) + for (ciRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) { // route already there return false; @@ -1314,7 +1314,7 @@ bool checkRoute(const QString& s, const QString& d) else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { RouteList* outRoutes = midiPorts[src.midiPort].outRoutes(); - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; @@ -1330,7 +1330,7 @@ bool checkRoute(const QString& s, const QString& d) // 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) + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { if (*i == dst) { // route already there return false; diff --git a/muse2/muse/route.h b/muse2/muse/route.h index 2f29bcf8..9809352c 100644 --- a/muse2/muse/route.h +++ b/muse2/muse/route.h @@ -9,9 +9,10 @@ #ifndef __ROUTE_H__ #define __ROUTE_H__ +#include + #include #include - #include "globaldefs.h" class QString; @@ -71,6 +72,8 @@ struct Route { void dump() const; }; +// Allow Routes to be a QVariant +Q_DECLARE_METATYPE(Route) ; //--------------------------------------------------------- // RouteList @@ -93,11 +96,11 @@ extern bool checkRoute(const QString&, const QString&); // RouteMenuMap //--------------------------------------------------------- -typedef std::map >::iterator iRouteMenuMap; -typedef std::map >::const_iterator ciRouteMenuMap; -typedef std::map > RouteMenuMap; -typedef std::pair pRouteMenuMap; -typedef std::pair rpRouteMenuMap; +//typedef std::map >::iterator iRouteMenuMap; +//typedef std::map >::const_iterator ciRouteMenuMap; +//typedef std::map > RouteMenuMap; +//typedef std::pair pRouteMenuMap; +//typedef std::pair rpRouteMenuMap; #endif diff --git a/muse2/muse/seqmsg.cpp b/muse2/muse/seqmsg.cpp index 950015b2..b4d65148 100644 --- a/muse2/muse/seqmsg.cpp +++ b/muse2/muse/seqmsg.cpp @@ -396,7 +396,7 @@ void Audio::msgSetChannels(AudioTrack* node, int n) else if ((i >= n) && ai->jackPort(i)) { RouteList* ir = node->inRoutes(); - for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) + for (ciRoute ii = ir->begin(); ii != ir->end(); ++ii) { Route r = *ii; if ((r.type == Route::JACK_ROUTE) && (r.channel == i)) @@ -427,7 +427,7 @@ void Audio::msgSetChannels(AudioTrack* node, int n) else if (i >= n && jp) { RouteList* ir = node->outRoutes(); - for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) + for (ciRoute ii = ir->begin(); ii != ir->end(); ++ii) { Route r = *ii; if ((r.type == Route::JACK_ROUTE) && (r.channel == i)) diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 28ea1210..6750203a 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -2926,7 +2926,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect) for(int ch = 0; ch < ao->channels(); ++ch) { RouteList* ir = ao->outRoutes(); - for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) + for (ciRoute ii = ir->begin(); ii != ir->end(); ++ii) { Route r = *ii; if ((r.type == Route::JACK_ROUTE) && (r.channel == ch)) @@ -2959,7 +2959,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect) for(int ch = 0; ch < ai->channels(); ++ch) { RouteList* ir = ai->inRoutes(); - for (iRoute ii = ir->begin(); ii != ir->end(); ++ii) + for (ciRoute ii = ir->begin(); ii != ir->end(); ++ii) { Route r = *ii; if ((r.type == Route::JACK_ROUTE) && (r.channel == ch)) diff --git a/muse2/muse/wavetrack.cpp b/muse2/muse/wavetrack.cpp index fdebc8b8..ad02084c 100644 --- a/muse2/muse/wavetrack.cpp +++ b/muse2/muse/wavetrack.cpp @@ -209,7 +209,7 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float* if ((song->bounceTrack != this) && !noInRoute()) { RouteList* irl = inRoutes(); - iRoute i = irl->begin(); + ciRoute i = irl->begin(); if(i->track->isMidiTrack()) { if(debugMsg) diff --git a/muse2/muse/widgets/CMakeLists.txt b/muse2/muse/widgets/CMakeLists.txt index 7589ddf0..a4da398f 100644 --- a/muse2/muse/widgets/CMakeLists.txt +++ b/muse2/muse/widgets/CMakeLists.txt @@ -47,6 +47,7 @@ QT4_WRAP_CPP (widget_mocs intlabel.h knob.h lcombo.h + menutitleitem.h meter.h metronome.h midisyncimpl.h @@ -63,6 +64,7 @@ QT4_WRAP_CPP (widget_mocs # posedit.h poslabel.h projectcreateimpl.h + routepopup.h scrollscale.h shortcutcapturedialog.h shortcutconfig.h @@ -142,6 +144,7 @@ file (GLOB widgets_source_files intlabel.cpp knob.cpp lcombo.cpp + menutitleitem.cpp meter.cpp metronome.cpp midisyncimpl.cpp @@ -159,6 +162,7 @@ file (GLOB widgets_source_files # posedit.cpp poslabel.cpp projectcreateimpl.cpp + routepopup.cpp scldiv.cpp scldraw.cpp sclif.cpp diff --git a/muse2/muse/widgets/genset.cpp b/muse2/muse/widgets/genset.cpp index edf3cfda..d8c76874 100644 --- a/muse2/muse/widgets/genset.cpp +++ b/muse2/muse/widgets/genset.cpp @@ -151,6 +151,7 @@ Shorter periods are desirable. oldStyleStopCheckBox->setChecked(config.useOldStyleStopShortCut); moveArmedCheckBox->setChecked(config.moveArmedCheckBox); projectSaveCheckBox->setChecked(config.useProjectSaveDialog); + popsDefStayOpenCheckBox->setChecked(config.popupsDefaultStayOpen); //updateSettings(); // TESTING @@ -263,6 +264,7 @@ void GlobalSettingsConfig::updateSettings() oldStyleStopCheckBox->setChecked(config.useOldStyleStopShortCut); moveArmedCheckBox->setChecked(config.moveArmedCheckBox); projectSaveCheckBox->setChecked(config.useProjectSaveDialog); + popsDefStayOpenCheckBox->setChecked(config.popupsDefaultStayOpen); } //--------------------------------------------------------- @@ -344,6 +346,7 @@ void GlobalSettingsConfig::apply() config.useOldStyleStopShortCut = oldStyleStopCheckBox->isChecked(); config.moveArmedCheckBox = moveArmedCheckBox->isChecked(); config.useProjectSaveDialog = projectSaveCheckBox->isChecked(); + config.popupsDefaultStayOpen = popsDefStayOpenCheckBox->isChecked(); //muse->showMixer(config.mixerVisible); muse->showMixer1(config.mixer1Visible); diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui index ca4b97f8..68f3ebb5 100644 --- a/muse2/muse/widgets/gensetbase.ui +++ b/muse2/muse/widgets/gensetbase.ui @@ -1333,7 +1333,7 @@ Adjusts responsiveness of audio controls and - + Qt::Vertical @@ -1346,6 +1346,27 @@ Adjusts responsiveness of audio controls and + + + + + + + Some popup menus stay open (else hold Ctrl) + + + + + + + Allows some popup menus to stay open. +Otherwise, hold Ctrl to keep them open. + + + + + + diff --git a/muse2/muse/widgets/menutitleitem.cpp b/muse2/muse/widgets/menutitleitem.cpp new file mode 100644 index 00000000..8769eb02 --- /dev/null +++ b/muse2/muse/widgets/menutitleitem.cpp @@ -0,0 +1,48 @@ +//============================================================================= +// MusE +// Linux Music Editor +// (C) Copyright 1999-2001 Werner Schweer (ws@seh.de) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include + +#include "menutitleitem.h" + +//--------------------------------------------------------- +// MenuTitleItem +//--------------------------------------------------------- + +MenuTitleItem::MenuTitleItem(const QString& ss, QWidget* parent) + : QWidgetAction(parent) + { + s = ss; + // Don't allow to click on it. + setEnabled(false); + // Just to be safe, set to -1 instead of default 0. + setData(-1); + } + +QWidget* MenuTitleItem::createWidget(QWidget *parent) +{ + QLabel* l = new QLabel(s, parent); + l->setAlignment(Qt::AlignCenter); + l->setAutoFillBackground(true); + //QPalette palette; + //palette.setColor(label->backgroundRole(), c); + //l->setPalette(palette); + l->setBackgroundRole(QPalette::Dark); + return l; +} + diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index 465b7130..6dd02931 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -26,6 +26,7 @@ #include "app.h" #include "route.h" #include "popupmenu.h" +#include "routepopup.h" //--------------------------------------------------------- // setTrack @@ -576,33 +577,6 @@ void MidiTrackInfo::iOutputPortChanged(int index) song->update(SC_MIDI_TRACK_PROP); // } -//--------------------------------------------------------- -// routingPopupMenuActivated -//--------------------------------------------------------- - -//void MidiTrackInfo::routingPopupMenuActivated(int n) -void MidiTrackInfo::routingPopupMenuActivated(QAction* act) -{ - ///if(!midiTrackInfo || gRoutingPopupMenuMaster != midiTrackInfo || !selected || !selected->isMidiTrack()) - if((gRoutingPopupMenuMaster != this) || !selected || !selected->isMidiTrack()) - return; - muse->routingPopupMenuActivated(selected, act->data().toInt()); -} - -#if 0 -//--------------------------------------------------------- -// routingPopupViewActivated -//--------------------------------------------------------- - -void MidiTrackInfo::routingPopupViewActivated(const QModelIndex& mdi) -{ - ///if(!midiTrackInfo || gRoutingPopupMenuMaster != midiTrackInfo || !selected || !selected->isMidiTrack()) - if(gRoutingPopupMenuMaster != this || !selected || !selected->isMidiTrack()) - return; - muse->routingPopupMenuActivated(selected, mdi.data().toInt()); -} -#endif - //--------------------------------------------------------- // inRoutesPressed //--------------------------------------------------------- @@ -614,44 +588,9 @@ void MidiTrackInfo::inRoutesPressed() if(!selected->isMidiTrack()) return; - PopupMenu* pup = muse->prepareRoutingPopupMenu(selected, false); - //PopupView* pup = muse->prepareRoutingPopupView(selected, false); - - /* - QPoint ppt = QCursor::pos(); - - int i = 0; - for( ; i < MIDI_PORTS; ++i) - { - if(midiPorts[i].device() && !midiPorts[pi].device()->isSynti()) - break; - } - if(!pup || i == MIDI_PORTS) - { - int ret = QMessageBox::warning(this, tr("No devices"), - tr("There are no midi port devices defined.\n" - "Do you want to open the midi configuration dialog?"), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok); - if (ret == QMessageBox::Ok) { - //printf("open config midi ports\n"); - muse->configMidiPorts(); - } - if(!pup) - return; - } - */ - - ///gRoutingPopupMenuMaster = midiTrackInfo; - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - //connect(pup, SIGNAL(activated(const QModelIndex&)), SLOT(routingPopupViewActivated(const QModelIndex&))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - //connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupViewAboutToHide())); - pup->popup(QCursor::pos()); - //pup->setVisible(true); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); iRButton->setDown(false); - return; + pup->exec(QCursor::pos(), selected, false); } //--------------------------------------------------------- @@ -665,17 +604,9 @@ void MidiTrackInfo::outRoutesPressed() if(!selected->isMidiTrack()) return; - PopupMenu* pup = muse->prepareRoutingPopupMenu(selected, true); - if(!pup) - return; - - ///gRoutingPopupMenuMaster = midiTrackInfo; - gRoutingPopupMenuMaster = this; - connect(pup, SIGNAL(triggered(QAction*)), SLOT(routingPopupMenuActivated(QAction*))); - connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); - pup->popup(QCursor::pos()); + RoutePopupMenu* pup = muse->getRoutingPopupMenu(); oRButton->setDown(false); - return; + pup->exec(QCursor::pos(), selected, true); } //--------------------------------------------------------- @@ -1044,7 +975,7 @@ void MidiTrackInfo::iPanChanged(int val) void MidiTrackInfo::instrPopupActivated(QAction* act) { - //printf("MidiTrackInfo::instrPopupActivated\n"); // REMOVE Tim + //printf("MidiTrackInfo::instrPopupActivated\n"); if(act && selected) { @@ -1076,11 +1007,11 @@ void MidiTrackInfo::instrPopup() //QMenu* pup = new QMenu; PopupMenu* pup = new PopupMenu(true); - ///instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM); + //instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM); instr->populatePatchPopup(pup, channel, song->mtype(), track->type() == Track::DRUM); - ///if(pop->actions().count() == 0) - /// return; + //if(pop->actions().count() == 0) + // return; if(pup->actions().count() == 0) { delete pup; @@ -1090,7 +1021,7 @@ void MidiTrackInfo::instrPopup() connect(pup, SIGNAL(triggered(QAction*)), SLOT(instrPopupActivated(QAction*))); //connect(pup, SIGNAL(hovered(QAction*)), SLOT(instrPopupActivated(QAction*))); - ///QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5))); + //QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5))); QAction *act = pup->exec(iPatch->mapToGlobal(QPoint(10,5))); if(act) { @@ -1310,15 +1241,6 @@ void MidiTrackInfo::updateTrackInfo(int flags) return; MidiTrack* track = (MidiTrack*)selected; - // p3.3.47 Update the routing popup menu if anything relevant changes. - //if(gRoutingPopupMenuMaster == midiTrackInfo && selected && (flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))) - if(flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) // p3.3.50 - // Use this handy shared routine. - //muse->updateRouteMenus(selected); - ///muse->updateRouteMenus(selected, midiTrackInfo); // p3.3.50 - muse->updateRouteMenus(selected, this); - - // Added by Tim. p3.3.9 setLabelText(); setLabelFont(); diff --git a/muse2/muse/widgets/mtrackinfo.h b/muse2/muse/widgets/mtrackinfo.h index 0e559f33..ed229ad6 100644 --- a/muse2/muse/widgets/mtrackinfo.h +++ b/muse2/muse/widgets/mtrackinfo.h @@ -46,8 +46,6 @@ class MidiTrackInfo : public QWidget, public Ui::MidiTrackInfoBase void recEchoToggled(bool); void inRoutesPressed(); void outRoutesPressed(); - void routingPopupMenuActivated(QAction*); - //void routingPopupViewActivated(const QModelIndex&); void instrPopupActivated(QAction*); protected slots: diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp index 8cb0b57e..993b0fb8 100644 --- a/muse2/muse/widgets/musewidgetsplug.cpp +++ b/muse2/muse/widgets/musewidgetsplug.cpp @@ -190,13 +190,14 @@ GlobalConfigValues config = { true, // useDenormalBias false, // useOutputLimiter true, // showDidYouKnow - false, // vstInPlace Enable VST in-place processing + false, // vstInPlace Enable VST in-place processing 44100, // Dummy audio preferred sample rate 512 // Dummy audio buffer size QString("./"), // projectBaseFolder true, // projectStoreInFolder true, // useProjectSaveDialog - 64 // minControlProcessPeriod + 64, // minControlProcessPeriod + false // popupsDefaultStayOpen }; //--------------------------------------------------------- diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index 263c8475..adbe7dd6 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -22,6 +22,8 @@ //#include #include "popupmenu.h" +#include "gconfig.h" +#include "route.h" //====================== @@ -82,7 +84,7 @@ void PopupMenu::clear() QMenu* menu = act->menu(); if(menu) { - menu->clear(); + menu->clear(); // Recursive. act->setMenu(0); // CHECK: Is this OK? delete menu; } @@ -97,7 +99,25 @@ void PopupMenu::clear() #endif // POPUP_MENU_DISABLE_AUTO_SCROLL } -QAction* PopupMenu::findActionFromData(QVariant v) const +void PopupMenu::clearAllChecks() const +{ + QList list = actions(); + for(int i = 0; i < list.size(); ++i) + { + QAction* act = list[i]; + PopupMenu* menu = static_cast (act->menu()); + if(menu) + menu->clearAllChecks(); // Recursive. + if(act->isCheckable()) + { + act->blockSignals(true); + act->setChecked(false); + act->blockSignals(false); + } + } +} + +QAction* PopupMenu::findActionFromData(const QVariant& v) const { QList list = actions(); for(int i = 0; i < list.size(); ++i) @@ -106,9 +126,21 @@ QAction* PopupMenu::findActionFromData(QVariant v) const PopupMenu* menu = (PopupMenu*)act->menu(); if(menu) { - if(QAction* actm = menu->findActionFromData(v)) + if(QAction* actm = menu->findActionFromData(v)) // Recursive. return actm; } + + // "Operator == Compares this QVariant with v and returns true if they are equal, + // otherwise returns false. In the case of custom types, their equalness operators + // are not called. Instead the values' addresses are compared." + // + // Take care of struct Route first. Insert other future custom structures here too ! + if(act->data().canConvert() && v.canConvert()) + { + if(act->data().value() == v.value()) + return act; + } + else if(act->data() == v) return act; } @@ -117,7 +149,7 @@ QAction* PopupMenu::findActionFromData(QVariant v) const bool PopupMenu::event(QEvent* event) { - //printf("PopupMenu::event type:%d\n", event->type()); // REMOVE Tim. + //printf("PopupMenu::event type:%d\n", event->type()); switch(event->type()) { @@ -125,6 +157,7 @@ bool PopupMenu::event(QEvent* event) case QEvent::MouseButtonDblClick: { if(_stayOpen) + //if(_stayOpen && config.popupsDefaultStayOpen) { QMouseEvent* e = static_cast(event); if(e->modifiers() == Qt::NoModifier) @@ -143,6 +176,7 @@ bool PopupMenu::event(QEvent* event) case QEvent::KeyPress: { if(_stayOpen) + //if(_stayOpen && config.popupsDefaultStayOpen) { QKeyEvent* e = static_cast(event); if(e->modifiers() == Qt::NoModifier && e->key() == Qt::Key_Space) @@ -169,7 +203,7 @@ bool PopupMenu::event(QEvent* event) int dw = QApplication::desktop()->width(); // We want the whole thing if multiple monitors. //printf("PopupMenu::event MouseMove: pos x:%d y:%d globPos x:%d y:%d\n", - // pos.x(), pos.y(), globPos.x(), globPos.y()); // REMOVE Tim. + // pos.x(), pos.y(), globPos.x(), globPos.y()); /* //QAction* action = actionAt(globPos); @@ -178,7 +212,7 @@ bool PopupMenu::event(QEvent* event) { QRect r = actionGeometry(action); //printf(" act x:%d y:%d w:%d h:%d popup px:%d py:%d pw:%d ph:%d\n", - // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height()); // REMOVE Tim. + // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height()); //action->hover(); } @@ -224,7 +258,7 @@ bool PopupMenu::event(QEvent* event) #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL void PopupMenu::timerHandler() { - // printf("PopupMenu::timerHandler\n"); // REMOVE Tim. + // printf("PopupMenu::timerHandler\n"); //if(!isVisible() || !hasFocus()) if(!isVisible()) @@ -261,9 +295,9 @@ void PopupMenu::popHovered(QAction* action) QRect r = actionGeometry(action); //printf("PopupMenu::popHovered x:%d y:%d w:%d h:%d px:%d py:%d pw:%d ph:%d\n", - // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height()); // REMOVE Tim. + // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height()); //printf("PopupMenu::popHovered x:%d y:%d w:%d h:%d px:%d py:%d pw:%d ph:%d dtw:%d\n", - // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height(), dw); // REMOVE Tim. + // r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height(), dw); //int x = r.x() + ctrlSubPop->x(); if(x() + r.x() < 0) //setGeometry(0, y(), width(), height()); @@ -295,49 +329,20 @@ void PopupMenu::mouseReleaseEvent(QMouseEvent *e) return; #else - if(!_stayOpen) + // Check for Ctrl to stay open. + if(!_stayOpen || (!config.popupsDefaultStayOpen && (e->modifiers() & Qt::ControlModifier) == 0)) { QMenu::mouseReleaseEvent(e); return; } - //printf("PopupMenu::mouseReleaseEvent\n"); // REMOVE Tim. - - //Q_D(QMenu); - //if (d->mouseEventTaken(e)) - // return; - - //d->mouseDown = false; - //QAction *action = d->actionAt(e->pos()); + //printf("PopupMenu::mouseReleaseEvent\n"); QAction *action = actionAt(e->pos()); - - //for(QWidget *caused = this; caused;) { - // if (QMenu *m = qobject_cast(caused)) { - // QAction *currentAction = d->currentAction; - // if(currentAction && (!currentAction->isEnabled() || currentAction->menu() || currentAction->isSeparator())) - // currentAction = 0; - // caused = m->d_func()->causedPopup.widget; - // if (m->d_func()->eventLoop) - // m->d_func()->syncAction = currentAction; // synchronous operation - // } else { - // break; - // } - //} - - //if (action && action == d->currentAction) { if (action && action == activeAction() && !action->isSeparator() && action->isEnabled()) - { - //if (action->menu()) - // action->menu()->d_func()->setFirstActionActive(); - //else - //d->activateAction(action, QAction::Trigger); - action->activate(QAction::Trigger); - } + action->activate(QAction::Trigger); else - //if (d->motions > 6) { - // d->hideUpToMenuBar(); - // } QMenu::mouseReleaseEvent(e); + #endif // POPUP_MENU_DISABLE_STAY_OPEN } diff --git a/muse2/muse/widgets/popupmenu.h b/muse2/muse/widgets/popupmenu.h index 47be57ae..e0e7d26f 100644 --- a/muse2/muse/widgets/popupmenu.h +++ b/muse2/muse/widgets/popupmenu.h @@ -60,8 +60,9 @@ class PopupMenu : public QMenu PopupMenu(const QString& title, QWidget* parent = 0, bool stayOpen = false); ~PopupMenu(); void clear(); - QAction* findActionFromData(QVariant) const; + QAction* findActionFromData(const QVariant&) const; bool stayOpen() const { return _stayOpen; } + void clearAllChecks() const; }; diff --git a/muse2/muse/widgets/routepopup.cpp b/muse2/muse/widgets/routepopup.cpp new file mode 100644 index 00000000..910d693d --- /dev/null +++ b/muse2/muse/widgets/routepopup.cpp @@ -0,0 +1,1416 @@ +//========================================================= +// MusE +// Linux Music Editor +// +// RoutePopupMenu.cpp +// (C) Copyright 2011 Tim E. Real (terminator356 A T sourceforge D O T net) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "app.h" +#include "routepopup.h" +#include "midiport.h" +#include "mididev.h" +#include "audio.h" +#include "driver/audiodev.h" +#include "song.h" +#include "track.h" +#include "synth.h" +#include "route.h" +#include "icons.h" +#include "menutitleitem.h" +#include "popupmenu.h" + +//--------------------------------------------------------- +// addMenuItem +//--------------------------------------------------------- + +int RoutePopupMenu::addMenuItem(AudioTrack* track, Track* route_track, PopupMenu* lb, int id, int channel, int channels, bool isOutput) +{ + // totalInChannels is only used by syntis. + 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; + + // 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(); + + QAction* act; + + QString s(route_track->name()); + + act = lb->addAction(s); + act->setCheckable(true); + + int ach = channel; + int bch = -1; + + Route r(route_track, isOutput ? ach : bch, channels); + + r.remoteChannel = isOutput ? bch : ach; + + act->setData(qVariantFromValue(r)); + + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + 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(compch == tcompch && compchs == tcompchs) + { + act->setChecked(true); + break; + } + } + } + return ++id; +} + +//--------------------------------------------------------- +// addAuxPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addAuxPorts(AudioTrack* t, PopupMenu* lb, int id, 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(t, track, lb, id, channel, channels, isOutput); + } + return id; + } + +//--------------------------------------------------------- +// addInPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addInPorts(AudioTrack* t, PopupMenu* lb, int id, 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(t, track, lb, id, channel, channels, isOutput); + } + return id; + } + +//--------------------------------------------------------- +// addOutPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addOutPorts(AudioTrack* t, PopupMenu* lb, int id, 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(t, track, lb, id, channel, channels, isOutput); + } + return id; + } + +//--------------------------------------------------------- +// addGroupPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addGroupPorts(AudioTrack* t, PopupMenu* lb, int id, 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(t, track, lb, id, channel, channels, isOutput); + } + return id; + } + +//--------------------------------------------------------- +// addWavePorts +//--------------------------------------------------------- + +int RoutePopupMenu::addWavePorts(AudioTrack* t, PopupMenu* lb, int id, 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(t, track, lb, id, channel, channels, isOutput); + } + return id; + } + +//--------------------------------------------------------- +// addSyntiPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addSyntiPorts(AudioTrack* t, PopupMenu* lb, int id, + int channel, int channels, bool isOutput) +{ + RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); + + QAction* act; + + SynthIList* al = song->syntis(); + for (iSynthI i = al->begin(); i != al->end(); ++i) + { + Track* track = *i; + if (t == track) + continue; + 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(); + + 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) + { + PopupMenu* chpup = new PopupMenu(lb, true); + chpup->setTitle(track->name()); + for(int ch = 0; ch < chans; ++ch) + { + char buffer[128]; + if(tchans == 2) + snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").toLatin1().constData(), ch+1, ch+2); + else + snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); + act = chpup->addAction(QString(buffer)); + act->setCheckable(true); + + int ach = (channel == -1) ? ch : channel; + int bch = (channel == -1) ? -1 : ch; + + Route rt(track, (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? ach : bch, tchans); + rt.remoteChannel = (t->type() != Track::AUDIO_SOFTSYNTH || isOutput) ? bch : ach; + + act->setData(qVariantFromValue(rt)); + + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + 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) + { + act->setChecked(true); + break; + } + } + } + ++id; + } + + lb->addMenu(chpup); + } + } + return id; +} + +//--------------------------------------------------------- +// addMultiChannelOutPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addMultiChannelPorts(AudioTrack* t, PopupMenu* pup, int id, 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. + // totalInChannels is only used by syntis. + int chans = (isOutput || t->type() != Track::AUDIO_SOFTSYNTH) ? toch : t->totalInChannels(); + + if(chans > 1) + pup->addAction(new MenuTitleItem("", pup)); + + // + // If it's more than one channel, create a sub-menu. If it's just one channel, don't bother with a sub-menu... + // + + PopupMenu* chpup = pup; + + for(int ch = 0; ch < chans; ++ch) + { + // If more than one channel, create the sub-menu. + if(chans > 1) + chpup = new PopupMenu(pup, true); + + if(isOutput) + { + switch(t->type()) + { + + case Track::AUDIO_INPUT: + case Track::WAVE: + case Track::AUDIO_GROUP: + case Track::AUDIO_SOFTSYNTH: + case Track::AUDIO_AUX: + id = addWavePorts(t, chpup, id, ch, 1, isOutput); + id = addOutPorts(t, chpup, id, ch, 1, isOutput); + id = addGroupPorts(t, chpup, id, ch, 1, isOutput); + id = addSyntiPorts(t, chpup, id, ch, 1, isOutput); + break; + default: + break; + } + } + else + { + switch(t->type()) + { + + case Track::AUDIO_OUTPUT: + id = addWavePorts(t, chpup, id, ch, 1, isOutput); + id = addInPorts(t, chpup, id, ch, 1, isOutput); + id = addGroupPorts(t, chpup, id, ch, 1, isOutput); + id = addAuxPorts(t, chpup, id, ch, 1, isOutput); + id = addSyntiPorts(t, chpup, id, ch, 1, isOutput); + break; + case Track::WAVE: + case Track::AUDIO_SOFTSYNTH: + case Track::AUDIO_GROUP: + id = addWavePorts(t, chpup, id, ch, 1, isOutput); + id = addInPorts(t, chpup, id, ch, 1, isOutput); + id = addGroupPorts(t, chpup, id, ch, 1, isOutput); + id = addAuxPorts(t, chpup, id, ch, 1, isOutput); + id = addSyntiPorts(t, chpup, id, ch, 1, 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").toLatin1().constData(), ch+1); + chpup->setTitle(QString(buffer)); + pup->addMenu(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->addSeparator(); + pup->addAction(new MenuTitleItem("", pup)); + + // + // If it's more than two channels, create a sub-menu. If it's just two channels, don't bother with a sub-menu... + // + + chpup = pup; + if(chans <= 2) + // Just do one iteration. + chans = 1; + + for(int ch = 0; ch < chans; ++ch) + { + // If more than two channels, create the sub-menu. + if(chans > 2) + chpup = new PopupMenu(pup, true); + + if(isOutput) + { + switch(t->type()) + { + case Track::AUDIO_INPUT: + case Track::WAVE: + case Track::AUDIO_GROUP: + case Track::AUDIO_SOFTSYNTH: + case Track::AUDIO_AUX: + id = addWavePorts(t, chpup, id, ch, 2, isOutput); + id = addOutPorts(t, chpup, id, ch, 2, isOutput); + id = addGroupPorts(t, chpup, id, ch, 2, isOutput); + id = addSyntiPorts(t, chpup, id, ch, 2, isOutput); + break; + default: + break; + } + } + else + { + switch(t->type()) + { + case Track::AUDIO_OUTPUT: + id = addWavePorts(t, chpup, id, ch, 2, isOutput); + id = addInPorts(t, chpup, id, ch, 2, isOutput); + id = addGroupPorts(t, chpup, id, ch, 2, isOutput); + id = addAuxPorts(t, chpup, id, ch, 2, isOutput); + id = addSyntiPorts(t, chpup, id, ch, 2, isOutput); + break; + case Track::WAVE: + case Track::AUDIO_SOFTSYNTH: + case Track::AUDIO_GROUP: + id = addWavePorts(t, chpup, id, ch, 2, isOutput); + id = addInPorts(t, chpup, id, ch, 2, isOutput); + id = addGroupPorts(t, chpup, id, ch, 2, isOutput); + id = addAuxPorts(t, chpup, id, ch, 2, isOutput); + id = addSyntiPorts(t, chpup, id, 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").toLatin1().constData(), ch+1, ch+2); + chpup->setTitle(QString(buffer)); + pup->addMenu(chpup); + } + } + } + + return id; +} + +//--------------------------------------------------------- +// nonSyntiTrackAddSyntis +//--------------------------------------------------------- + +int RoutePopupMenu::nonSyntiTrackAddSyntis(AudioTrack* t, PopupMenu* lb, int id, bool isOutput) +{ + RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); + + QAction* act; + SynthIList* al = song->syntis(); + for (iSynthI i = al->begin(); i != al->end(); ++i) + { + Track* track = *i; + if (t == track) + continue; + + 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(); + + //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) + { + PopupMenu* chpup = new PopupMenu(lb, true); + chpup->setTitle(track->name()); + if(chans > 1) + chpup->addAction(new MenuTitleItem("", chpup)); + + for(int ch = 0; ch < chans; ++ch) + { + char buffer[128]; + snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); + act = chpup->addAction(QString(buffer)); + act->setCheckable(true); + + int ach = ch; + int bch = -1; + + Route rt(track, isOutput ? bch : ach, 1); + + rt.remoteChannel = isOutput ? ach : bch; + + act->setData(qVariantFromValue(rt)); + + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + 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) + { + act->setChecked(true); + break; + } + } + } + ++id; + } + + chans -= 1; + if(chans > 0) + { + // Ignore odd numbered left-over channels. + //int schans = (chans & ~1) - 1; + + chpup->addSeparator(); + chpup->addAction(new MenuTitleItem("", chpup)); + + for(int ch = 0; ch < chans; ++ch) + { + char buffer[128]; + snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").toLatin1().constData(), ch+1, ch+2); + act = chpup->addAction(QString(buffer)); + act->setCheckable(true); + + int ach = ch; + int bch = -1; + + Route rt(track, isOutput ? bch : ach, 2); + + rt.remoteChannel = isOutput ? ach : bch; + + act->setData(qVariantFromValue(rt)); + + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + 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) + { + act->setChecked(true); + break; + } + } + } + ++id; + } + } + + lb->addMenu(chpup); + } + } + return id; +} + +//--------------------------------------------------------- +// addMidiPorts +//--------------------------------------------------------- + +int RoutePopupMenu::addMidiPorts(AudioTrack* t, PopupMenu* pup, int id, bool isOutput) +{ + QAction* act; + for(int i = 0; i < MIDI_PORTS; ++i) + { + MidiPort* mp = &midiPorts[i]; + MidiDevice* md = mp->device(); + + // This is desirable, but could lead to 'hidden' routes unless we add more support + // such as removing the existing routes when user changes flags. + // So for now, just list all valid ports whether read or write. + if(!md) + continue; + //if(!(md->rwFlags() & (isOutput ? 1 : 2))) + // continue; + + // Do not list synth devices! + if(md->isSynti()) + continue; + + RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); + + PopupMenu* subp = new PopupMenu(pup, true); + subp->setTitle(md->name()); + + int chanmask = 0; + // To reduce number of routes required, from one per channel to just one containing a channel mask. + // Look for the first route to this midi port. There should always be only a single route for each midi port, now. + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) + { + // We have a route to the midi port. Grab the channel mask. + chanmask = ir->channel; + break; + } + } + + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + { + act = subp->addAction(QString("Channel %1").arg(ch+1)); + act->setCheckable(true); + + int chbit = 1 << ch; + Route srcRoute(i, chbit); // In accordance with channel mask, use the bit position. + + act->setData(qVariantFromValue(srcRoute)); + + if(chanmask & chbit) // Is the channel already set? Show item check mark. + act->setChecked(true); + + ++id; + } + + //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. + act = subp->addAction(QString("Toggle all")); + //act->setCheckable(true); + Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. + act->setData(qVariantFromValue(togRoute)); + ++id; + + pup->addMenu(subp); + } + return id; +} + + +//====================== +// RoutePopupMenu +//====================== + +RoutePopupMenu::RoutePopupMenu(QWidget* parent, Track* track, bool isOutput) + : _track(track), _isOutMenu(isOutput) +{ + _pup = new PopupMenu(parent, true); + init(); +} + +RoutePopupMenu::RoutePopupMenu(const QString& title, QWidget* parent, Track* track, bool isOutput) + : _track(track), _isOutMenu(isOutput) +{ + _pup = new PopupMenu(title, parent, true); + init(); +} + +RoutePopupMenu::~RoutePopupMenu() +{ + //printf("RoutePopupMenu::~RoutePopupMenu\n"); + // Make sure to clear which clears and deletes any sub popups. + _pup->clear(); + delete _pup; +} + +void RoutePopupMenu::init() +{ + connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); +} + +void RoutePopupMenu::songChanged(int val) +{ + if(val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)) + updateRouteMenus(); +} + +void RoutePopupMenu::updateRouteMenus() +{ + // NOTE: The purpose of this routine is to make sure the items actually reflect + // the routing status. + // In case for some reason a route could not be added (or removed). + // Then the item will be properly un-checked (or checked) here. + + //printf("RoutePopupMenu::updateRouteMenus\n"); + + if(!_track || !_pup || _pup->actions().isEmpty() || !_pup->isVisible()) + return; + + RouteList* rl = _isOutMenu ? _track->outRoutes() : _track->inRoutes(); + + // Clear all the action check marks. + _pup->clearAllChecks(); + + // Take care of Midi Port to Audio Input routes first... + if(_isOutMenu && _track->isMidiTrack()) + { + int port = ((MidiTrack*)_track)->outPort(); + if(port >= 0 && port < MIDI_PORTS) + { + MidiPort* mp = &midiPorts[port]; + RouteList* mprl = mp->outRoutes(); + for (ciRoute ir = mprl->begin(); ir != mprl->end(); ++ir) + { + if(ir->type == Route::TRACK_ROUTE && ir->track && ir->track->type() == Track::AUDIO_INPUT) + { + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + { + int chbits = 1 << ch; + if(ir->channel & chbits) + { + Route r(ir->track, chbits); + //printf("RoutePopupMenu::updateRouteMenus MidiPort to AudioInput chbits:%d\n", chbits); + QAction* act = _pup->findActionFromData(qVariantFromValue(r)); + if(act) + act->setChecked(true); + } + } + } + } + } + } + + // Now check the ones that are found in the route list. + for(ciRoute irl = rl->begin(); irl != rl->end(); ++irl) + { + // Do MidiTrack to MidiPort routes... + if(irl->type == Route::MIDI_PORT_ROUTE) + { + //printf("RoutePopupMenu::updateRouteMenus MIDI_PORT_ROUTE\n"); + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + { + int chbits = 1 << ch; + if(irl->channel & chbits) + { + Route r(irl->midiPort, chbits); + QAction* act = _pup->findActionFromData(qVariantFromValue(r)); + if(act) + act->setChecked(true); + } + } + } + else + // Do all other routes... + { + //printf("RoutePopupMenu::updateRouteMenus other irl type:%d\n", irl->type); + QAction* act = _pup->findActionFromData(qVariantFromValue(*irl)); + if(act) + act->setChecked(true); + } + } +} + +void RoutePopupMenu::popupActivated(QAction* action) +{ + if(!action || !_track || !_pup || _pup->actions().isEmpty()) + return; + + if(_track->isMidiTrack()) + { + RouteList* rl = _isOutMenu ? _track->outRoutes() : _track->inRoutes(); + + // Take care of Route data items first... + if(qVariantCanConvert(action->data())) + { + Route aRoute = action->data().value(); + + // Support Midi Port to Audio Input track routes. + if(aRoute.type == Route::TRACK_ROUTE && aRoute.track && aRoute.track->type() == Track::AUDIO_INPUT) + { + //if(gIsOutRoutingPopupMenu) // Try to avoid splitting like this. + { + int chbit = aRoute.channel; + int port = ((MidiTrack*)_track)->outPort(); + if(port < 0 || port >= MIDI_PORTS) + return; + + MidiPort* mp = &midiPorts[port]; + //MidiDevice* md = mp->device(); + + // This is desirable, but could lead to 'hidden' routes unless we add more support + // such as removing the existing routes when user changes flags. + // So for now, just list all valid ports whether read or write. + //if(!md) + // return; + //if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) + // return; + + Route bRoute(port, chbit); + + int chmask = 0; + RouteList* mprl = _isOutMenu ? mp->outRoutes() : mp->inRoutes(); + ciRoute ir = mprl->begin(); + for (; ir != mprl->end(); ++ir) + { + if(ir->type == Route::TRACK_ROUTE && ir->track == aRoute.track) // Is there already a route to this port? + { + chmask = ir->channel; // Grab the channel mask. + break; + } + } + if ((chmask & chbit) == chbit) // Is the channel's bit(s) set? + { + // disconnect + if(_isOutMenu) + audio->msgRemoveRoute(bRoute, aRoute); + else + audio->msgRemoveRoute(aRoute, bRoute); + } + else + { + // connect + if(_isOutMenu) + audio->msgAddRoute(bRoute, aRoute); + else + audio->msgAddRoute(aRoute, bRoute); + } + + audio->msgUpdateSoloStates(); + song->update(SC_ROUTE); + + } + return; + } + else if(aRoute.type == Route::MIDI_PORT_ROUTE) + { + int chbit = aRoute.channel; + Route bRoute(_track, chbit); + int mdidx = aRoute.midiPort; + + MidiPort* mp = &midiPorts[mdidx]; + MidiDevice* md = mp->device(); + //if(!md) // Rem. Allow connections to ports with no device. + // return; + + //if(!(md->rwFlags() & 2)) + //if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) + if(md && !(md->rwFlags() & (_isOutMenu ? 1 : 2))) + return; + + int chmask = 0; + ciRoute iir = rl->begin(); + for (; iir != rl->end(); ++iir) + { + if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx) // Is there already a route to this port? + { + chmask = iir->channel; // Grab the channel mask. + break; + } + } + if ((chmask & chbit) == chbit) // Is the channel's bit(s) set? + { + // disconnect + if(_isOutMenu) + audio->msgRemoveRoute(bRoute, aRoute); + else + audio->msgRemoveRoute(aRoute, bRoute); + } + else + { + // connect + if(_isOutMenu) + audio->msgAddRoute(bRoute, aRoute); + else + audio->msgAddRoute(aRoute, bRoute); + } + + audio->msgUpdateSoloStates(); + song->update(SC_ROUTE); + } + } + else + // ... now take care of integer data items. + if(qVariantCanConvert(action->data())) + { + int n = action->data().value(); + if(!_isOutMenu && n == 0) + muse->configMidiPorts(); + return; + } + } + else + { + AudioTrack* t = (AudioTrack*)_track; + RouteList* rl = _isOutMenu ? t->outRoutes() : t->inRoutes(); + + if(!qVariantCanConvert(action->data())) + return; + + if(_isOutMenu) + { + Route dstRoute = action->data().value(); + Route srcRoute(t, dstRoute.channel, dstRoute.channels); + srcRoute.remoteChannel = dstRoute.remoteChannel; + + // check if route src->dst exists: + ciRoute irl = rl->begin(); + for (; irl != rl->end(); ++irl) { + if (*irl == dstRoute) + break; + } + if (irl != rl->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); + } + else + { + Route srcRoute = action->data().value(); + + // Support Midi Port to Audio Input routes. + if(_track->type() == Track::AUDIO_INPUT && srcRoute.type == Route::MIDI_PORT_ROUTE) + { + int chbit = srcRoute.channel; + Route dstRoute(t, chbit); + int mdidx = srcRoute.midiPort; + int chmask = 0; + ciRoute iir = rl->begin(); + for (; iir != rl->end(); ++iir) + { + if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx) // Is there already a route to this port? + { + chmask = iir->channel; // Grab the channel mask. + break; + } + } + + if ((chmask & chbit) == chbit) // Is the channel's bit(s) set? + { + //printf("routingPopupMenuActivated: removing src route ch:%d dst route ch:%d\n", srcRoute.channel, dstRoute.channel); + audio->msgRemoveRoute(srcRoute, dstRoute); + } + else + { + //printf("routingPopupMenuActivated: adding src route ch:%d dst route ch:%d\n", srcRoute.channel, dstRoute.channel); + audio->msgAddRoute(srcRoute, dstRoute); + } + + audio->msgUpdateSoloStates(); + song->update(SC_ROUTE); + return; + } + + Route dstRoute(t, srcRoute.channel, srcRoute.channels); + dstRoute.remoteChannel = srcRoute.remoteChannel; + + ciRoute irl = rl->begin(); + for (; irl != rl->end(); ++irl) { + if (*irl == srcRoute) + break; + } + if (irl != rl->end()) { + // disconnect + audio->msgRemoveRoute(srcRoute, dstRoute); + } + else { + // connect + audio->msgAddRoute(srcRoute, dstRoute); + } + audio->msgUpdateSoloStates(); + song->update(SC_ROUTE); + } + + + } + //else + //{ + //} +} + +void RoutePopupMenu::prepare() +{ + _pup->disconnect(); + _pup->clear(); + + if(!_track) + return; + + connect(_pup, SIGNAL(triggered(QAction*)), SLOT(popupActivated(QAction*))); + + if(_track->isMidiTrack()) + { + RouteList* rl = _isOutMenu ? _track->outRoutes() : _track->inRoutes(); + + int gid = 0; + QAction* act = 0; + + if(_isOutMenu) + { + // Support Midi Port to Audio Input track routes. + int port = ((MidiTrack*)_track)->outPort(); + if(port >= 0 && port < MIDI_PORTS) + { + MidiPort* mp = &midiPorts[port]; + + // Do not list synth devices! Requiring valid device is desirable, + // but could lead to 'hidden' routes unless we add more support + // such as removing the existing routes when user changes flags. + // So for now, just list all valid ports whether read or write. + if(mp->device() && !mp->device()->isSynti()) + { + RouteList* mprl = mp->outRoutes(); + int chbits = 1 << ((MidiTrack*)_track)->outChannel(); + //MidiDevice* md = mp->device(); + //if(!md) + // continue; + + _pup->addSeparator(); + _pup->addAction(new MenuTitleItem(tr("Soloing chain"), _pup)); + PopupMenu* subp = new PopupMenu(_pup, true); + subp->setTitle(tr("Audio returns")); + _pup->addMenu(subp); + + InputList* al = song->inputs(); + for (ciAudioInput i = al->begin(); i != al->end(); ++i) + { + Track* t = *i; + QString s(t->name()); + act = subp->addAction(s); + act->setCheckable(true); + Route r(t, chbits); + act->setData(qVariantFromValue(r)); + for(ciRoute ir = mprl->begin(); ir != mprl->end(); ++ir) + { + if(ir->type == Route::TRACK_ROUTE && ir->track == t && (ir->channel & chbits)) + { + act->setChecked(true); + break; + } + } + ++gid; + } + } + } + } + else + { + // Warn if no devices available. Add an item to open midi config. + int pi = 0; + for( ; pi < MIDI_PORTS; ++pi) + { + MidiDevice* md = midiPorts[pi].device(); + if(md && !md->isSynti() && (md->rwFlags() & 2)) + break; + } + if(pi == MIDI_PORTS) + { + act = _pup->addAction(tr("Warning: No midi input devices!")); + act->setCheckable(false); + act->setData(-1); + _pup->addSeparator(); + } + act = _pup->addAction(QIcon(*settings_midiport_softsynthsIcon), tr("Open midi config...")); + act->setCheckable(false); + act->setData(gid); + _pup->addSeparator(); + ++gid; + + _pup->addAction(new MenuTitleItem("Midi input ports", _pup)); + + for(int i = 0; i < MIDI_PORTS; ++i) + { + // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick with ports. + MidiPort* mp = &midiPorts[i]; + MidiDevice* md = mp->device(); + //if(!md) + // continue; + + // Do not list synth devices! + if(md && md->isSynti()) + continue; + + if(md && !(md->rwFlags() & 2)) + continue; + + //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i); + + int chanmask = 0; + // To reduce number of routes required, from one per channel to just one containing a channel mask. + // Look for the first route to this midi port. There should always be only a single route for each midi port, now. + ciRoute ir = rl->begin(); + for( ; ir != rl->end(); ++ir) + { + if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) + { + // We have a route to the midi port. Grab the channel mask. + chanmask = ir->channel; + break; + } + } + // List ports with no device, but with routes to this track, in the main popup. + if(!md && ir == rl->end()) + continue; + + PopupMenu* subp = new PopupMenu(_pup, true); + subp->setTitle(QString("%1:").arg(i+1) + (md ? md->name() : tr(""))); + + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + { + act = subp->addAction(QString("Channel %1").arg(ch+1)); + act->setCheckable(true); + int chbit = 1 << ch; + Route srcRoute(i, chbit); // In accordance with channel mask, use the bit position. + act->setData(qVariantFromValue(srcRoute)); + if(chanmask & chbit) // Is the channel already set? Show item check mark. + act->setChecked(true); + ++gid; + } + //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. + act = subp->addAction(tr("Toggle all")); + //act->setCheckable(true); + Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. + act->setData(qVariantFromValue(togRoute)); + ++gid; + _pup->addMenu(subp); + } + + #if 0 + // p4.0.17 List ports with no device and no in routes, in a separate popup. + PopupMenu* morep = new PopupMenu(pup, true); + morep->setTitle(tr("More...")); + for(int i = 0; i < MIDI_PORTS; ++i) + { + MidiPort* mp = &midiPorts[i]; + if(mp->device()) + continue; + + PopupMenu* subp = new PopupMenu(morep, true); + subp->setTitle(QString("%1:").arg(i) + tr("")); + + // MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers! + //connect(subp, SIGNAL(triggered(QAction*)), pup, SIGNAL(triggered(QAction*))); + //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide())); + + iRoute ir = rl->begin(); + for( ; ir != rl->end(); ++ir) + { + if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i) + break; + } + if(ir != rl->end()) + continue; + + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + { + act = subp->addAction(QString("Channel %1").arg(ch+1)); + act->setCheckable(true); + act->setData(gid); + + int chbit = 1 << ch; + Route srcRoute(i, chbit); // In accordance with new channel mask, use the bit position. + + gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) ); + + //if(chanmask & chbit) // Is the channel already set? Show item check mark. + // act->setChecked(true); + + ++gid; + } + //gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id. + act = subp->addAction(QString("Toggle all")); + //act->setCheckable(true); + act->setData(gid); + Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits. + gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) ); + ++gid; + morep->addMenu(subp); + } + pup->addMenu(morep); + #endif + + } + return; + } + else + { + AudioTrack* t = (AudioTrack*)_track; + int channel = t->channels(); + if(_isOutMenu) + { + RouteList* orl = t->outRoutes(); + + QAction* act = 0; + int gid = 0; + gid = 0; + + switch(_track->type()) + { + case Track::AUDIO_OUTPUT: + { + for(int i = 0; i < channel; ++i) + { + char buffer[128]; + snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); + MenuTitleItem* titel = new MenuTitleItem(QString(buffer), _pup); + _pup->addAction(titel); + + if(!checkAudioDevice()) + { + _pup->clear(); + return; + } + std::list ol = audioDevice->inputPorts(); + for(std::list::iterator ip = ol.begin(); ip != ol.end(); ++ip) + { + act = _pup->addAction(*ip); + act->setCheckable(true); + + Route dst(*ip, true, i, Route::JACK_ROUTE); + act->setData(qVariantFromValue(dst)); + ++gid; + for(ciRoute ir = orl->begin(); ir != orl->end(); ++ir) + { + if(*ir == dst) + { + act->setChecked(true); + break; + } + } + } + if(i+1 != channel) + _pup->addSeparator(); + } + + // + // Display using separate menu for audio inputs: + // + _pup->addSeparator(); + _pup->addAction(new MenuTitleItem(tr("Soloing chain"), _pup)); + PopupMenu* subp = new PopupMenu(_pup, true); + subp->setTitle(tr("Audio returns")); + _pup->addMenu(subp); + gid = addInPorts(t, subp, gid, -1, -1, true); + // + // Display all in the same menu: + // + //_pup->addSeparator(); + //MenuTitleItem* title = new MenuTitleItem(tr("Audio returns"), _pup); + //_pup->addAction(title); + //gid = addInPorts(t, _pup, gid, -1, -1, true); + } + break; + case Track::AUDIO_SOFTSYNTH: + gid = addMultiChannelPorts(t, _pup, gid, true); + break; + + case Track::AUDIO_INPUT: + case Track::WAVE: + case Track::AUDIO_GROUP: + case Track::AUDIO_AUX: + gid = addWavePorts( t, _pup, gid, -1, -1, true); + gid = addOutPorts( t, _pup, gid, -1, -1, true); + gid = addGroupPorts( t, _pup, gid, -1, -1, true); + gid = nonSyntiTrackAddSyntis(t, _pup, gid, true); + break; + default: + _pup->clear(); + return; + } + } + else + { + if(_track->type() == Track::AUDIO_AUX) + return; + + RouteList* irl = t->inRoutes(); + + QAction* act = 0; + int gid = 0; + gid = 0; + + switch(_track->type()) + { + case Track::AUDIO_INPUT: + { + for(int i = 0; i < channel; ++i) + { + char buffer[128]; + snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); + MenuTitleItem* titel = new MenuTitleItem(QString(buffer), _pup); + _pup->addAction(titel); + + if(!checkAudioDevice()) + { + _pup->clear(); + return; + } + std::list ol = audioDevice->outputPorts(); + for(std::list::iterator ip = ol.begin(); ip != ol.end(); ++ip) + { + act = _pup->addAction(*ip); + act->setCheckable(true); + + Route dst(*ip, true, i, Route::JACK_ROUTE); + act->setData(qVariantFromValue(dst)); + ++gid; + for(ciRoute ir = irl->begin(); ir != irl->end(); ++ir) + { + if(*ir == dst) + { + act->setChecked(true); + break; + } + } + } + if(i+1 != channel) + _pup->addSeparator(); + } + + // + // Display using separate menus for midi ports and audio outputs: + // + _pup->addSeparator(); + _pup->addAction(new MenuTitleItem(tr("Soloing chain"), _pup)); + PopupMenu* subp = new PopupMenu(_pup, true); + subp->setTitle(tr("Audio sends")); + _pup->addMenu(subp); + gid = addOutPorts(t, subp, gid, -1, -1, false); + subp = new PopupMenu(_pup, true); + subp->setTitle(tr("Midi port sends")); + _pup->addMenu(subp); + addMidiPorts(t, subp, gid, false); + // + // Display all in the same menu: + // + //_pup->addAction(new MenuTitleItem(tr("Audio sends"), _pup)); + //gid = addOutPorts(t, _pup, gid, -1, -1, false); + //_pup->addSeparator(); + //_pup->addAction(new MenuTitleItem(tr("Midi sends"), _pup)); + //addMidiPorts(t, _pup, gid, false); + } + break; + case Track::AUDIO_OUTPUT: + gid = addWavePorts( t, _pup, gid, -1, -1, false); + gid = addInPorts( t, _pup, gid, -1, -1, false); + gid = addGroupPorts(t, _pup, gid, -1, -1, false); + gid = addAuxPorts( t, _pup, gid, -1, -1, false); + gid = nonSyntiTrackAddSyntis(t, _pup, gid, false); + break; + case Track::WAVE: + gid = addWavePorts( t, _pup, gid, -1, -1, false); + gid = addInPorts( t, _pup, gid, -1, -1, false); + gid = addGroupPorts(t, _pup, gid, -1, -1, false); + gid = addAuxPorts( t, _pup, gid, -1, -1, false); + gid = nonSyntiTrackAddSyntis(t, _pup, gid, false); + break; + case Track::AUDIO_GROUP: + gid = addWavePorts( t, _pup, gid, -1, -1, false); + gid = addInPorts( t, _pup, gid, -1, -1, false); + gid = addGroupPorts(t, _pup, gid, -1, -1, false); + gid = addAuxPorts( t, _pup, gid, -1, -1, false); + gid = nonSyntiTrackAddSyntis(t, _pup, gid, false); + break; + + case Track::AUDIO_SOFTSYNTH: + gid = addMultiChannelPorts(t, _pup, gid, false); + break; + default: + _pup->clear(); + return; + } + } + } +} + +void RoutePopupMenu::exec(Track* track, bool isOutput) +{ + if(track) + { + _track = track; + _isOutMenu = isOutput; + } + prepare(); + _pup->exec(); +} + +void RoutePopupMenu::exec(const QPoint& p, Track* track, bool isOutput) +{ + if(track) + { + _track = track; + _isOutMenu = isOutput; + } + prepare(); + _pup->exec(p); +} + +void RoutePopupMenu::popup(const QPoint& p, Track* track, bool isOutput) +{ + if(track) + { + _track = track; + _isOutMenu = isOutput; + } + prepare(); + _pup->popup(p); +} + diff --git a/muse2/muse/widgets/routepopup.h b/muse2/muse/widgets/routepopup.h new file mode 100644 index 00000000..6772e8ca --- /dev/null +++ b/muse2/muse/widgets/routepopup.h @@ -0,0 +1,73 @@ +//========================================================= +// MusE +// Linux Music Editor +// +// RoutePopupMenu.h +// (C) Copyright 2011 Tim E. Real (terminator356 A T sourceforge D O T net) +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __ROUTEPOPUPMENU_H__ +#define __ROUTEPOPUPMENU_H__ + +#include + +class Track; +class AudioTrack; +class PopupMenu; +class QWidget; +class QString; +class QAction; +class QPoint; + +class RoutePopupMenu : public QObject +{ + Q_OBJECT + + PopupMenu* _pup; + Track* _track; + // Whether the route popup was shown by clicking the output routes button, or input routes button. + bool _isOutMenu; + + void init(); + void prepare(); + + int addMenuItem(AudioTrack* track, Track* route_track, PopupMenu* lb, int id, int channel, + int channels, bool isOutput); + int addAuxPorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addInPorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addOutPorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addGroupPorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addWavePorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addSyntiPorts(AudioTrack* t, PopupMenu* lb, int id, int channel, int channels, bool isOutput); + int addMultiChannelPorts(AudioTrack* t, PopupMenu* pup, int id, bool isOutput); + int nonSyntiTrackAddSyntis(AudioTrack* t, PopupMenu* lb, int id, bool isOutput); + int addMidiPorts(AudioTrack* t, PopupMenu* pup, int id, bool isOutput); + + private slots: + void popupActivated(QAction*); + void songChanged(int); + + public: + RoutePopupMenu(QWidget* parent = 0, Track* track = 0, bool isOutput = false); + RoutePopupMenu(const QString& title, QWidget* parent = 0, Track* track = 0, bool isOutput = false); + ~RoutePopupMenu(); + + void updateRouteMenus(); + void exec(Track* track = 0, bool isOutput = false); + void exec(const QPoint& p, Track* track = 0, bool isOutput = false); + void popup(const QPoint& p, Track* track = 0, bool isOutput = false); +}; + +#endif diff --git a/muse2/synti/deicsonze/deicsonzeplugin.cpp b/muse2/synti/deicsonze/deicsonzeplugin.cpp index 36684f5f..54eee202 100644 --- a/muse2/synti/deicsonze/deicsonzeplugin.cpp +++ b/muse2/synti/deicsonze/deicsonzeplugin.cpp @@ -406,7 +406,7 @@ void DeicsOnzeGui::setChorusCheckBox(double v, int i) { else printf("setChorusCheckBox Error : cannot send controller upper than 225\n"); } -void DeicsOnzeGui::setReverbFloatEntry(double v, int i) { +void DeicsOnzeGui::setReverbFloatEntry(double /*v*/, int /*i*/) { if(_deicsOnze->_pluginIReverb) { // FIXME FIXME Tim @@ -420,7 +420,7 @@ void DeicsOnzeGui::setReverbFloatEntry(double v, int i) { } else printf("Warning : no DeicsOnze reverb loaded\n"); } -void DeicsOnzeGui::setReverbSlider(double v, int i) { +void DeicsOnzeGui::setReverbSlider(double /*v*/, int /*i*/) { if(_deicsOnze->_pluginIReverb) { // FIXME FIXME Tim @@ -434,7 +434,7 @@ void DeicsOnzeGui::setReverbSlider(double v, int i) { } else printf("Warning : no DeicsOnze reverb loaded\n"); } -void DeicsOnzeGui::setChorusFloatEntry(double v, int i) { +void DeicsOnzeGui::setChorusFloatEntry(double /*v*/, int /*i*/) { if(_deicsOnze->_pluginIReverb) { // FIXME FIXME Tim @@ -448,7 +448,7 @@ void DeicsOnzeGui::setChorusFloatEntry(double v, int i) { } else printf("Warning : no DeicsOnze chorus loaded\n"); } -void DeicsOnzeGui::setChorusSlider(double v, int i) { +void DeicsOnzeGui::setChorusSlider(double /*v*/, int /*i*/) { if(_deicsOnze->_pluginIReverb) { // FIXME FIXME Tim -- cgit v1.2.3