summaryrefslogtreecommitdiff
path: root/muse2/muse
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2011-06-03 14:24:08 +0000
committerFlorian Jung <flo@windfisch.org>2011-06-03 14:24:08 +0000
commitdb164b62e3892bd17d1a2eabca76bde3b67072df (patch)
treeab71ac4b4f05ab94c008d75ef7052bef5af6cc74 /muse2/muse
parentdef4fdb391f5207ebbe61881416f39f3d896cc5d (diff)
parent9187899632c14d64b3fae6477b7f941240f912a6 (diff)
merged with trunk and adapted new functions
Diffstat (limited to 'muse2/muse')
-rw-r--r--muse2/muse/CMakeLists.txt2
-rw-r--r--muse2/muse/app.cpp1089
-rw-r--r--muse2/muse/app.h32
-rw-r--r--muse2/muse/appearance.h6
-rw-r--r--muse2/muse/arranger/arranger.cpp4
-rw-r--r--muse2/muse/arranger/pcanvas.cpp23
-rw-r--r--muse2/muse/arranger/pcanvas.h3
-rw-r--r--muse2/muse/arranger/tlist.cpp111
-rw-r--r--muse2/muse/arranger/tlist.h11
-rw-r--r--muse2/muse/audioconvert.cpp3
-rw-r--r--muse2/muse/audioconvert.h3
-rw-r--r--muse2/muse/audiotrack.cpp1
-rw-r--r--muse2/muse/cleftypes.h13
-rw-r--r--muse2/muse/cliplist/cliplist.cpp4
-rw-r--r--muse2/muse/conf.cpp43
-rw-r--r--muse2/muse/confmport.cpp10
-rw-r--r--muse2/muse/confmport.h3
-rw-r--r--muse2/muse/ctrl/ctrlcanvas.h4
-rw-r--r--muse2/muse/ctrl/ctrledit.cpp10
-rw-r--r--muse2/muse/ctrl/ctrledit.h3
-rw-r--r--muse2/muse/ctrl/ctrlpanel.cpp265
-rw-r--r--muse2/muse/ctrl/ctrlpanel.h7
-rw-r--r--muse2/muse/driver/jack.cpp24
-rw-r--r--muse2/muse/driver/jackmidi.cpp8
-rw-r--r--muse2/muse/dssihost.cpp6
-rw-r--r--muse2/muse/dssihost.h6
-rw-r--r--muse2/muse/functions.cpp389
-rw-r--r--muse2/muse/functions.h39
-rw-r--r--muse2/muse/gconfig.cpp3
-rw-r--r--muse2/muse/gconfig.h1
-rw-r--r--muse2/muse/globals.cpp5
-rw-r--r--muse2/muse/globals.h11
-rw-r--r--muse2/muse/helper.cpp20
-rw-r--r--muse2/muse/helper.h4
-rw-r--r--muse2/muse/instruments/minstrument.cpp9
-rw-r--r--muse2/muse/instruments/minstrument.h6
-rw-r--r--muse2/muse/liste/editevent.cpp32
-rw-r--r--muse2/muse/liste/listedit.h4
-rw-r--r--muse2/muse/marker/markerview.h4
-rw-r--r--muse2/muse/master/lmaster.h4
-rw-r--r--muse2/muse/master/master.h3
-rw-r--r--muse2/muse/master/masteredit.h4
-rw-r--r--muse2/muse/master/tscale.h3
-rw-r--r--muse2/muse/midictrl.cpp78
-rw-r--r--muse2/muse/midictrl.h3
-rw-r--r--muse2/muse/mididev.cpp10
-rw-r--r--muse2/muse/midiedit/dcanvas.cpp79
-rw-r--r--muse2/muse/midiedit/dcanvas.h13
-rw-r--r--muse2/muse/midiedit/dlist.cpp158
-rw-r--r--muse2/muse/midiedit/dlist.h27
-rw-r--r--muse2/muse/midiedit/drumedit.cpp19
-rw-r--r--muse2/muse/midiedit/drumedit.h4
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp134
-rw-r--r--muse2/muse/midiedit/ecanvas.h3
-rw-r--r--muse2/muse/midiedit/piano.h4
-rw-r--r--muse2/muse/midiedit/pianoroll.cpp21
-rw-r--r--muse2/muse/midiedit/pianoroll.h4
-rw-r--r--muse2/muse/midiedit/prcanvas.cpp167
-rw-r--r--muse2/muse/midiedit/prcanvas.h16
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp563
-rw-r--r--muse2/muse/midiedit/scoreedit.h71
-rw-r--r--muse2/muse/mixer/amixer.h4
-rw-r--r--muse2/muse/mixer/astrip.cpp1058
-rw-r--r--muse2/muse/mixer/astrip.h6
-rw-r--r--muse2/muse/mixer/mstrip.cpp52
-rw-r--r--muse2/muse/mixer/mstrip.h5
-rw-r--r--muse2/muse/mixer/rack.h5
-rw-r--r--muse2/muse/mplugins/mrconfig.cpp7
-rw-r--r--muse2/muse/mplugins/mrconfig.h1
-rw-r--r--muse2/muse/mplugins/mrconfigbase.ui42
-rw-r--r--muse2/muse/node.cpp2
-rw-r--r--muse2/muse/route.cpp22
-rw-r--r--muse2/muse/route.h15
-rw-r--r--muse2/muse/seqmsg.cpp4
-rw-r--r--muse2/muse/song.cpp105
-rw-r--r--muse2/muse/song.h4
-rw-r--r--muse2/muse/songfile.cpp8
-rw-r--r--muse2/muse/steprec.cpp159
-rw-r--r--muse2/muse/steprec.h35
-rw-r--r--muse2/muse/synth.cpp5
-rw-r--r--muse2/muse/synth.h12
-rw-r--r--muse2/muse/ticksynth.cpp6
-rw-r--r--muse2/muse/track.cpp5
-rw-r--r--muse2/muse/track.h5
-rw-r--r--muse2/muse/transport.h10
-rw-r--r--muse2/muse/undo.cpp14
-rw-r--r--muse2/muse/value.h8
-rw-r--r--muse2/muse/vst.h6
-rw-r--r--muse2/muse/waveedit/waveedit.h4
-rw-r--r--muse2/muse/waveedit/waveview.h3
-rw-r--r--muse2/muse/waveevent.cpp2
-rw-r--r--muse2/muse/wavetrack.cpp2
-rw-r--r--muse2/muse/widgets/CMakeLists.txt4
-rw-r--r--muse2/muse/widgets/bigtime.h4
-rw-r--r--muse2/muse/widgets/comment.h4
-rw-r--r--muse2/muse/widgets/function_dialogs/CMakeLists.txt3
-rw-r--r--muse2/muse/widgets/function_dialogs/crescendo.h3
-rw-r--r--muse2/muse/widgets/function_dialogs/deloverlaps.h3
-rw-r--r--muse2/muse/widgets/function_dialogs/gatetime.h5
-rw-r--r--muse2/muse/widgets/function_dialogs/legato.cpp88
-rw-r--r--muse2/muse/widgets/function_dialogs/legato.h43
-rw-r--r--muse2/muse/widgets/function_dialogs/legatobase.ui233
-rw-r--r--muse2/muse/widgets/function_dialogs/move.h3
-rw-r--r--muse2/muse/widgets/function_dialogs/quantize.h3
-rw-r--r--muse2/muse/widgets/function_dialogs/remove.cpp20
-rw-r--r--muse2/muse/widgets/function_dialogs/remove.h7
-rw-r--r--muse2/muse/widgets/function_dialogs/removebase.ui129
-rw-r--r--muse2/muse/widgets/function_dialogs/setlen.h3
-rw-r--r--muse2/muse/widgets/function_dialogs/transpose.h1
-rw-r--r--muse2/muse/widgets/function_dialogs/velocity.h3
-rw-r--r--muse2/muse/widgets/genset.cpp3
-rw-r--r--muse2/muse/widgets/gensetbase.ui23
-rw-r--r--muse2/muse/widgets/header.cpp135
-rw-r--r--muse2/muse/widgets/header.h4
-rw-r--r--muse2/muse/widgets/lcombo.h3
-rw-r--r--muse2/muse/widgets/menutitleitem.cpp48
-rw-r--r--muse2/muse/widgets/menutitleitem.h4
-rw-r--r--muse2/muse/widgets/meter.h3
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp151
-rw-r--r--muse2/muse/widgets/mtrackinfo.h3
-rw-r--r--muse2/muse/widgets/musewidgetsplug.cpp5
-rw-r--r--muse2/muse/widgets/noteinfo.h4
-rw-r--r--muse2/muse/widgets/pitchlabel.h4
-rw-r--r--muse2/muse/widgets/popupmenu.cpp312
-rw-r--r--muse2/muse/widgets/popupmenu.h34
-rw-r--r--muse2/muse/widgets/poslabel.h4
-rw-r--r--muse2/muse/widgets/projectcreateimpl.h2
-rw-r--r--muse2/muse/widgets/routepopup.cpp1416
-rw-r--r--muse2/muse/widgets/routepopup.h73
-rw-r--r--muse2/muse/widgets/scrollscale.h5
-rw-r--r--muse2/muse/widgets/swidget.h3
-rw-r--r--muse2/muse/widgets/tb1.h5
-rw-r--r--muse2/muse/widgets/tempolabel.h4
-rw-r--r--muse2/muse/widgets/tools.h1
-rw-r--r--muse2/muse/widgets/unusedwavefiles.h1
-rw-r--r--muse2/muse/widgets/verticalmeter.h4
-rw-r--r--muse2/muse/widgets/view.h4
-rw-r--r--muse2/muse/widgets/visibletracks.cpp2
138 files changed, 4780 insertions, 3264 deletions
diff --git a/muse2/muse/CMakeLists.txt b/muse2/muse/CMakeLists.txt
index e6a90a59..cea95083 100644
--- a/muse2/muse/CMakeLists.txt
+++ b/muse2/muse/CMakeLists.txt
@@ -63,6 +63,7 @@ QT4_WRAP_CPP ( muse_moc_headers
song.h
transport.h
value.h
+ steprec.h
)
##
@@ -135,6 +136,7 @@ file (GLOB core_source_files
waveevent.cpp
wavetrack.cpp
xml.cpp
+ steprec.cpp
)
file (GLOB main_source_files
main.cpp
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp
index adac840a..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);
}
@@ -1815,7 +1812,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll
}
else {
Xml xml(f);
- read(xml, !loadAll);
+ read(xml, !loadAll, songTemplate);
bool fileError = ferror(f);
popenFlag ? pclose(f) : fclose(f);
if (fileError) {
@@ -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,1080 +2287,18 @@ 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);
+ 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);
- 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);
- subp->setTitle(QString("%1:").arg(i+1) + (md ? md->name() : tr("<none>")));
-
- 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);
- 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);
- subp->setTitle(QString("%1:").arg(i) + tr("<none>"));
-
- // 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;
-}
-
-#if 0
-//---------------------------------------------------------
-// getRoutingPopupView
-//---------------------------------------------------------
-
-PopupView* MusE::getRoutingPopupView()
-{
- if(!routingPopupView)
- //routingPopupView = new PopupView(this);
- routingPopupView = new PopupView();
- return routingPopupView;
-}
-
-//---------------------------------------------------------
-// routingPopupViewActivated
-//---------------------------------------------------------
-
-void MusE::routingPopupViewActivated(Track* track, int n)
-{
- //if(!track || (track != gRoutingPopupMenuMaster))
- if(!track)
- return;
-
- if(track->isMidiTrack())
- {
- PopupView* pup = getRoutingPopupView();
-
- //printf("MusE::routingPopupMenuActivated midi n:%d count:%d\n", n, pup->count());
-
- if(pup->model()->rowCount() == 0)
- return;
-
- //MidiTrack* t = (MidiTrack*)track;
- RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes();
-
- if(n == -1)
- return;
-
- iRouteMenuMap imm = gRoutingMenuMap.find(n);
- if(imm == gRoutingMenuMap.end())
- 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)
- return;
-
- //if(!(md->rwFlags() & 2))
- if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2)))
- 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.
- }
- //else
- //{
- //}
-}
-
-//---------------------------------------------------------
-// prepareRoutingPopupView
-//---------------------------------------------------------
-
-PopupView* MusE::prepareRoutingPopupView(Track* track, bool dst)
-{
- if(!track)
- return 0;
-
- //QPoint ppt = QCursor::pos();
-
- if(track->isMidiTrack())
- {
-
- //QPoint ppt = parent->rect().bottomLeft();
-
- //if(dst)
- //{
- // TODO
-
- //}
- //else
- //{
- RouteList* rl = dst ? track->outRoutes() : track->inRoutes();
- //Route dst(track, -1);
-
- ///QPopupMenu* pup = new QPopupMenu(parent);
-
- PopupView* pup = getRoutingPopupView();
- pup->disconnect();
- //connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
- //connect(pup, SIGNAL(aboutToHide()), SLOT(routingPopupMenuAboutToHide()));
-
- ///pup->setCheckable(true);
-
- int gid = 0;
- //int n;
-
- // Routes can't be re-read until the message sent from msgAddRoute1()
- // has had time to be sent and actually affected the routes.
- ///_redisplay:
-
- pup->clear();
- gRoutingMenuMap.clear();
- gid = 0;
-
- //MidiInPortList* tl = song->midiInPorts();
- //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)
- for(int i = 0; i < MIDI_PORTS; ++i)
- {
- //MidiInPort* track = *i;
- // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick with ports.
- MidiPort* mp = &midiPorts[i];
- MidiDevice* md = mp->device();
- if(!md)
- continue;
-
- if(!(md->rwFlags() & (dst ? 1 : 2)))
- continue;
-
- //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i);
-
- //QMenu* m = menu->addMenu(track->name());
- //QPopupMenu* subp = new QPopupMenu(parent);
- //PopupMenu* subp = new PopupMenu(this);
- QStandardItem* subp = new QStandardItem(QT_TRANSLATE_NOOP("@default", md->name()));
-/// connect(subp, SIGNAL(activated(int)), pup, SIGNAL(activated(int)));
- //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.
- 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)
- {
- //QAction* a = m->addAction(QString("Channel %1").arg(ch+1));
- //subp->insertItem(QT_TRANSLATE_NOOP("@default", QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch);
- gid = i * MIDI_CHANNELS + ch;
-
- //printf("MusE::prepareRoutingPopupMenu inserting gid:%d\n", gid);
-
-/// subp->insertItem(QString("Channel %1").arg(ch+1), gid);
- QStandardItem* sti = new QStandardItem(QString("Channel %1").arg(ch+1));
- sti->setCheckable(true);
- sti->setData(gid);
- subp->appendRow(sti);
-
- //a->setCheckable(true);
- //Route src(track, ch, RouteNode::TRACK);
- //Route src(md, ch);
- //Route r = Route(src, dst);
- //a->setData(QVariant::fromValue(r));
- //a->setChecked(rl->indexOf(r) != -1);
-
- //Route srcRoute(md, ch);
- //Route srcRoute(i, ch); // p3.3.49 New: Midi port route.
- 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) );
-
- //for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) // p3.3.50 Removed.
- //{
- //if(*ir == dst)
- // if(*ir == srcRoute)
- // {
- // subp->setItemChecked(id, true);
- // break;
- // }
- //}
- if(chanmask & chbit) // p3.3.50 Is the channel already set? Show item check mark.
-/// subp->setItemChecked(gid, true);
- sti->setCheckState(Qt::Checked);
- }
- //subp->insertItem(QString("Toggle all"), 1000+i);
- // p3.3.50 One route with all channel bits set.
- gid = MIDI_PORTS * MIDI_CHANNELS + i; // Make sure each 'toggle' item gets a unique id.
-/// subp->insertItem(QString("Toggle all"), gid);
- QStandardItem* sti = new QStandardItem(QString("Toggle all"));
- sti->setData(gid);
- subp->appendRow(sti);
-
- Route togRoute(i, (1 << MIDI_CHANNELS) - 1); // Set all channel bits.
- gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) );
-
-/// pup->insertItem(QT_TRANSLATE_NOOP("@default", md->name()), subp);
- pup->model()->appendRow(subp);
- pup->updateView();
- }
-
- /*
- QPopupMenu* pup = new QPopupMenu(iR);
- pup->setCheckable(true);
- //MidiTrack* t = (MidiTrack*)track;
- RouteList* irl = track->inRoutes();
-
- MidiTrack* t = (MidiTrack*)track;
- int gid = 0;
- for (int i = 0; i < channel; ++i)
- {
- char buffer[128];
- snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1);
- MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
- pup->insertItem(titel);
-
- if (!checkAudioDevice()) return;
- std::list<QString> ol = audioDevice->outputPorts();
- for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) {
- int id = pup->insertItem(*ip, (gid * 16) + i);
- Route dst(*ip, true, i);
- ++gid;
- for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) {
- if (*ir == dst) {
- pup->setItemChecked(id, true);
- break;
- }
- }
- }
- if (i+1 != channel)
- pup->addSeparator();
- }
- */
-
-/// if(pup->count() == 0)
- if(pup->model()->rowCount() == 0)
- {
- ///delete pup;
- gRoutingPopupMenuMaster = 0;
- //pup->clear();
- //pup->disconnect();
- gRoutingMenuMap.clear();
- //oR->setDown(false);
- return 0;
- }
-
- gIsOutRoutingPopupMenu = dst;
- return pup;
- }
-
- return 0;
-}
-#endif
-
-//---------------------------------------------------------
// saveAs
//---------------------------------------------------------
diff --git a/muse2/muse/app.h b/muse2/muse/app.h
index 70aac8fc..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;
@@ -195,7 +190,7 @@ class MusE : public QMainWindow
QMenu* openRecent;
bool readMidi(FILE*);
- void read(Xml& xml, bool skipConfig);
+ void read(Xml& xml, bool skipConfig, bool isTemplate);
void processTrack(MidiTrack* track);
void write(Xml& xml) const;
@@ -286,7 +281,7 @@ class MusE : public QMainWindow
void startMidiTransformer();
void writeGlobalConfiguration() const;
- void startEditInstrument();
+ //void startEditInstrument();
void startClipList(bool);
void openRecentMenu();
@@ -337,7 +332,6 @@ class MusE : public QMainWindow
private:
void adjustGlobalLists(int startPos, int diff);
-
public slots:
bool saveAs();
void bounceToFile(AudioOutput* ao = 0);
@@ -357,8 +351,7 @@ class MusE : public QMainWindow
void importMidi(const QString &file);
void setUsedTool(int);
void showDidYouKnowDialog();
-
- void routingPopupMenuAboutToHide();
+ void startEditInstrument();
void configMidiPorts();
public:
@@ -370,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();
@@ -383,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/appearance.h b/muse2/muse/appearance.h
index ef99adbe..ec266f8e 100644
--- a/muse2/muse/appearance.h
+++ b/muse2/muse/appearance.h
@@ -15,6 +15,10 @@ class GlobalConfigValues;
//---------------------------------------------------------
class Appearance : public QDialog, public Ui::AppearanceDialogBase {
+
+ Q_OBJECT
+
+ private:
Arranger* arr;
QColor* color;
GlobalConfigValues* config;
@@ -24,7 +28,7 @@ class Appearance : public QDialog, public Ui::AppearanceDialogBase {
QTreeWidgetItem* lastSelectedBgItem;
QTreeWidgetItem* lastSelectedColorItem;
- Q_OBJECT
+
void updateFonts();
void updateColor();
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp
index d74bed78..e1205d6f 100644
--- a/muse2/muse/arranger/arranger.cpp
+++ b/muse2/muse/arranger/arranger.cpp
@@ -69,6 +69,7 @@ void Arranger::setHeaderToolTips()
header->setToolTip(COL_OPORT, tr("Midi output port or synth midi port"));
header->setToolTip(COL_TIMELOCK, tr("Time Lock"));
header->setToolTip(COL_AUTOMATION, tr("Automation parameter selection"));
+ header->setToolTip(COL_CLEF, tr("Notation clef"));
}
@@ -87,6 +88,7 @@ void Arranger::setHeaderWhatsThis()
header->setWhatsThis(COL_OCHANNEL, tr("Midi/drum track: Output channel number.\nAudio track: Channels.\nMid/right-click to change."));
header->setWhatsThis(COL_OPORT, tr("Midi/drum track: Output port.\nSynth track: Assigned midi port.\nLeft-click to change.\nRight-click to show GUI."));
header->setWhatsThis(COL_TIMELOCK, tr("Time lock"));
+ header->setToolTip(COL_CLEF, tr("Notation clef. Select this tracks notation clef."));
}
//---------------------------------------------------------
@@ -290,6 +292,7 @@ Arranger::Arranger(QMainWindow* parent, const char* name)
header->setColumnLabel(tr("Ch"), COL_OCHANNEL, 30);
header->setColumnLabel(tr("T"), COL_TIMELOCK, fm1.width('T')+fw);
header->setColumnLabel(tr("Automation"), COL_AUTOMATION, 75);
+ header->setColumnLabel(tr("Clef"), COL_CLEF, 75);
header->setResizeMode(COL_RECORD, QHeaderView::Fixed);
header->setResizeMode(COL_MUTE, QHeaderView::Fixed);
header->setResizeMode(COL_SOLO, QHeaderView::Fixed);
@@ -299,6 +302,7 @@ Arranger::Arranger(QMainWindow* parent, const char* name)
header->setResizeMode(COL_OCHANNEL, QHeaderView::Fixed);
header->setResizeMode(COL_TIMELOCK, QHeaderView::Fixed);
header->setResizeMode(COL_AUTOMATION, QHeaderView::Interactive);
+ header->setResizeMode(COL_CLEF, QHeaderView::Interactive);
setHeaderToolTips();
setHeaderWhatsThis();
diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index 006b9333..d65b8957 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -1624,7 +1624,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
int hoffset = (mt->height() - th ) / 2; // offset from bottom
if (ctrl_type == CTRL_PITCH)
- p.drawLine(t, hoffset + r.y() + th/2, t, hoffset + r.y() + val*th/8192/2 + th/2);
+ p.drawLine(t, hoffset + r.y() + th/2, t, hoffset + r.y() - val*th/8192/2 + th/2);
}
}
@@ -1641,7 +1641,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
int hoffset = (mt->height() - th ) / 2; // offset from bottom
if (ctrl_type == 10)
- p.drawLine(t, hoffset + r.y() + val*th/127, t, hoffset + r.y() + th);
+ p.drawLine(t, hoffset + r.y() + th - val*th/127, t, hoffset + r.y() + th);
}
}
@@ -1658,7 +1658,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
int hoffset = (mt->height() - th ) / 2; // offset from bottom
if (ctrl_type == 7)
- p.drawLine(t, hoffset + r.y() + val*th/127, t, hoffset + r.y() + th);
+ p.drawLine(t, hoffset + r.y() + th - val*th/127, t, hoffset + r.y() + th);
}
}
@@ -1690,7 +1690,7 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
if (config.canvasShowPartType & 4) //y-stretch?
{
- for (iEvent i = events->begin(); i != ito; ++i)
+ for (iEvent i = events->begin(); i != events->end(); ++i)
{
if (i->second.type()==Note)
{
@@ -1725,6 +1725,19 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
lowest_pitch--;
highest_pitch++;
}
+
+ if (heavyDebugMsg)
+ {
+ if (!isdrum)
+ printf("DEBUG: arranger: cakewalk enabled, y-stretching from %i to %i. eventlist=%p\n",lowest_pitch, highest_pitch, events);
+ else
+ {
+ printf("DEBUG: arranger: cakewalk enabled, y-stretching drums: ");;
+ for (map<int,int>::iterator it=y_mapper.begin(); it!=y_mapper.end(); it++)
+ printf("%i ", it->first);
+ printf("; eventlist=%p\n",events);
+ }
+ }
}
else
{
@@ -1734,6 +1747,8 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, EventList* events, Midi
if (isdrum)
for (int cnt=0;cnt<127;cnt++)
y_mapper[cnt]=cnt;
+
+ if (heavyDebugMsg) printf("DEBUG: arranger: cakewalk enabled, y-stretch disabled\n");
}
p.setPen(QColor(color_brightness,color_brightness,color_brightness));
diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h
index e48af2d4..18e47426 100644
--- a/muse2/muse/arranger/pcanvas.h
+++ b/muse2/muse/arranger/pcanvas.h
@@ -57,6 +57,7 @@ class CtrlVal;
//---------------------------------------------------------
class PartCanvas : public Canvas {
+ Q_OBJECT
int* _raster;
TrackList* tracks;
@@ -69,7 +70,7 @@ class PartCanvas : public Canvas {
AutomationObject automation;
//std::vector<TrackAutomationView*> automationViews;
- Q_OBJECT
+
virtual void keyPress(QKeyEvent*);
virtual void mousePress(QMouseEvent*);
virtual void mouseMove(QMouseEvent* event);
diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp
index 4b531607..4f050c46 100644
--- a/muse2/muse/arranger/tlist.cpp
+++ b/muse2/muse/arranger/tlist.cpp
@@ -11,7 +11,7 @@
#include <QKeyEvent>
#include <QLineEdit>
-#include <QMenu>
+//#include <QMenu>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>
@@ -21,6 +21,7 @@
#include <QScrollBar>
#include <QWheelEvent>
#include <QIcon>
+#include <QSpinBox>
#include "popupmenu.h"
#include "globals.h"
@@ -44,6 +45,7 @@
#include "midiedit/drummap.h"
#include "synth.h"
#include "config.h"
+#include "popupmenu.h"
#ifdef DSSI_SUPPORT
#include "dssihost.h"
@@ -230,13 +232,15 @@ void TList::paint(const QRect& r)
switch (section) {
case COL_RECORD:
- if (track->canRecord()) {
+ if (track->canRecord() && !header->isSectionHidden(COL_RECORD)) {
drawCenteredPixmap(p,
track->recordFlag() ? record_on_Icon : record_off_Icon, r);
}
break;
case COL_CLASS:
{
+ if (header->isSectionHidden(COL_CLASS))
+ break;
const QPixmap* pm = 0;
switch(type) {
case Track::MIDI:
@@ -297,7 +301,11 @@ void TList::paint(const QRect& r)
{
QString s;
int n;
- if (track->isMidiTrack()) {
+ if (track->isMidiTrack() && track->type() == Track::DRUM) {
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, "-");
+ break;
+ }
+ else if (track->isMidiTrack()) {
n = ((MidiTrack*)track)->outChannel() + 1;
}
else {
@@ -356,6 +364,18 @@ void TList::paint(const QRect& r)
p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
}
break;
+ case COL_CLEF:
+ if (track->isMidiTrack()) {
+ QString s = tr("no clef");
+ if (((MidiTrack*)track)->getClef() == trebleClef)
+ s=tr("Treble");
+ else if (((MidiTrack*)track)->getClef() == bassClef)
+ s=tr("Bass");
+ else if (((MidiTrack*)track)->getClef() == grandStaff)
+ s=tr("Grand");
+ p.drawText(r, Qt::AlignVCenter|Qt::AlignLeft, s);
+ }
+ break;
default:
break;
}
@@ -419,6 +439,20 @@ void TList::returnPressed()
setFocus();
}
+void TList::chanValueChanged(int val)
+{
+ Track* track = editTrack->clone(false);
+ ((MidiTrack*)editTrack)->setOutChannel(val-1);
+ audio->msgChangeTrack(track, editTrack);
+}
+
+void TList::chanValueFinished()
+{
+ editTrack = 0;
+ chan_edit->hide();
+ setFocus();
+}
+
//---------------------------------------------------------
// adjustScrollbar
//---------------------------------------------------------
@@ -472,7 +506,7 @@ void TList::mouseDoubleClickEvent(QMouseEvent* ev)
if (section == COL_NAME) {
editTrack = t;
if (editor == 0) {
- editor = new QLineEdit(this);
+ editor = new QLineEdit(this);
/*connect(editor, SIGNAL(returnPressed()),
SLOT(returnPressed()));*/
editor->setFrame(true);
@@ -483,6 +517,25 @@ void TList::mouseDoubleClickEvent(QMouseEvent* ev)
editMode = true;
editor->show();
}
+ else if (section == COL_OCHANNEL) {
+ if (t->isMidiTrack() && t->type() != Track::DRUM)
+ {
+ editTrack=t;
+ if (chan_edit==0) {
+ chan_edit=new QSpinBox(this);
+ chan_edit->setMinimum(1);
+ chan_edit->setMaximum(16);
+ connect(chan_edit, SIGNAL(valueChanged(int)), SLOT(chanValueChanged(int)));
+ connect(chan_edit, SIGNAL(editingFinished()), SLOT(chanValueFinished()));
+ }
+ chan_edit->setValue(((MidiTrack*)editTrack)->outChannel()+1);
+ int w=colw;
+ if (w < chan_edit->sizeHint().width()) w=chan_edit->sizeHint().width();
+ chan_edit->setGeometry(colx, coly, w, colh);
+ chan_edit->show();
+ chan_edit->setFocus();
+ }
+ }
else
mousePressEvent(ev);
}
@@ -883,9 +936,11 @@ void TList::changeAutomationColor(QAction* act)
//---------------------------------------------------------
// colorMenu
//---------------------------------------------------------
-QMenu* TList::colorMenu(QColor c, int id)
+//QMenu* TList::colorMenu(QColor c, int id)
+PopupMenu* TList::colorMenu(QColor c, int id)
{
- QMenu * m = new QMenu(this);
+ //QMenu * m = new QMenu(this);
+ PopupMenu * m = new PopupMenu(this); //, true); TODO
for (int i = 0; i< 6; i++) {
QPixmap pix(10,10);
QPainter p(&pix);
@@ -1054,11 +1109,39 @@ void TList::mousePressEvent(QMouseEvent* ev)
mode = START_DRAG;
switch (col) {
+ case COL_CLEF:
+ if (t->isMidiTrack()) {
+ QMenu* p = new QMenu;
+ p->addAction(tr("Treble clef"))->setData(0);
+ p->addAction(tr("Bass clef"))->setData(1);
+ p->addAction(tr("Grand Staff"))->setData(2);
+
+ // Show the menu
+ QAction* act = p->exec(ev->globalPos(), 0);
+ if (act) {
+ switch (act->data().toInt()) {
+ case 0:
+ ((MidiTrack*)t)->setClef(trebleClef);
+ break;
+ case 1:
+ ((MidiTrack*)t)->setClef(bassClef);
+ break;
+ case 2:
+ ((MidiTrack*)t)->setClef(grandStaff);
+ break;
+ default:
+ break;
+ }
+ }
+ delete p;
+ }
+
+ break;
case COL_AUTOMATION:
{
if (!t->isMidiTrack()) {
editAutomation = t;
- PopupMenu* p = new PopupMenu();
+ PopupMenu* p = new PopupMenu(true);
p->disconnect();
p->clear();
p->setTitle(tr("Viewable automation"));
@@ -1075,12 +1158,11 @@ void TList::mousePressEvent(QMouseEvent* ev)
int data = cl->id() * 256; // shift 8 bits
data += 150; // illegal color > 100
act->setData(data);
- QMenu *m = colorMenu(cl->color(), cl->id());
+ //QMenu *m = colorMenu(cl->color(), cl->id());
+ PopupMenu *m = colorMenu(cl->color(), cl->id());
act->setMenu(m);
}
connect(p, SIGNAL(triggered(QAction*)), SLOT(changeAutomation(QAction*)));
- //connect(p, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
- //p->popup(QCursor::pos());
p->exec(QCursor::pos());
delete p;
@@ -1236,8 +1318,10 @@ void TList::mousePressEvent(QMouseEvent* ev)
{
MidiTrack* mt = dynamic_cast<MidiTrack*>(t);
if (mt == 0)
- break;
-
+ break;
+ if (mt->type() == Track::DRUM)
+ break;
+
int channel = mt->outChannel();
channel += delta;
if(channel >= MIDI_CHANNELS)
@@ -1511,6 +1595,9 @@ void TList::wheelEvent(QWheelEvent* ev)
case COL_OCHANNEL:
if (t->isMidiTrack()) {
MidiTrack* mt = (MidiTrack*)t;
+ if (mt && mt->type() == Track::DRUM)
+ break;
+
int channel = mt->outChannel() + delta;
if (channel >= MIDI_CHANNELS)
diff --git a/muse2/muse/arranger/tlist.h b/muse2/muse/arranger/tlist.h
index 8bebef95..607ca8c0 100644
--- a/muse2/muse/arranger/tlist.h
+++ b/muse2/muse/arranger/tlist.h
@@ -14,12 +14,14 @@
class QKeyEvent;
class QLineEdit;
+class QSpinBox;
class QMouseEvent;
class QPaintEvent;
class QResizeEvent;
class QScrollBar;
class QWheelEvent;
-class QMenu;
+//class QMenu;
+class PopupMenu;
class ScrollScale;
class Track;
@@ -36,6 +38,7 @@ enum TrackColumn {
COL_OCHANNEL,
COL_TIMELOCK,
COL_AUTOMATION,
+ COL_CLEF,
COL_NONE = -1
};
@@ -55,6 +58,7 @@ class TList : public QWidget {
Header* header;
QScrollBar* _scroll;
QLineEdit* editor;
+ QSpinBox* chan_edit;
Track* editTrack;
Track* editAutomation;
@@ -85,10 +89,13 @@ class TList : public QWidget {
void classesPopupMenu(Track*, int x, int y);
TrackList getRecEnabledTracks();
void setHeaderToolTips();
- QMenu* colorMenu(QColor c, int id);
+ //QMenu* colorMenu(QColor c, int id);
+ PopupMenu* colorMenu(QColor c, int id);
private slots:
void returnPressed();
+ void chanValueChanged(int);
+ void chanValueFinished();
void songChanged(int flags);
void changeAutomation(QAction*);
void changeAutomationColor(QAction*);
diff --git a/muse2/muse/audioconvert.cpp b/muse2/muse/audioconvert.cpp
index 552b5e95..ced8e703 100644
--- a/muse2/muse/audioconvert.cpp
+++ b/muse2/muse/audioconvert.cpp
@@ -5,7 +5,8 @@
//
// (C) Copyright 1999-2009 Werner Schweer (ws@seh.de)
//
-// Audio converter module created by Tim terminator356
+// Audio converter module created by Tim
+// (C) Copyright 2009-2011 Tim E. Real (terminator356 A T sourceforge D O T net)
//=========================================================
#include <math.h>
diff --git a/muse2/muse/audioconvert.h b/muse2/muse/audioconvert.h
index 039af912..0933de60 100644
--- a/muse2/muse/audioconvert.h
+++ b/muse2/muse/audioconvert.h
@@ -5,7 +5,8 @@
//
// (C) Copyright 1999-2009 Werner Schweer (ws@seh.de)
//
-// Audio converter module created by Tim terminator356
+// Audio converter module created by Tim
+// (C) Copyright 2009-2011 Tim E. Real (terminator356 A T sourceforge D O T net)
//=========================================================
#ifndef __AUDIOCONVERT_H__
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 <const int, QString> jackRouteNameMap;
std::map <const AudioTrack*, jackRouteNameMap > jackRouteNameCache;
diff --git a/muse2/muse/cleftypes.h b/muse2/muse/cleftypes.h
new file mode 100644
index 00000000..8c14a6d3
--- /dev/null
+++ b/muse2/muse/cleftypes.h
@@ -0,0 +1,13 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// cleftypes.h
+// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net)
+//=========================================================
+
+#ifndef __CLEFTYPES_H__
+#define __CLEFTYPES_H__
+
+enum clefTypes { trebleClef, bassClef, grandStaff };
+
+#endif
diff --git a/muse2/muse/cliplist/cliplist.cpp b/muse2/muse/cliplist/cliplist.cpp
index 967c608d..96636463 100644
--- a/muse2/muse/cliplist/cliplist.cpp
+++ b/muse2/muse/cliplist/cliplist.cpp
@@ -235,7 +235,7 @@ void ClipListEdit::clipSelectionChanged()
editor->start->setEnabled(false);
editor->len->setEnabled(false);
return;
-#if 0
+/*
}
editor->start->setEnabled(true);
editor->len->setEnabled(true);
@@ -246,7 +246,7 @@ void ClipListEdit::clipSelectionChanged()
len.setFrame(curClip.lenFrame());
editor->start->setValue(pos);
editor->len->setValue(len);
-#endif
+*/
}
//---------------------------------------------------------
diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp
index e7eef503..89cdd04d 100644
--- a/muse2/muse/conf.cpp
+++ b/muse2/muse/conf.cpp
@@ -481,6 +481,8 @@ static void readSeqConfiguration(Xml& xml)
rcGotoLeftMarkNote = xml.parseInt();
else if (tag == "rcPlay")
rcPlayNote = xml.parseInt();
+ else if (tag == "rcSteprec")
+ rcSteprecNote = xml.parseInt();
else
xml.unknown("Seq");
break;
@@ -946,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;
@@ -1061,6 +1066,7 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
xml.intTag(level, "rcRecord", rcRecordNote);
xml.intTag(level, "rcGotoLeft", rcGotoLeftMarkNote);
xml.intTag(level, "rcPlay", rcPlayNote);
+ xml.intTag(level, "rcSteprec", rcSteprecNote);
if (writePortInfo) {
//
@@ -1214,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);
@@ -1223,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];
@@ -1276,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, "<mtcoffset>%02d:%02d:%02d:%02d:%02d</mtcoffset>\n",
diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp
index 8c27d9eb..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)
@@ -609,7 +609,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
return;
#else
{
- defpup = new PopupMenu(this);
+ defpup = new PopupMenu(this, true);
defpup->addAction(new MenuTitleItem("Channel", defpup));
QAction* act = 0;
int chbits = midiPorts[no].defaultInChannels();
@@ -649,7 +649,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)
return;
#else
{
- defpup = new PopupMenu(this);
+ defpup = new PopupMenu(this, true);
defpup->addAction(new MenuTitleItem("Channel", defpup));
QAction* act = 0;
int chbits = midiPorts[no].defaultOutChannels();
diff --git a/muse2/muse/confmport.h b/muse2/muse/confmport.h
index 3c139ee2..6901035a 100644
--- a/muse2/muse/confmport.h
+++ b/muse2/muse/confmport.h
@@ -28,6 +28,7 @@ class Xml;
//---------------------------------------------------------
class MPConfig : public QDialog, Ui::SynthConfigBase {
+ Q_OBJECT
QMenu* instrPopup;
//QMenu* popup;
PopupMenu* defpup;
@@ -36,7 +37,7 @@ class MPConfig : public QDialog, Ui::SynthConfigBase {
void setToolTip(QTableWidgetItem *item, int col);
void addItem(int row, int col, QTableWidgetItem *item, QTableWidget *table);
- Q_OBJECT
+
private slots:
void rbClicked(QTableWidgetItem*);
diff --git a/muse2/muse/ctrl/ctrlcanvas.h b/muse2/muse/ctrl/ctrlcanvas.h
index 300cac19..e6864003 100644
--- a/muse2/muse/ctrl/ctrlcanvas.h
+++ b/muse2/muse/ctrl/ctrlcanvas.h
@@ -81,6 +81,8 @@ class CEventList: public std::list<CEvent*> {
//---------------------------------------------------------
class CtrlCanvas : public View {
+ Q_OBJECT
+
MidiEditor* editor;
MidiTrack* curTrack;
MidiPart* curPart;
@@ -120,7 +122,7 @@ class CtrlCanvas : public View {
void pdrawItems(QPainter&, const QRect&, const MidiPart*, bool, bool);
void partControllers(const MidiPart*, int, int*, int*, MidiController**, MidiCtrlValList**);
- Q_OBJECT
+
protected:
enum DragMode { DRAG_OFF, DRAG_NEW, DRAG_MOVE_START, DRAG_MOVE,
diff --git a/muse2/muse/ctrl/ctrledit.cpp b/muse2/muse/ctrl/ctrledit.cpp
index 8842ba97..c4e33822 100644
--- a/muse2/muse/ctrl/ctrledit.cpp
+++ b/muse2/muse/ctrl/ctrledit.cpp
@@ -69,7 +69,8 @@ void CtrlEdit::writeStatus(int level, Xml& xml)
{
if (canvas->controller()) {
xml.tag(level++, "ctrledit");
- xml.strTag(level, "ctrl", canvas->controller()->name());
+ //xml.strTag(level, "ctrl", canvas->controller()->name());
+ xml.intTag(level, "ctrlnum", canvas->controller()->num());
xml.tag(level, "/ctrledit");
}
}
@@ -89,6 +90,8 @@ void CtrlEdit::readStatus(Xml& xml)
return;
case Xml::TagStart:
if (tag == "ctrl") {
+ xml.parse1(); // Obsolete.
+ /*
QString name = xml.parse1();
int portno = canvas->track()->outPort();
MidiPort* port = &midiPorts[portno];
@@ -101,6 +104,11 @@ void CtrlEdit::readStatus(Xml& xml)
break;
}
}
+ */
+ }
+ else if (tag == "ctrlnum") {
+ int num = xml.parseInt();
+ canvas->setController(num);
}
else
xml.unknown("CtrlEdit");
diff --git a/muse2/muse/ctrl/ctrledit.h b/muse2/muse/ctrl/ctrledit.h
index eec235b1..c5f5935e 100644
--- a/muse2/muse/ctrl/ctrledit.h
+++ b/muse2/muse/ctrl/ctrledit.h
@@ -24,10 +24,11 @@ class Xml;
//---------------------------------------------------------
class CtrlEdit : public QWidget {
+ Q_OBJECT
CtrlCanvas* canvas;
CtrlPanel* panel;
- Q_OBJECT
+
private slots:
void destroy();
diff --git a/muse2/muse/ctrl/ctrlpanel.cpp b/muse2/muse/ctrl/ctrlpanel.cpp
index 9e990861..b23ce855 100644
--- a/muse2/muse/ctrl/ctrlpanel.cpp
+++ b/muse2/muse/ctrl/ctrlpanel.cpp
@@ -11,7 +11,8 @@
#include "ctrlpanel.h"
#include "ctrlcanvas.h"
-#include <QMenu>
+//#include <QMenu>
+#include <QAction>
#include <QPushButton>
#include <QSizePolicy>
#include <QHBoxLayout>
@@ -20,10 +21,12 @@
#include <math.h>
+#include "app.h"
#include "globals.h"
#include "midictrl.h"
#include "instruments/minstrument.h"
#include "midiport.h"
+#include "mididev.h"
#include "xml.h"
#include "icons.h"
#include "event.h"
@@ -37,6 +40,8 @@
#include "doublelabel.h"
#include "midi.h"
#include "audio.h"
+#include "menutitleitem.h"
+#include "popupmenu.h"
//---------------------------------------------------------
// CtrlPanel
@@ -47,6 +52,8 @@ CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, const char* name)
{
setObjectName(name);
inHeartBeat = true;
+ //ctrlMainPop = 0;
+ //ctrlSubPop = 0;
editor = e;
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
QVBoxLayout* vbox = new QVBoxLayout;
@@ -514,6 +521,7 @@ void CtrlPanel::setHeight(int h)
setFixedHeight(h);
}
+#if 0
struct CI {
QString s;
bool used;
@@ -673,6 +681,261 @@ void CtrlPanel::ctrlPopup()
}
}
+#else // p4.0.25 Tim
+struct CI {
+ int num;
+ QString s;
+ bool used;
+ bool instrument;
+ CI(int n, const QString& ss, bool u, bool i) : num(n), s(ss), used(u), instrument(i) {}
+ };
+
+void CtrlPanel::ctrlPopup()
+ {
+ //---------------------------------------------------
+ // build list of midi controllers for current
+ // MidiPort/channel
+ //---------------------------------------------------
+
+ PartList* parts = editor->parts();
+ Part* part = editor->curCanvasPart();
+ MidiTrack* track = (MidiTrack*)(part->track());
+ int channel = track->outChannel();
+ MidiPort* port = &midiPorts[track->outPort()];
+ int curDrumInstrument = editor->curDrumInstrument();
+ bool isDrum = track->type() == Track::DRUM;
+ MidiInstrument* instr = port->instrument();
+ MidiControllerList* mcl = instr->controller();
+
+ MidiCtrlValListList* cll = port->controller();
+ int min = channel << 24;
+ int max = min + 0x1000000;
+
+ std::list<CI> sList;
+ typedef std::list<CI>::iterator isList;
+
+ for (iMidiCtrlValList i = cll->lower_bound(min); i != cll->lower_bound(max); ++i) {
+ MidiCtrlValList* cl = i->second;
+ MidiController* c = port->midiController(cl->num());
+ // dont show drum specific controller if not a drum track
+ if ((c->num() & 0xff) == 0xff) {
+ if (!isDrum)
+ continue;
+ // only show controller for curDrumInstrument:
+ if ((cl->num() & 0xff) != drumMap[curDrumInstrument].anote) {
+ continue;
+ }
+ }
+ isList i = sList.begin();
+ for (; i != sList.end(); ++i) {
+ //if (i->s == c->name())
+ if (i->num == c->num())
+ break;
+ }
+ if (i == sList.end()) {
+ bool used = false;
+ for (iPart ip = parts->begin(); ip != parts->end(); ++ip) {
+ EventList* el = ip->second->events();
+ for (iEvent ie = el->begin(); ie != el->end(); ++ie) {
+ Event e = ie->second;
+ if ((e.type() == Controller) && (e.dataA() == cl->num())) {
+ used = true;
+ break;
+ }
+ }
+ if (used)
+ break;
+ }
+ //sList.push_back(CI(c->name(), used));
+ bool isinstr = ( mcl->find(c->num()) != mcl->end() );
+ int cnum = c->num();
+ // Need to distinguish between global default controllers and
+ // instrument defined controllers. Instrument takes priority over global
+ // ie they 'overtake' definition of a global controller such that the
+ // global def is no longer available.
+ sList.push_back(CI(cnum,
+ isinstr ? midiCtrlNumString(cnum, true) + c->name() : midiCtrlName(cnum, true),
+ used, isinstr));
+ }
+ }
+
+ PopupMenu* ctrlMainPop = new PopupMenu;
+
+ //ctrlMainPop->addSeparator();
+ ctrlMainPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlMainPop));
+
+ //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1);
+
+ // Add instrument-defined controllers.
+ for (isList i = sList.begin(); i != sList.end(); ++i)
+ {
+ if(!i->instrument)
+ continue;
+ if (i->used)
+ ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
+ else
+ ctrlMainPop->addAction(i->s)->setData(i->num);
+ }
+
+ ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1);
+ //ctrlMainPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2);
+
+ ctrlMainPop->addSeparator();
+ ctrlMainPop->addAction(new MenuTitleItem(tr("Others"), ctrlMainPop));
+
+ //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3);
+
+ ctrlMainPop->addAction(tr("Velocity"))->setData(max);
+
+ // Add global default controllers (all controllers not found in instrument).
+ for (isList i = sList.begin(); i != sList.end(); ++i)
+ {
+ if(i->instrument)
+ continue;
+ if (i->used)
+ ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num);
+ else
+ ctrlMainPop->addAction(i->s)->setData(i->num);
+ }
+
+ ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3);
+
+ //connect(ctrlMainPop, SIGNAL(hovered(QAction*)), SLOT(ctrlMainPopHovered(QAction*)));
+
+ QAction *act = ctrlMainPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ selCtrl->setDown(false);
+
+ if (!act)
+ {
+ delete ctrlMainPop;
+ return;
+ }
+
+ int rv = act->data().toInt();
+ delete ctrlMainPop;
+
+ if (rv == max) { // special case velocity
+ emit controllerChanged(CTRL_VELOCITY);
+ }
+ else if (rv == max + 1) { // add new instrument controller
+
+ PopupMenu * ctrlSubPop = new PopupMenu(this);
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlSubPop));
+
+ //
+ // populate popup with all controllers available for
+ // current instrument
+ //
+
+ //ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2);
+
+ for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ int num = ci->second->num();
+ if((num & 0xff) == 0xff)
+ {
+ // dont show drum specific controller if not a drum track
+ if(!isDrum)
+ continue;
+ num = (num & ~0xff) + drumMap[curDrumInstrument].anote;
+ }
+
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(midiCtrlNumString(num, true) + ci->second->name())->setData(num);
+ }
+
+ // Don't allow editing instrument if it's a synth
+ if(!port->device() || port->device()->deviceType() != MidiDevice::SYNTH_MIDI)
+ ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2);
+
+ //connect(ctrlSubPop, SIGNAL(hovered(QAction*)), SLOT(ctrlSubPopHovered(QAction*)));
+
+ QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ if (act2)
+ {
+ int rv2 = act2->data().toInt();
+
+ if (rv2 == max + 2) // edit instrument
+ muse->startEditInstrument();
+ else // select new instrument control
+ {
+ MidiController* c;
+ for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)
+ {
+ c = ci->second;
+ int num = c->num();
+ if (isDrum && ((num & 0xff) == 0xff))
+ num = (num & ~0xff) + drumMap[curDrumInstrument].anote;
+
+ if(num != rv2)
+ continue;
+
+ if(cll->find(channel, num) == cll->end())
+ {
+ MidiCtrlValList* vl = new MidiCtrlValList(num);
+
+ cll->add(channel, vl);
+ emit controllerChanged(c->num());
+ //song->update(SC_MIDI_CONTROLLER_ADD);
+ }
+ else
+ emit controllerChanged(c->num());
+ break;
+ }
+ }
+ }
+ delete ctrlSubPop;
+ }
+
+ //else if (rv == max + 2) // edit instrument
+ // muse->startEditInstrument();
+
+ else if (rv == max + 3) { // add new other controller
+ PopupMenu* ctrlSubPop = new PopupMenu(this);
+ ctrlSubPop->addAction(new MenuTitleItem(tr("Common Controls"), ctrlSubPop));
+
+ for(int num = 0; num < 127; ++num)
+ if(cll->find(channel, num) == cll->end())
+ ctrlSubPop->addAction(midiCtrlName(num, true))->setData(num);
+ QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0)));
+ if (act2) {
+ int rv2 = act2->data().toInt();
+ int num = rv2;
+ if (isDrum && ((num & 0xff) == 0xff))
+ num = (num & ~0xff) + drumMap[curDrumInstrument].anote;
+ if(cll->find(channel, num) == cll->end())
+ {
+ MidiCtrlValList* vl = new MidiCtrlValList(num);
+
+ cll->add(channel, vl);
+ emit controllerChanged(rv2);
+ //song->update(SC_MIDI_CONTROLLER_ADD);
+ }
+ else
+ emit controllerChanged(rv2);
+ }
+ delete ctrlSubPop;
+ }
+ else { // Select a control
+ //QString s = act->text();
+ iMidiCtrlValList i = cll->begin();
+ for (; i != cll->end(); ++i) {
+ MidiCtrlValList* cl = i->second;
+ MidiController* c = port->midiController(cl->num());
+ //if (c->name() == s) {
+ if (c->num() == rv) {
+ emit controllerChanged(c->num());
+ break;
+ }
+ }
+ if (i == cll->end()) {
+ //printf("CtrlPanel: controller %s not found!", s.toLatin1().constData());
+ printf("CtrlPanel: controller number %d not found!", rv);
+ }
+ }
+ }
+#endif
+
//---------------------------------------------------------
// ctrlRightClicked
//---------------------------------------------------------
diff --git a/muse2/muse/ctrl/ctrlpanel.h b/muse2/muse/ctrl/ctrlpanel.h
index a0e5f915..3f6de205 100644
--- a/muse2/muse/ctrl/ctrlpanel.h
+++ b/muse2/muse/ctrl/ctrlpanel.h
@@ -12,7 +12,6 @@
class MidiController;
-class QMenu;
class QPushButton;
class MidiEditor;
@@ -26,7 +25,9 @@ class MidiTrack;
//---------------------------------------------------------
class CtrlPanel: public QWidget {
- ///QMenu* pop;
+ Q_OBJECT
+
+ //QMenu* pop;
QPushButton* selCtrl;
MidiEditor* editor;
@@ -38,7 +39,7 @@ class CtrlPanel: public QWidget {
DoubleLabel* _dl;
int _val;
- Q_OBJECT
+
signals:
void destroyPanel();
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/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index c950e096..1765fabb 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -974,13 +974,17 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
}
//
- // transfer noteOn events to gui for step recording and keyboard
- // remote control
+ // transfer noteOn and Off events to gui for step recording and keyboard
+ // remote control (changed by flo93: added noteOff-events)
//
if (typ == ME_NOTEON) {
int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
song->putEvent(pv);
}
+ else if (typ == ME_NOTEOFF) {
+ int pv = ((event.dataA() & 0xff)<<8) + (0x00); //send an event with velo=0
+ song->putEvent(pv);
+ }
//if(_recordFifo.put(MidiPlayEvent(event)))
// printf("MidiJackDevice::recordEvent: fifo overflow\n");
diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp
index 49a63643..2384ed02 100644
--- a/muse2/muse/dssihost.cpp
+++ b/muse2/muse/dssihost.cpp
@@ -37,7 +37,7 @@
#include <QDir>
#include <QFileInfo>
-#include <QMenu>
+//#include <QMenu>
#include "dssihost.h"
#include "synth.h"
@@ -61,6 +61,8 @@
#include "globaldefs.h"
//#include "al/dsp.h"
#include "gconfig.h"
+#include "popupmenu.h"
+
/*
static lo_server_thread serverThread;
@@ -3388,7 +3390,7 @@ const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, MType /*type*/, bo
//---------------------------------------------------------
//void DssiSynthIF::populatePatchPopup(QMenu* menu, int)
-void DssiSynthIF::populatePatchPopup(QMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/)
+void DssiSynthIF::populatePatchPopup(PopupMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/)
{
// The plugin can change the programs, patches etc.
// So make sure we're up to date by calling queryPrograms.
diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h
index 096c84c7..b917bbf6 100644
--- a/muse2/muse/dssihost.h
+++ b/muse2/muse/dssihost.h
@@ -42,7 +42,8 @@
#include "plugin.h"
-#include <QMenu>
+//#include <QMenu>
+#include "popupmenu.h"
#define DSSI_PARAMSAVE_VERSION_MAJOR 0
#define DSSI_PARAMSAVE_VERSION_MINOR 1
@@ -199,7 +200,8 @@ class DssiSynthIF : public SynthIF, public PluginIBase
virtual const char* getPatchName(int, int, MType, bool);
//virtual void populatePatchPopup(QMenu*, int);
- virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool);
//virtual void write(Xml& xml) const;
virtual void write(int level, Xml& xml) const;
diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp
index ba16640c..4a65d19c 100644
--- a/muse2/muse/functions.cpp
+++ b/muse2/muse/functions.cpp
@@ -13,9 +13,19 @@
#include "audio.h"
#include "gconfig.h"
+#include <values.h>
#include <iostream>
-
+#include <errno.h>
+#include <values.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <QMimeData>
+#include <QByteArray>
+#include <QDrag>
#include <QMessageBox>
+#include <QClipboard>
using namespace std;
@@ -28,6 +38,7 @@ Setlen* set_notelen_dialog=NULL;
Move* move_notes_dialog=NULL;
Transpose* transpose_dialog=NULL;
Crescendo* crescendo_dialog=NULL;
+Legato* legato_dialog=NULL;
void init_function_dialogs(QWidget* parent)
{
@@ -40,6 +51,7 @@ void init_function_dialogs(QWidget* parent)
move_notes_dialog = new Move(parent);
transpose_dialog = new Transpose(parent);
crescendo_dialog = new Crescendo(parent);
+ legato_dialog = new Legato(parent);
}
set<Part*> partlist_to_set(PartList* pl)
@@ -52,6 +64,13 @@ set<Part*> partlist_to_set(PartList* pl)
return result;
}
+set<Part*> part_to_set(Part* p)
+{
+ set<Part*> result;
+ result.insert(p);
+ return result;
+}
+
bool is_relevant(const Event& event, const Part* part, int range)
{
unsigned tick;
@@ -109,7 +128,8 @@ bool quantize_notes(const set<Part*>& parts)
return false;
quantize_notes(parts, quantize_dialog->range, (config.division*4)/(1<<quantize_dialog->raster_power2),
- quantize_dialog->strength, quantize_dialog->swing, quantize_dialog->threshold);
+ quantize_dialog->quant_len, quantize_dialog->strength, quantize_dialog->swing,
+ quantize_dialog->threshold);
return true;
}
@@ -119,7 +139,8 @@ bool erase_notes(const set<Part*>& parts)
if (!erase_dialog->exec())
return false;
- erase_notes(parts,erase_dialog->range);
+ erase_notes(parts,erase_dialog->range, erase_dialog->velo_threshold, erase_dialog->velo_thres_used,
+ erase_dialog->len_threshold, erase_dialog->len_thres_used );
return true;
}
@@ -180,9 +201,19 @@ bool crescendo(const set<Part*>& parts)
return true;
}
+bool legato(const set<Part*>& parts)
+{
+ if (!legato_dialog->exec())
+ return false;
+
+ legato(parts,legato_dialog->range, legato_dialog->min_len, !legato_dialog->allow_shortening);
+
+ return true;
+}
+
-void modify_velocity(const set<Part*>& parts, int range, int rate, int offset)
+bool modify_velocity(const set<Part*>& parts, int range, int rate, int offset)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -212,12 +243,13 @@ void modify_velocity(const set<Part*>& parts, int range, int rate, int offset)
}
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void modify_off_velocity(const set<Part*>& parts, int range, int rate, int offset)
+bool modify_off_velocity(const set<Part*>& parts, int range, int rate, int offset)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -247,12 +279,13 @@ void modify_off_velocity(const set<Part*>& parts, int range, int rate, int offse
}
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void modify_notelen(const set<Part*>& parts, int range, int rate, int offset)
+bool modify_notelen(const set<Part*>& parts, int range, int rate, int offset)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -280,14 +313,15 @@ void modify_notelen(const set<Part*>& parts, int range, int rate, int offset)
}
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void set_notelen(const set<Part*>& parts, int range, int len)
+bool set_notelen(const set<Part*>& parts, int range, int len)
{
- modify_notelen(parts, range, 0, len);
+ return modify_notelen(parts, range, 0, len);
}
unsigned quantize_tick(unsigned tick, unsigned raster, int swing)
@@ -312,7 +346,7 @@ unsigned quantize_tick(unsigned tick, unsigned raster, int swing)
return tick_dest3;
}
-void quantize_notes(const set<Part*>& parts, int range, int raster, int strength, int swing, int threshold)
+bool quantize_notes(const set<Part*>& parts, int range, int raster, bool quant_len, int strength, int swing, int threshold)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -336,7 +370,7 @@ void quantize_notes(const set<Part*>& parts, int range, int raster, int strength
unsigned end_tick = begin_tick + len;
int len_diff = quantize_tick(end_tick, raster, swing) - end_tick;
- if (abs(len_diff) > threshold)
+ if ((abs(len_diff) > threshold) && quant_len)
len = len + len_diff*strength/100;
if (len <= 0)
@@ -352,12 +386,13 @@ void quantize_notes(const set<Part*>& parts, int range, int raster, int strength
}
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void erase_notes(const set<Part*>& parts, int range)
+bool erase_notes(const set<Part*>& parts, int range, int velo_threshold, bool velo_thres_used, int len_threshold, bool len_thres_used)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -369,15 +404,19 @@ void erase_notes(const set<Part*>& parts, int range)
Event& event=*(it->first);
Part* part=it->second;
- operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
+ if ( (!velo_thres_used && !len_thres_used) ||
+ (velo_thres_used && event.velo() < velo_threshold) ||
+ (len_thres_used && int(event.lenTick()) < len_threshold) )
+ operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps)
+bool transpose_notes(const set<Part*>& parts, int range, signed int halftonesteps)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -397,12 +436,13 @@ void transpose_notes(const set<Part*>& parts, int range, signed int halftonestep
operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void crescendo(const set<Part*>& parts, int range, int start_val, int end_val, bool absolute)
+bool crescendo(const set<Part*>& parts, int range, int start_val, int end_val, bool absolute)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -434,12 +474,13 @@ void crescendo(const set<Part*>& parts, int range, int start_val, int end_val, b
operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void move_notes(const set<Part*>& parts, int range, signed int ticks) //TODO FINDMICH: safety checks
+bool move_notes(const set<Part*>& parts, int range, signed int ticks) //TODO: clipping
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -450,18 +491,36 @@ void move_notes(const set<Part*>& parts, int range, signed int ticks) //TODO FIN
{
Event& event=*(it->first);
Part* part=it->second;
+ bool del=false;
Event newEvent = event.clone();
- newEvent.setTick(event.tick()+ticks);
- operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
+ if ((signed)event.tick()+ticks < 0) //don't allow moving before the part's begin
+ newEvent.setTick(0);
+ else
+ newEvent.setTick(event.tick()+ticks);
+
+ if (newEvent.endTick() > part->lenTick()) //if exceeding the part's end, clip
+ {
+ if (part->lenTick() > newEvent.tick())
+ newEvent.setLenTick(part->lenTick() - newEvent.tick());
+ else
+ del=true; //if the new length would be <= 0, erase the note
+ }
+
+ if (del==false)
+ operations.push_back(UndoOp(UndoOp::ModifyEvent, newEvent, event, part, false, false));
+ else
+ operations.push_back(UndoOp(UndoOp::DeleteEvent, event, part, false, false));
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
}
+ else
+ return false;
}
-void delete_overlaps(const set<Part*>& parts, int range)
+
+bool delete_overlaps(const set<Part*>& parts, int range)
{
map<Event*, Part*> events = get_events(parts, range);
Undo operations;
@@ -510,11 +569,266 @@ void delete_overlaps(const set<Part*>& parts, int range)
}
}
- if (!operations.empty())
- song->applyOperationGroup(operations);
+ return song->applyOperationGroup(operations);
+ }
+ else
+ return false;
+}
+
+bool legato(const set<Part*>& parts, int range, int min_len, bool dont_shorten)
+{
+ map<Event*, Part*> events = get_events(parts, range);
+ Undo operations;
+
+ if (min_len<=0) min_len=1;
+
+ if (!events.empty())
+ {
+ for (map<Event*, Part*>::iterator it1=events.begin(); it1!=events.end(); it1++)
+ {
+ Event& event1=*(it1->first);
+ Part* part1=it1->second;
+
+ unsigned len=MAXINT;
+ // we may NOT optimize by letting it2 start at (it1 +1); this optimisation
+ // is only allowed when events was sorted by time. it is, however, sorted
+ // randomly by pointer.
+ for (map<Event*, Part*>::iterator it2=events.begin(); it2!=events.end(); it2++)
+ {
+ Event& event2=*(it2->first);
+ Part* part2=it2->second;
+
+ bool relevant = (event2.tick() >= event1.tick() + min_len);
+ if (dont_shorten)
+ relevant = relevant && (event2.tick() >= event1.endTick());
+
+ if ( (part1->events()==part2->events()) && // part1 and part2 are the same or are duplicates
+ relevant && // they're not too near (respect min_len and dont_shorten)
+ (event2.tick()-event1.tick() < len ) ) // that's the nearest relevant following note
+ len=event2.tick()-event1.tick();
+ }
+
+ if (len==MAXINT) len=event1.lenTick(); // if no following note was found, keep the length
+
+ if (event1.lenTick() != len)
+ {
+ Event new_event1 = event1.clone();
+ new_event1.setLenTick(len);
+
+ operations.push_back(UndoOp(UndoOp::ModifyEvent, new_event1, event1, part1, false, false));
+ }
+ }
+
+ return song->applyOperationGroup(operations);
+ }
+ else
+ return false;
+}
+
+
+
+void copy_notes(const set<Part*>& parts, int range)
+{
+ QMimeData* drag = selected_events_to_mime(parts,range);
+
+ if (drag)
+ QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
+}
+
+void paste_notes(Part* dest_part)
+{
+ QString tmp="x-muse-eventlist"; // QClipboard::text() expects a QString&, not a QString :(
+ QString s = QApplication::clipboard()->text(tmp, QClipboard::Clipboard); // TODO CHECK Tim.
+ paste_at(dest_part, s, song->cpos());
+}
+
+QMimeData* selected_events_to_mime(const set<Part*>& parts, int range)
+{
+ map<Event*, Part*> events=get_events(parts,range);
+
+ //---------------------------------------------------
+ // generate event list from selected events
+ //---------------------------------------------------
+
+ EventList el;
+ unsigned startTick = MAXINT; //will be the tick of the first event or MAXINT if no events are there
+
+ for (map<Event*, Part*>::iterator it=events.begin(); it!=events.end(); it++)
+ {
+ Event& e = *it->first;
+
+ if (e.tick() < startTick)
+ startTick = e.tick();
+
+ el.add(e);
+ }
+
+ //---------------------------------------------------
+ // write events as XML into tmp file
+ //---------------------------------------------------
+
+ FILE* tmp = tmpfile();
+ if (tmp == 0)
+ {
+ fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ Xml xml(tmp);
+ int level = 0;
+
+ xml.tag(level++, "eventlist");
+ for (ciEvent e = el.begin(); e != el.end(); ++e)
+ e->second.write(level, xml, -startTick);
+ xml.etag(--level, "eventlist");
+
+ //---------------------------------------------------
+ // read tmp file into drag Object
+ //---------------------------------------------------
+
+ fflush(tmp);
+ struct stat f_stat;
+ if (fstat(fileno(tmp), &f_stat) == -1)
+ {
+ fprintf(stderr, "PianoCanvas::copy() fstat failed:<%s>\n",
+ strerror(errno));
+ fclose(tmp);
+ return 0;
+ }
+ int n = f_stat.st_size;
+ char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fileno(tmp), 0);
+ fbuf[n] = 0;
+
+ QByteArray data(fbuf);
+ QMimeData* md = new QMimeData();
+
+ md->setData("text/x-muse-eventlist", data);
+
+ munmap(fbuf, n);
+ fclose(tmp);
+
+ return md;
+}
+
+void paste_at(Part* dest_part, const QString& pt, int pos)
+{
+ Undo operations;
+
+ Xml xml(pt.toLatin1().constData());
+ for (;;)
+ {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token)
+ {
+ case Xml::Error:
+ case Xml::End:
+ goto end_of_paste_at;
+
+ case Xml::TagStart:
+ if (tag == "eventlist")
+ {
+ EventList el;
+ el.read(xml, "eventlist", true);
+ for (iEvent i = el.begin(); i != el.end(); ++i)
+ {
+ Event e = i->second;
+ int tick = e.tick() + pos - dest_part->tick();
+ if (tick<0)
+ {
+ printf("ERROR: trying to add event before current part!\n");
+ goto end_of_paste_at;
+ }
+
+ e.setTick(tick);
+ e.setSelected(true);
+ int diff = e.endTick()-dest_part->lenTick();
+ if (diff > 0) // too short part? extend it
+ {
+ Part* newPart = dest_part->clone();
+ newPart->setLenTick(newPart->lenTick()+diff);
+ // Indicate no undo, and do port controller values but not clone parts.
+ operations.push_back(UndoOp(UndoOp::ModifyPart,dest_part, newPart, true, false)); //FINDMICHJETZT oder andersrum?
+ dest_part = newPart; // reassign TODO FINDME does this work, or has dest_part to be a nonconst reference?
+ }
+ // Indicate no undo, and do not do port controller values and clone parts.
+ operations.push_back(UndoOp(UndoOp::AddEvent,e, dest_part, false, false));
+ }
+ song->applyOperationGroup(operations);
+ goto end_of_paste_at;
+ }
+ else
+ xml.unknown("pasteAt");
+ break;
+
+ case Xml::Attribut:
+ case Xml::TagEnd:
+ default:
+ break;
+ }
}
+
+ end_of_paste_at:
+ song->update(SC_SELECTION);
+}
+
+void select_all(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(true);
+ }
+ song->update(SC_SELECTION);
}
+void select_none(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(false);
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_invert(const std::set<Part*>& parts)
+{
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(!event.selected());
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_in_loop(const std::set<Part*>& parts)
+{
+ select_none(parts);
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected((event.tick()>=song->lpos() && event.endTick()<=song->rpos()));
+ }
+ song->update(SC_SELECTION);
+}
+
+void select_not_in_loop(const std::set<Part*>& parts)
+{
+ select_none(parts);
+ for (set<Part*>::iterator part=parts.begin(); part!=parts.end(); part++)
+ for (iEvent ev_it=(*part)->events()->begin(); ev_it!=(*part)->events()->end(); ev_it++)
+ {
+ Event& event=ev_it->second;
+ event.setSelected(!(event.tick()>=song->lpos() && event.endTick()<=song->rpos()));
+ }
+ song->update(SC_SELECTION);
+}
void read_function_dialog_config(Xml& xml)
@@ -554,6 +868,8 @@ void read_function_dialog_config(Xml& xml)
transpose_dialog->read_configuration(xml);
else if (tag == "crescendo")
crescendo_dialog->read_configuration(xml);
+ else if (tag == "legato")
+ legato_dialog->read_configuration(xml);
else
xml.unknown("function_dialogs");
break;
@@ -581,6 +897,7 @@ void write_function_dialog_config(int level, Xml& xml)
move_notes_dialog->write_configuration(level, xml);
transpose_dialog->write_configuration(level, xml);
crescendo_dialog->write_configuration(level, xml);
+ legato_dialog->write_configuration(level, xml);
xml.tag(level, "/dialogs");
}
diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h
index 2b6dc711..bc2bb8f4 100644
--- a/muse2/muse/functions.h
+++ b/muse2/muse/functions.h
@@ -17,10 +17,13 @@
#include "widgets/function_dialogs/setlen.h"
#include "widgets/function_dialogs/move.h"
#include "widgets/function_dialogs/deloverlaps.h"
+#include "widgets/function_dialogs/legato.h"
#include <set>
#include "part.h"
+class QString;
+class QMimeData;
extern GateTime* gatetime_dialog;
extern Velocity* velocity_dialog;
@@ -31,24 +34,27 @@ extern Setlen* set_notelen_dialog;
extern Move* move_notes_dialog;
extern Transpose* transpose_dialog;
extern Crescendo* crescendo_dialog;
+extern Legato* legato_dialog;
void init_function_dialogs(QWidget* parent);
std::set<Part*> partlist_to_set(PartList* pl);
+std::set<Part*> part_to_set(Part* p);
std::map<Event*, Part*> get_events(const std::set<Part*>& parts, int range);
//these functions simply do their job, non-interactively
-void modify_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0);
-void modify_off_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0);
-void modify_notelen(const std::set<Part*>& parts, int range, int rate, int offset=0);
-void quantize_notes(const std::set<Part*>& parts, int range, int raster, int strength=100, int swing=0, int threshold=0);
-void erase_notes(const std::set<Part*>& parts, int range);
-void delete_overlaps(const std::set<Part*>& parts, int range);
-void set_notelen(const std::set<Part*>& parts, int range, int len);
-void move_notes(const std::set<Part*>& parts, int range, signed int ticks);
-void transpose_notes(const std::set<Part*>& parts, int range, signed int halftonesteps);
-void crescendo(const std::set<Part*>& parts, int range, int start_val, int end_val, bool absolute);
+bool modify_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0);
+bool modify_off_velocity(const std::set<Part*>& parts, int range, int rate, int offset=0);
+bool modify_notelen(const std::set<Part*>& parts, int range, int rate, int offset=0);
+bool quantize_notes(const std::set<Part*>& parts, int range, int raster, bool len=false, int strength=100, int swing=0, int threshold=0);
+bool erase_notes(const std::set<Part*>& parts, int range, int velo_threshold=0, bool velo_thres_used=false, int len_threshold=0, bool len_thres_used=false);
+bool delete_overlaps(const std::set<Part*>& parts, int range);
+bool set_notelen(const std::set<Part*>& parts, int range, int len);
+bool move_notes(const std::set<Part*>& parts, int range, signed int ticks);
+bool transpose_notes(const std::set<Part*>& parts, int range, signed int halftonesteps);
+bool crescendo(const std::set<Part*>& parts, int range, int start_val, int end_val, bool absolute);
+bool legato(const std::set<Part*>& parts, int range, int min_len=1, bool dont_shorten=false);
//the below functions automatically open the dialog
@@ -62,8 +68,21 @@ bool transpose_notes(const std::set<Part*>& parts);
bool crescendo(const std::set<Part*>& parts);
bool erase_notes(const std::set<Part*>& parts);
bool delete_overlaps(const std::set<Part*>& parts);
+bool legato(const std::set<Part*>& parts);
+//functions for copy'n'paste
+void copy_notes(const std::set<Part*>& parts, int range);
+void paste_notes(Part* dest_part);
+QMimeData* selected_events_to_mime(const std::set<Part*>& parts, int range);
+void paste_at(Part* dest_part, const QString& pt, int pos);
+
+//functions for selections
+void select_all(const std::set<Part*>& parts);
+void select_none(const std::set<Part*>& parts);
+void select_invert(const std::set<Part*>& parts);
+void select_in_loop(const std::set<Part*>& parts);
+void select_not_in_loop(const std::set<Part*>& parts);
//functions for reading and writing default values
class Xml;
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 f8ae4454..7f346f87 100644
--- a/muse2/muse/globals.cpp
+++ b/muse2/muse/globals.cpp
@@ -347,12 +347,9 @@ unsigned char rcStopNote = 28;
unsigned char rcRecordNote = 31;
unsigned char rcGotoLeftMarkNote = 33;
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 894f1baf..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 <unistd.h>
@@ -167,19 +166,11 @@ extern unsigned char rcStopNote;
extern unsigned char rcRecordNote;
extern unsigned char rcGotoLeftMarkNote;
extern unsigned char rcPlayNote;
+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/helper.cpp b/muse2/muse/helper.cpp
index 605d6f5c..be45e048 100644
--- a/muse2/muse/helper.cpp
+++ b/muse2/muse/helper.cpp
@@ -6,6 +6,9 @@
//=========================================================
#include "helper.h"
+#include "part.h"
+#include "track.h"
+#include "song.h"
extern bool hIsB;
static const char* vall[] = {
@@ -38,3 +41,20 @@ QString pitch2string(int v)
}
+
+
+Part* partFromSerialNumber(int serial)
+{
+ TrackList* tl = song->tracks();
+ for (iTrack it = tl->begin(); it != tl->end(); ++it)
+ {
+ PartList* pl = (*it)->parts();
+ iPart ip;
+ for (ip = pl->begin(); ip != pl->end(); ++ip)
+ if (ip->second->sn() == serial)
+ return ip->second;
+ }
+
+ printf("ERROR: partFromSerialNumber(%i) wasn't able to find an appropriate part!\n",serial);
+ return NULL;
+}
diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h
index f772ebf6..109ecbee 100644
--- a/muse2/muse/helper.h
+++ b/muse2/muse/helper.h
@@ -10,7 +10,11 @@
#include <QString>
+class Part;
+
extern QString pitch2string(int v);
+Part* partFromSerialNumber(int serial);
+
#endif
diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp
index 4fde7bf3..10cb3ec2 100644
--- a/muse2/muse/instruments/minstrument.cpp
+++ b/muse2/muse/instruments/minstrument.cpp
@@ -11,7 +11,7 @@
#include <QAction>
#include <QDir>
#include <QFileInfo>
-#include <QMenu>
+//#include <QMenu>
#include <QMessageBox>
#include "minstrument.h"
@@ -25,6 +25,7 @@
#include "mpevent.h"
#include "midictrl.h"
#include "gconfig.h"
+#include "popupmenu.h"
MidiInstrumentList midiInstruments;
MidiInstrument* genericMidiInstrument;
@@ -881,7 +882,7 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru
// populatePatchPopup
//---------------------------------------------------------
-void MidiInstrument::populatePatchPopup(QMenu* menu, int chan, MType songType, bool drum)
+void MidiInstrument::populatePatchPopup(PopupMenu* menu, int chan, MType songType, bool drum)
{
menu->clear();
int mask = 0;
@@ -905,7 +906,9 @@ void MidiInstrument::populatePatchPopup(QMenu* menu, int chan, MType songType, b
if (pg.size() > 1) {
for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
PatchGroup* pgp = *i;
- QMenu* pm = menu->addMenu(pgp->name);
+ //QMenu* pm = menu->addMenu(pgp->name);
+ PopupMenu* pm = new PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here.
+ menu->addMenu(pm);
pm->setFont(config.fonts[0]);
const PatchList& pl = pgp->patches;
for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h
index a8fb1168..15942537 100644
--- a/muse2/muse/instruments/minstrument.h
+++ b/muse2/muse/instruments/minstrument.h
@@ -14,7 +14,8 @@
#include <vector>
class MidiPort;
-class QMenu;
+//class QMenu;
+class PopupMenu;
class MidiPlayEvent;
class Xml;
class EventList;
@@ -118,7 +119,8 @@ class MidiInstrument {
virtual void reset(int, MType);
virtual QString getPatchName(int,int,MType,bool);
- virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool);
void read(Xml&);
void write(int level, Xml&);
diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp
index b162a3e6..fd74d5d3 100644
--- a/muse2/muse/liste/editevent.cpp
+++ b/muse2/muse/liste/editevent.cpp
@@ -12,7 +12,7 @@
#include <QGridLayout>
#include <QLabel>
#include <QListWidget>
-#include <QMenu>
+//#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
@@ -36,6 +36,7 @@
#include "midiedit/drummap.h"
#include "instruments/minstrument.h"
#include "midi.h"
+#include "popupmenu.h"
//---------------------------------------------------------
// string2qhex
@@ -679,7 +680,8 @@ EditCtrlDialog::EditCtrlDialog(int tick, const Event& event,
void EditCtrlDialog::newController()
{
- QMenu* pup = new QMenu(this);
+ //QMenu* pup = new QMenu(this);
+ PopupMenu* pup = new PopupMenu(this);
//pup->setCheckable(this);//not necessary in Qt4
//
// populate popup with all controllers available for
@@ -715,7 +717,9 @@ void EditCtrlDialog::newController()
cll->add(channel, vl);
//song->update(SC_MIDI_CONTROLLER_ADD);
}
- for (int idx = 0; ;++idx) {
+ //for (int idx = 0; ;++idx) {
+ int idx = 0;
+ for (; idx < ctrlList->count() ;++idx) { // p4.0.25 Fix segfault
QString str = ctrlList->item(idx)->text();
if (s == str)
{
@@ -723,13 +727,20 @@ void EditCtrlDialog::newController()
ctrlListClicked(ctrlList->item(idx));
break;
}
- if (str.isNull()) {
- ctrlList->addItem(s);
- ctrlList->item(idx)->setSelected(true);
- ctrlListClicked(ctrlList->item(idx));
- break;
- }
+ //if (str.isNull()) {
+ // ctrlList->addItem(s);
+ // ctrlList->item(idx)->setSelected(true);
+ // ctrlListClicked(ctrlList->item(idx));
+ // break;
+ // }
}
+ if (idx >= ctrlList->count()) { // p4.0.25 Fix segfault
+ ctrlList->addItem(s);
+ ctrlList->item(idx)->setSelected(true);
+ ctrlListClicked(ctrlList->item(idx));
+ break;
+ }
+
break;
}
@@ -844,7 +855,8 @@ void EditCtrlDialog::instrPopup()
MidiInstrument* instr = midiPorts[port].instrument();
///instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM);
- QMenu* pup = new QMenu(this);
+ //QMenu* pup = new QMenu(this);
+ PopupMenu* pup = new PopupMenu(this);
instr->populatePatchPopup(pup, channel, song->mtype(), track->type() == Track::DRUM);
///if(pop->actions().count() == 0)
diff --git a/muse2/muse/liste/listedit.h b/muse2/muse/liste/listedit.h
index 5cf60a59..397a5e08 100644
--- a/muse2/muse/liste/listedit.h
+++ b/muse2/muse/liste/listedit.h
@@ -32,6 +32,8 @@ class Xml;
//---------------------------------------------------------
class ListEdit : public MidiEditor {
+ Q_OBJECT
+
QTreeWidget* liste;
QMenu* menuEdit;
QActionGroup* insertItems;
@@ -43,7 +45,7 @@ class ListEdit : public MidiEditor {
enum { CMD_DELETE };
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
virtual void keyPressEvent(QKeyEvent*);
void initShortcuts();
diff --git a/muse2/muse/marker/markerview.h b/muse2/muse/marker/markerview.h
index a271873c..5ad4f4bd 100644
--- a/muse2/muse/marker/markerview.h
+++ b/muse2/muse/marker/markerview.h
@@ -49,6 +49,8 @@ class MarkerItem : public QTreeWidgetItem {
//---------------------------------------------------------
class MarkerView : public TopWin {
+ Q_OBJECT
+
QTreeWidget* table;
QLineEdit* editName;
///PosEdit* editSMPTE;
@@ -58,7 +60,7 @@ class MarkerView : public TopWin {
QToolButton* lock;
QToolBar* tools;
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
private slots:
diff --git a/muse2/muse/master/lmaster.h b/muse2/muse/master/lmaster.h
index 150e8236..b2919b23 100644
--- a/muse2/muse/master/lmaster.h
+++ b/muse2/muse/master/lmaster.h
@@ -114,13 +114,15 @@ class LMasterSigEventItem : public LMasterLViewItem {
//---------------------------------------------------------
class LMaster : public MidiEditor {
+ Q_OBJECT
+
QTreeWidget* view;
QToolBar* tools;
QMenu* menuEdit;
enum { CMD_DELETE, CMD_INSERT_SIG, CMD_INSERT_TEMPO, CMD_EDIT_BEAT, CMD_EDIT_VALUE, CMD_INSERT_KEY };
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
void updateList();
void insertTempo(const TEvent*);
diff --git a/muse2/muse/master/master.h b/muse2/muse/master/master.h
index 52040aeb..2415b15e 100644
--- a/muse2/muse/master/master.h
+++ b/muse2/muse/master/master.h
@@ -26,6 +26,7 @@ class ScrollScale;
//---------------------------------------------------------
class Master : public View {
+ Q_OBJECT
enum DragMode { DRAG_OFF, DRAG_NEW, DRAG_MOVE_START, DRAG_MOVE,
DRAG_DELETE, DRAG_COPY_START, DRAG_COPY,
DRAG_RESIZE, DRAG_LASSO_START, DRAG_LASSO
@@ -37,7 +38,7 @@ class Master : public View {
DragMode drag;
MidiEditor* editor;
- Q_OBJECT
+
virtual void pdraw(QPainter&, const QRect&);
virtual void viewMouseMoveEvent(QMouseEvent* event);
virtual void leaveEvent(QEvent*e);
diff --git a/muse2/muse/master/masteredit.h b/muse2/muse/master/masteredit.h
index 59a5ab05..b2b06291 100644
--- a/muse2/muse/master/masteredit.h
+++ b/muse2/muse/master/masteredit.h
@@ -40,6 +40,8 @@ class TempoLabel;
//---------------------------------------------------------
class MasterEdit : public MidiEditor {
+ Q_OBJECT
+
Master* canvas;
ScrollScale* hscroll;
ScrollScale* vscroll;
@@ -62,7 +64,7 @@ class MasterEdit : public MidiEditor {
static int _widthInit, _heightInit;
static QByteArray _toolbarInit;
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
virtual void resizeEvent(QResizeEvent*);
virtual void focusOutEvent(QFocusEvent*);
diff --git a/muse2/muse/master/tscale.h b/muse2/muse/master/tscale.h
index 35fa39f2..d7ce86c9 100644
--- a/muse2/muse/master/tscale.h
+++ b/muse2/muse/master/tscale.h
@@ -15,8 +15,9 @@
//---------------------------------------------------------
class TScale : public View {
- double curTempo;
Q_OBJECT
+
+ double curTempo;
virtual void viewMouseMoveEvent(QMouseEvent* event);
virtual void leaveEvent(QEvent*e);
diff --git a/muse2/muse/midictrl.cpp b/muse2/muse/midictrl.cpp
index 66f8d87e..4cf1886a 100644
--- a/muse2/muse/midictrl.cpp
+++ b/muse2/muse/midictrl.cpp
@@ -139,15 +139,85 @@ void initMidiController()
}
//---------------------------------------------------------
+// midiCtrlNumString
+//---------------------------------------------------------
+
+QString midiCtrlNumString(int ctrl, bool fullyQualified)
+{
+ int h = (ctrl >> 8) & 0xff;
+ int l = ctrl & 0xff;
+ QString s1 = QString("%1").arg(h);
+ QString s2 = ( l == 0xff ? QString("* ") : QString("%1 ").arg(l) );
+ MidiController::ControllerType type = midiControllerType(ctrl);
+ switch (type)
+ {
+ case MidiController::Controller7:
+ if(fullyQualified)
+ return s2;
+ else
+ return QString();
+ case MidiController::Controller14:
+ return s1 + QString("CF") + s2;
+ case MidiController::RPN:
+ return s1 + QString("R") + s2;
+ case MidiController::NRPN:
+ return s1 + QString("N") + s2;
+ case MidiController::Pitch: // Don't show internal controller numbers.
+ return QString();
+ case MidiController::Program:
+ return QString();
+ case MidiController::Velo:
+ return QString();
+ case MidiController::RPN14:
+ return s1 + QString("RF") + s2;
+ case MidiController::NRPN14:
+ return s1 + QString("NF") + s2;
+ }
+ return s1 + QString("?") + s2;
+}
+
+//---------------------------------------------------------
// midiCtrlName
//---------------------------------------------------------
-QString midiCtrlName(int ctrl)
+QString midiCtrlName(int ctrl, bool fullyQualified)
+{
+ //if (ctrl < 0x10000)
+ // return QString(ctrlName[ctrl]);
+ //return QString("?N?");
+
+ // p4.0.25 Tim
+ int h = (ctrl >> 8) & 0xff;
+ int l = ctrl & 0xff;
+ QString s1 = QString("%1").arg(h);
+ QString s2 = ( l == 0xff ? QString("*") : QString("%1").arg(l) );
+ MidiController::ControllerType type = midiControllerType(ctrl);
+ switch (type)
{
- if (ctrl < 0x10000)
- return QString(ctrlName[ctrl]);
- return QString("?N?");
+ case MidiController::Controller7:
+ if(fullyQualified)
+ return s2 + QString(" ") + QString(ctrlName[l]);
+ else
+ return QString(ctrlName[l]);
+ case MidiController::Controller14:
+ return s1 + QString("CF") + s2;
+ case MidiController::RPN:
+ return s1 + QString("R") + s2;
+ case MidiController::NRPN:
+ return s1 + QString("N") + s2;
+ case MidiController::Pitch:
+ return QString("Pitch");
+ case MidiController::Program:
+ return QString("Program");
+ case MidiController::Velo:
+ return QString("Velocity");
+ case MidiController::RPN14:
+ return s1 + QString("RF") + s2;
+ case MidiController::NRPN14:
+ return s1 + QString("NF") + s2;
}
+ return s1 + QString("?") + s2;
+}
//---------------------------------------------------------
// MidiController
diff --git a/muse2/muse/midictrl.h b/muse2/muse/midictrl.h
index 27f8e7be..3b18ba91 100644
--- a/muse2/muse/midictrl.h
+++ b/muse2/muse/midictrl.h
@@ -243,7 +243,8 @@ extern MidiController::ControllerType midiControllerType(int num);
extern const QString& int2ctrlType(int n);
extern MidiController::ControllerType ctrlType2Int(const QString& s);
-extern QString midiCtrlName(int ctrl);
+extern QString midiCtrlName(int ctrl, bool fullyQualified = false);
+extern QString midiCtrlNumString(int ctrl, bool fullyQualified = false);
extern MidiController veloCtrl;
diff --git a/muse2/muse/mididev.cpp b/muse2/muse/mididev.cpp
index b5445b71..b13f571b 100644
--- a/muse2/muse/mididev.cpp
+++ b/muse2/muse/mididev.cpp
@@ -315,7 +315,7 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
if (filterEvent(event, midiRecordType, false))
return;
-
+
if (!applyMidiInputTransformation(event)) {
if (midiInputTrace)
printf(" midi input transformation: event filtered\n");
@@ -323,13 +323,17 @@ void MidiDevice::recordEvent(MidiRecordEvent& event)
}
//
- // transfer noteOn events to gui for step recording and keyboard
- // remote control
+ // transfer noteOn and Off events to gui for step recording and keyboard
+ // remote control (changed by flo93: added noteOff-events)
//
if (typ == ME_NOTEON) {
int pv = ((event.dataA() & 0xff)<<8) + (event.dataB() & 0xff);
song->putEvent(pv);
}
+ else if (typ == ME_NOTEOFF) {
+ int pv = ((event.dataA() & 0xff)<<8) + (0x00); //send an event with velo=0
+ song->putEvent(pv);
+ }
///if(_recBufFlipped)
/// _recordEvents2.add(event); // add event to secondary list of recorded events
diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp
index 61e98aea..92e514af 100644
--- a/muse2/muse/midiedit/dcanvas.cpp
+++ b/muse2/muse/midiedit/dcanvas.cpp
@@ -34,6 +34,7 @@
#include "audio.h"
#include "shortcuts.h"
#include "icons.h"
+#include "functions.h"
#define CARET 10
#define CARET2 5
@@ -88,7 +89,11 @@ DrumCanvas::DrumCanvas(MidiEditor* pr, QWidget* parent, int sx,
setVirt(false);
cursorPos= QPoint(0,0);
_stepSize=1;
+
+ steprec=new StepRec(NULL);
+
songChanged(SC_TRACK_INSERTED);
+ connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int)));
}
//---------------------------------------------------------
@@ -538,26 +543,7 @@ int DrumCanvas::pitch2y(int pitch) const
void DrumCanvas::cmd(int cmd)
{
- switch(cmd) {
- case CMD_CUT:
- copy();
- song->startUndo();
- for (iCItem i = items.begin(); i != items.end(); ++i) {
- if (!i->second->isSelected())
- continue;
- DEvent* e = (DEvent*)(i->second);
- Event event = e->event();
- // Indicate no undo, and do not do port controller values and clone parts.
- audio->msgDeleteEvent(event, e->part(), false, false, false);
- }
- song->endUndo(SC_EVENT_REMOVED);
- break;
- case CMD_COPY:
- copy();
- break;
- case CMD_PASTE:
- paste();
- break;
+ switch (cmd) {
case CMD_SELECT_ALL: // select all
for (iCItem k = items.begin(); k != items.end(); ++k) {
if (!k->second->isSelected())
@@ -698,41 +684,12 @@ void DrumCanvas::cmd(int cmd)
//---------------------------------------------------------
-// copy
-// cut copy paste
-//---------------------------------------------------------
-
-void DrumCanvas::copy()
- {
- QMimeData* md = getTextDrag();
-
- if (md)
- QApplication::clipboard()->setMimeData(md, QClipboard::Clipboard);
- }
-
-
-//---------------------------------------------------------
-// paste
-// paste events
-//---------------------------------------------------------
-
-void DrumCanvas::paste()
- {
- QString stype("x-muse-eventlist");
-
- //QString s = QApplication::clipboard()->text(stype, QClipboard::Selection);
- QString s = QApplication::clipboard()->text(stype, QClipboard::Clipboard); // TODO CHECK Tim.
-
- pasteAt(s, song->cpos());
- }
-
-//---------------------------------------------------------
// startDrag
//---------------------------------------------------------
void DrumCanvas::startDrag(CItem* /* item*/, bool copymode)
{
- QMimeData* md = getTextDrag();
+ QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1);
if (md) {
// "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object.
@@ -788,6 +745,10 @@ void DrumCanvas::keyPressed(int index, int velocity)
// play note:
MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity);
audio->msgPlayMidiEvent(&e);
+
+ if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart)
+ steprec->record(curPart,index,drumMap[index].len,editor->raster(),velocity,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier);
+
}
//---------------------------------------------------------
@@ -818,7 +779,7 @@ void DrumCanvas::mapChanged(int spitch, int dpitch)
typedef std::vector< std::pair<Part*, Event*> >::iterator idel_ev;
typedef std::vector< std::pair<Part*, Event> >::iterator iadd_ev;
-
+
MidiTrackList* tracks = song->midis();
for (ciMidiTrack t = tracks->begin(); t != tracks->end(); t++) {
MidiTrack* curTrack = *t;
@@ -1163,3 +1124,19 @@ void DrumCanvas::moveAwayUnused()
used.erase(it++);
}
}
+
+
+//---------------------------------------------------------
+// midiNote
+//---------------------------------------------------------
+void DrumCanvas::midiNote(int pitch, int velo)
+ {
+ if (debugMsg) printf("DrumCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo);
+
+ if (_midiin && _steprec && curPart
+ && !audio->isPlaying() && velo && pos[0] >= start_tick
+ && pos[0] < end_tick
+ && !(globalKeyState & Qt::AltModifier)) {
+ steprec->record(curPart,drumInmap[pitch],drumMap[(int)drumInmap[pitch]].len,editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier);
+ }
+ }
diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h
index cc3b8fff..868113a6 100644
--- a/muse2/muse/midiedit/dcanvas.h
+++ b/muse2/muse/midiedit/dcanvas.h
@@ -10,6 +10,7 @@
#include "ecanvas.h"
#include "song.h"
+#include "steprec.h"
#define TH 18
@@ -40,12 +41,15 @@ class PianoRoll;
//---------------------------------------------------------
class DrumCanvas : public EventCanvas {
-
+ Q_OBJECT
+
+ StepRec* steprec;
+
// Cursor tool position
QPoint cursorPos;
int _stepSize;
- Q_OBJECT
+
virtual void drawCanvas(QPainter&, const QRect&);
virtual void drawItem(QPainter&, const CItem*, const QRect&);
void drawTopItem(QPainter& p, const QRect& rect);
@@ -61,8 +65,6 @@ class DrumCanvas : public EventCanvas {
int y2pitch(int y) const;
int pitch2y(int pitch) const;
- void copy();
- void paste();
void startDrag(CItem*, bool copymode);
void dragEnterEvent(QDragEnterEvent* event);
void dragMoveEvent(QDragMoveEvent*);
@@ -75,6 +77,9 @@ class DrumCanvas : public EventCanvas {
signals:
void newWidth(int);
+ private slots:
+ void midiNote(int pitch, int velo);
+
public slots:
void mapChanged(int, int);
void keyPressed(int, int);
diff --git a/muse2/muse/midiedit/dlist.cpp b/muse2/muse/midiedit/dlist.cpp
index 0b8bf3aa..66922e83 100644
--- a/muse2/muse/midiedit/dlist.cpp
+++ b/muse2/muse/midiedit/dlist.cpp
@@ -23,7 +23,6 @@
#include "song.h"
#include "scrollscale.h"
-
//---------------------------------------------------------
// draw
//---------------------------------------------------------
@@ -244,7 +243,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev)
dm->mute = !dm->mute;
break;
case COL_PORT:
- if (button == Qt::RightButton) {
+ if ((button == Qt::RightButton) || (button == Qt::LeftButton)) {
bool changeAll = ev->modifiers() & Qt::ControlModifier;
devicesPopupMenu(dm, mapx(x), mapy(pitch * TH), changeAll);
}
@@ -296,7 +295,6 @@ void DList::viewMousePressEvent(QMouseEvent* ev)
if(val != dm->anote)
{
audio->msgIdle(true);
- //audio->msgRemapPortDrumCtlEvents(pitch, val, -1, -1);
song->remapPortDrumCtrlEvents(pitch, val, -1, -1);
audio->msgIdle(false);
dm->anote = val;
@@ -372,24 +370,7 @@ void DList::viewMousePressEvent(QMouseEvent* ev)
case COL_NAME:
emit keyPressed(pitch, 100); //Mapping done on other side, send index
break;
-#if 0
- case COL_CHANNEL:
- {
- int channel = t->channel();
- if (button == Qt::RightButton) {
- if (channel < 15)
- ++channel;
- }
- else if (button == Qt::MidButton) {
- if (channel > 0)
- --channel;
- }
- if (channel != t->channel()) {
- t->setChannel(channel);
- emit channelChanged();
- }
- }
-#endif
+
default:
break;
}
@@ -409,10 +390,13 @@ void DList::viewMouseDoubleClickEvent(QMouseEvent* ev)
int section = header->logicalIndexAt(x);
if ((section == COL_NAME || section == COL_VOL || section == COL_LEN || section == COL_LV1 ||
- section == COL_LV2 || section == COL_LV3 || section == COL_LV4) && (ev->button() == Qt::LeftButton))
+ section == COL_LV2 || section == COL_LV3 || section == COL_LV4 || section == COL_CHANNEL ||
+ section == COL_QNT) && (ev->button() == Qt::LeftButton))
{
lineEdit(pitch, section);
}
+ else if ((section == COL_ANOTE || section == COL_ENOTE) && (ev->button() == Qt::LeftButton))
+ pitchEdit(pitch, section);
else
viewMousePressEvent(ev);
}
@@ -467,6 +451,14 @@ void DList::lineEdit(int line, int section)
case COL_LV4:
editor->setText(QString::number(dm->lv4));
break;
+
+ case COL_QNT:
+ editor->setText(QString::number(dm->quant));
+ break;
+
+ case COL_CHANNEL:
+ editor->setText(QString::number(dm->channel+1));
+ break;
}
editor->end(false);
@@ -479,6 +471,40 @@ void DList::lineEdit(int line, int section)
}
+//---------------------------------------------------------
+// pitchEdit
+//---------------------------------------------------------
+void DList::pitchEdit(int line, int section)
+ {
+ DrumMap* dm = &drumMap[line];
+ editEntry = dm;
+ if (pitch_editor == 0) {
+ pitch_editor = new DPitchEdit(this);
+ connect(pitch_editor, SIGNAL(editingFinished()),
+ SLOT(pitchEdited()));
+ pitch_editor->setFrame(true);
+ }
+ int colx = mapx(header->sectionPosition(section));
+ int colw = rmapx(header->sectionSize(section));
+ int coly = mapy(line * TH);
+ int colh = rmapy(TH);
+ selectedColumn = section; //Store selected column to have an idea of which one was selected when return is pressed
+ switch (section) {
+ case COL_ENOTE:
+ pitch_editor->setValue(dm->enote);
+ break;
+
+ case COL_ANOTE:
+ pitch_editor->setValue(dm->anote);
+ break;
+ }
+
+ pitch_editor->setGeometry(colx, coly, colw, colh);
+ pitch_editor->show();
+ pitch_editor->setFocus();
+
+ }
+
//---------------------------------------------------------
// x2col
@@ -534,22 +560,35 @@ void DList::returnPressed()
{
///val = atoi(editor->text().ascii());
val = atoi(editor->text().toAscii().constData());
- if (selectedColumn != COL_LEN)
+
+ switch (selectedColumn)
{
- if(selectedColumn == COL_VOL)
- {
+ case COL_VOL:
if (val > 200) //Check bounds for volume
val = 200;
if (val < 0)
val = 0;
- }
- else
- {
+ break;
+
+ case COL_LV1:
+ case COL_LV2:
+ case COL_LV3:
+ case COL_LV4:
if (val > 127) //Check bounds for lv1-lv4 values
val = 127;
if (val < 0)
val = 0;
- }
+ break;
+
+ case COL_CHANNEL:
+ val--;
+ if (val >= 16)
+ val = 15;
+ if (val < 0)
+ val = 0;
+ break;
+
+ default: break;
}
}
@@ -583,6 +622,14 @@ void DList::returnPressed()
editEntry->lv4 = val;
break;
+ case COL_QNT:
+ editEntry->quant = val;
+ break;
+
+ case COL_CHANNEL:
+ editEntry->channel = val;
+ break;
+
default:
printf("Return pressed in unknown column\n");
break;
@@ -595,6 +642,52 @@ void DList::returnPressed()
}
//---------------------------------------------------------
+// pitchValueChanged
+//---------------------------------------------------------
+
+void DList::pitchEdited()
+{
+ int val=pitch_editor->value();
+ int pitch=(editEntry-drumMap);
+
+ switch(selectedColumn) {
+ case COL_ANOTE:
+ if(val != editEntry->anote)
+ {
+ audio->msgIdle(true);
+ song->remapPortDrumCtrlEvents(pitch, val, -1, -1);
+ audio->msgIdle(false);
+ editEntry->anote = val;
+ song->update(SC_DRUMMAP);
+ }
+ break;
+
+ case COL_ENOTE:
+ //Check if there is any other drumMap with the same inmap value (there should be one (and only one):-)
+ //If so, switch the inmap between the instruments
+ for (int i=0; i<DRUM_MAPSIZE; i++) {
+ if (drumMap[i].enote == val && &drumMap[i] != editEntry) {
+ drumInmap[int(editEntry->enote)] = i;
+ drumMap[i].enote = editEntry->enote;
+ break;
+ }
+ }
+ //TODO: Set all the notes on the track with pitch=dm->enote to pitch=val
+ editEntry->enote = val;
+ drumInmap[val] = pitch;
+ break;
+ default:
+ printf("Value changed in unknown column\n");
+ break;
+ }
+ selectedColumn = -1;
+ pitch_editor->hide();
+ editEntry = 0;
+ setFocus();
+ redraw();
+ }
+
+//---------------------------------------------------------
// moved
//---------------------------------------------------------
@@ -641,6 +734,7 @@ DList::DList(QHeaderView* h, QWidget* parent, int ymag)
setFocusPolicy(Qt::StrongFocus);
drag = NORMAL;
editor = 0;
+ pitch_editor = 0;
editEntry = 0;
// always select a drum instrument
currentlySelected = &drumMap[0];
@@ -696,9 +790,9 @@ void DList::viewMouseReleaseEvent(QMouseEvent* ev)
emit mapChanged(sPitch, dPitch); //Track pitch change done in canvas
}
drag = NORMAL;
-//?? redraw();
- if (editEntry)
- editor->setFocus();
+//?? redraw(); //commented out NOT by flo93; was already commented out
+// if (editEntry) //removed by flo93; seems to work without it
+// editor->setFocus(); //and causes segfaults after adding the pitchedits
int x = ev->x();
int y = ev->y();
bool shift = ev->modifiers() & Qt::ShiftModifier;
diff --git a/muse2/muse/midiedit/dlist.h b/muse2/muse/midiedit/dlist.h
index f57b7501..00f21c55 100644
--- a/muse2/muse/midiedit/dlist.h
+++ b/muse2/muse/midiedit/dlist.h
@@ -11,6 +11,7 @@
#include <QKeyEvent>
#include <QLineEdit>
+#include "awl/pitchedit.h"
#include "view.h"
#define TH 18 // normal Track-hight
@@ -46,13 +47,35 @@ class DLineEdit: public QLineEdit
};
//---------------------------------------------------------
+// DPitchEdit
+//---------------------------------------------------------
+class DPitchEdit: public Awl::PitchEdit
+{
+ public:
+ DPitchEdit(QWidget* parent) : PitchEdit(parent) {}
+ virtual ~DPitchEdit() {};
+
+ virtual void keyPressEvent(QKeyEvent* keyItem) {
+ if ((keyItem->key() == Qt::Key_Escape) || (keyItem->key() == Qt::Key_Return)) {
+ parentWidget()->setFocus();
+ hide();
+ }
+ else
+ PitchEdit::keyPressEvent(keyItem);
+ }
+};
+
+//---------------------------------------------------------
// DList
//---------------------------------------------------------
class DList : public View {
+ Q_OBJECT
+
QHeaderView* header;
ScrollScale* scroll;
QLineEdit* editor;
+ DPitchEdit* pitch_editor;
DrumMap* editEntry;
DrumMap* currentlySelected;
int selectedColumn;
@@ -71,12 +94,13 @@ class DList : public View {
int x2col(int x) const;
void devicesPopupMenu(DrumMap* t, int x, int y, bool changeAll);
- Q_OBJECT
+
//void setCurDrumInstrument(int n);
private slots:
void sizeChange(int, int, int);
void returnPressed();
+ void pitchEdited();
void moved(int, int, int);
signals:
@@ -91,6 +115,7 @@ class DList : public View {
void songChanged(int);
public:
void lineEdit(int line, int section);
+ void pitchEdit(int line, int section);
void setCurDrumInstrument(int n);
DList(QHeaderView*, QWidget* parent, int ymag);
~DList();
diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp
index 9e64d7a7..1e678432 100644
--- a/muse2/muse/midiedit/drumedit.cpp
+++ b/muse2/muse/midiedit/drumedit.cpp
@@ -302,7 +302,7 @@ DrumEdit::DrumEdit(PartList* pl, QWidget* parent, const char* name, unsigned ini
midiin->setIcon(*midiinIcon);
midiin->setCheckable(true);
tools->addWidget(midiin);
-
+
tools2 = new EditToolBar(this, drumeditTools);
addToolBar(tools2);
@@ -903,12 +903,27 @@ void DrumEdit::reset()
void DrumEdit::cmd(int cmd)
{
switch(cmd) {
+ case DrumCanvas::CMD_CUT:
+ copy_notes(partlist_to_set(parts()), 1);
+ erase_notes(partlist_to_set(parts()), 1);
+ break;
+ case DrumCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break;
+ case DrumCanvas::CMD_PASTE:
+ ((DrumCanvas*)canvas)->cmd(DrumCanvas::CMD_SELECT_NONE);
+ paste_notes(canvas->part());
+ break;
case DrumCanvas::CMD_LOAD: load(); break;
case DrumCanvas::CMD_SAVE: save(); break;
case DrumCanvas::CMD_RESET: reset(); break;
case DrumCanvas::CMD_MODIFY_VELOCITY: modify_velocity(partlist_to_set(parts())); break;
case DrumCanvas::CMD_CRESCENDO: crescendo(partlist_to_set(parts())); break;
- case DrumCanvas::CMD_QUANTIZE: quantize_notes(partlist_to_set(parts())); break;
+ case DrumCanvas::CMD_QUANTIZE:
+ if (quantize_dialog->exec())
+ quantize_notes(partlist_to_set(parts()), quantize_dialog->range,
+ (config.division*4)/(1<<quantize_dialog->raster_power2),
+ /* quant_len= */false, quantize_dialog->strength,
+ quantize_dialog->swing, quantize_dialog->threshold);
+ break;
case DrumCanvas::CMD_ERASE_EVENT: erase_notes(partlist_to_set(parts())); break;
case DrumCanvas::CMD_DEL: erase_notes(partlist_to_set(parts()),1); break; //delete selected events
case DrumCanvas::CMD_DELETE_OVERLAPS: delete_overlaps(partlist_to_set(parts())); break;
diff --git a/muse2/muse/midiedit/drumedit.h b/muse2/muse/midiedit/drumedit.h
index 30fe8487..64390cd9 100644
--- a/muse2/muse/midiedit/drumedit.h
+++ b/muse2/muse/midiedit/drumedit.h
@@ -49,6 +49,8 @@ class SNode;
//---------------------------------------------------------
class DrumEdit : public MidiEditor {
+ Q_OBJECT
+
Event selEvent;
MidiPart* selPart;
int selTick;
@@ -79,7 +81,7 @@ class DrumEdit : public MidiEditor {
QAction *sallAction, *snoneAction, *invAction, *inAction , *outAction;
QAction *prevAction, *nextAction;
- Q_OBJECT
+
void initShortcuts();
virtual void closeEvent(QCloseEvent*);
diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp
index 9ce84147..ef47e0d6 100644
--- a/muse2/muse/midiedit/ecanvas.cpp
+++ b/muse2/muse/midiedit/ecanvas.cpp
@@ -25,6 +25,7 @@
#include "event.h"
#include "shortcuts.h"
#include "audio.h"
+#include "functions.h"
//---------------------------------------------------------
// EventCanvas
@@ -364,137 +365,6 @@ void EventCanvas::keyPress(QKeyEvent* event)
event->ignore();
}
-//---------------------------------------------------------
-// getTextDrag
-//---------------------------------------------------------
-
-//QDrag* EventCanvas::getTextDrag(QWidget* parent)
-QMimeData* EventCanvas::getTextDrag()
- {
- //---------------------------------------------------
- // generate event list from selected events
- //---------------------------------------------------
-
- EventList el;
- unsigned startTick = MAXINT;
- for (iCItem i = items.begin(); i != items.end(); ++i) {
- if (!i->second->isSelected())
- continue;
- ///NEvent* ne = (NEvent*)(i->second);
- CItem* ne = i->second;
- Event e = ne->event();
- if (startTick == MAXINT)
- startTick = e.tick();
- el.add(e);
- }
-
- //---------------------------------------------------
- // write events as XML into tmp file
- //---------------------------------------------------
-
- FILE* tmp = tmpfile();
- if (tmp == 0) {
- fprintf(stderr, "EventCanvas::getTextDrag() fopen failed: %s\n",
- strerror(errno));
- return 0;
- }
- Xml xml(tmp);
-
- int level = 0;
- xml.tag(level++, "eventlist");
- for (ciEvent e = el.begin(); e != el.end(); ++e)
- e->second.write(level, xml, -startTick);
- xml.etag(--level, "eventlist");
-
- //---------------------------------------------------
- // read tmp file into drag Object
- //---------------------------------------------------
-
- fflush(tmp);
- struct stat f_stat;
- if (fstat(fileno(tmp), &f_stat) == -1) {
- fprintf(stderr, "PianoCanvas::copy() fstat failes:<%s>\n",
- strerror(errno));
- fclose(tmp);
- return 0;
- }
- int n = f_stat.st_size;
- char* fbuf = (char*)mmap(0, n+1, PROT_READ|PROT_WRITE,
- MAP_PRIVATE, fileno(tmp), 0);
- fbuf[n] = 0;
-
- QByteArray data(fbuf);
- QMimeData* md = new QMimeData();
- //QDrag* drag = new QDrag(parent);
-
- md->setData("text/x-muse-eventlist", data);
- //drag->setMimeData(md);
-
- munmap(fbuf, n);
- fclose(tmp);
-
- //return drag;
- return md;
- }
-
-//---------------------------------------------------------
-// pasteAt
-//---------------------------------------------------------
-
-void EventCanvas::pasteAt(const QString& pt, int pos)
- {
- QByteArray ba = pt.toLatin1();
- const char* p = ba.constData();
- Xml xml(p);
- for (;;) {
- Xml::Token token = xml.parse();
- const QString& tag = xml.s1();
- switch (token) {
- case Xml::Error:
- case Xml::End:
- return;
- case Xml::TagStart:
- if (tag == "eventlist") {
- Undo operations;
- EventList* el = new EventList();
- el->read(xml, "eventlist", true);
- int modified = SC_EVENT_INSERTED;
- for (iEvent i = el->begin(); i != el->end(); ++i) {
- Event e = i->second;
- int tick = e.tick() + pos - curPart->tick();
- if (tick<0) {
- printf("ERROR: trying to add event before current part!\n");
- delete el;
- return;
- }
-
- e.setTick(tick);
- int diff = e.endTick()-curPart->lenTick();
- if (diff > 0) {// too short part? extend it
- Part* newPart = curPart->clone();
- newPart->setLenTick(newPart->lenTick()+diff);
- // Do port controller values but not clone parts.
- operations.push_back(UndoOp(UndoOp::ModifyPart, curPart, newPart, true, false));
- modified=modified|SC_PART_MODIFIED;
- curPart = newPart; // reassign
- }
- // Do not do port controller values and clone parts.
- operations.push_back(UndoOp(UndoOp::AddEvent, e, curPart, false, false));
- }
- song->applyOperationGroup(operations);
- delete el;
- return;
- }
- else
- xml.unknown("pasteAt");
- break;
- case Xml::Attribut:
- case Xml::TagEnd:
- default:
- break;
- }
- }
- }
//---------------------------------------------------------
// dropEvent
@@ -515,7 +385,7 @@ void EventCanvas::viewDropEvent(QDropEvent* event)
int x = editor->rasterVal(event->pos().x());
if (x < 0)
x = 0;
- pasteAt(text, x);
+ paste_at(curPart, text, x);
//event->accept(); // TODO
}
else {
diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h
index b3275607..b847f0f9 100644
--- a/muse2/muse/midiedit/ecanvas.h
+++ b/muse2/muse/midiedit/ecanvas.h
@@ -80,9 +80,6 @@ class EventCanvas : public Canvas {
void range(int* s, int* e) const { *s = start_tick; *e = end_tick; }
void playEvents(bool flag) { _playEvents = flag; }
void selectAtTick(unsigned int tick);
- //QDrag* getTextDrag(QWidget* parent);
- QMimeData* getTextDrag();
- void pasteAt(const QString& pt, int pos);
void viewDropEvent(QDropEvent* event);
virtual void modifySelected(NoteInfo::ValType, int) {}
virtual void keyPress(QKeyEvent*);
diff --git a/muse2/muse/midiedit/piano.h b/muse2/muse/midiedit/piano.h
index 35106d64..f8deec52 100644
--- a/muse2/muse/midiedit/piano.h
+++ b/muse2/muse/midiedit/piano.h
@@ -23,6 +23,8 @@ class QPixmap;
class Piano : public View
{
+ Q_OBJECT
+
int curPitch;
QPixmap* octave;
QPixmap* c_keys[10];
@@ -34,7 +36,7 @@ class Piano : public View
bool shift;
int button;
- Q_OBJECT
+
int y2pitch(int) const;
int pitch2y(int) const;
void viewMouseMoveEvent(QMouseEvent* event);
diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp
index 9105a446..b2fe55ee 100644
--- a/muse2/muse/midiedit/pianoroll.cpp
+++ b/muse2/muse/midiedit/pianoroll.cpp
@@ -198,11 +198,11 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i
mapper->setMapping(funcTransposeAction, PianoCanvas::CMD_TRANSPOSE);
connect(funcTransposeAction, SIGNAL(triggered()), mapper, SLOT(map()));
- funcEraseEventAction = menuFunctions->addAction(tr("Erase Event"));
+ funcEraseEventAction = menuFunctions->addAction(tr("Erase Events"));
mapper->setMapping(funcEraseEventAction, PianoCanvas::CMD_ERASE_EVENT);
connect(funcEraseEventAction, SIGNAL(triggered()), mapper, SLOT(map()));
- funcNoteShiftAction = menuFunctions->addAction(tr("Note Shift"));
+ funcNoteShiftAction = menuFunctions->addAction(tr("Move Notes"));
mapper->setMapping(funcNoteShiftAction, PianoCanvas::CMD_NOTE_SHIFT);
connect(funcNoteShiftAction, SIGNAL(triggered()), mapper, SLOT(map()));
@@ -213,7 +213,12 @@ PianoRoll::PianoRoll(PartList* pl, QWidget* parent, const char* name, unsigned i
funcDelOverlapsAction = menuFunctions->addAction(tr("Delete Overlaps"));
mapper->setMapping(funcDelOverlapsAction, PianoCanvas::CMD_DELETE_OVERLAPS);
connect(funcDelOverlapsAction, SIGNAL(triggered()), mapper, SLOT(map()));
-
+
+ QAction* funcLegatoAction = menuFunctions->addAction(tr("Legato"));
+ mapper->setMapping(funcLegatoAction, PianoCanvas::CMD_LEGATO);
+ connect(funcLegatoAction, SIGNAL(triggered()), mapper, SLOT(map()));
+
+
menuPlugins = menuBar()->addMenu(tr("&Plugins"));
song->populateScriptMenu(menuPlugins, this);
@@ -600,6 +605,15 @@ void PianoRoll::cmd(int cmd)
{
switch (cmd)
{
+ case PianoCanvas::CMD_CUT:
+ copy_notes(partlist_to_set(parts()), 1);
+ erase_notes(partlist_to_set(parts()), 1);
+ break;
+ case PianoCanvas::CMD_COPY: copy_notes(partlist_to_set(parts()), 1); break;
+ case PianoCanvas::CMD_PASTE:
+ ((PianoCanvas*)canvas)->cmd(PianoCanvas::CMD_SELECT_NONE);
+ paste_notes(canvas->part());
+ break;
case PianoCanvas::CMD_MODIFY_GATE_TIME: modify_notelen(partlist_to_set(parts())); break;
case PianoCanvas::CMD_MODIFY_VELOCITY: modify_velocity(partlist_to_set(parts())); break;
case PianoCanvas::CMD_CRESCENDO: crescendo(partlist_to_set(parts())); break;
@@ -610,6 +624,7 @@ void PianoRoll::cmd(int cmd)
case PianoCanvas::CMD_NOTE_SHIFT: move_notes(partlist_to_set(parts())); break;
case PianoCanvas::CMD_FIXED_LEN: set_notelen(partlist_to_set(parts())); break;
case PianoCanvas::CMD_DELETE_OVERLAPS: delete_overlaps(partlist_to_set(parts())); break;
+ case PianoCanvas::CMD_LEGATO: legato(partlist_to_set(parts())); break;
default: ((PianoCanvas*)canvas)->cmd(cmd);
}
diff --git a/muse2/muse/midiedit/pianoroll.h b/muse2/muse/midiedit/pianoroll.h
index 58c2487a..1f53254d 100644
--- a/muse2/muse/midiedit/pianoroll.h
+++ b/muse2/muse/midiedit/pianoroll.h
@@ -51,6 +51,8 @@ class QScrollArea;
//---------------------------------------------------------
class PianoRoll : public MidiEditor {
+ Q_OBJECT
+
Event selEvent;
MidiPart* selPart;
int selTick;
@@ -125,7 +127,7 @@ class PianoRoll : public MidiEditor {
//QScrollBar* infoScroll;
QScrollArea* infoScroll;
- Q_OBJECT
+
void initShortcuts();
void setEventColorMode(int);
QWidget* genToolbar(QWidget* parent);
diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp
index 05fe8252..091582ef 100644
--- a/muse2/muse/midiedit/prcanvas.cpp
+++ b/muse2/muse/midiedit/prcanvas.cpp
@@ -15,6 +15,8 @@
#include <QDropEvent>
#include <QMouseEvent>
+#include <set>
+
#include <values.h>
#include <stdio.h>
#include <math.h>
@@ -84,14 +86,10 @@ PianoCanvas::PianoCanvas(MidiEditor* pr, QWidget* parent, int sx, int sy)
{
colorMode = 0;
playedPitch = -1;
+ for (int i=0;i<128;i++) noteHeldDown[i]=false;
- chordTimer = new QTimer(this);
- chordTimer->setSingleShot(true);
- chordTimer->setInterval(CHORD_TIMEOUT);
- chordTimer->stop();
+ steprec=new StepRec(noteHeldDown);
- connect(chordTimer, SIGNAL(timeout()), SLOT(chordTimerTimedOut()));
-
songChanged(SC_TRACK_INSERTED);
connect(song, SIGNAL(midiNote(int, int)), SLOT(midiNote(int,int)));
}
@@ -669,28 +667,10 @@ void PianoCanvas::pianoPressed(int pitch, int velocity, bool shift)
// play note:
MidiPlayEvent e(0, port, channel, 0x90, pitch, velocity);
audio->msgPlayMidiEvent(&e);
-
- if (_steprec && pos[0] >= start_tick && pos[0] < end_tick) {
- if (curPart) {
- int len = editor->raster();
- unsigned tick = pos[0] - curPart->tick(); //CDW
- if (shift)
- tick -= editor->rasterStep(tick);
- Event e(Note);
- e.setTick(tick);
- e.setPitch(pitch);
- e.setVelo(127);
- e.setLenTick(len);
- // Indicate do undo, and do not do port controller values and clone parts.
- audio->msgAddEvent(e, curPart, true, false, false);
- tick += editor->rasterStep(tick) + curPart->tick();
- if (tick != song->cpos()) {
- Pos p(tick, true);
- song->setPos(0, p, true, false, true);
- }
- }
+
+ if (_steprec && pos[0] >= start_tick && pos[0] < end_tick && curPart) {
+ steprec->record(curPart,pitch,editor->raster(),editor->raster(),velocity,globalKeyState&Qt::ControlModifier,shift);
}
-
}
//---------------------------------------------------------
@@ -796,16 +776,6 @@ void PianoCanvas::drawCanvas(QPainter& p, const QRect& rect)
void PianoCanvas::cmd(int cmd)
{
switch (cmd) {
- case CMD_CUT:
- copy();
- erase_notes(partlist_to_set(editor->parts()),1); //FINDMICH is this correct? or must i do this on current_part?
- break;
- case CMD_COPY:
- copy();
- break;
- case CMD_PASTE:
- paste();
- break;
case CMD_SELECT_ALL: // select all
for (iCItem k = items.begin(); k != items.end(); ++k) {
if (!k->second->isSelected())
@@ -904,125 +874,40 @@ void PianoCanvas::cmd(int cmd)
//---------------------------------------------------------
// midiNote
//---------------------------------------------------------
-
void PianoCanvas::midiNote(int pitch, int velo)
{
- if (_midiin && _steprec && curPart
- && !audio->isPlaying() && velo && pos[0] >= start_tick
- && pos[0] < end_tick
- && !(globalKeyState & Qt::AltModifier)) {
- chordTimer->stop();
-
- //len has been changed by flo: set to raster() instead of quant()
- //reason: the quant-toolbar has been removed; the flexibility you
- //lose with this can be re-gained by applying a "modify note len"
- //on the notes you have entered.
- unsigned int len = editor->raster();//prevent compiler warning: comparison singed/unsigned
- unsigned tick = pos[0]; //CDW
- unsigned starttick = tick;
-
- //
- // extend len of last note?
- //
- EventList* events = curPart->events();
- if (globalKeyState & Qt::ControlModifier) {
- for (iEvent i = events->begin(); i != events->end(); ++i) {
- Event ev = i->second;
- if (!ev.isNote())
- continue;
- if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == /*(int)*/starttick)) {
- Event e = ev.clone();
- e.setLenTick(ev.lenTick() + editor->rasterStep(starttick));
- // Indicate do undo, and do not do port controller values and clone parts.
- audio->msgChangeEvent(ev, e, curPart, true, false, false);
-
- if (! (globalKeyState & Qt::ShiftModifier)) {
- chordTimer_setToTick = tick + editor->rasterStep(tick);
- chordTimer->start();
- }
- return;
- }
- }
- }
+ if (debugMsg) printf("PianoCanvas::midiNote: pitch=%i, velo=%i\n", pitch, velo);
- //
- // if we already entered the note, delete it
- //
- EventRange range = events->equal_range(tick);
- for (iEvent i = range.first; i != range.second; ++i) {
- Event ev = i->second;
- if (ev.isNote() && ev.pitch() == pitch) {
- // Indicate do undo, and do not do port controller values and clone parts.
- audio->msgDeleteEvent(ev, curPart, true, false, false);
-
- if (! (globalKeyState & Qt::ShiftModifier)) {
- chordTimer_setToTick = tick + editor->rasterStep(tick);
- chordTimer->start();
- }
-
- return;
- }
- }
- Event e(Note);
- e.setTick(tick - curPart->tick());
- e.setPitch(pitch);
- e.setVelo(velo);
- e.setLenTick(len);
- // Indicate do undo, and do not do port controller values and clone parts.
- audio->msgAddEvent(e, curPart, true, false, false);
-
- if (! (globalKeyState & Qt::ShiftModifier)) {
- chordTimer_setToTick = tick + editor->rasterStep(tick);
- chordTimer->start();
- }
- }
- }
-
-void PianoCanvas::chordTimerTimedOut()
-{
- if (chordTimer_setToTick != song->cpos())
- {
- Pos p(chordTimer_setToTick, true);
- song->setPos(0, p, true, false, true);
- }
-}
-
-//---------------------------------------------------------
-// copy
-// cut copy paste
-//---------------------------------------------------------
+ if (velo)
+ noteHeldDown[pitch]=true;
+ else
+ noteHeldDown[pitch]=false;
-void PianoCanvas::copy()
+ if (heavyDebugMsg)
{
- //QDrag* drag = getTextDrag();
- QMimeData* drag = getTextDrag();
-
- if (drag)
- QApplication::clipboard()->setMimeData(drag, QClipboard::Clipboard);
+ printf(" held down notes are: ");
+ for (int i=0;i<128;i++)
+ if (noteHeldDown[i])
+ printf("%i ",i);
+ printf("\n");
}
-
-//---------------------------------------------------------
-// paste
-// paste events
-//---------------------------------------------------------
-
-void PianoCanvas::paste()
- {
- QString stype("x-muse-eventlist");
-
- //QString s = QApplication::clipboard()->text(stype, QClipboard::Selection);
- QString s = QApplication::clipboard()->text(stype, QClipboard::Clipboard); // TODO CHECK Tim.
- pasteAt(s, song->cpos());
+ if (_midiin && _steprec && curPart
+ && !audio->isPlaying() && velo && pos[0] >= start_tick
+ && pos[0] < end_tick
+ && !(globalKeyState & Qt::AltModifier)) {
+ steprec->record(curPart,pitch,editor->raster(),editor->raster(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier);
+ }
}
+
//---------------------------------------------------------
// startDrag
//---------------------------------------------------------
void PianoCanvas::startDrag(CItem* /* item*/, bool copymode)
{
- QMimeData* md = getTextDrag();
+ QMimeData* md = selected_events_to_mime(partlist_to_set(editor->parts()), 1);
if (md) {
// "Note that setMimeData() assigns ownership of the QMimeData object to the QDrag object.
diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h
index 7c77b229..c6e47c9e 100644
--- a/muse2/muse/midiedit/prcanvas.h
+++ b/muse2/muse/midiedit/prcanvas.h
@@ -17,6 +17,8 @@
#include <QDragLeaveEvent>
#include <QTimer>
+#include "steprec.h"
+
#define KH 13
//---------------------------------------------------------
@@ -38,13 +40,16 @@ class QRect;
//---------------------------------------------------------
class PianoCanvas : public EventCanvas {
+ Q_OBJECT
+
int colorMode;
int playedPitch;
- QTimer* chordTimer;
- unsigned chordTimer_setToTick;
+ bool noteHeldDown[128];
+
+ StepRec* steprec;
- Q_OBJECT
+
virtual void viewMouseDoubleClickEvent(QMouseEvent*);
virtual void drawItem(QPainter&, const CItem*, const QRect&);
void drawTopItem(QPainter &p, const QRect &rect);
@@ -64,8 +69,6 @@ class PianoCanvas : public EventCanvas {
int y2pitch(int) const;
int pitch2y(int) const;
virtual void drawCanvas(QPainter&, const QRect&);
- void copy();
- void paste();
virtual void itemPressed(const CItem*);
virtual void itemReleased(const CItem*, const QPoint&);
virtual void itemMoved(const CItem*, const QPoint&);
@@ -74,7 +77,6 @@ class PianoCanvas : public EventCanvas {
private slots:
void midiNote(int pitch, int velo);
- void chordTimerTimedOut();
signals:
void quantChanged(int);
@@ -96,7 +98,7 @@ class PianoCanvas : public EventCanvas {
CMD_TRANSPOSE, CMD_THIN_OUT, CMD_ERASE_EVENT,
CMD_NOTE_SHIFT, CMD_MOVE_CLOCK, CMD_COPY_MEASURE,
CMD_ERASE_MEASURE, CMD_DELETE_MEASURE, CMD_CREATE_MEASURE,
- CMD_FIXED_LEN, CMD_DELETE_OVERLAPS
+ CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO
};
PianoCanvas(MidiEditor*, QWidget*, int, int);
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp
index 7f7382f4..0eb61554 100644
--- a/muse2/muse/midiedit/scoreedit.cpp
+++ b/muse2/muse/midiedit/scoreedit.cpp
@@ -51,13 +51,13 @@ using namespace std;
#include "icons.h"
#include "audio.h"
#include "functions.h"
-
+#include "helper.h"
#include "cmd.h"
#include "sig.h"
#include "song.h"
+#include "shortcuts.h"
//#include "../ctrl/ctrledit.h"
-//#include "shortcuts.h"
string IntToStr(int i);
@@ -211,6 +211,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
undo_tools->addActions(undoRedo->actions());
addToolBar(undo_tools);
+ QToolBar* steprec_tools=addToolBar(tr("Step recording tools"));
+ steprec_tools->setObjectName("Step recording tools");
+ srec = new QToolButton();
+ srec->setToolTip(tr("Step Record"));
+ srec->setIcon(*steprecIcon);
+ srec->setCheckable(true);
+ steprec_tools->addWidget(srec);
+ connect(srec, SIGNAL(toggled(bool)), score_canvas, SLOT(set_steprec(bool)));
+
+
edit_tools = new EditToolBar(this, PointerTool | PencilTool | RubberTool);
addToolBar(edit_tools);
edit_tools->set(PointerTool);
@@ -323,9 +333,59 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
quant_toolbar->addWidget(px_per_whole_spinbox);
px_per_whole_spinbox->setValue(300);
+ QMenu* edit_menu = menuBar()->addMenu(tr("&Edit"));
+
+ edit_menu->addActions(undoRedo->actions());
+ edit_menu->addSeparator();
+
+ cut_action = edit_menu->addAction(QIcon(*editcutIconSet), tr("C&ut"));
+ menu_mapper->setMapping(cut_action, CMD_CUT);
+ connect(cut_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ copy_action = edit_menu->addAction(QIcon(*editcopyIconSet), tr("&Copy"));
+ menu_mapper->setMapping(copy_action, CMD_COPY);
+ connect(copy_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ paste_action = edit_menu->addAction(QIcon(*editpasteIconSet), tr("&Paste"));
+ menu_mapper->setMapping(paste_action, CMD_PASTE);
+ connect(paste_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ edit_menu->addSeparator();
+
+ del_action = edit_menu->addAction(tr("Delete &Events"));
+ menu_mapper->setMapping(del_action, CMD_DEL);
+ connect(del_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ edit_menu->addSeparator();
+
+ QMenu* select_menu = edit_menu->addMenu(QIcon(*selectIcon), tr("&Select"));
+
+ select_all_action = select_menu->addAction(QIcon(*select_allIcon), tr("Select &All"));
+ menu_mapper->setMapping(select_all_action, CMD_SELECT_ALL);
+ connect(select_all_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_none_action = select_menu->addAction(QIcon(*select_deselect_allIcon), tr("&Deselect All"));
+ menu_mapper->setMapping(select_none_action, CMD_SELECT_NONE);
+ connect(select_none_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_invert_action = select_menu->addAction(QIcon(*select_invert_selectionIcon), tr("Invert &Selection"));
+ menu_mapper->setMapping(select_invert_action, CMD_SELECT_INVERT);
+ connect(select_invert_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_menu->addSeparator();
+
+ select_iloop_action = select_menu->addAction(QIcon(*select_inside_loopIcon), tr("&Inside Loop"));
+ menu_mapper->setMapping(select_iloop_action, CMD_SELECT_ILOOP);
+ connect(select_iloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+ select_oloop_action = select_menu->addAction(QIcon(*select_outside_loopIcon), tr("&Outside Loop"));
+ menu_mapper->setMapping(select_oloop_action, CMD_SELECT_OLOOP);
+ connect(select_oloop_action, SIGNAL(triggered()), menu_mapper, SLOT(map()));
+
+
QMenu* settings_menu = menuBar()->addMenu(tr("&Settings"));
- QMenu* color_menu = settings_menu->addMenu(tr("Note head &colors"));
+ color_menu = settings_menu->addMenu(tr("Note head &colors"));
color_actions = new QActionGroup(this);
color_black_action = color_menu->addAction(tr("&Black"), menu_mapper, SLOT(map()));
color_velo_action = color_menu->addAction(tr("&Velocity"), menu_mapper, SLOT(map()));
@@ -361,14 +421,36 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
QMenu* functions_menu = menuBar()->addMenu(tr("&Functions"));
- QAction* func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map()));
- QAction* func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map()));
- QAction* func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map()));
- QAction* func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map()));
+ func_quantize_action = functions_menu->addAction(tr("&Quantize"), menu_mapper, SLOT(map()));
+ func_notelen_action = functions_menu->addAction(tr("Change note &length"), menu_mapper, SLOT(map()));
+ func_velocity_action = functions_menu->addAction(tr("Change note &velocity"), menu_mapper, SLOT(map()));
+ func_cresc_action = functions_menu->addAction(tr("Crescendo/Decrescendo"), menu_mapper, SLOT(map()));
+ func_transpose_action = functions_menu->addAction(tr("Transpose"), menu_mapper, SLOT(map()));
+ func_erase_action = functions_menu->addAction(tr("Erase Events"), menu_mapper, SLOT(map()));
+ func_move_action = functions_menu->addAction(tr("Move Notes"), menu_mapper, SLOT(map()));
+ func_fixed_len_action = functions_menu->addAction(tr("Set Fixed Length"), menu_mapper, SLOT(map()));
+ func_del_overlaps_action = functions_menu->addAction(tr("Delete Overlaps"), menu_mapper, SLOT(map()));
+ func_legato_action = functions_menu->addAction(tr("Legato"), menu_mapper, SLOT(map()));
menu_mapper->setMapping(func_quantize_action, CMD_QUANTIZE);
menu_mapper->setMapping(func_notelen_action, CMD_NOTELEN);
menu_mapper->setMapping(func_velocity_action, CMD_VELOCITY);
menu_mapper->setMapping(func_cresc_action, CMD_CRESCENDO);
+ menu_mapper->setMapping(func_transpose_action, CMD_TRANSPOSE);
+ menu_mapper->setMapping(func_erase_action, CMD_ERASE);
+ menu_mapper->setMapping(func_move_action, CMD_MOVE);
+ menu_mapper->setMapping(func_fixed_len_action, CMD_FIXED_LEN);
+ menu_mapper->setMapping(func_del_overlaps_action, CMD_DELETE_OVERLAPS);
+ menu_mapper->setMapping(func_legato_action, CMD_LEGATO);
+
+ init_shortcuts();
+
+ connect(muse, SIGNAL(configChanged()), SLOT(init_shortcuts()));
+
+ QClipboard* cb = QApplication::clipboard();
+ connect(cb, SIGNAL(dataChanged()), SLOT(clipboard_changed()));
+
+ clipboard_changed();
+ selection_changed();
if (!default_toolbar_state.isEmpty())
restoreState(default_toolbar_state);
@@ -387,6 +469,32 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)
apply_velo=true;
}
+void ScoreEdit::init_shortcuts()
+{
+ cut_action->setShortcut(shortcuts[SHRT_CUT].key);
+ copy_action->setShortcut(shortcuts[SHRT_COPY].key);
+ paste_action->setShortcut(shortcuts[SHRT_PASTE].key);
+ del_action->setShortcut(shortcuts[SHRT_DELETE].key);
+
+ select_all_action->setShortcut(shortcuts[SHRT_SELECT_ALL].key);
+ select_none_action->setShortcut(shortcuts[SHRT_SELECT_NONE].key);
+ select_invert_action->setShortcut(shortcuts[SHRT_SELECT_INVERT].key);
+ select_iloop_action->setShortcut(shortcuts[SHRT_SELECT_ILOOP].key);
+ select_oloop_action->setShortcut(shortcuts[SHRT_SELECT_OLOOP].key);
+
+ color_menu->menuAction()->setShortcut(shortcuts[SHRT_EVENT_COLOR].key);
+
+ func_quantize_action->setShortcut(shortcuts[SHRT_QUANTIZE].key);
+ func_notelen_action->setShortcut(shortcuts[SHRT_MODIFY_GATE_TIME].key);
+ func_velocity_action->setShortcut(shortcuts[SHRT_MODIFY_VELOCITY].key);
+ func_transpose_action->setShortcut(shortcuts[SHRT_TRANSPOSE].key);
+ func_erase_action->setShortcut(shortcuts[SHRT_ERASE_EVENT].key);
+ func_move_action->setShortcut(shortcuts[SHRT_NOTE_SHIFT].key);
+ func_fixed_len_action->setShortcut(shortcuts[SHRT_FIXED_LEN].key);
+ func_del_overlaps_action->setShortcut(shortcuts[SHRT_DELETE_OVERLAPS].key);
+}
+
+
void ScoreEdit::add_parts(PartList* pl, bool all_in_one)
{
score_canvas->add_staves(pl, all_in_one);
@@ -482,6 +590,8 @@ void ScoreEdit::song_changed(int flags)
if (velo>=0) velo_spinbox->setValue(velo);
if (velo_off>=0) velo_off_spinbox->setValue(velo_off);
}
+
+ selection_changed();
}
}
@@ -568,16 +678,51 @@ void ScoreEdit::menu_command(int cmd)
}
break;
+ case CMD_SELECT_ALL: select_all(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_NONE: select_none(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_INVERT: select_invert(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_ILOOP: select_in_loop(score_canvas->get_all_parts()); break;
+ case CMD_SELECT_OLOOP: select_not_in_loop(score_canvas->get_all_parts()); break;
+
+ case CMD_CUT:
+ copy_notes(score_canvas->get_all_parts(), 1);
+ erase_notes(score_canvas->get_all_parts(), 1);
+ break;
+ case CMD_COPY: copy_notes(score_canvas->get_all_parts(), 1); break;
+ case CMD_PASTE:
+ menu_command(CMD_SELECT_NONE);
+ paste_notes(score_canvas->get_selected_part());
+ break;
case CMD_QUANTIZE: quantize_notes(score_canvas->get_all_parts()); break;
case CMD_VELOCITY: modify_velocity(score_canvas->get_all_parts()); break;
case CMD_CRESCENDO: crescendo(score_canvas->get_all_parts()); break;
case CMD_NOTELEN: modify_notelen(score_canvas->get_all_parts()); break;
-
+ case CMD_TRANSPOSE: transpose_notes(score_canvas->get_all_parts()); break;
+ case CMD_ERASE: erase_notes(score_canvas->get_all_parts()); break;
+ case CMD_DEL: erase_notes(score_canvas->get_all_parts(),1); break;
+ case CMD_MOVE: move_notes(score_canvas->get_all_parts()); break;
+ case CMD_FIXED_LEN: set_notelen(score_canvas->get_all_parts()); break;
+ case CMD_DELETE_OVERLAPS: delete_overlaps(score_canvas->get_all_parts()); break;
+ case CMD_LEGATO: legato(score_canvas->get_all_parts()); break;
+
default:
score_canvas->menu_command(cmd);
}
}
+void ScoreEdit::clipboard_changed()
+{
+ paste_action->setEnabled(QApplication::clipboard()->mimeData()->hasFormat(QString("text/x-muse-eventlist")));
+}
+
+void ScoreEdit::selection_changed()
+{
+ bool flag = !get_events(score_canvas->get_all_parts(),1).empty();
+ cut_action->setEnabled(flag);
+ copy_action->setEnabled(flag);
+ del_action->setEnabled(flag);
+}
+
//duplicated from songfile.cpp's MusE::readPart(); the only differences:
//"none" is supported and tag_name is settable
@@ -604,9 +749,11 @@ Part* read_part(Xml& xml, QString tag_name="part")
else
{
sscanf(tag.toLatin1().constData(), "%d:%d", &trackIdx, &partIdx);
+ if (debugMsg) cout << "read_part: trackIdx="<<trackIdx<<", partIdx="<<partIdx;
Track* track = song->tracks()->index(trackIdx);
if (track)
part = track->parts()->find(partIdx);
+ if (debugMsg) cout << ", track="<<track<<", part="<<part<<endl;
}
}
break;
@@ -656,12 +803,15 @@ void staff_t::read_status(Xml& xml)
case Xml::TagEnd:
if (tag == "staff")
- return;
+ goto staff_readstatus_end;
default:
break;
}
}
+
+ staff_readstatus_end:
+ update_part_indices();
}
@@ -695,6 +845,7 @@ void ScoreEdit::writeStatus(int level, Xml& xml) const
xml.strTag(level, "name", name);
xml.intTag(level, "tool", edit_tools->curTool());
+ xml.intTag(level, "steprec", srec->isChecked());
xml.intTag(level, "quantPower", score_canvas->quant_power2());
xml.intTag(level, "pxPerWhole", score_canvas->pixels_per_whole());
xml.intTag(level, "newNoteVelo", velo_spinbox->value());
@@ -787,6 +938,8 @@ void ScoreEdit::readStatus(Xml& xml)
set_name(xml.parse1());
else if (tag == "tool")
edit_tools->set(xml.parseInt());
+ else if (tag == "steprec")
+ srec->setChecked(xml.parseInt());
else if (tag == "quantPower")
quant_combobox->setCurrentIndex(xml.parseInt()-1);
else if (tag == "pxPerWhole")
@@ -911,55 +1064,101 @@ void ScoreEdit::write_configuration(int level, Xml& xml)
void ScoreCanvas::add_staves(PartList* pl, bool all_in_one)
{
- staff_t staff(this);
-
- if (all_in_one)
+ if (!pl->empty())
{
- staff.parts.clear();
- for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++)
- staff.parts.insert(part_it->second);
- staff.cleanup_parts();
-
- staff.type=GRAND_TOP; //FINDME_INITCLEF
- staff.clef=VIOLIN;
- staves.push_back(staff);
-
- staff.type=GRAND_BOTTOM;
- staff.clef=BASS;
- staves.push_back(staff);
- }
- else
- {
- set<Track*> tracks;
- for (ciPart it=pl->begin(); it!=pl->end(); it++)
- tracks.insert(it->second->track());
-
- TrackList* tracklist = song->tracks();
- // this loop is used for inserting track-staves in the
- // correct order. simply iterating through tracks's contents
- // would sort after the pointer values, i.e. randomly
- for (ciTrack track_it=tracklist->begin(); track_it!=tracklist->end(); track_it++)
- if (tracks.find(*track_it)!=tracks.end())
+ staff_t staff(this);
+
+ if (all_in_one)
+ {
+ clefTypes clef=((MidiTrack*)pl->begin()->second->track())->getClef();
+
+ staff.parts.clear();
+ for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++)
{
- staff.parts.clear();
- for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++)
- if (part_it->second->track() == *track_it)
- staff.parts.insert(part_it->second);
- staff.cleanup_parts();
-
- staff.type=GRAND_TOP; //FINDME_INITCLEF
- staff.clef=VIOLIN;
- staves.push_back(staff);
+ if (((MidiTrack*)part_it->second->track())->getClef() != clef)
+ clef=grandStaff;
+
+ staff.parts.insert(part_it->second);
+ }
+ staff.cleanup_parts();
+ staff.update_part_indices();
- staff.type=GRAND_BOTTOM;
- staff.clef=BASS;
- staves.push_back(staff);
+ switch (clef)
+ {
+ case trebleClef:
+ staff.type=NORMAL;
+ staff.clef=VIOLIN;
+ staves.push_back(staff);
+ break;
+
+ case bassClef:
+ staff.type=NORMAL;
+ staff.clef=BASS;
+ staves.push_back(staff);
+ break;
+
+ case grandStaff:
+ staff.type=GRAND_TOP;
+ staff.clef=VIOLIN;
+ staves.push_back(staff);
+
+ staff.type=GRAND_BOTTOM;
+ staff.clef=BASS;
+ staves.push_back(staff);
+ break;
}
+ }
+ else
+ {
+ set<Track*> tracks;
+ for (ciPart it=pl->begin(); it!=pl->end(); it++)
+ tracks.insert(it->second->track());
+
+ TrackList* tracklist = song->tracks();
+ // this loop is used for inserting track-staves in the
+ // correct order. simply iterating through tracks's contents
+ // would sort after the pointer values, i.e. randomly
+ for (ciTrack track_it=tracklist->begin(); track_it!=tracklist->end(); track_it++)
+ if (tracks.find(*track_it)!=tracks.end())
+ {
+ staff.parts.clear();
+ for (ciPart part_it=pl->begin(); part_it!=pl->end(); part_it++)
+ if (part_it->second->track() == *track_it)
+ staff.parts.insert(part_it->second);
+ staff.cleanup_parts();
+ staff.update_part_indices();
+
+ switch (((MidiTrack*)(*track_it))->getClef())
+ {
+ case trebleClef:
+ staff.type=NORMAL;
+ staff.clef=VIOLIN;
+ staves.push_back(staff);
+ break;
+
+ case bassClef:
+ staff.type=NORMAL;
+ staff.clef=BASS;
+ staves.push_back(staff);
+ break;
+
+ case grandStaff:
+ staff.type=GRAND_TOP;
+ staff.clef=VIOLIN;
+ staves.push_back(staff);
+
+ staff.type=GRAND_BOTTOM;
+ staff.clef=BASS;
+ staves.push_back(staff);
+ break;
+ }
+ }
+ }
+
+ cleanup_staves();
+ fully_recalculate();
+ recalc_staff_pos();
}
-
- cleanup_staves();
- fully_recalculate();
- recalc_staff_pos();
}
@@ -973,17 +1172,21 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi
init_pixmaps();
+ srec=false;
+ for (int i=0;i<128;i++) held_notes[i]=false;
+ steprec=new StepRec(held_notes);
+ connect(song, SIGNAL(midiNote(int, int)), SLOT(midi_note(int,int)));
+
x_pos=0;
x_left=0;
y_pos=0;
have_lasso=false;
+ inserting=false;
dragging=false;
drag_cursor_changed=false;
mouse_erases_notes=false;
mouse_inserts_notes=true;
-
undo_started=false;
- undo_flags=0;
selected_part=NULL;
@@ -1155,6 +1358,8 @@ void ScoreCanvas::merge_staves(list<staff_t>::iterator dest, list<staff_t>::iter
dest->parts.insert(src->parts.begin(), src->parts.end());
}
+ dest->update_part_indices();
+
remove_staff(src);
fully_recalculate();
@@ -1223,6 +1428,26 @@ void ScoreCanvas::fully_recalculate()
void ScoreCanvas::song_changed(int flags)
{
+ if (flags & (SC_PART_MODIFIED | SC_PART_REMOVED | SC_PART_INSERTED | SC_TRACK_REMOVED))
+ {
+ update_parts();
+
+ if (flags & (SC_PART_REMOVED | SC_TRACK_REMOVED))
+ {
+ for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
+ it->cleanup_parts();
+
+ cleanup_staves();
+
+ for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
+ it->recalculate();
+
+ recalc_staff_pos();
+
+ redraw();
+ }
+ }
+
if (flags & (SC_PART_MODIFIED |
SC_EVENT_INSERTED | SC_EVENT_MODIFIED | SC_EVENT_REMOVED |
SC_SIG | SC_KEY) )
@@ -1238,26 +1463,6 @@ void ScoreCanvas::song_changed(int flags)
emit canvas_width_changed(canvas_width());
}
- if (flags & SC_PART_REMOVED)
- {
- bool something_changed=false;
-
- for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
- {
- if (it->cleanup_parts())
- something_changed=true;
- }
-
- cleanup_staves();
-
- for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
- it->recalculate();
-
- recalc_staff_pos();
-
- redraw();
- }
-
if (flags & SC_SELECTION)
{
redraw();
@@ -3312,10 +3517,9 @@ int ScoreCanvas::y_to_pitch(int y, int t, clef_t clef)
void ScoreCanvas::mousePressEvent (QMouseEvent* event)
{
- keystate=((QInputEvent*)event)->modifiers();
-
+ keystate=event->modifiers();
bool ctrl=keystate & Qt::ControlModifier;
-
+
// den errechneten tick immer ABrunden!
// denn der "bereich" eines schlags geht von schlag_begin bis nächsterschlag_begin-1
// noten werden aber genau in die mitte dieses bereiches gezeichnet
@@ -3325,10 +3529,6 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
int y=event->y() + y_pos - staff_it->y_draw;
int x=event->x()+x_pos-x_left;
int tick=flo_quantize_floor(x_to_tick(x), quant_ticks());
-
- if (event->button()==Qt::LeftButton)
- if (!ctrl)
- deselect_all();
if (staff_it!=staves.end())
{
@@ -3389,7 +3589,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
int this_begin=tick;
int this_end=this_begin+calc_len(set_it->len, set_it->dots);
- selected_part=set_it->source_part;
+ set_selected_part(set_it->source_part);
//that's the only note corresponding to the event?
if (this_begin==total_begin && this_end==total_end)
@@ -3419,9 +3619,10 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
+ clicked_event_ptr=set_it->source_event;
dragged_event=*set_it->source_event;
+ original_dragged_event=dragged_event.clone();
dragged_event_part=set_it->source_part;
- dragged_event_original_pitch=dragged_event.pitch();
if ((mouse_erases_notes) || (event->button()==Qt::MidButton)) //erase?
{
@@ -3429,14 +3630,9 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
}
else if (event->button()==Qt::LeftButton) //edit?
{
- set_it->source_event->setSelected(!set_it->source_event->selected());
- song_changed(SC_SELECTION);
-
setMouseTracking(true);
dragging=true;
drag_cursor_changed=false;
- undo_started=false;
- undo_flags=SC_EVENT_MODIFIED;
}
}
else //we found nothing?
@@ -3468,11 +3664,9 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
if (relative_tick<0)
cerr << "ERROR: THIS SHOULD NEVER HAPPEN: relative_tick is negative!" << endl;
song->startUndo();
- undo_started=true;
- undo_flags=SC_EVENT_INSERTED | SC_EVENT_MODIFIED;
- //stopping undo at the end of this function is unneccessary
- //because we'll begin a drag right after it. finishing
- //this drag will stop undo as well (in mouseReleaseEvent)
+
+ if (!ctrl)
+ deselect_all();
Event newevent(Note);
newevent.setPitch(y_to_pitch(y,tick, staff_it->clef));
@@ -3481,7 +3675,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
newevent.setTick(relative_tick);
newevent.setLenTick((new_len>0)?new_len:last_len);
newevent.setSelected(true);
-
+
if (flo_quantize(newevent.lenTick(), quant_ticks()) <= 0)
{
newevent.setLenTick(quant_ticks());
@@ -3499,7 +3693,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
dragged_event_part=curr_part;
dragged_event=newevent;
- dragged_event_original_pitch=newevent.pitch();
+ original_dragged_event=dragged_event.clone();
mouse_down_pos=event->pos();
mouse_operation=NO_OP;
@@ -3509,9 +3703,12 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
setMouseTracking(true);
dragging=true;
+ inserting=true;
drag_cursor_changed=true;
setCursor(Qt::SizeAllCursor);
- //song->startUndo(); unneccessary because we have started it already above
+
+ song->endUndo(SC_EVENT_INSERTED);
+ song->update(SC_SELECTION);
}
}
else // !mouse_inserts_notes. open a lasso
@@ -3525,16 +3722,16 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
}
}
}
-
- if (event->button()==Qt::LeftButton)
- song->update(SC_SELECTION);
}
void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)
{
+ keystate=event->modifiers();
+ bool ctrl=keystate & Qt::ControlModifier;
+
if (dragging && event->button()==Qt::LeftButton)
{
- if ((mouse_operation==LENGTH) || (mouse_operation==BEGIN)) //also BEGIN can change the len by clipping
+ if (mouse_operation==LENGTH)
{
if (flo_quantize(dragged_event.lenTick(), quant_ticks()) <= 0)
{
@@ -3545,15 +3742,29 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)
{
last_len=flo_quantize(dragged_event.lenTick(), quant_ticks());
}
+
+ if (undo_started)
+ song->endUndo(SC_EVENT_MODIFIED | SC_EVENT_REMOVED);
}
+
- if (undo_started)
- song->endUndo(undo_flags);
+ if (mouse_operation==NO_OP && !inserting)
+ {
+ if (event->button()==Qt::LeftButton)
+ if (!ctrl)
+ deselect_all();
+
+ clicked_event_ptr->setSelected(!clicked_event_ptr->selected());
+
+ song->update(SC_SELECTION);
+ }
setMouseTracking(false);
unsetCursor();
+ inserting=false;
dragging=false;
drag_cursor_changed=false;
+ undo_started=false;
x_scroll_speed=0; x_scroll_pos=0;
}
@@ -3583,6 +3794,9 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)
if (have_lasso && event->button()==Qt::LeftButton)
{
+ if (!ctrl)
+ deselect_all();
+
set<Event*> already_processed;
for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
@@ -3600,6 +3814,9 @@ void ScoreCanvas::mouseReleaseEvent (QMouseEvent* event)
void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
{
+ keystate=event->modifiers();
+ bool ctrl=keystate & Qt::ControlModifier;
+
if (dragging)
{
int dx=event->x()-mouse_down_pos.x();
@@ -3630,6 +3847,22 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
mouse_operation=PITCH;
setCursor(Qt::SizeVerCursor);
}
+
+ if (mouse_operation!=NO_OP)
+ {
+ if (!inserting && clicked_event_ptr->selected()==false)
+ {
+ if (!ctrl)
+ deselect_all();
+
+ clicked_event_ptr->setSelected(true);
+
+ song->update(SC_SELECTION);
+ }
+
+ old_pitch=-1;
+ old_dest_tick=MAXINT;
+ }
}
int new_pitch;
@@ -3640,70 +3873,41 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
break;
case PITCH:
- if (debugMsg) cout << "changing pitch, delta="<<nearbyint((float)dy/PITCH_DELTA)<<endl;
- new_pitch=dragged_event_original_pitch - nearbyint((float)dy/PITCH_DELTA);
+ if (heavyDebugMsg) cout << "trying to change pitch, delta="<<-nearbyint((float)dy/PITCH_DELTA)<<endl;
+ new_pitch=original_dragged_event.pitch() - nearbyint((float)dy/PITCH_DELTA);
if (new_pitch < 0) new_pitch=0;
if (new_pitch > 127) new_pitch=127;
- if (dragged_event.pitch()!=new_pitch)
+ if (new_pitch != old_pitch)
{
- if (!undo_started)
- {
- song->startUndo();
- undo_started=true;
- }
-
- Event tmp=dragged_event.clone();
- tmp.setPitch(new_pitch);
-
- audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
- dragged_event=tmp;
-
- fully_recalculate();
+ if (debugMsg) cout << "changing pitch, delta="<<new_pitch-original_dragged_event.pitch()<<endl;
+ if (undo_started) song->undo();
+ undo_started=transpose_notes(part_to_set(dragged_event_part),1, new_pitch-original_dragged_event.pitch());
+ old_pitch=new_pitch;
}
break;
case BEGIN:
- if (dragged_event.tick()+dragged_event_part->tick() != unsigned(tick))
{
- if (!undo_started)
- {
- song->startUndo();
- undo_started=true;
- }
-
- Event tmp=dragged_event.clone();
signed relative_tick=tick-signed(dragged_event_part->tick());
+ unsigned dest_tick;
if (relative_tick >= 0)
- tmp.setTick(relative_tick);
+ dest_tick=relative_tick;
else
{
- tmp.setTick(0);
+ dest_tick=0;
if (debugMsg) cout << "not moving note before begin of part; setting it directly to the begin" << endl;
}
- if (tmp.endTick() > dragged_event_part->lenTick())
+ if (dest_tick != old_dest_tick)
{
- signed new_len=dragged_event_part->lenTick() - tmp.tick();
- if (new_len>=0)
- {
- tmp.setLenTick(dragged_event_part->lenTick() - tmp.tick());
- if (debugMsg) cout << "moved note would exceed its part; clipping length to " << tmp.lenTick() << endl;
- }
- else
- {
- tmp.setLenTick(0);
- if (debugMsg) cout << "moved note would exceed its part; clipping length to 0 (actually negative)" << endl;
- }
+ if (undo_started) song->undo();
+ undo_started=move_notes(part_to_set(dragged_event_part),1, (signed)dest_tick-original_dragged_event.tick());
+ old_dest_tick=dest_tick;
}
-
- audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
- dragged_event=tmp;
-
- fully_recalculate();
}
break;
@@ -4007,6 +4211,7 @@ void ScoreCanvas::menu_command(int cmd)
case CMD_NOTELEN_16: new_len=TICKS_PER_WHOLE/16; break;
case CMD_NOTELEN_32: new_len=TICKS_PER_WHOLE/32; break;
case CMD_NOTELEN_LAST: new_len=-1; break;
+
default:
cerr << "ERROR: ILLEGAL FUNCTION CALL: ScoreCanvas::menu_command called with unknown command ("<<cmd<<")"<<endl;
}
@@ -4123,14 +4328,6 @@ void ScoreCanvas::deselect_all()
song->update(SC_SELECTION);
}
-void ScoreCanvas::keyPressEvent(QKeyEvent* event)
-{
- if (event->key()==Qt::Key_Delete)
- {
- erase_notes(get_all_parts(), 1); // 1 means "all selected"
- }
-}
-
bool staff_t::cleanup_parts()
{
bool did_something=false;
@@ -4162,6 +4359,7 @@ bool staff_t::cleanup_parts()
it++;
}
+ if (did_something) update_part_indices();
return did_something;
}
@@ -4191,6 +4389,48 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed)
}
}
+void ScoreCanvas::set_steprec(bool flag)
+{
+ srec=flag;
+}
+
+void ScoreCanvas::midi_note(int pitch, int velo)
+{
+ if (velo)
+ held_notes[pitch]=true;
+ else
+ held_notes[pitch]=false;
+
+ if ( srec && selected_part && !audio->isPlaying() && velo )
+ steprec->record(selected_part,pitch,quant_ticks(),quant_ticks(),velo,globalKeyState&Qt::ControlModifier,globalKeyState&Qt::ShiftModifier);
+}
+
+
+
+void ScoreCanvas::update_parts()
+{
+ if (selected_part!=NULL) //if it's null, let it be null
+ selected_part=partFromSerialNumber(selected_part_index);
+
+ for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)
+ it->update_parts();
+}
+
+void staff_t::update_parts()
+{
+ parts.clear();
+
+ for (set<int>::iterator it=part_indices.begin(); it!=part_indices.end(); it++)
+ parts.insert(partFromSerialNumber(*it));
+}
+
+void staff_t::update_part_indices()
+{
+ part_indices.clear();
+
+ for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++)
+ part_indices.insert((*it)->sn());
+}
//the following assertions are made:
// pix_quarter.width() == pix_half.width()
@@ -4221,29 +4461,29 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed)
* o rename stuff: UndoOp -> Operation, Undo -> OpList,
* UndoType -> OpType, iUndoOp, riUndoOp -> iOperation,
* undo.cpp/.h -> operations.cpp/.h
+ * o either remove these "hidden notes", or deal with them in the score editor
+ * o investigate with valgrind
+ * o controller view in score editor
+ * o deal with expanding parts
+ * o fix sigedit boxes
+ * o mid-click in pianoroll: change to "delete", or initiate drag and drop between windows?
*
*
* o drum list: scroll while dragging
*
* IMPORTANT TODO
- * o add a select-clef-toolbox for tracks
- * o respect the track's clef (has to be implemented first in muse)
* o do partial recalculating; recalculating can take pretty long
* (0,5 sec) when displaying a whole song in scores
* o transpose etc. must also transpose key-pressure events
* o transpose: support in-key-transpose
- * o legato: extend length to next note
- * o delete: add velo and len threshold
* o thin out: remove unneeded ctrl messages
*
* less important stuff
- * o controller view in score editor
* o quantize-templates (everything is forced into a specified
* rhythm)
* o part-templates (you specify some notes and a control-chord;
* the notes are set according to the chord then)
* o add functions like set velo, mod/set velo-off
- * o deal with expanding parts
* o use bars instead of flags over groups of 8ths / 16ths etc
* o support different keys in different tracks at the same time
* calc_pos_add_list and calc_item_pos will be affected by this
@@ -4260,6 +4500,7 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed)
* o refuse to resize so that width gets smaller or equal than x_left
* o draw a margin around notes which are in a bright color
* o support drum tracks (x-note-heads etc.)
+ * o drum list: scroll while dragging: probably unneccessary with the "reorder list" function
*
*
* stuff for the other muse developers
@@ -4271,8 +4512,6 @@ void staff_t::apply_lasso(QRect rect, set<Event*>& already_processed)
* ( (2+2+3)/4 or (3+2+2)/4 instead of 7/4 )
* o maybe do expanding parts inside the msgChangeEvent or
* msgNewEvent functions (see my e-mail)
- *
- * o make quantize and other stuff faster (by assymetric communication)
*/
diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h
index 4004452f..e7302a46 100644
--- a/muse2/muse/midiedit/scoreedit.h
+++ b/muse2/muse/midiedit/scoreedit.h
@@ -22,6 +22,7 @@
#include <QActionGroup>
#include <QGridLayout>
#include <QByteArray>
+#include <QToolButton>
#include <values.h>
#include "noteinfo.h"
@@ -32,6 +33,9 @@
#include "part.h"
#include "keyevent.h"
#include "mtscale_flo.h"
+#include "steprec.h"
+#include "cleftypes.h"
+#include "helper.h"
#include <set>
#include <map>
@@ -58,7 +62,12 @@ enum {CMD_COLOR_BLACK, CMD_COLOR_VELO, CMD_COLOR_PART,
CMD_NOTELEN_1, CMD_NOTELEN_2, CMD_NOTELEN_4, CMD_NOTELEN_8,
CMD_NOTELEN_16, CMD_NOTELEN_32, CMD_NOTELEN_LAST,
- CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN };
+ CMD_QUANTIZE, CMD_VELOCITY, CMD_CRESCENDO, CMD_NOTELEN, CMD_TRANSPOSE,
+ CMD_ERASE, CMD_MOVE, CMD_FIXED_LEN, CMD_DELETE_OVERLAPS, CMD_LEGATO,
+ CMD_CUT, CMD_COPY, CMD_PASTE, CMD_DEL,
+ CMD_SELECT_ALL, CMD_SELECT_NONE, CMD_SELECT_INVERT,
+ CMD_SELECT_ILOOP, CMD_SELECT_OLOOP};
+
class ScoreCanvas;
class EditToolBar;
@@ -70,7 +79,6 @@ class EditToolBar;
class ScoreEdit : public TopWin
{
Q_OBJECT
-
private:
virtual void closeEvent(QCloseEvent*);
virtual void resizeEvent(QResizeEvent*);
@@ -106,6 +114,32 @@ class ScoreEdit : public TopWin
QAction* color_black_action;
QAction* color_velo_action;
QAction* color_part_action;
+
+ QMenu* color_menu;
+
+ QAction* cut_action;
+ QAction* copy_action;
+ QAction* paste_action;
+ QAction* del_action;
+
+ QAction* select_all_action;
+ QAction* select_none_action;
+ QAction* select_invert_action;
+ QAction* select_iloop_action;
+ QAction* select_oloop_action;
+
+ QAction* func_quantize_action;
+ QAction* func_notelen_action;
+ QAction* func_velocity_action;
+ QAction* func_cresc_action;
+ QAction* func_transpose_action;
+ QAction* func_erase_action;
+ QAction* func_move_action;
+ QAction* func_fixed_len_action;
+ QAction* func_del_overlaps_action;
+ QAction* func_legato_action;
+
+ QToolButton* srec;
QScrollBar* xscroll;
QScrollBar* yscroll;
@@ -129,6 +163,9 @@ class ScoreEdit : public TopWin
void menu_command(int);
void velo_box_changed();
void velo_off_box_changed();
+ void init_shortcuts();
+ void selection_changed();
+ void clipboard_changed();
signals:
void deleted(unsigned long);
@@ -481,6 +518,7 @@ enum staff_mode_t
struct staff_t
{
set<Part*> parts;
+ set<int> part_indices;
ScoreEventList eventlist;
ScoreItemList itemlist;
@@ -524,6 +562,7 @@ struct staff_t
clef=clef_;
parts=parts_;
parent=parent_;
+ update_part_indices();
}
bool cleanup_parts();
@@ -532,6 +571,9 @@ struct staff_t
void read_status(Xml& xml);
void write_status(int level, Xml& xml) const;
+
+ void update_parts(); //re-populates the set<Part*> from the set<int>
+ void update_part_indices(); //re-populates the set<int> from the set<Part*>
};
list<int> calc_accidentials(key_enum key, clef_t clef, key_enum next_key=KEY_C);
@@ -612,6 +654,8 @@ class ScoreCanvas : public View
list<staff_t> staves;
+ StepRec* steprec;
+
// the drawing area is split into a "preamble" containing clef,
// key and time signature, and the "item's area" containing the
// actual items (notes, bars, rests, etc.)
@@ -633,6 +677,8 @@ class ScoreCanvas : public View
float y_scroll_pos;
Part* selected_part;
+ int selected_part_index;
+
int last_len;
int new_len; //when zero or negative, last_len is used
@@ -651,20 +697,26 @@ class ScoreCanvas : public View
bool mouse_erases_notes;
bool mouse_inserts_notes;
+ bool inserting;
bool dragging;
bool drag_cursor_changed;
Part* dragged_event_part;
Event dragged_event;
- int dragged_event_original_pitch;
+ Event original_dragged_event;
+ Event* clicked_event_ptr;
+
+ int old_pitch;
+ unsigned old_dest_tick;
bool have_lasso;
QPoint lasso_start;
QRect lasso;
bool undo_started;
- int undo_flags;
-
+ bool temp_undo;
+ bool srec;
+ bool held_notes[128];
enum {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO} coloring_mode;
bool preamble_contains_keysig;
@@ -692,6 +744,7 @@ class ScoreCanvas : public View
void config_changed();
void deselect_all();
+ void midi_note(int pitch, int velo);
public slots:
void x_scroll_event(int);
@@ -711,7 +764,10 @@ class ScoreCanvas : public View
void set_velo(int);
void set_velo_off(int);
-
+
+ void set_steprec(bool);
+
+ void update_parts(); //re-populates the set<Part*>s from the set<int>s
signals:
void xscroll_changed(int);
void yscroll_changed(int);
@@ -731,7 +787,6 @@ class ScoreCanvas : public View
virtual void mouseMoveEvent (QMouseEvent* event);
virtual void mouseReleaseEvent (QMouseEvent* event);
virtual void resizeEvent(QResizeEvent*);
- virtual void keyPressEvent(QKeyEvent* event);
public:
ScoreCanvas(ScoreEdit*, QWidget*);
@@ -755,7 +810,7 @@ class ScoreCanvas : public View
void set_last_len(int l) {last_len=l;}
Part* get_selected_part() {return selected_part;}
- void set_selected_part(Part* p) {selected_part=p;}
+ void set_selected_part(Part* p) {selected_part=p; if (selected_part) selected_part_index=selected_part->sn();}
set<Part*> get_all_parts();
diff --git a/muse2/muse/mixer/amixer.h b/muse2/muse/mixer/amixer.h
index f8e365c3..ca8a3f4c 100644
--- a/muse2/muse/mixer/amixer.h
+++ b/muse2/muse/mixer/amixer.h
@@ -62,6 +62,8 @@ class ScrollArea : public QScrollArea
//---------------------------------------------------------
class AudioMixerApp : public QMainWindow {
+ Q_OBJECT
+
//QString name;
MixerConfig* cfg;
StripList stripList;
@@ -84,7 +86,7 @@ class AudioMixerApp : public QMainWindow {
QAction* showAuxTracksId;
QAction* showSyntiTracksId;
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
void addStrip(Track*, int);
diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp
index 265061ad..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();
}
@@ -1007,898 +973,14 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)
}
//---------------------------------------------------------
-// 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);
- 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("<Mono>", 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);
-
- 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("<Stereo>", 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);
-
- 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);
- chpup->setTitle(track->name());
- if(chans > 1)
- chpup->addAction(new MenuTitleItem("<Mono>", 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("<Stereo>", 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);
- 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<QString> ol = audioDevice->outputPorts();
- for(std::list<QString>::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);
- subp->setTitle(tr("Audio sends"));
- pup->addMenu(subp);
- gid = addOutPorts(t, subp, gid, gRoutingMenuMap, -1, -1, false);
- subp = new PopupMenu(pup);
- 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<QString> ol = audioDevice->inputPorts();
- for(std::list<QString>::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);
- 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 <vector>
#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
}
//---------------------------------------------------------
@@ -1007,35 +999,14 @@ void MidiStrip::setReverbSend(double 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/mixer/rack.h b/muse2/muse/mixer/rack.h
index 33c846bd..2b1bbb66 100644
--- a/muse2/muse/mixer/rack.h
+++ b/muse2/muse/mixer/rack.h
@@ -24,8 +24,11 @@ class Xml;
//---------------------------------------------------------
class EffectRack : public QListWidget {
- AudioTrack* track;
Q_OBJECT
+
+
+ AudioTrack* track;
+
virtual QSize minimumSizeHint() const;
virtual QSize sizeHint() const;
diff --git a/muse2/muse/mplugins/mrconfig.cpp b/muse2/muse/mplugins/mrconfig.cpp
index f64384af..1a55c826 100644
--- a/muse2/muse/mplugins/mrconfig.cpp
+++ b/muse2/muse/mplugins/mrconfig.cpp
@@ -26,12 +26,14 @@ MRConfig::MRConfig(QWidget* parent, Qt::WFlags fl)
sb2->setValue(rcRecordNote);
sb3->setValue(rcGotoLeftMarkNote);
sb4->setValue(rcPlayNote);
+ steprec_box->setValue(rcSteprecNote);
connect(b1, SIGNAL(toggled(bool)), SLOT(setRcEnable(bool)));
connect(sb1, SIGNAL(valueChanged(int)), SLOT(setRcStopNote(int)));
connect(sb2, SIGNAL(valueChanged(int)), SLOT(setRcRecordNote(int)));
connect(sb3, SIGNAL(valueChanged(int)), SLOT(setRcGotoLeftMarkNote(int)));
connect(sb4, SIGNAL(valueChanged(int)), SLOT(setRcPlayNote(int)));
+ connect(steprec_box, SIGNAL(valueChanged(int)), SLOT(setRcSteprecNote(int)));
}
//---------------------------------------------------------
@@ -69,3 +71,8 @@ void MRConfig::setRcPlayNote(int val)
rcPlayNote = val;
}
+void MRConfig::setRcSteprecNote(int val)
+ {
+ rcSteprecNote = val;
+ }
+
diff --git a/muse2/muse/mplugins/mrconfig.h b/muse2/muse/mplugins/mrconfig.h
index e829c15c..5e4b38af 100644
--- a/muse2/muse/mplugins/mrconfig.h
+++ b/muse2/muse/mplugins/mrconfig.h
@@ -32,6 +32,7 @@ class MRConfig : public QWidget, public Ui::MRConfigBase {
void setRcRecordNote(int);
void setRcGotoLeftMarkNote(int);
void setRcPlayNote(int);
+ void setRcSteprecNote(int);
public:
MRConfig(QWidget* parent=0, Qt::WFlags fl = 0);
diff --git a/muse2/muse/mplugins/mrconfigbase.ui b/muse2/muse/mplugins/mrconfigbase.ui
index ed04c334..18050c78 100644
--- a/muse2/muse/mplugins/mrconfigbase.ui
+++ b/muse2/muse/mplugins/mrconfigbase.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>298</width>
- <height>249</height>
+ <height>267</height>
</rect>
</property>
<property name="windowTitle">
@@ -95,19 +95,29 @@
</widget>
</item>
<item row="0" column="1">
- <widget class="PitchEdit" name="sb1" native="true"/>
+ <widget class="Awl::PitchEdit" name="sb1"/>
</item>
<item row="1" column="1">
- <widget class="PitchEdit" name="sb2" native="true"/>
+ <widget class="Awl::PitchEdit" name="sb2"/>
</item>
<item row="2" column="1">
- <widget class="PitchEdit" name="sb3" native="true"/>
+ <widget class="Awl::PitchEdit" name="sb3"/>
</item>
<item row="3" column="1">
- <widget class="PitchEdit" name="sb4" native="true"/>
+ <widget class="Awl::PitchEdit" name="sb4"/>
</item>
- <item row="0" column="2">
- <spacer name="Spacer1">
+ <item row="4" column="1">
+ <widget class="Awl::PitchEdit" name="steprec_box"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Insert rest (step rec) </string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <spacer name="Spacer4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -122,8 +132,8 @@
</property>
</spacer>
</item>
- <item row="1" column="2">
- <spacer name="Spacer2">
+ <item row="2" column="2">
+ <spacer name="Spacer3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -138,8 +148,8 @@
</property>
</spacer>
</item>
- <item row="2" column="2">
- <spacer name="Spacer3">
+ <item row="1" column="2">
+ <spacer name="Spacer2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -154,8 +164,8 @@
</property>
</spacer>
</item>
- <item row="3" column="2">
- <spacer name="Spacer4">
+ <item row="0" column="2">
+ <spacer name="Spacer1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -178,9 +188,9 @@
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
- <class>PitchEdit</class>
- <extends>QWidget</extends>
- <header>pitchedit.h</header>
+ <class>Awl::PitchEdit</class>
+ <extends>QSpinBox</extends>
+ <header>awl/pitchedit.h</header>
</customwidget>
</customwidgets>
<includes>
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 <QMetaType>
+
#include <vector>
#include <map>
-
#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<int, Route, std::less<int> >::iterator iRouteMenuMap;
-typedef std::map<int, Route, std::less<int> >::const_iterator ciRouteMenuMap;
-typedef std::map<int, Route, std::less<int> > RouteMenuMap;
-typedef std::pair<int, Route> pRouteMenuMap;
-typedef std::pair<iRouteMenuMap, bool > rpRouteMenuMap;
+//typedef std::map<int, Route, std::less<int> >::iterator iRouteMenuMap;
+//typedef std::map<int, Route, std::less<int> >::const_iterator ciRouteMenuMap;
+//typedef std::map<int, Route, std::less<int> > RouteMenuMap;
+//typedef std::pair<int, Route> pRouteMenuMap;
+//typedef std::pair<iRouteMenuMap, bool > rpRouteMenuMap;
#endif
diff --git a/muse2/muse/seqmsg.cpp b/muse2/muse/seqmsg.cpp
index 3fb91293..0aa74aaa 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 f781b8f0..6d0541a3 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))
@@ -3685,8 +3685,8 @@ void Song::executeScript(const char* scriptfile, PartList* parts, int quant, boo
//const char* tmp = tmpnam(NULL);
char tmp[16] = "muse-tmp-XXXXXX";
int fd = mkstemp(tmp);
- printf("script input filename=%s\n",tmp);
- //FILE *fp = fopen(tmp, "w");
+ if (debugMsg)
+ printf("executeScript: script input filename=%s\n",tmp);
FILE *fp = fdopen(fd , "w");
MidiPart *part = (MidiPart*)(i->second);
int partStart = part->endTick()-part->lenTick();
@@ -3717,7 +3717,6 @@ void Song::executeScript(const char* scriptfile, PartList* parts, int quant, boo
}
fclose(fp);
-// QString program(scriptfile);
QStringList arguments;
arguments << tmp;
@@ -3725,64 +3724,58 @@ void Song::executeScript(const char* scriptfile, PartList* parts, int quant, boo
myProcess->start(scriptfile, arguments);
myProcess->waitForFinished();
QByteArray errStr = myProcess->readAllStandardError();
- if (errStr.size()) {
- QMessageBox::warning(muse, tr("MusE - external script failed"),
- "Script returned the following error\n"+ QString(errStr));
- endUndo(SC_EVENT_REMOVED);
- return;
- } else if (myProcess->exitCode()) {
+ if (myProcess->exitCode()) {
QMessageBox::warning(muse, tr("MusE - external script failed"),
- tr("MusE was unable to launch the script\n")
+ tr("MusE was unable to launch the script, error message:\n ")+ QString(errStr)
);
endUndo(SC_EVENT_REMOVED);
return;
}
- else { // d0 the fun55or5!
- // TODO: Create a new part, update the entire editor from it, hehh....
+ if (errStr.size()> 0) {
+ printf("script execution produced the following error:\n%s\n", QString(errStr).toLatin1().data());
+ }
+ QFile file(tmp);
+ if ( file.open( QIODevice::ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine(); // line of text excluding '\n'
+ if (line.startsWith("NOTE"))
+ {
+ QStringList sl = line.split(" ");
+
+ Event e(Note);
+ int tick = sl[1].toInt();
+ int pitch = sl[2].toInt();
+ int len = sl[3].toInt();
+ int velo = sl[4].toInt();
+ e.setTick(tick);
+ e.setPitch(pitch);
+ e.setVelo(velo);
+ e.setLenTick(len);
+ // Indicate no undo, and do not do port controller values and clone parts.
+ audio->msgAddEvent(e, part, false, false, false);
+ }
+ if (line.startsWith("CONTROLLER"))
+ {
+ QStringList sl = line.split(" ");
+
+ Event e(Controller);
+ //int tick = sl[1].toInt();
+ int a = sl[2].toInt();
+ int b = sl[3].toInt();
+ int c = sl[4].toInt();
+ e.setA(a);
+ e.setB(b);
+ e.setB(c);
+ // Indicate no undo, and do not do port controller values and clone parts.
+ audio->msgAddEvent(e, part, false, false, false);
+ }
+ }
+ file.close();
+ }
- QFile file(tmp);
- if ( file.open( QIODevice::ReadOnly ) ) {
- QTextStream stream( &file );
- QString line;
- while ( !stream.atEnd() ) {
- line = stream.readLine(); // line of text excluding '\n'
- if (line.startsWith("NOTE"))
- {
- QStringList sl = line.split(" ");
-
- Event e(Note);
- int tick = sl[1].toInt();
- int pitch = sl[2].toInt();
- int len = sl[3].toInt();
- int velo = sl[4].toInt();
- //printf ("tick=%d pitch=%d velo=%d len=%d\n", tick,pitch,velo,len);
- e.setTick(tick);
- e.setPitch(pitch);
- e.setVelo(velo);
- e.setLenTick(len);
- // Indicate no undo, and do not do port controller values and clone parts.
- audio->msgAddEvent(e, part, false, false, false);
- }
- if (line.startsWith("CONTROLLER"))
- {
- QStringList sl = line.split(" ");
-
- Event e(Controller);
- int a = sl[2].toInt();
- int b = sl[3].toInt();
- int c = sl[4].toInt();
- //printf ("tick=%d a=%d b=%d c=%d\n", tick,a,b,c);
- e.setA(a);
- e.setB(b);
- e.setB(c);
- // Indicate no undo, and do not do port controller values and clone parts.
- audio->msgAddEvent(e, part, false, false, false);
- }
- }
- file.close();
- }
- }
remove(tmp);
}
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index 17d70833..fd88b278 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -147,7 +147,7 @@ class Song : public QObject {
Song(const char* name = 0);
~Song();
- void applyOperationGroup(Undo& group, bool doUndo=true);
+ bool applyOperationGroup(Undo& group, bool doUndo=true);
void putEvent(int pv);
void endMsgCmd();
@@ -164,7 +164,7 @@ class Song : public QObject {
AudioOutput* bounceOutput;
void updatePos();
- void read(Xml&);
+ void read(Xml&, bool isTemplate=false);
void write(int, Xml&) const;
void writeFont(int level, Xml& xml, const char* name,
const QFont& font) const;
diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp
index a8134b1d..72cacfaa 100644
--- a/muse2/muse/songfile.cpp
+++ b/muse2/muse/songfile.cpp
@@ -1213,7 +1213,7 @@ void Song::readMarker(Xml& xml)
// read
//---------------------------------------------------------
-void Song::read(Xml& xml)
+void Song::read(Xml& xml, bool isTemplate)
{
cloneList.clear();
for (;;) {
@@ -1260,7 +1260,7 @@ void Song::read(Xml& xml)
_follow = FollowMode(xml.parseInt());
else if (tag == "sampleRate") {
int sRate = xml.parseInt();
- if (audioDevice->deviceType() != AudioDevice::DUMMY_AUDIO && sRate != sampleRate)
+ if (!isTemplate && audioDevice->deviceType() != AudioDevice::DUMMY_AUDIO && sRate != sampleRate)
QMessageBox::warning(muse,"Wrong sample rate", "The sample rate in this project and the current system setting differs, the project may not work as intended!");
}
else if (tag == "tempolist") {
@@ -1373,7 +1373,7 @@ void Song::read(Xml& xml)
// read song
//---------------------------------------------------------
-void MusE::read(Xml& xml, bool skipConfig)
+void MusE::read(Xml& xml, bool skipConfig, bool isTemplate)
{
bool skipmode = true;
for (;;) {
@@ -1398,7 +1398,7 @@ void MusE::read(Xml& xml, bool skipConfig)
readConfiguration(xml, false);
else if (tag == "song")
{
- song->read(xml);
+ song->read(xml, isTemplate);
audio->msgUpdateSoloStates();
}
else if (tag == "midiport")
diff --git a/muse2/muse/steprec.cpp b/muse2/muse/steprec.cpp
new file mode 100644
index 00000000..29cb9540
--- /dev/null
+++ b/muse2/muse/steprec.cpp
@@ -0,0 +1,159 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// steprec.cpp
+// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net)
+//=========================================================
+
+#include "steprec.h"
+#include "part.h"
+#include "event.h"
+#include "globals.h"
+
+#include "song.h"
+#include "audio.h"
+
+#include <set>
+
+#define CHORD_TIMEOUT 75
+
+StepRec::StepRec(bool* note_held_down_array)
+{
+ note_held_down=note_held_down_array;
+
+ chord_timer=new QTimer(this);
+ chord_timer->setSingleShot(true);
+ chord_timer->setInterval(CHORD_TIMEOUT);
+ chord_timer->stop();
+ connect(chord_timer, SIGNAL(timeout()), SLOT(timeout()));
+}
+
+void StepRec::timeout()
+{
+ if (chord_timer_set_to_tick != song->cpos())
+ {
+ Pos p(chord_timer_set_to_tick, true);
+ song->setPos(0, p, true, false, true);
+ }
+}
+
+void StepRec::record(Part* part, int pitch, int len, int step, int velo, bool ctrl, bool shift)
+{
+ unsigned tick = song->cpos();
+
+ if (pitch!=rcSteprecNote) {
+ chord_timer->stop();
+
+
+ //
+ // extend len of last note?
+ //
+ EventList* events = part->events();
+ if (ctrl) {
+ for (iEvent i = events->begin(); i != events->end(); ++i) {
+ Event ev = i->second;
+ if (!ev.isNote())
+ continue;
+ if (ev.pitch() == pitch && ((ev.tick() + ev.lenTick()) == tick)) {
+ Event e = ev.clone();
+ e.setLenTick(ev.lenTick() + len);
+ // Indicate do undo, and do not do port controller values and clone parts.
+ audio->msgChangeEvent(ev, e, part, true, false, false);
+
+ if (!shift) {
+ chord_timer_set_to_tick = tick + step;
+ chord_timer->start();
+ }
+ return;
+ }
+ }
+ }
+
+ //
+ // if we already entered the note, delete it
+ //
+ EventRange range = events->equal_range(tick);
+ for (iEvent i = range.first; i != range.second; ++i) {
+ Event ev = i->second;
+ if (ev.isNote() && ev.pitch() == pitch) {
+ // Indicate do undo, and do not do port controller values and clone parts.
+ //audio->msgDeleteEvent(ev, part);
+ audio->msgDeleteEvent(ev, part, true, false, false);
+
+ if (!shift) {
+ chord_timer_set_to_tick = tick + step;
+ chord_timer->start();
+ }
+
+ return;
+ }
+ }
+
+ Event e(Note);
+ e.setTick(tick - part->tick());
+ e.setPitch(pitch);
+ e.setVelo(velo);
+ e.setLenTick(len);
+ // Indicate do undo, and do not do port controller values and clone parts.
+ //audio->msgAddEvent(e, part);
+ audio->msgAddEvent(e, part, true, false, false);
+
+ if (! (globalKeyState & Qt::ShiftModifier)) {
+ chord_timer_set_to_tick = tick + step;
+ chord_timer->start();
+ }
+ }
+ else { // equals if (pitch==rcSteprecNote)
+ bool held_notes=false;
+ if (note_held_down!=NULL)
+ {
+ for (int i=0;i<128;i++)
+ if (note_held_down[i]) { held_notes=true; break; }
+ }
+ else
+ held_notes=false;
+
+
+ if (held_notes)
+ {
+ chord_timer->stop();
+
+ // extend len of last note(s)
+ using std::set;
+
+ set<Event*> extend_set;
+ EventList* events = part->events();
+ for (iEvent i = events->begin(); i != events->end(); ++i) {
+ Event& ev = i->second;
+ if (!ev.isNote())
+ continue;
+
+ if (note_held_down[ev.pitch()] && ((ev.tick() + ev.lenTick()) == tick))
+ extend_set.insert(&ev);
+ }
+ for (set<Event*>::iterator it=extend_set.begin(); it!=extend_set.end(); it++)
+ {
+ Event& ev=**it;
+ Event e = ev.clone();
+ e.setLenTick(ev.lenTick() + len);
+ // Indicate do undo, and do not do port controller values and clone parts.
+ audio->msgChangeEvent(ev, e, part, true, false, false);
+ }
+
+ if (!shift) {
+ chord_timer_set_to_tick = tick + step;
+ chord_timer->start();
+ }
+ return;
+
+ }
+ else // equals if (!held_notes)
+ {
+ chord_timer->stop();
+
+ //simply proceed, inserting a rest
+ Pos p(song->cpos() + step, true);
+ song->setPos(0, p, true, false, true);
+ }
+ }
+}
diff --git a/muse2/muse/steprec.h b/muse2/muse/steprec.h
new file mode 100644
index 00000000..02eab46c
--- /dev/null
+++ b/muse2/muse/steprec.h
@@ -0,0 +1,35 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// steprec.h
+// (C) Copyright 2011 Florian Jung (flo93@users.sourceforge.net)
+//=========================================================
+
+#ifndef __STEPREC_H__
+#define __STEPREC_H__
+
+#include <QObject>
+#include <QTimer>
+
+#include "part.h"
+
+
+class StepRec : public QObject
+{
+ Q_OBJECT
+
+ public:
+ StepRec(bool* note_held_down_array);
+
+ void record(Part* part, int pitch, int len, int step, int velo=80, bool ctrl=false, bool shift=false);
+
+ private slots:
+ void timeout();
+
+ private:
+ QTimer* chord_timer;
+ unsigned int chord_timer_set_to_tick;
+ bool* note_held_down;
+};
+
+#endif
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index 521c7d63..4f43a02a 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -17,7 +17,7 @@
#include <dlfcn.h>
#include <QDir>
-#include <QMenu>
+//#include <QMenu>
#include "app.h"
#include "synth.h"
@@ -35,6 +35,7 @@
#include "midiseq.h"
#include "midictrl.h"
//#include "stringparam.h"
+#include "popupmenu.h"
std::vector<Synth*> synthis; // array of available synthis
@@ -864,7 +865,7 @@ const char* MessSynthIF::getPatchName(int channel, int prog, MType type, bool dr
// populatePatchPopup
//---------------------------------------------------------
-void MessSynthIF::populatePatchPopup(QMenu* menu, int ch, MType, bool)
+void MessSynthIF::populatePatchPopup(PopupMenu* menu, int ch, MType, bool)
{
menu->clear();
const MidiPatch* mp = _mess->getPatchInfo(ch, 0);
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index b11ea2d9..88fa70b8 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -22,7 +22,8 @@
#include <QFileInfo>
-class QMenu;
+//class QMenu;
+class PopupMenu;
//class MidiEvent;
class MidiPlayEvent;
@@ -147,7 +148,8 @@ class SynthIF {
virtual void deactivate3() = 0;
virtual const char* getPatchName(int, int, int, bool) const = 0;
virtual const char* getPatchName(int, int, MType, bool) = 0;
- virtual void populatePatchPopup(QMenu*, int, MType, bool) = 0;
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool) = 0;
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool) = 0;
virtual void write(int level, Xml& xml) const = 0;
virtual float getParameter(unsigned long idx) const = 0;
virtual void setParameter(unsigned long idx, float value) = 0;
@@ -231,7 +233,8 @@ class SynthI : public AudioTrack, public MidiDevice,
return _sif->getPatchName(ch, prog, t, dr);
}
- virtual void populatePatchPopup(QMenu* m, int i, MType t, bool d) {
+ //virtual void populatePatchPopup(QMenu* m, int i, MType t, bool d) {
+ virtual void populatePatchPopup(PopupMenu* m, int i, MType t, bool d) {
_sif->populatePatchPopup(m, i, t, d);
}
@@ -313,7 +316,8 @@ class MessSynthIF : public SynthIF {
virtual void deactivate3();
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool);
- virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool);
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool);
virtual void write(int level, Xml& xml) const;
virtual float getParameter(unsigned long) const { return 0.0; }
virtual void setParameter(unsigned long, float) {}
diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp
index c5d3a1e7..7456b856 100644
--- a/muse2/muse/ticksynth.cpp
+++ b/muse2/muse/ticksynth.cpp
@@ -9,7 +9,8 @@
#include "ticksynth.h"
#include "default_click.h"
-#include <QMenu>
+//#include <QMenu>
+#include "popupmenu.h"
// Added by Tim. p3.3.18
//#define METRONOME_DEBUG
@@ -90,7 +91,8 @@ class MetronomeSynthIF : public SynthIF
virtual void deactivate3() {}
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
- virtual void populatePatchPopup(QMenu*, int, MType, bool) {};
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool) {};
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool) {};
virtual void write(int, Xml&) const {}
virtual float getParameter(unsigned long) const { return 0.0; }
virtual void setParameter(unsigned long, float) {}
diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp
index 2a93968d..5f358375 100644
--- a/muse2/muse/track.cpp
+++ b/muse2/muse/track.cpp
@@ -369,6 +369,7 @@ MidiTrack::MidiTrack()
init();
_events = new EventList;
_mpevents = new MPEventList;
+ clefType=trebleClef;
}
//MidiTrack::MidiTrack(const MidiTrack& mt)
@@ -388,6 +389,7 @@ MidiTrack::MidiTrack(const MidiTrack& mt, bool cloneParts)
len = mt.len;
compression = mt.compression;
_recEcho = mt.recEcho();
+ clefType=trebleClef;
}
MidiTrack::~MidiTrack()
@@ -894,6 +896,7 @@ void MidiTrack::write(int level, Xml& xml) const
xml.intTag(level, "len", len);
xml.intTag(level, "compression", compression);
xml.intTag(level, "automation", int(automationType()));
+ xml.intTag(level, "clef", int(clefType));
const PartList* pl = cparts();
for (ciPart p = pl->begin(); p != pl->end(); ++p)
@@ -955,6 +958,8 @@ void MidiTrack::read(Xml& xml)
_recEcho = xml.parseInt();
else if (tag == "automation")
setAutomationType(AutomationType(xml.parseInt()));
+ else if (tag == "clef")
+ clefType = (clefTypes)xml.parseInt();
else if (Track::readProperties(xml, tag)) {
// version 1.0 compatibility:
if (tag == "track" && xml.majorVersion() == 1 && xml.minorVersion() == 0)
diff --git a/muse2/muse/track.h b/muse2/muse/track.h
index aec765da..50870166 100644
--- a/muse2/muse/track.h
+++ b/muse2/muse/track.h
@@ -20,6 +20,7 @@
#include "route.h"
#include "ctrl.h"
#include "globaldefs.h"
+#include "cleftypes.h"
class Pipeline;
class Xml;
@@ -208,6 +209,7 @@ class MidiTrack : public Track {
EventList* _events; // tmp Events during midi import
MPEventList* _mpevents; // tmp Events druring recording
static bool _isVisible;
+ clefTypes clefType;
public:
MidiTrack();
@@ -273,6 +275,9 @@ class MidiTrack : public Track {
virtual bool canRecord() const { return true; }
static void setVisible(bool t) { _isVisible = t; }
static bool visible() { return _isVisible; }
+
+ void setClef(clefTypes i) { clefType = i; }
+ clefTypes getClef() { return clefType; }
};
//---------------------------------------------------------
diff --git a/muse2/muse/transport.h b/muse2/muse/transport.h
index b2d3facf..ce8dcf1b 100644
--- a/muse2/muse/transport.h
+++ b/muse2/muse/transport.h
@@ -34,10 +34,12 @@ class Pos;
//---------------------------------------------------------
class TempoSig : public QWidget {
+ Q_OBJECT
+
DoubleLabel* l1;
SigLabel* l2;
QLabel* l3;
- Q_OBJECT
+
private slots:
void configChanged();
@@ -76,6 +78,8 @@ class TimeLLabel;
class Transport : public QWidget
{
+ Q_OBJECT
+
PosEdit* tl1; // left mark
PosEdit* tl2; // right mark
PosEdit* time1; // tick time
@@ -99,9 +103,7 @@ class Transport : public QWidget
Handle *lefthandle, *righthandle;
- Q_OBJECT
-
- private slots:
+ private slots:
void cposChanged(const Pos&);
void cposChanged(int);
void lposChanged(const Pos&);
diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp
index 2a11c3dc..c57bb5c1 100644
--- a/muse2/muse/undo.cpp
+++ b/muse2/muse/undo.cpp
@@ -186,6 +186,9 @@ void UndoList::clearDelete()
void Song::startUndo()
{
+ redoList->clear(); // added by flo93: redo must be invalidated when
+ redoAction->setEnabled(false); // a new undo is started
+
undoList->push_back(Undo());
updateFlags = 0;
undoMode = true;
@@ -203,7 +206,7 @@ void Song::endUndo(int flags)
}
-void Song::applyOperationGroup(Undo& group, bool doUndo)
+bool Song::applyOperationGroup(Undo& group, bool doUndo)
{
if (!group.empty())
{
@@ -216,7 +219,16 @@ void Song::applyOperationGroup(Undo& group, bool doUndo)
undoList->pop_back();
undoAction->setEnabled(!undoList->empty());
}
+ else
+ {
+ redoList->clear(); // added by flo93: redo must be invalidated when
+ redoAction->setEnabled(false); // a new undo is started
+ }
+
+ return doUndo;
}
+ else
+ return false;
}
diff --git a/muse2/muse/value.h b/muse2/muse/value.h
index 22aa9b5a..e5c74b20 100644
--- a/muse2/muse/value.h
+++ b/muse2/muse/value.h
@@ -18,9 +18,9 @@ class Xml;
//---------------------------------------------------------
class IValue : public QObject {
- int val;
-
Q_OBJECT
+
+ int val;
signals:
void valueChanged(int);
@@ -39,9 +39,11 @@ class IValue : public QObject {
//---------------------------------------------------------
class BValue : public QObject {
+ Q_OBJECT
+
bool val;
- Q_OBJECT
+
signals:
void valueChanged(bool);
diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h
index d41502e5..bb675c22 100644
--- a/muse2/muse/vst.h
+++ b/muse2/muse/vst.h
@@ -10,7 +10,8 @@
#include "synth.h"
-class QMenu;
+//class QMenu;
+class PopupMenu;
struct _FSTHandle;
struct _FST;
@@ -76,7 +77,8 @@ class VstSynthIF : public SynthIF
virtual void deactivate3();
virtual const char* getPatchName(int, int, int, bool) const { return ""; }
virtual const char* getPatchName(int, int, MType, bool) { return ""; }
- virtual void populatePatchPopup(QMenu*, int, MType, bool) {};
+ //virtual void populatePatchPopup(QMenu*, int, MType, bool) {};
+ virtual void populatePatchPopup(PopupMenu*, int, MType, bool) {};
virtual void write(int level, Xml& xml) const;
virtual float getParameter(unsigned long idx) const;
virtual void setParameter(unsigned long idx, float value);
diff --git a/muse2/muse/waveedit/waveedit.h b/muse2/muse/waveedit/waveedit.h
index e966a635..1ff8a65b 100644
--- a/muse2/muse/waveedit/waveedit.h
+++ b/muse2/muse/waveedit/waveedit.h
@@ -33,6 +33,8 @@ class QAction;
//---------------------------------------------------------
class WaveEdit : public MidiEditor {
+ Q_OBJECT
+
WaveView* view;
QSlider* ymag;
QToolBar* tools;
@@ -49,7 +51,7 @@ class WaveEdit : public MidiEditor {
static int _widthInit, _heightInit;
static QByteArray _toolbarInit;
- Q_OBJECT
+
virtual void closeEvent(QCloseEvent*);
virtual void keyPressEvent(QKeyEvent*);
virtual void resizeEvent(QResizeEvent* ev);
diff --git a/muse2/muse/waveedit/waveview.h b/muse2/muse/waveedit/waveview.h
index c7992952..1a646af9 100644
--- a/muse2/muse/waveedit/waveview.h
+++ b/muse2/muse/waveedit/waveview.h
@@ -34,6 +34,8 @@ typedef std::list<WaveEventSelection>::iterator iWaveSelection;
//---------------------------------------------------------
class WaveView : public View {
+ Q_OBJECT
+
MidiEditor* editor;
unsigned pos[3];
int yScale;
@@ -50,7 +52,6 @@ class WaveView : public View {
unsigned selectionStart, selectionStop, dragstartx;
- Q_OBJECT
virtual void pdraw(QPainter&, const QRect&);
virtual void draw(QPainter&, const QRect&);
virtual void viewMousePressEvent(QMouseEvent*);
diff --git a/muse2/muse/waveevent.cpp b/muse2/muse/waveevent.cpp
index 867ce5c8..9f81b7e3 100644
--- a/muse2/muse/waveevent.cpp
+++ b/muse2/muse/waveevent.cpp
@@ -151,7 +151,7 @@ void WaveEventBase::write(int level, Xml& xml, const Pos& offset, bool forcePath
//off_t WaveEventBase::readAudio(SRC_STATE* src_state, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
//off_t WaveEventBase::readAudio(AudioConverter* audConv, off_t sfCurFrame, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
// p3.3.33
-void WaveEventBase::readAudio(WavePart* part, unsigned offset, float** buffer, int channel, int n, bool doSeek, bool overwrite)
+void WaveEventBase::readAudio(WavePart* /*part*/, unsigned offset, float** buffer, int channel, int n, bool /*doSeek*/, bool overwrite)
{
// Added by Tim. p3.3.17
#ifdef WAVEEVENT_DEBUG_PRC
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/bigtime.h b/muse2/muse/widgets/bigtime.h
index bb32cedc..eff0ef92 100644
--- a/muse2/muse/widgets/bigtime.h
+++ b/muse2/muse/widgets/bigtime.h
@@ -13,9 +13,11 @@ class MusE;
//---------------------------------------------------------
class BigTime : public QWidget {
+ Q_OBJECT
+
bool tickmode;
MusE* seq;
- Q_OBJECT
+
bool setString(unsigned);
diff --git a/muse2/muse/widgets/comment.h b/muse2/muse/widgets/comment.h
index 688d7b2f..0dbd953b 100644
--- a/muse2/muse/widgets/comment.h
+++ b/muse2/muse/widgets/comment.h
@@ -36,8 +36,10 @@ class Comment : public QWidget, public Ui::CommentBase {
//---------------------------------------------------------
class TrackComment : public Comment {
- Track* track;
Q_OBJECT
+
+ Track* track;
+
private:
virtual void setText(const QString& s);
diff --git a/muse2/muse/widgets/function_dialogs/CMakeLists.txt b/muse2/muse/widgets/function_dialogs/CMakeLists.txt
index 7ddc6bee..db1f3229 100644
--- a/muse2/muse/widgets/function_dialogs/CMakeLists.txt
+++ b/muse2/muse/widgets/function_dialogs/CMakeLists.txt
@@ -30,6 +30,7 @@ QT4_WRAP_CPP (widgets_functiondialogs_mocs
remove.h
setlen.h
transpose.h
+ legato.h
velocity.h
)
@@ -45,6 +46,7 @@ file (GLOB widgets_functiondialogs_ui_files
removebase.ui
setlenbase.ui
transposebase.ui
+ legatobase.ui
velocitybase.ui
)
@@ -62,6 +64,7 @@ file (GLOB widgets_functiondialogs_source_files
remove.cpp
setlen.cpp
transpose.cpp
+ legato.cpp
velocity.cpp
)
diff --git a/muse2/muse/widgets/function_dialogs/crescendo.h b/muse2/muse/widgets/function_dialogs/crescendo.h
index eb00e94f..73a7e088 100644
--- a/muse2/muse/widgets/function_dialogs/crescendo.h
+++ b/muse2/muse/widgets/function_dialogs/crescendo.h
@@ -15,8 +15,9 @@ class Xml;
class Crescendo : public QDialog, public Ui::CrescendoBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/deloverlaps.h b/muse2/muse/widgets/function_dialogs/deloverlaps.h
index 813192a6..d151d5a5 100644
--- a/muse2/muse/widgets/function_dialogs/deloverlaps.h
+++ b/muse2/muse/widgets/function_dialogs/deloverlaps.h
@@ -15,8 +15,9 @@ class Xml;
class DelOverlaps : public QDialog, public Ui::DelOverlapsBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/gatetime.h b/muse2/muse/widgets/function_dialogs/gatetime.h
index d2555872..baa5a97b 100644
--- a/muse2/muse/widgets/function_dialogs/gatetime.h
+++ b/muse2/muse/widgets/function_dialogs/gatetime.h
@@ -11,7 +11,6 @@
#include "ui_gatetimebase.h"
class QButtonGroup;
-class QDialog;
class Xml;
//---------------------------------------------------------
@@ -19,9 +18,9 @@ class Xml;
//---------------------------------------------------------
class GateTime : public QDialog, public Ui::GateTimeBase {
+ Q_OBJECT
private:
- Q_OBJECT
-
+
QButtonGroup *rangeGroup;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/legato.cpp b/muse2/muse/widgets/function_dialogs/legato.cpp
new file mode 100644
index 00000000..0a181106
--- /dev/null
+++ b/muse2/muse/widgets/function_dialogs/legato.cpp
@@ -0,0 +1,88 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: legato.cpp,v 1.1.1.1 2011/05/05 18:51:04 flo93 Exp $
+// (C) Copyright 2011 Florian Jung (flo93@sourceforge.net)
+//=========================================================
+
+#include <QButtonGroup>
+#include "legato.h"
+#include "xml.h"
+
+Legato::Legato(QWidget* parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ range_group = new QButtonGroup;
+ range_group->addButton(all_events_button,0);
+ range_group->addButton(selected_events_button,1);
+ range_group->addButton(looped_events_button,2);
+ range_group->addButton(selected_looped_button,3);
+
+ pull_values();
+}
+
+void Legato::pull_values()
+{
+ range = range_group->checkedId();
+ min_len = len_spinbox->value();
+ allow_shortening = allow_shorten_checkbox->isChecked();
+}
+
+void Legato::accept()
+{
+ pull_values();
+ QDialog::accept();
+}
+
+int Legato::exec()
+{
+ if ((range < 0) || (range > 3)) range=0;
+
+ range_group->button(range)->setChecked(true);
+ len_spinbox->setValue(min_len);
+ allow_shorten_checkbox->setChecked(allow_shortening);
+
+ return QDialog::exec();
+}
+
+void Legato::read_configuration(Xml& xml)
+{
+ for (;;)
+ {
+ Xml::Token token = xml.parse();
+ if (token == Xml::Error || token == Xml::End)
+ break;
+
+ const QString& tag = xml.s1();
+ switch (token)
+ {
+ case Xml::TagStart:
+ if (tag == "range")
+ range=xml.parseInt();
+ else if (tag == "min_len")
+ min_len=xml.parseInt();
+ else if (tag == "allow_shortening")
+ allow_shortening=xml.parseInt();
+ else
+ xml.unknown("Legato");
+ break;
+
+ case Xml::TagEnd:
+ if (tag == "legato")
+ return;
+
+ default:
+ break;
+ }
+ }
+}
+
+void Legato::write_configuration(int level, Xml& xml)
+{
+ xml.tag(level++, "legato");
+ xml.intTag(level, "range", range);
+ xml.intTag(level, "min_len", min_len);
+ xml.intTag(level, "allow_shortening", allow_shortening);
+ xml.tag(level, "/legato");
+}
diff --git a/muse2/muse/widgets/function_dialogs/legato.h b/muse2/muse/widgets/function_dialogs/legato.h
new file mode 100644
index 00000000..00831830
--- /dev/null
+++ b/muse2/muse/widgets/function_dialogs/legato.h
@@ -0,0 +1,43 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: legato.h,v 1.1.1.1 2011/05/05 18:51:04 flo93 Exp $
+// (C) Copyright 2011 Florian Jung (flo93@sourceforge.net)
+//=========================================================
+
+#ifndef __LEGATO_H__
+#define __LEGATO_H__
+
+#include "ui_legatobase.h"
+
+class QButtonGroup;
+class Xml;
+
+class Legato : public QDialog, public Ui::LegatoBase
+{
+ Q_OBJECT
+ private:
+
+ QButtonGroup* range_group;
+
+ protected slots:
+ void accept();
+ void pull_values();
+
+ public:
+ Legato(QWidget* parent = 0);
+
+ int range;
+ int min_len;
+ bool allow_shortening;
+
+ void read_configuration(Xml& xml);
+ void write_configuration(int level, Xml& xml);
+
+
+ public slots:
+ int exec();
+};
+
+#endif
+
diff --git a/muse2/muse/widgets/function_dialogs/legatobase.ui b/muse2/muse/widgets/function_dialogs/legatobase.ui
new file mode 100644
index 00000000..7bc406df
--- /dev/null
+++ b/muse2/muse/widgets/function_dialogs/legatobase.ui
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LegatoBase</class>
+ <widget class="QDialog" name="LegatoBase">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>275</width>
+ <height>289</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MusE: Legato</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="rangeBox">
+ <property name="title">
+ <string>Range</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="all_events_button">
+ <property name="text">
+ <string>All Events</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="selected_events_button">
+ <property name="text">
+ <string>Selected Events</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="looped_events_button">
+ <property name="text">
+ <string>Looped Events</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="selected_looped_button">
+ <property name="text">
+ <string>Selected Looped</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Settings</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="len_spinbox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="accelerated">
+ <bool>true</bool>
+ </property>
+ <property name="suffix">
+ <string> ticks</string>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>10000</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Minimum Length</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Allow shortening notes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="allow_shorten_checkbox">
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item>
+ <spacer name="Spacer1">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="okButton">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>okButton</sender>
+ <signal>clicked()</signal>
+ <receiver>LegatoBase</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>LegatoBase</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>20</x>
+ <y>20</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/muse2/muse/widgets/function_dialogs/move.h b/muse2/muse/widgets/function_dialogs/move.h
index 4c90a922..5049c567 100644
--- a/muse2/muse/widgets/function_dialogs/move.h
+++ b/muse2/muse/widgets/function_dialogs/move.h
@@ -15,8 +15,9 @@ class Xml;
class Move : public QDialog, public Ui::MoveBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/quantize.h b/muse2/muse/widgets/function_dialogs/quantize.h
index 399e2545..a857e667 100644
--- a/muse2/muse/widgets/function_dialogs/quantize.h
+++ b/muse2/muse/widgets/function_dialogs/quantize.h
@@ -15,8 +15,9 @@ class Xml;
class Quantize : public QDialog, public Ui::QuantBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/remove.cpp b/muse2/muse/widgets/function_dialogs/remove.cpp
index 5ad272ab..4a875135 100644
--- a/muse2/muse/widgets/function_dialogs/remove.cpp
+++ b/muse2/muse/widgets/function_dialogs/remove.cpp
@@ -25,6 +25,10 @@ Remove::Remove(QWidget* parent)
void Remove::pull_values()
{
range = range_group->checkedId();
+ len_thres_used=len_checkbox->isChecked();
+ len_threshold=len_spinbox->value();
+ velo_thres_used=velo_checkbox->isChecked();
+ velo_threshold=velo_spinbox->value();
}
void Remove::accept()
@@ -38,6 +42,10 @@ int Remove::exec()
if ((range < 0) || (range > 3)) range=0;
range_group->button(range)->setChecked(true);
+ len_checkbox->setChecked(len_thres_used);
+ len_spinbox->setValue(len_threshold);
+ velo_checkbox->setChecked(velo_thres_used);
+ velo_spinbox->setValue(velo_threshold);
return QDialog::exec();
}
@@ -56,6 +64,14 @@ void Remove::read_configuration(Xml& xml)
case Xml::TagStart:
if (tag == "range")
range=xml.parseInt();
+ else if (tag == "velo_threshold")
+ velo_threshold=xml.parseInt();
+ else if (tag == "velo_thres_used")
+ velo_thres_used=xml.parseInt();
+ else if (tag == "len_threshold")
+ len_threshold=xml.parseInt();
+ else if (tag == "len_thres_used")
+ len_thres_used=xml.parseInt();
else
xml.unknown("Erase");
break;
@@ -74,5 +90,9 @@ void Remove::write_configuration(int level, Xml& xml)
{
xml.tag(level++, "erase");
xml.intTag(level, "range", range);
+ xml.intTag(level, "velo_threshold", velo_threshold);
+ xml.intTag(level, "velo_thres_used", velo_thres_used);
+ xml.intTag(level, "len_threshold", len_threshold);
+ xml.intTag(level, "len_thres_used", len_thres_used);
xml.tag(level, "/erase");
}
diff --git a/muse2/muse/widgets/function_dialogs/remove.h b/muse2/muse/widgets/function_dialogs/remove.h
index 5615ed42..33ac3fd0 100644
--- a/muse2/muse/widgets/function_dialogs/remove.h
+++ b/muse2/muse/widgets/function_dialogs/remove.h
@@ -15,8 +15,9 @@ class Xml;
class Remove : public QDialog, public Ui::RemoveBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
@@ -27,6 +28,10 @@ class Remove : public QDialog, public Ui::RemoveBase
Remove(QWidget* parent = 0);
int range;
+ int velo_threshold;
+ bool velo_thres_used;
+ int len_threshold;
+ bool len_thres_used;
void read_configuration(Xml& xml);
void write_configuration(int level, Xml& xml);
diff --git a/muse2/muse/widgets/function_dialogs/removebase.ui b/muse2/muse/widgets/function_dialogs/removebase.ui
index 3381795c..79d541cc 100644
--- a/muse2/muse/widgets/function_dialogs/removebase.ui
+++ b/muse2/muse/widgets/function_dialogs/removebase.ui
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>275</width>
- <height>195</height>
+ <height>443</height>
</rect>
</property>
<property name="windowTitle">
@@ -70,6 +70,101 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Thresholds</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="velo_spinbox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="accelerated">
+ <bool>true</bool>
+ </property>
+ <property name="suffix">
+ <string/>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>127</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>16</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="len_spinbox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="suffix">
+ <string> ticks</string>
+ </property>
+ <property name="maximum">
+ <number>10000</number>
+ </property>
+ <property name="value">
+ <number>12</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="velo_checkbox">
+ <property name="text">
+ <string>Velocity</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="len_checkbox">
+ <property name="text">
+ <string>Length</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:7px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If nothing is checked, everything is removed.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:7px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If velocity is checked, only notes with velo &amp;lt; threshold are removed.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;If both are checked, notes with velo &amp;lt; threshold OR with length &amp;lt; threshold are removed.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::AutoText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>6</number>
@@ -149,5 +244,37 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>velo_checkbox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>velo_spinbox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>83</x>
+ <y>192</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>198</x>
+ <y>193</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>len_checkbox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>len_spinbox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>83</x>
+ <y>221</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>198</x>
+ <y>222</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
</ui>
diff --git a/muse2/muse/widgets/function_dialogs/setlen.h b/muse2/muse/widgets/function_dialogs/setlen.h
index ad66a38b..6a052bdb 100644
--- a/muse2/muse/widgets/function_dialogs/setlen.h
+++ b/muse2/muse/widgets/function_dialogs/setlen.h
@@ -15,8 +15,9 @@ class Xml;
class Setlen : public QDialog, public Ui::SetlenBase
{
+ Q_OBJECT
private:
- Q_OBJECT
+
QButtonGroup* range_group;
protected slots:
diff --git a/muse2/muse/widgets/function_dialogs/transpose.h b/muse2/muse/widgets/function_dialogs/transpose.h
index 97dd443e..b85bb827 100644
--- a/muse2/muse/widgets/function_dialogs/transpose.h
+++ b/muse2/muse/widgets/function_dialogs/transpose.h
@@ -15,7 +15,6 @@ class Xml;
class Transpose : public QDialog, public Ui::TransposeBase
{
- private:
Q_OBJECT
QButtonGroup* range_group;
diff --git a/muse2/muse/widgets/function_dialogs/velocity.h b/muse2/muse/widgets/function_dialogs/velocity.h
index cbea4e22..83aac54d 100644
--- a/muse2/muse/widgets/function_dialogs/velocity.h
+++ b/muse2/muse/widgets/function_dialogs/velocity.h
@@ -18,8 +18,9 @@ class Xml;
//---------------------------------------------------------
class Velocity : public QDialog, public Ui::VelocityBase {
- private:
Q_OBJECT
+ private:
+
QButtonGroup* rangeGroup;
protected slots:
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.</string>
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
</property>
</widget>
</item>
- <item row="4" column="0">
+ <item row="5" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -1346,6 +1346,27 @@ Adjusts responsiveness of audio controls and
</property>
</spacer>
</item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="TextLabel1_3">
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="text">
+ <string>Some popup menus stay open (else hold Ctrl)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="popsDefStayOpenCheckBox">
+ <property name="toolTip">
+ <string>Allows some popup menus to stay open.
+Otherwise, hold Ctrl to keep them open.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/muse2/muse/widgets/header.cpp b/muse2/muse/widgets/header.cpp
index 16cc374b..c12c8eaf 100644
--- a/muse2/muse/widgets/header.cpp
+++ b/muse2/muse/widgets/header.cpp
@@ -7,46 +7,69 @@
#include "header.h"
#include "xml.h"
+#include "popupmenu.h"
#include <QStringList>
#include <QStandardItemModel>
+#include <QMouseEvent>
//---------------------------------------------------------
// readStatus
//---------------------------------------------------------
void Header::readStatus(Xml& xml)
- {
- for (;;) {
- Xml::Token token = xml.parse();
- const QString& tag = xml.s1();
- switch (token) {
- case Xml::Error:
- case Xml::End:
- return;
- case Xml::Text:
- {
- //QStringList l = QStringList::split(QString(" "), tag);
- QStringList l = tag.split(QString(" "), QString::SkipEmptyParts);
- int index = count() -1;
- for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
- int section = visualIndex((*it).toInt());
- moveSection(section, index);
- --index;
+{
+
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::Text:
+ {
+ QStringList l = tag.split(QString(" "), QString::SkipEmptyParts);
+ int index = count() -1;
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ int logialIdx=abs((*it).toInt());
+ bool isHidden = (*it).toInt() < 0 ? true:false;
+ int section = visualIndex(logialIdx);
+ moveSection(section, index);
+ if (isHidden)
+ hideSection(logialIdx-1);
+ else
+ showSection(logialIdx);
+ --index;
+ }
+
+ // loop again looking for missing indexes
+ for (int i =0; i < count(); i++) {
+ bool foundIt=false;
+ for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
+ int id=((*it).toInt());
+ if ( id == i || i ==1-id )
+ foundIt=true;
}
- }
- break;
- case Xml::TagStart:
- xml.unknown("Header");
- break;
- case Xml::TagEnd:
- if (tag ==objectName())
- return;
- default:
- break;
- }
- }
- }
+ if (foundIt == false) {
+ int section = visualIndex(i);
+ moveSection(section, i);
+ //printf("Adding missing i %d index %d section %d!\n", i, index, section);
+ }
+ }
+ }
+ break;
+ case Xml::TagStart:
+ xml.unknown("Header");
+ break;
+ case Xml::TagEnd:
+ if (tag ==objectName())
+ return;
+ default:
+ break;
+ }
+ }
+}
//---------------------------------------------------------
// writeStatus
@@ -56,9 +79,13 @@ void Header::writeStatus(int level, Xml& xml) const
{
//xml.nput(level, "<%s> ", name());
xml.nput(level, "<%s> ", Xml::xmlString(objectName()).toLatin1().constData());
- int n = count() - 1;
- for (int i = n; i >= 0; --i)
- xml.nput("%d ", logicalIndex(i));
+ int n = count();
+ for (int i = n; i >= 0; --i) {
+ if (isSectionHidden(logicalIndex(i)))
+ xml.nput("%d ", -logicalIndex(i)-1); // hidden is stored as negative value starting from -1
+ else
+ xml.nput("%d ", logicalIndex(i));
+ }
//xml.put("</%s>", name());
xml.put("</%s>", Xml::xmlString(objectName()).toLatin1().constData());
}
@@ -73,8 +100,9 @@ Header::Header(QWidget* parent, const char* name)
setObjectName(name);
itemModel = new QStandardItemModel;
setModel(itemModel);
- //setResizeMode(QHeaderView::ResizeToContents);
setDefaultSectionSize(30);
+ setStretchLastSection(true);
+
}
//---------------------------------------------------------
@@ -86,7 +114,7 @@ void Header::setColumnLabel(const QString & text, int col, int width )
QStandardItem *sitem = new QStandardItem(text );
itemModel->setHorizontalHeaderItem(col, sitem);
if (width > -1)
- resizeSection(col, width);
+ resizeSection(col, width);
}
//---------------------------------------------------------
@@ -109,3 +137,40 @@ void Header::setWhatsThis(int col, const QString &text)
item->setWhatsThis(text);
}
+void Header::mousePressEvent ( QMouseEvent * e )
+{
+ if (e->button() == Qt::RightButton) {
+
+ PopupMenu* p = new PopupMenu();
+ p->disconnect();
+ p->clear();
+ p->setTitle(tr("Track Info Columns"));
+ QAction* act = 0;
+
+ for(int i=0; i < count(); i++) {
+ act = p->addAction(itemModel->horizontalHeaderItem(logicalIndex(i))->text() +
+ "\t - "+ itemModel->horizontalHeaderItem(logicalIndex(i))->toolTip());
+
+ act->setCheckable(true);
+ act->setChecked(!isSectionHidden(logicalIndex(i)));
+ int data = logicalIndex(i);
+ act->setData(data);
+ }
+ connect(p, SIGNAL(triggered(QAction*)), SLOT(changeColumns(QAction*)));
+ p->exec(QCursor::pos());
+
+ delete p;
+ return;
+ }
+
+ QHeaderView::mousePressEvent(e);
+
+}
+void Header::changeColumns(QAction *a)
+{
+ int section = a->data().toInt();
+ if (isSectionHidden(section))
+ showSection(section);
+ else
+ hideSection(section);
+}
diff --git a/muse2/muse/widgets/header.h b/muse2/muse/widgets/header.h
index 83680f8a..3e7b73a4 100644
--- a/muse2/muse/widgets/header.h
+++ b/muse2/muse/widgets/header.h
@@ -9,6 +9,7 @@
#define __HEADER_H__
#include <QHeaderView>
+#include <QAction>
class QStandardItemModel;
@@ -26,6 +27,9 @@ class Header : public QHeaderView {
void setColumnLabel( const QString & s, int col, int width = -1 );
void setToolTip(int col, const QString &text);
void setWhatsThis(int col, const QString &text);
+ void mousePressEvent ( QMouseEvent * e );
+ private slots:
+ void changeColumns(QAction* a);
};
#endif
diff --git a/muse2/muse/widgets/lcombo.h b/muse2/muse/widgets/lcombo.h
index b125fce5..760d4512 100644
--- a/muse2/muse/widgets/lcombo.h
+++ b/muse2/muse/widgets/lcombo.h
@@ -20,8 +20,9 @@ class QString;
//---------------------------------------------------------
class LabelCombo : public QWidget {
- QComboBox* box;
Q_OBJECT
+ QComboBox* box;
+
signals:
void activated(int);
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 <QLabel>
+
+#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/menutitleitem.h b/muse2/muse/widgets/menutitleitem.h
index 016d4663..20583bd1 100644
--- a/muse2/muse/widgets/menutitleitem.h
+++ b/muse2/muse/widgets/menutitleitem.h
@@ -15,6 +15,10 @@
//---------------------------------------------------------
class MenuTitleItem : public QWidgetAction {
+ Q_OBJECT
+ private:
+
+
QString s;
public:
diff --git a/muse2/muse/widgets/meter.h b/muse2/muse/widgets/meter.h
index 2b816040..cced6e7a 100644
--- a/muse2/muse/widgets/meter.h
+++ b/muse2/muse/widgets/meter.h
@@ -17,6 +17,7 @@ class QPainter;
class Meter : public QFrame {
+ Q_OBJECT
public:
enum MeterType {DBMeter, LinMeter};
private:
@@ -29,7 +30,7 @@ class Meter : public QFrame {
void drawVU(QPainter& p, int, int, int);
- Q_OBJECT
+
void paintEvent(QPaintEvent*);
void resizeEvent(QResizeEvent*);
void mousePressEvent(QMouseEvent*);
diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp
index acdfb42f..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
@@ -44,10 +45,13 @@ void MidiTrackInfo::setTrack(Track* t)
selected = t;
QPalette pal;
- if(selected->type() == Track::DRUM)
+ if(selected->type() == Track::DRUM) {
pal.setColor(trackNameLabel->backgroundRole(), config.drumTrackLabelBg);
- else
- pal.setColor(trackNameLabel->backgroundRole(), config.midiTrackLabelBg);
+ iOutputChannel->setEnabled(false);
+ } else {
+ pal.setColor(trackNameLabel->backgroundRole(), config.midiTrackLabelBg);
+ iOutputChannel->setEnabled(true);
+ }
trackNameLabel->setPalette(pal);
updateTrackInfo(-1);
@@ -574,33 +578,6 @@ void MidiTrackInfo::iOutputPortChanged(int index)
}
//---------------------------------------------------------
-// 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
//---------------------------------------------------------
@@ -611,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);
}
//---------------------------------------------------------
@@ -662,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);
}
//---------------------------------------------------------
@@ -1036,6 +970,29 @@ void MidiTrackInfo::iPanChanged(int val)
}
//---------------------------------------------------------
+// instrPopupActivated
+//---------------------------------------------------------
+
+void MidiTrackInfo::instrPopupActivated(QAction* act)
+{
+ //printf("MidiTrackInfo::instrPopupActivated\n");
+
+ if(act && selected)
+ {
+ int rv = act->data().toInt();
+ if(rv != -1)
+ {
+ MidiTrack* track = (MidiTrack*)selected;
+ int channel = track->outChannel();
+ int port = track->outPort();
+ MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv);
+ audio->msgPlayMidiEvent(&ev);
+ updateTrackInfo(-1);
+ }
+ }
+}
+
+//---------------------------------------------------------
// instrPopup
//---------------------------------------------------------
@@ -1047,26 +1004,35 @@ void MidiTrackInfo::instrPopup()
int channel = track->outChannel();
int port = track->outPort();
MidiInstrument* instr = midiPorts[port].instrument();
- QMenu* pup = new QMenu;
- ///instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM);
+ //QMenu* pup = new QMenu;
+ PopupMenu* pup = new PopupMenu(true);
+
+ //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;
return;
}
- ///QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5)));
+ 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 = pup->exec(iPatch->mapToGlobal(QPoint(10,5)));
- if (act) {
- int rv = act->data().toInt();
- MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv);
- audio->msgPlayMidiEvent(&ev);
- updateTrackInfo(-1);
- }
+ if(act)
+ {
+ int rv = act->data().toInt();
+ if(rv != -1)
+ {
+ MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv);
+ audio->msgPlayMidiEvent(&ev);
+ updateTrackInfo(-1);
+ }
+ }
delete pup;
}
@@ -1275,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 4e06f1d0..ed229ad6 100644
--- a/muse2/muse/widgets/mtrackinfo.h
+++ b/muse2/muse/widgets/mtrackinfo.h
@@ -46,8 +46,7 @@ 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:
virtual void heartBeat();
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/noteinfo.h b/muse2/muse/widgets/noteinfo.h
index cc8fe16d..64842988 100644
--- a/muse2/muse/widgets/noteinfo.h
+++ b/muse2/muse/widgets/noteinfo.h
@@ -25,6 +25,8 @@ class Pos;
//---------------------------------------------------------
class NoteInfo : public QToolBar {
+ Q_OBJECT
+
///PosEdit* selTime;
Awl::PosEdit* selTime;
QSpinBox* selLen;
@@ -33,7 +35,7 @@ class NoteInfo : public QToolBar {
QSpinBox* selVelOff;
bool deltaMode;
- Q_OBJECT
+
public:
enum ValType {VAL_TIME, VAL_LEN, VAL_VELON, VAL_VELOFF, VAL_PITCH };
diff --git a/muse2/muse/widgets/pitchlabel.h b/muse2/muse/widgets/pitchlabel.h
index 6372f711..d29a4ee4 100644
--- a/muse2/muse/widgets/pitchlabel.h
+++ b/muse2/muse/widgets/pitchlabel.h
@@ -15,9 +15,11 @@
//---------------------------------------------------------
class PitchLabel : public QLabel {
+ Q_OBJECT
+
bool _pitchMode;
int _value;
- Q_OBJECT
+
protected:
QSize sizeHint() const;
diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp
index 862bda91..adbe7dd6 100644
--- a/muse2/muse/widgets/popupmenu.cpp
+++ b/muse2/muse/widgets/popupmenu.cpp
@@ -6,25 +6,51 @@
// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
//
// PopupMenu sub-class of QMenu created by Tim.
+// (C) Copyright 2010-2011 Tim E. Real (terminator356 A T sourceforge D O T net)
//=========================================================
//#include <stdio.h>
#include <QMouseEvent>
+#include <QHoverEvent>
#include <QAction>
+#include <QPoint>
+#include <QDesktopWidget>
+#include <QApplication>
+//#include <QTimer>
+
#include <stdio.h>
//#include <QStandardItemModel>
#include "popupmenu.h"
+#include "gconfig.h"
+#include "route.h"
+
//======================
// PopupMenu
//======================
-PopupMenu::PopupMenu(QWidget* parent)
- : QMenu(parent)
+//PopupMenu::PopupMenu()
+//{
+// init();
+//}
+
+PopupMenu::PopupMenu(bool stayOpen)
+ : _stayOpen(stayOpen)
{
- // Menus will trigger! Set to make sure our trigger handlers ignore menus.
- menuAction()->setData(-1);
+ init();
+}
+
+PopupMenu::PopupMenu(QWidget* parent, bool stayOpen)
+ : QMenu(parent), _stayOpen(stayOpen)
+{
+ init();
+}
+
+PopupMenu::PopupMenu(const QString& title, QWidget* parent, bool stayOpen)
+ : QMenu(title, parent), _stayOpen(stayOpen)
+{
+ init();
}
PopupMenu::~PopupMenu()
@@ -32,6 +58,23 @@ PopupMenu::~PopupMenu()
//printf("PopupMenu::~PopupMenu\n");
}
+void PopupMenu::init()
+{
+ // Menus will trigger! Set to make sure our trigger handlers ignore menus.
+ menuAction()->setData(-1);
+
+ //_stayOpen = false;
+ moveDelta = 0;
+
+ #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ timer = new QTimer(this);
+ timer->setInterval(100);
+ timer->setSingleShot(false);
+ connect(this, SIGNAL(hovered(QAction*)), SLOT(popHovered(QAction*)));
+ connect(timer, SIGNAL(timeout()), SLOT(timerHandler()));
+ #endif // POPUP_MENU_DISABLE_AUTO_SCROLL
+}
+
void PopupMenu::clear()
{
QList<QAction*> list = actions();
@@ -41,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;
}
@@ -49,9 +92,32 @@ void PopupMenu::clear()
// Now let QT remove and delete this menu's actions.
QMenu::clear();
+
+ #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ connect(this, SIGNAL(hovered(QAction*)), SLOT(popHovered(QAction*)));
+ connect(timer, SIGNAL(timeout()), SLOT(timerHandler()));
+ #endif // POPUP_MENU_DISABLE_AUTO_SCROLL
}
-QAction* PopupMenu::findActionFromData(QVariant v)
+void PopupMenu::clearAllChecks() const
+{
+ QList<QAction*> list = actions();
+ for(int i = 0; i < list.size(); ++i)
+ {
+ QAction* act = list[i];
+ PopupMenu* menu = static_cast <PopupMenu*>(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<QAction*> list = actions();
for(int i = 0; i < list.size(); ++i)
@@ -60,52 +126,224 @@ QAction* PopupMenu::findActionFromData(QVariant v)
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<Route>() && v.canConvert<Route>())
+ {
+ if(act->data().value<Route>() == v.value<Route>())
+ return act;
+ }
+ else
if(act->data() == v)
return act;
}
return 0;
}
-void PopupMenu::mouseReleaseEvent(QMouseEvent *e)
+bool PopupMenu::event(QEvent* event)
{
- //Q_D(QMenu);
- //if (d->mouseEventTaken(e))
- // return;
+ //printf("PopupMenu::event type:%d\n", event->type());
+
+ switch(event->type())
+ {
+ #ifndef POPUP_MENU_DISABLE_STAY_OPEN
+ case QEvent::MouseButtonDblClick:
+ {
+ if(_stayOpen)
+ //if(_stayOpen && config.popupsDefaultStayOpen)
+ {
+ QMouseEvent* e = static_cast<QMouseEvent*>(event);
+ if(e->modifiers() == Qt::NoModifier)
+ {
+ event->accept();
+ // Convert into a return press, which selects the item and closes the menu.
+ // Note that with double click, it's a press followed by release followed by double click.
+ // That would toggle our item twice eg on->off->on, which is hopefully OK.
+ QKeyEvent ke(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier);
+ //ke.ignore(); // Pass it on
+ return QMenu::event(&ke);
+ }
+ }
+ }
+ break;
+ case QEvent::KeyPress:
+ {
+ if(_stayOpen)
+ //if(_stayOpen && config.popupsDefaultStayOpen)
+ {
+ QKeyEvent* e = static_cast<QKeyEvent*>(event);
+ if(e->modifiers() == Qt::NoModifier && e->key() == Qt::Key_Space)
+ {
+ QAction* act = activeAction();
+ if(act)
+ {
+ act->trigger();
+ event->accept();
+ return true; // We handled it.
+ }
+ }
+ }
+ }
+ break;
+ #endif // POPUP_MENU_DISABLE_STAY_OPEN
+
+ #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ case QEvent::MouseMove:
+ {
+ QMouseEvent* e = static_cast<QMouseEvent*>(event);
+ QPoint globPos = e->globalPos();
+ //QPoint pos = e->pos();
+ 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());
+
+ /*
+ //QAction* action = actionAt(globPos);
+ QAction* action = actionAt(pos);
+ if(action)
+ {
+ 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());
+
+ //action->hover();
+ }
+ */
+
+ if(x() < 0 && globPos.x() <= 0) // If on the very first pixel (or beyond)
+ {
+ moveDelta = 32;
+ if(!timer->isActive())
+ timer->start();
+ event->accept();
+ return true;
+ }
+ else
+ if(x() + width() >= dw && globPos.x() >= (dw -1)) // If on the very last pixel (or beyond)
+ {
+ moveDelta = -32;
+ if(!timer->isActive())
+ timer->start();
+ event->accept();
+ return true;
+ }
+
+ if(timer->isActive())
+ timer->stop();
+
+ //event->accept();
+ //return true;
+
+ event->ignore(); // Pass it on
+ //return QMenu::event(event);
+ }
+ break;
+ #endif // POPUP_MENU_DISABLE_AUTO_SCROLL
+
+ default:
+ break;
+ }
+
+ return QMenu::event(event);
+}
- //d->mouseDown = false;
- //QAction *action = d->actionAt(e->pos());
- QAction *action = actionAt(e->pos());
+#ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+void PopupMenu::timerHandler()
+{
+ // printf("PopupMenu::timerHandler\n");
+
+ //if(!isVisible() || !hasFocus())
+ if(!isVisible())
+ {
+ timer->stop();
+ return;
+ }
+
+ int dw = QApplication::desktop()->width(); // We want the whole thing if multiple monitors.
+ int nx = x() + moveDelta;
+ if(moveDelta < 0 && nx + width() < dw)
+ {
+ timer->stop();
+ nx = dw - width();
+ }
+ else
+ if(moveDelta > 0 && nx > 0)
+ {
+ timer->stop();
+ nx = 0;
+ }
+
+ move(nx, y());
+}
+
+void PopupMenu::popHovered(QAction* action)
+{
+ //timer->stop();
+
+ //moveDelta = 0;
+ if(action)
+ {
+ int dw = QApplication::desktop()->width(); // We want the whole thing if multiple monitors.
- //for(QWidget *caused = this; caused;) {
- // if (QMenu *m = qobject_cast<QMenu*>(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;
- // }
- //}
+ 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());
+ //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);
+ //int x = r.x() + ctrlSubPop->x();
+ if(x() + r.x() < 0)
+ //setGeometry(0, y(), width(), height());
+ //scroll(-x, 0);
+ //move(-r.x() + 32, y()); // Allow some of left column to show so that mouse can move over it.
+ //move(-r.x() + r.width(), y()); // Allow some of left column to show so that mouse can move over it.
+ //moveDelta = x() - r.x() + 32;
+ move(-r.x(), y());
+ else
+ if(r.x() + r.width() + x() > dw)
+ //setGeometry(1200 - r.x() - r.width(), y(), width(), height());
+ //scroll(-x + 1200, 0);
+ //move(dw - r.x() - r.width() - 32, y()); // Allow some of right column to show so that mouse can move over it.
+ //move(dw - r.x(), y()); // Allow some of right column to show so that mouse can move over it.
+ //moveDelta = x() + dw - r.x() - r.width() - 32;
+ move(dw - r.x() - r.width(), y());
+ }
+
+ //if(moveDelta == 0)
+ // timer->stop();
- //if (action && action == d->currentAction) {
- if (action && action == activeAction() && !action->isSeparator() && action->isEnabled())
+}
+#endif // POPUP_MENU_DISABLE_AUTO_SCROLL
+
+void PopupMenu::mouseReleaseEvent(QMouseEvent *e)
+{
+ #ifdef POPUP_MENU_DISABLE_STAY_OPEN
+ QMenu::mouseReleaseEvent(e);
+ return;
+
+ #else
+ // Check for Ctrl to stay open.
+ if(!_stayOpen || (!config.popupsDefaultStayOpen && (e->modifiers() & Qt::ControlModifier) == 0))
{
- //if (action->menu())
- // action->menu()->d_func()->setFirstActionActive();
- //else
- //d->activateAction(action, QAction::Trigger);
- action->activate(QAction::Trigger);
- }
+ QMenu::mouseReleaseEvent(e);
+ return;
+ }
+
+ //printf("PopupMenu::mouseReleaseEvent\n");
+ QAction *action = actionAt(e->pos());
+ if (action && action == activeAction() && !action->isSeparator() && action->isEnabled())
+ 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 c06d51f4..e0e7d26f 100644
--- a/muse2/muse/widgets/popupmenu.h
+++ b/muse2/muse/widgets/popupmenu.h
@@ -6,12 +6,21 @@
// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
//
// PopupMenu sub-class of QMenu created by Tim.
+// (C) Copyright 2010-2011 Tim E. Real (terminator356 A T sourceforge D O T net)
//=========================================================
#ifndef __POPUPMENU_H__
#define __POPUPMENU_H__
+// Just in case Qt ever adds these features natively, we would need to turn our features off!
+//#define POPUP_MENU_DISABLE_STAY_OPEN
+//#define POPUP_MENU_DISABLE_AUTO_SCROLL
+
#include <QMenu>
+#ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ #include <QTimer>
+#endif
+
//#include <QMouseEvent>
//#include <QColumnView>
@@ -19,20 +28,41 @@ class QWidget;
class QMouseEvent;
class QVariant;
class QAction;
+class QEvent;
+//class QTimer;
//class QStandardItemModel;
class PopupMenu : public QMenu
{
Q_OBJECT
+ bool _stayOpen;
+ #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ QTimer* timer;
+ #endif
+ int moveDelta;
+ void init();
+
+ private slots:
+ #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL
+ void popHovered(QAction*);
+ void timerHandler();
+ #endif
+
protected:
void mouseReleaseEvent(QMouseEvent *);
+ bool event(QEvent*);
public:
- PopupMenu(QWidget* parent=0);
+ //PopupMenu();
+ PopupMenu(bool stayOpen);
+ PopupMenu(QWidget* parent=0, bool stayOpen = false);
+ PopupMenu(const QString& title, QWidget* parent = 0, bool stayOpen = false);
~PopupMenu();
void clear();
- QAction* findActionFromData(QVariant);
+ QAction* findActionFromData(const QVariant&) const;
+ bool stayOpen() const { return _stayOpen; }
+ void clearAllChecks() const;
};
diff --git a/muse2/muse/widgets/poslabel.h b/muse2/muse/widgets/poslabel.h
index 29c5297d..7be236ec 100644
--- a/muse2/muse/widgets/poslabel.h
+++ b/muse2/muse/widgets/poslabel.h
@@ -15,10 +15,12 @@
//---------------------------------------------------------
class PosLabel : public QLabel {
+ Q_OBJECT
+
bool _smpte;
unsigned _tickValue;
unsigned _sampleValue;
- Q_OBJECT
+
void updateValue();
diff --git a/muse2/muse/widgets/projectcreateimpl.h b/muse2/muse/widgets/projectcreateimpl.h
index 77547c1a..3ca61e36 100644
--- a/muse2/muse/widgets/projectcreateimpl.h
+++ b/muse2/muse/widgets/projectcreateimpl.h
@@ -6,7 +6,7 @@
class ProjectCreateImpl : public QDialog, Ui::ProjectCreate
{
-Q_OBJECT
+ Q_OBJECT
QString directoryPath;
public:
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("<Mono>", 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("<Stereo>", 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("<Mono>", 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("<Stereo>", 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<Route>(action->data()))
+ {
+ Route aRoute = action->data().value<Route>();
+
+ // 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<int>(action->data()))
+ {
+ int n = action->data().value<int>();
+ if(!_isOutMenu && n == 0)
+ muse->configMidiPorts();
+ return;
+ }
+ }
+ else
+ {
+ AudioTrack* t = (AudioTrack*)_track;
+ RouteList* rl = _isOutMenu ? t->outRoutes() : t->inRoutes();
+
+ if(!qVariantCanConvert<Route>(action->data()))
+ return;
+
+ if(_isOutMenu)
+ {
+ Route dstRoute = action->data().value<Route>();
+ 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<Route>();
+
+ // 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("<none>")));
+
+ 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("<none>"));
+
+ // 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<QString> ol = audioDevice->inputPorts();
+ for(std::list<QString>::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<QString> ol = audioDevice->outputPorts();
+ for(std::list<QString>::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 <QObject>
+
+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/muse/widgets/scrollscale.h b/muse2/muse/widgets/scrollscale.h
index 32043070..67cfe573 100644
--- a/muse2/muse/widgets/scrollscale.h
+++ b/muse2/muse/widgets/scrollscale.h
@@ -21,6 +21,8 @@ class QToolButton;
//---------------------------------------------------------
class ScrollScale : public QWidget {
+ Q_OBJECT
+
QSlider* scale;
QScrollBar* scroll;
int minVal, maxVal;
@@ -38,8 +40,7 @@ class ScrollScale : public QWidget {
double logbase;
virtual void resizeEvent(QResizeEvent*);
- Q_OBJECT
-
+
private slots:
void pageUp();
void pageDown();
diff --git a/muse2/muse/widgets/swidget.h b/muse2/muse/widgets/swidget.h
index c5f4fd6a..45f8cad0 100644
--- a/muse2/muse/widgets/swidget.h
+++ b/muse2/muse/widgets/swidget.h
@@ -17,8 +17,9 @@
//---------------------------------------------------------
class SWidget : public QWidget {
- virtual void resizeEvent(QResizeEvent*);
Q_OBJECT
+ virtual void resizeEvent(QResizeEvent*);
+
signals:
void heightChanged(int);
diff --git a/muse2/muse/widgets/tb1.h b/muse2/muse/widgets/tb1.h
index ff31593f..3e721e74 100644
--- a/muse2/muse/widgets/tb1.h
+++ b/muse2/muse/widgets/tb1.h
@@ -23,14 +23,15 @@ class LabelCombo;
//---------------------------------------------------------
class Toolbar1 : public QToolBar {
+ Q_OBJECT
+
QToolButton* solo;
PosLabel* pos;
PitchLabel* pitch;
LabelCombo* raster;
QTableWidget* rlist;
bool showPitch;
- Q_OBJECT
-
+
private slots:
void _rasterChanged(int);
diff --git a/muse2/muse/widgets/tempolabel.h b/muse2/muse/widgets/tempolabel.h
index 71aeb4b8..69dc1450 100644
--- a/muse2/muse/widgets/tempolabel.h
+++ b/muse2/muse/widgets/tempolabel.h
@@ -16,9 +16,11 @@
//---------------------------------------------------------
class TempoLabel : public QLabel {
+ Q_OBJECT
+
double _value;
- Q_OBJECT
+
protected:
QSize sizeHint() const;
diff --git a/muse2/muse/widgets/tools.h b/muse2/muse/widgets/tools.h
index be479a50..2116b958 100644
--- a/muse2/muse/widgets/tools.h
+++ b/muse2/muse/widgets/tools.h
@@ -46,6 +46,7 @@ extern ToolB toolList[];
class EditToolBar : public QToolBar {
Q_OBJECT
+
Action** actions;
int nactions;
diff --git a/muse2/muse/widgets/unusedwavefiles.h b/muse2/muse/widgets/unusedwavefiles.h
index fd1f524c..e28754de 100644
--- a/muse2/muse/widgets/unusedwavefiles.h
+++ b/muse2/muse/widgets/unusedwavefiles.h
@@ -10,6 +10,7 @@ namespace Ui {
class UnusedWaveFiles : public QDialog
{
Q_OBJECT
+
QStringList allWaveFiles;
public:
explicit UnusedWaveFiles(QWidget *parent = 0);
diff --git a/muse2/muse/widgets/verticalmeter.h b/muse2/muse/widgets/verticalmeter.h
index 699be1e5..facc8b8c 100644
--- a/muse2/muse/widgets/verticalmeter.h
+++ b/muse2/muse/widgets/verticalmeter.h
@@ -17,6 +17,8 @@ class QMouseEvent;
class QPainter;
class VerticalMeter : public Meter {
+ Q_OBJECT
+
private:
MeterType mtype;
bool overflow;
@@ -27,7 +29,7 @@ class VerticalMeter : public Meter {
void drawVU(QPainter& p, int, int, int);
- Q_OBJECT
+
void paintEvent(QPaintEvent*);
void resizeEvent(QResizeEvent*);
diff --git a/muse2/muse/widgets/view.h b/muse2/muse/widgets/view.h
index f8b0c90f..f53c4c72 100644
--- a/muse2/muse/widgets/view.h
+++ b/muse2/muse/widgets/view.h
@@ -24,12 +24,14 @@ class QResizeEvent;
//---------------------------------------------------------
class View : public QWidget {
+ Q_OBJECT
+
QPixmap pm; // for double buffering
bool pmValid;
QPixmap bgPixmap; // background Pixmap
QBrush brush;
bool _virt;
- Q_OBJECT
+
protected:
int xorg;
diff --git a/muse2/muse/widgets/visibletracks.cpp b/muse2/muse/widgets/visibletracks.cpp
index e261c274..f6acf206 100644
--- a/muse2/muse/widgets/visibletracks.cpp
+++ b/muse2/muse/widgets/visibletracks.cpp
@@ -87,7 +87,7 @@ void VisibleTracks::updateVisibleTracksButtons()
void VisibleTracks::visibilityChanged(QAction* action)
{
- printf("update visibility\n");
+// printf("update visibility\n");
switch (((Action*)action)->id()) {
case 0:
WaveTrack::setVisible(action->isChecked());