diff options
author | Florian Jung <flo@windfisch.org> | 2011-12-21 17:39:57 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2011-12-21 17:39:57 +0000 |
commit | 1057d7190242cdf9248671b316a398db805f5f56 (patch) | |
tree | ab50268a7db2f80cfb45a7ad6578fe735ab84ce5 /muse2/muse | |
parent | 9977c7114089b8708d310268833b83343caa0fd1 (diff) | |
parent | c36a5508aa42e596b005425208054af9a60734b4 (diff) |
merged with trunk (that is, pulled the fixes from release_2_0)
only quickly tested, seems okay on the first glance
Diffstat (limited to 'muse2/muse')
149 files changed, 5493 insertions, 3880 deletions
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index 386cf226..c71e23fc 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -4,6 +4,7 @@ // $Id: app.cpp,v 1.113.2.68 2009/12/21 14:51:51 spamatica Exp $ // // (C) Copyright 1999-2011 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -33,6 +34,8 @@ #include <QProgressDialog> #include <QMdiArea> #include <QMdiSubWindow> +#include <QSocketNotifier> +#include <QString> #include <iostream> @@ -55,6 +58,7 @@ #include "filedialog.h" #include "gconfig.h" #include "gui.h" +#include "helper.h" #include "icons.h" #include "instruments/editinstrument.h" #include "listedit.h" @@ -84,8 +88,11 @@ extern void exitJackAudio(); extern void exitDummyAudio(); extern void exitOSC(); extern void exitMidiAlsa(); -} +extern void initMidiSequencer(); +extern void initAudio(); +extern void initAudioPrefetch(); +} namespace MusEGui { @@ -93,31 +100,13 @@ namespace MusEGui { static pthread_t watchdogThread; //ErrorHandler *error; -static const char* fileOpenText = - QT_TRANSLATE_NOOP("@default", "Click this button to open a <em>new song</em>.<br>" - "You can also select the <b>Open command</b> from the File menu."); -static const char* fileSaveText = - QT_TRANSLATE_NOOP("@default", "Click this button to save the song you are " - "editing. You will be prompted for a file name.\n" - "You can also select the Save command from the File menu."); -static const char* fileNewText = QT_TRANSLATE_NOOP("@default", "Create New Song"); - -static const char* infoLoopButton = QT_TRANSLATE_NOOP("@default", "loop between left mark and right mark"); -static const char* infoPunchinButton = QT_TRANSLATE_NOOP("@default", "record starts at left mark"); -static const char* infoPunchoutButton = QT_TRANSLATE_NOOP("@default", "record stops at right mark"); -static const char* infoStartButton = QT_TRANSLATE_NOOP("@default", "rewind to start position"); -static const char* infoRewindButton = QT_TRANSLATE_NOOP("@default", "rewind current position"); -static const char* infoForwardButton = QT_TRANSLATE_NOOP("@default", "move current position"); -static const char* infoStopButton = QT_TRANSLATE_NOOP("@default", "stop sequencer"); -static const char* infoPlayButton = QT_TRANSLATE_NOOP("@default", "start sequencer play"); -static const char* infoRecordButton = QT_TRANSLATE_NOOP("@default", "to record press record and then play"); -static const char* infoPanicButton = QT_TRANSLATE_NOOP("@default", "send note off to all midi channels"); #define PROJECT_LIST_LEN 6 static QString* projectList[PROJECT_LIST_LEN]; #ifdef HAVE_LASH #include <lash/lash.h> +#include <lo/lo_osc_types.h> lash_client_t * lash_client = 0; extern snd_seq_t * alsaSeq; #endif /* HAVE_LASH */ @@ -189,14 +178,7 @@ bool MusE::seqStart() if(MusEGlobal::realTimeScheduling) { { - //pfprio = MusEGlobal::realTimePriority - 5; - // p3.3.40 pfprio = MusEGlobal::realTimePriority + 1; - - //midiprio = MusEGlobal::realTimePriority - 2; - // p3.3.37 - //midiprio = MusEGlobal::realTimePriority + 1; - // p3.3.40 midiprio = MusEGlobal::realTimePriority + 2; } } @@ -216,9 +198,6 @@ bool MusE::seqStart() MusEGlobal::audioPrefetch->msgSeek(0, true); // force - //MusEGlobal::midiSeqRunning = !midiSeq->start(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0); - // Changed by Tim. p3.3.22 - //MusEGlobal::midiSeq->start(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0); MusEGlobal::midiSeq->start(midiprio); int counter=0; @@ -242,7 +221,7 @@ bool MusE::seqStart() } return true; } - + //--------------------------------------------------------- // stop //--------------------------------------------------------- @@ -276,6 +255,7 @@ bool MusE::seqRestart() } seqStop(); } + if(!seqStart()) return false; @@ -317,7 +297,7 @@ void addProject(const QString& name) //--------------------------------------------------------- //MusE::MusE(int argc, char** argv) : QMainWindow(0, "mainwindow") -MusE::MusE(int argc, char** argv) : QMainWindow() +MusE::MusE(int /*argc*/, char** /*argv*/) : QMainWindow() { // By T356. For LADSPA plugins in plugin.cpp // QWidgetFactory::addWidgetFactory( new PluginWidgetFactory ); ddskrjo @@ -351,6 +331,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow() progress = 0; activeTopWin = NULL; currentMenuSharingTopwin = NULL; + waitingForTopwin = NULL; appName = QString("MusE"); setWindowTitle(appName); @@ -364,8 +345,6 @@ MusE::MusE(int argc, char** argv) : QMainWindow() MusEGlobal::heartBeatTimer = new QTimer(this); MusEGlobal::heartBeatTimer->setObjectName("timer"); connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), MusEGlobal::song, SLOT(beat())); - - connect(this, SIGNAL(activeTopWinChanged(MusEGui::TopWin*)), SLOT(activeTopWinChangedSlot(MusEGui::TopWin*))); #ifdef ENABLE_PYTHON @@ -411,21 +390,21 @@ MusE::MusE(int argc, char** argv) : QMainWindow() tr("Loop"), MusEGlobal::transportAction); MusEGlobal::loopAction->setCheckable(true); - MusEGlobal::loopAction->setWhatsThis(tr(infoLoopButton)); + MusEGlobal::loopAction->setWhatsThis(tr("loop between left mark and right mark")); connect(MusEGlobal::loopAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setLoop(bool))); MusEGlobal::punchinAction = new QAction(QIcon(*MusEGui::punchin1Icon), tr("Punchin"), MusEGlobal::transportAction); MusEGlobal::punchinAction->setCheckable(true); - MusEGlobal::punchinAction->setWhatsThis(tr(infoPunchinButton)); + MusEGlobal::punchinAction->setWhatsThis(tr("record starts at left mark")); connect(MusEGlobal::punchinAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setPunchin(bool))); MusEGlobal::punchoutAction = new QAction(QIcon(*MusEGui::punchout1Icon), tr("Punchout"), MusEGlobal::transportAction); MusEGlobal::punchoutAction->setCheckable(true); - MusEGlobal::punchoutAction->setWhatsThis(tr(infoPunchoutButton)); + MusEGlobal::punchoutAction->setWhatsThis(tr("record stops at right mark")); connect(MusEGlobal::punchoutAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setPunchout(bool))); QAction *tseparator = new QAction(this); @@ -435,26 +414,26 @@ MusE::MusE(int argc, char** argv) : QMainWindow() MusEGlobal::startAction = new QAction(QIcon(*MusEGui::startIcon), tr("Start"), MusEGlobal::transportAction); - MusEGlobal::startAction->setWhatsThis(tr(infoStartButton)); + MusEGlobal::startAction->setWhatsThis(tr("rewind to start position")); connect(MusEGlobal::startAction, SIGNAL(activated()), MusEGlobal::song, SLOT(rewindStart())); MusEGlobal::rewindAction = new QAction(QIcon(*MusEGui::frewindIcon), tr("Rewind"), MusEGlobal::transportAction); - MusEGlobal::rewindAction->setWhatsThis(tr(infoRewindButton)); + MusEGlobal::rewindAction->setWhatsThis(tr("rewind current position")); connect(MusEGlobal::rewindAction, SIGNAL(activated()), MusEGlobal::song, SLOT(rewind())); MusEGlobal::forwardAction = new QAction(QIcon(*MusEGui::fforwardIcon), tr("Forward"), MusEGlobal::transportAction); - MusEGlobal::forwardAction->setWhatsThis(tr(infoForwardButton)); + MusEGlobal::forwardAction->setWhatsThis(tr("move current position")); connect(MusEGlobal::forwardAction, SIGNAL(activated()), MusEGlobal::song, SLOT(forward())); MusEGlobal::stopAction = new QAction(QIcon(*MusEGui::stopIcon), tr("Stop"), MusEGlobal::transportAction); MusEGlobal::stopAction->setCheckable(true); - MusEGlobal::stopAction->setWhatsThis(tr(infoStopButton)); + MusEGlobal::stopAction->setWhatsThis(tr("stop sequencer")); MusEGlobal::stopAction->setChecked(true); connect(MusEGlobal::stopAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setStop(bool))); @@ -462,23 +441,23 @@ MusE::MusE(int argc, char** argv) : QMainWindow() tr("Play"), MusEGlobal::transportAction); MusEGlobal::playAction->setCheckable(true); - MusEGlobal::playAction->setWhatsThis(tr(infoPlayButton)); + MusEGlobal::playAction->setWhatsThis(tr("start sequencer play")); MusEGlobal::playAction->setChecked(false); connect(MusEGlobal::playAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setPlay(bool))); MusEGlobal::recordAction = new QAction(QIcon(*MusEGui::recordIcon), tr("Record"), MusEGlobal::transportAction); MusEGlobal::recordAction->setCheckable(true); - MusEGlobal::recordAction->setWhatsThis(tr(infoRecordButton)); + MusEGlobal::recordAction->setWhatsThis(tr("to record press record and then play")); connect(MusEGlobal::recordAction, SIGNAL(toggled(bool)), MusEGlobal::song, SLOT(setRecord(bool))); MusEGlobal::panicAction = new QAction(QIcon(*MusEGui::panicIcon), tr("Panic"), this); - MusEGlobal::panicAction->setWhatsThis(tr(infoPanicButton)); + MusEGlobal::panicAction->setWhatsThis(tr("send note off to all midi channels")); connect(MusEGlobal::panicAction, SIGNAL(activated()), MusEGlobal::song, SLOT(panic())); - MusECore::initMidiInstruments(); + MusECore::initMidiInstruments(); MusECore::initMidiPorts(); MusECore::initMidiDevices(); @@ -486,20 +465,26 @@ MusE::MusE(int argc, char** argv) : QMainWindow() //-------- File Actions fileNewAction = new QAction(QIcon(*MusEGui::filenewIcon), tr("&New"), this); - fileNewAction->setToolTip(tr(fileNewText)); - fileNewAction->setWhatsThis(tr(fileNewText)); + fileNewAction->setToolTip(tr("Create New Song")); + fileNewAction->setWhatsThis(tr("Create New Song")); fileOpenAction = new QAction(QIcon(*MusEGui::openIcon), tr("&Open"), this); - fileOpenAction->setToolTip(tr(fileOpenText)); - fileOpenAction->setWhatsThis(tr(fileOpenText)); + fileOpenAction->setToolTip(tr("Click this button to open a <em>new song</em>.<br>" + "You can also select the <b>Open command</b> from the File menu.")); + fileOpenAction->setWhatsThis(tr("Click this button to open a <em>new song</em>.<br>" + "You can also select the <b>Open command</b> from the File menu.")); openRecent = new QMenu(tr("Open &Recent"), this); fileSaveAction = new QAction(QIcon(*MusEGui::saveIcon), tr("&Save"), this); - fileSaveAction->setToolTip(tr(fileSaveText)); - fileSaveAction->setWhatsThis(tr(fileSaveText)); + fileSaveAction->setToolTip(tr("Click this button to save the song you are " + "editing. You will be prompted for a file name.\n" + "You can also select the Save command from the File menu.")); + fileSaveAction->setWhatsThis(tr("Click this button to save the song you are " + "editing. You will be prompted for a file name.\n" + "You can also select the Save command from the File menu.")); fileSaveAsAction = new QAction(tr("Save &As"), this); @@ -718,7 +703,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow() //rlimit lim; //getrlimit(RLIMIT_RTPRIO, &lim); //printf("RLIMIT_RTPRIO soft:%d hard:%d\n", lim.rlim_cur, lim.rlim_max); // Reported 80, 80 even with non-RT kernel. - + if (MusEGlobal::realTimePriority < sched_get_priority_min(SCHED_FIFO)) MusEGlobal::realTimePriority = sched_get_priority_min(SCHED_FIFO); else if (MusEGlobal::realTimePriority > sched_get_priority_max(SCHED_FIFO)) @@ -733,18 +718,19 @@ MusE::MusE(int argc, char** argv) : QMainWindow() MusEGlobal::midiRTPrioOverride = sched_get_priority_max(SCHED_FIFO); } - // Changed by Tim. p3.3.17 - //MusEGlobal::midiSeq = new MusECore::MidiSeq(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0, "Midi"); - MusEGlobal::midiSeq = new MusECore::MidiSeq("Midi"); - MusEGlobal::audio = new MusECore::Audio(); - //MusEGlobal::audioPrefetch = new MusECore::AudioPrefetch(0, "Disc"); - MusEGlobal::audioPrefetch = new MusECore::AudioPrefetch("Prefetch"); - + MusECore::initMidiSequencer(); + MusECore::initAudio(); + + // Moved here from Audio::Audio + QSocketNotifier* ss = new QSocketNotifier(MusEGlobal::audio->getFromThreadFdr(), QSocketNotifier::Read, this); + connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int))); + + MusECore::initAudioPrefetch(); + //--------------------------------------------------- // Popups //--------------------------------------------------- - // when adding a menu to the main window, remember adding it to // either the leadingMenus or trailingMenus list! // also do NOT use menuBar()->addMenu(QString&), but ALWAYS @@ -973,6 +959,11 @@ MusE::MusE(int argc, char** argv) : QMainWindow() transport = new MusEGui::Transport(this, "transport"); bigtime = 0; + MusEGlobal::song->blockSignals(false); + + // Load start song moved to main.cpp p4.0.41 REMOVE Tim. + /* + //--------------------------------------------------- // load project // if no songname entered on command line: @@ -987,7 +978,8 @@ MusE::MusE(int argc, char** argv) : QMainWindow() name = argv[0]; else if (MusEGlobal::config.startMode == 0) { if (argc < 2) - name = projectList[0] ? *projectList[0] : QString("untitled"); + //name = projectList[0] ? *projectList[0] : QString("untitled"); + name = projectList[0] ? *projectList[0] : MusEGui::getUniqueUntitledName(); // p4.0.40 else name = argv[0]; printf("starting with selected song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); @@ -1001,19 +993,47 @@ MusE::MusE(int argc, char** argv) : QMainWindow() printf("starting with pre configured song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); name = MusEGlobal::config.startSong; } - MusEGlobal::song->blockSignals(false); - loadProjectFile(name, useTemplate, true); - + + // loadProjectFile(name, useTemplate, true); //commented out by flo: see below (*) + */ + changeConfig(false); QSettings settings("MusE", "MusE-qt"); restoreGeometry(settings.value("MusE/geometry").toByteArray()); //restoreState(settings.value("MusE/windowState").toByteArray()); - MusEGlobal::song->update(); - - updateWindowMenu(); + MusEGlobal::song->update(); // commented out by flo: will be done by the below (*) + updateWindowMenu(); // same here + + // Load start song moved to main.cpp p4.0.41 REMOVE Tim. + /* + + // this is (*). + // this is a really hackish workaround for the loading-on-startup problem. + // i have absolutely no idea WHY it breaks when using loadProjectFile() + // above, but it does on my machine (it doesn't on others!). + // the problem can be worked around by delaying loading the song file. + // i use hackishSongOpenTimer for this, which calls after 10ms a slot + // which then does the actual loadProjectFile() call. + // FIXME: please, if anyone finds the real problem, FIX it and + // remove that dirty, dirty workaround! + hackishSongOpenFilename=name; + hackishSongOpenUseTemplate=useTemplate; + hackishSongOpenTimer=new QTimer(this); + hackishSongOpenTimer->setInterval(10); + hackishSongOpenTimer->setSingleShot(true); + connect(hackishSongOpenTimer, SIGNAL(timeout()), this, SLOT(hackishSongOpenTimerTimeout())); + hackishSongOpenTimer->start(); + */ } +// Load start song moved to main.cpp p4.0.41 REMOVE Tim. +//void MusE::hackishSongOpenTimerTimeout() +//{ + ///loadProjectFile(hackishSongOpenFilename, hackishSongOpenUseTemplate, true); + //loadProjectFile(hackishSongOpenFilename, hackishSongOpenUseTemplate, !hackishSongOpenUseTemplate); +//} + MusE::~MusE() { } @@ -1027,6 +1047,44 @@ void MusE::setHeartBeat() MusEGlobal::heartBeatTimer->start(1000/MusEGlobal::config.guiRefresh); } +//--------------------------------------------------- +// loadDefaultSong +// if no songname entered on command line: +// startMode: 0 - load last song +// 1 - load default template +// 2 - load configured start song +//--------------------------------------------------- + +void MusE::loadDefaultSong(int argc, char** argv) +{ + QString name; + bool useTemplate = false; + if (argc >= 2) + name = argv[0]; + else if (MusEGlobal::config.startMode == 0) { + if (argc < 2) + //name = projectList[0] ? *projectList[0] : QString("untitled"); + name = projectList[0] ? *projectList[0] : MusEGui::getUniqueUntitledName(); // p4.0.40 + else + name = argv[0]; + printf("starting with selected song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); + } + else if (MusEGlobal::config.startMode == 1) { + printf("starting with default template\n"); + name = MusEGlobal::museGlobalShare + QString("/templates/default.med"); + useTemplate = true; + } + else if (MusEGlobal::config.startMode == 2) { + printf("starting with pre configured song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); + name = MusEGlobal::config.startSong; + } + //loadProjectFile(name, useTemplate, true); + loadProjectFile(name, useTemplate, !useTemplate); + + //MusEGlobal::song->update(); + //updateWindowMenu(); +} + //--------------------------------------------------------- // resetDevices //--------------------------------------------------------- @@ -1168,7 +1226,8 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll QApplication::restoreOverrideCursor(); return; } - project.setFile("untitled"); + //project.setFile("untitled"); + project.setFile(MusEGui::getUniqueUntitledName()); // p4.0.40 MusEGlobal::museProject = MusEGlobal::museProjectInitPath; } else { @@ -1226,7 +1285,8 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll } if (!songTemplate) { addProject(project.absoluteFilePath()); - setWindowTitle(QString("MusE: Song: ") + project.completeBaseName()); + //setWindowTitle(QString("MusE: Song: ") + project.completeBaseName()); + setWindowTitle(QString("MusE: Song: ") + MusEGui::projectTitleFromFilename(project.absoluteFilePath())); } MusEGlobal::song->dirty = false; progress->setValue(30); @@ -1248,7 +1308,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll // set the geometry if the mixer has already been created. if(mixer1) { - //if(mixer1->geometry().size() != MusEGlobal::config.mixer1.geometry.size()) // p3.3.53 Moved below + //if(mixer1->geometry().size() != MusEGlobal::config.mixer1.geometry.size()) // Moved below // mixer1->resize(MusEGlobal::config.mixer1.geometry.size()); if(mixer1->geometry().topLeft() != MusEGlobal::config.mixer1.geometry.topLeft()) @@ -1256,7 +1316,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll } if(mixer2) { - //if(mixer2->geometry().size() != MusEGlobal::config.mixer2.geometry.size()) // p3.3.53 Moved below + //if(mixer2->geometry().size() != MusEGlobal::config.mixer2.geometry.size()) // Moved below // mixer2->resize(MusEGlobal::config.mixer2.geometry.size()); if(mixer2->geometry().topLeft() != MusEGlobal::config.mixer2.geometry.topLeft()) @@ -1285,7 +1345,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll arrangerView->scoreNamingChanged(); // inform the score menus about the new scores and their names progress->setValue(50); - // p3.3.53 Try this AFTER the song update above which does a mixer update... Tested OK - mixers resize properly now. + // Try this AFTER the song update above which does a mixer update... Tested OK - mixers resize properly now. if (loadAll) { if(mixer1) @@ -1348,10 +1408,13 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll void MusE::setUntitledProject() { setConfigDefaults(); - QString name("untitled"); + //QString name("untitled"); + QString name(MusEGui::getUniqueUntitledName()); // p4.0.40 + MusEGlobal::museProject = "./"; //QFileInfo(name).absolutePath(); project.setFile(name); - setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(name))); } //--------------------------------------------------------- @@ -1403,14 +1466,14 @@ void MusE::loadTemplate() if (!fn.isEmpty()) { // MusEGlobal::museProject = QFileInfo(fn).absolutePath(); - loadProjectFile(fn, true, true); + //loadProjectFile(fn, true, true); // With templates, don't clear midi ports. // Any named ports in the template file are useless since they likely // would not be found on other users' machines. // So keep whatever the user currently has set up for ports. // Note that this will also keep the current window configurations etc. // but actually that's also probably a good thing. p4.0.17 Tim. TESTING: Maybe some problems... - //loadProjectFile(fn, true, false); + loadProjectFile(fn, true, false); setUntitledProject(); } @@ -1422,7 +1485,11 @@ void MusE::loadTemplate() bool MusE::save() { - if (project.completeBaseName() == "untitled") + //if (project.completeBaseName() == "untitled") // p4.0.40 Must catch "untitled 1" "untitled 2" etc + //if (MusEGui::projectTitleFromFilename(project.absoluteFilePath()) == "untitled") + //if (MusEGui::projectTitleFromFilename(project.absoluteFilePath()) == MusEGui::getUniqueUntitledName()) + ///if (project.absoluteFilePath() == MusEGui::getUniqueUntitledName()) + if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath ) return saveAs(); else return save(project.filePath(), false); @@ -1554,7 +1621,7 @@ void MusE::closeEvent(QCloseEvent* event) MusECore::exitMetronome(); // 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 + // Even though it is a child of MusE, it just passes MusE onto the underlying PopupMenus. if(routingPopupMenu) delete routingPopupMenu; #if 0 @@ -1584,7 +1651,7 @@ void MusE::closeEvent(QCloseEvent* event) } #ifdef HAVE_LASH - // Disconnect gracefully from LASH. Tim. p3.3.14 + // Disconnect gracefully from LASH. if(lash_client) { if(MusEGlobal::debugMsg) @@ -1602,7 +1669,6 @@ void MusE::closeEvent(QCloseEvent* event) printf("MusE: Exiting OSC\n"); MusECore::exitOSC(); - // p3.3.47 delete MusEGlobal::audioPrefetch; delete MusEGlobal::audio; delete MusEGlobal::midiSeq; @@ -1631,8 +1697,8 @@ void MusE::showMarker(bool flag) markerView = new MusEGui::MarkerView(this); connect(markerView, SIGNAL(closed()), SLOT(markerClosed())); - toplevels.push_back(markerView); markerView->show(); + toplevels.push_back(markerView); } markerView->setVisible(flag); viewMarkerAction->setChecked(flag); @@ -1654,6 +1720,20 @@ void MusE::markerClosed() setCurrentMenuSharingTopwin(NULL); updateWindowMenu(); + + // focus the last activated topwin which is not the marker view + QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); + for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) + if ((*lit)->isVisible() && (*lit)->widget() != markerView) + { + if (MusEGlobal::debugMsg) + printf("bringing '%s' to front instead of closed arranger window\n",(*lit)->widget()->windowTitle().toAscii().data()); + + bringToFront((*lit)->widget()); + + break; + } + } //--------------------------------------------------------- @@ -1687,6 +1767,20 @@ void MusE::arrangerClosed() { viewArrangerAction->setChecked(false); updateWindowMenu(); + + // focus the last activated topwin which is not the arranger view + QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); + for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) + if ((*lit)->isVisible() && (*lit)->widget() != arrangerView) + { + if (MusEGlobal::debugMsg) + printf("bringing '%s' to front instead of closed arranger window\n",(*lit)->widget()->windowTitle().toAscii().data()); + + bringToFront((*lit)->widget()); + + break; + } + } //--------------------------------------------------------- @@ -1728,7 +1822,7 @@ MusEGui::RoutePopupMenu* MusE::getRoutingPopupMenu() bool MusE::saveAs() { QString name; - if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath ) { + //if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath ) // Use project dialog always now. if (MusEGlobal::config.useProjectSaveDialog) { MusEGui::ProjectCreateImpl pci(MusEGlobal::muse); if (pci.exec() == QDialog::Rejected) { @@ -1749,10 +1843,11 @@ bool MusE::saveAs() QMessageBox::warning(this,"Path error","Can't create project path", QMessageBox::Ok); return false; } - } - else { - name = MusEGui::getSaveFileName(QString(""), MusEGlobal::med_file_save_pattern, this, tr("MusE: Save As")); - } + //} + //else { + // name = MusEGui::getSaveFileName(QString(""), MusEGlobal::med_file_save_pattern, this, tr("MusE: Save As")); + //} + bool ok = false; if (!name.isEmpty()) { QString tempOldProj = MusEGlobal::museProject; @@ -1760,7 +1855,8 @@ bool MusE::saveAs() ok = save(name, true); if (ok) { project.setFile(name); - setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(name))); addProject(name); } else @@ -1843,9 +1939,9 @@ void MusE::openInScoreEdit(MusEGui::ScoreEdit* destination, MusECore::PartList* if (destination==NULL) // if no destination given, create a new one { destination = new MusEGui::ScoreEdit(this, 0, _arranger->cursorValue()); - destination->show(); toplevels.push_back(destination); - connect(destination, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + destination->show(); + connect(destination, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); connect(destination, SIGNAL(name_changed()), arrangerView, SLOT(scoreNamingChanged())); //connect(muse, SIGNAL(configChanged()), destination, SLOT(config_changed())); //commented out by flo, because the ScoreEditor connects to all @@ -1879,11 +1975,11 @@ void MusE::startPianoroll(MusECore::PartList* pl, bool showDefaultCtrls) { MusEGui::PianoRoll* pianoroll = new MusEGui::PianoRoll(pl, this, 0, _arranger->cursorValue()); - if(showDefaultCtrls) // p4.0.12 + if(showDefaultCtrls) pianoroll->addCtrl(); - pianoroll->show(); toplevels.push_back(pianoroll); - connect(pianoroll, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + pianoroll->show(); + connect(pianoroll, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); connect(MusEGlobal::muse, SIGNAL(configChanged()), pianoroll, SLOT(configChanged())); updateWindowMenu(); } @@ -1903,9 +1999,9 @@ void MusE::startListEditor() void MusE::startListEditor(MusECore::PartList* pl) { MusEGui::ListEdit* listEditor = new MusEGui::ListEdit(pl); - listEditor->show(); toplevels.push_back(listEditor); - connect(listEditor, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + listEditor->show(); + connect(listEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); connect(MusEGlobal::muse,SIGNAL(configChanged()), listEditor, SLOT(configChanged())); updateWindowMenu(); } @@ -1917,9 +2013,9 @@ void MusE::startListEditor(MusECore::PartList* pl) void MusE::startMasterEditor() { MusEGui::MasterEdit* masterEditor = new MusEGui::MasterEdit(); - masterEditor->show(); toplevels.push_back(masterEditor); - connect(masterEditor, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + masterEditor->show(); + connect(masterEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); updateWindowMenu(); } @@ -1930,9 +2026,9 @@ void MusE::startMasterEditor() void MusE::startLMasterEditor() { MusEGui::LMaster* lmaster = new MusEGui::LMaster(); - lmaster->show(); toplevels.push_back(lmaster); - connect(lmaster, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + lmaster->show(); + connect(lmaster, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); connect(MusEGlobal::muse, SIGNAL(configChanged()), lmaster, SLOT(configChanged())); updateWindowMenu(); } @@ -1952,11 +2048,11 @@ void MusE::startDrumEditor() void MusE::startDrumEditor(MusECore::PartList* pl, bool showDefaultCtrls) { MusEGui::DrumEdit* drumEditor = new MusEGui::DrumEdit(pl, this, 0, _arranger->cursorValue()); - if(showDefaultCtrls) // p4.0.12 + if(showDefaultCtrls) drumEditor->addCtrl(); - drumEditor->show(); toplevels.push_back(drumEditor); - connect(drumEditor, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + drumEditor->show(); + connect(drumEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); connect(MusEGlobal::muse, SIGNAL(configChanged()), drumEditor, SLOT(configChanged())); updateWindowMenu(); } @@ -1979,9 +2075,9 @@ void MusE::startWaveEditor(MusECore::PartList* pl) { MusEGui::WaveEdit* waveEditor = new MusEGui::WaveEdit(pl); waveEditor->show(); - connect(MusEGlobal::muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged())); toplevels.push_back(waveEditor); - connect(waveEditor, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + connect(MusEGlobal::muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged())); + connect(waveEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); updateWindowMenu(); } @@ -2039,7 +2135,7 @@ void MusE::startClipList(bool checked) //clipListEdit = new ClipListEdit(); clipListEdit = new MusEGui::ClipListEdit(this); toplevels.push_back(clipListEdit); - connect(clipListEdit, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); + connect(clipListEdit, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); } clipListEdit->show(); viewCliplistAction->setChecked(checked); @@ -2077,7 +2173,11 @@ void MusE::selectProject(QAction* act) if (!act) return; int id = act->data().toInt(); - assert(id < PROJECT_LIST_LEN); + if (!(id < PROJECT_LIST_LEN)) + { + printf("THIS SHOULD NEVER HAPPEN: id(%i) < PROJECT_LIST_LEN(%i) in MusE::selectProject!\n",id, PROJECT_LIST_LEN); + return; + } QString* name = projectList[id]; if (name == 0) return; @@ -2085,10 +2185,10 @@ void MusE::selectProject(QAction* act) } //--------------------------------------------------------- -// toplevelDeleted +// toplevelDeleting //--------------------------------------------------------- -void MusE::toplevelDeleted(MusEGui::TopWin* tl) +void MusE::toplevelDeleting(MusEGui::TopWin* tl) { for (MusEGui::iToplevel i = toplevels.begin(); i != toplevels.end(); ++i) { if (*i == tl) { @@ -2097,6 +2197,19 @@ void MusE::toplevelDeleted(MusEGui::TopWin* tl) { activeTopWin=NULL; emit activeTopWinChanged(NULL); + + // focus the last activated topwin which is not the deleting one + QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); + for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) + if ((*lit)->isVisible() && (*lit)->widget() != tl) + { + if (MusEGlobal::debugMsg) + printf("bringing '%s' to front instead of closed window\n",(*lit)->widget()->windowTitle().toAscii().data()); + + bringToFront((*lit)->widget()); + + break; + } } if (tl == currentMenuSharingTopwin) @@ -2133,19 +2246,16 @@ void MusE::toplevelDeleted(MusEGui::TopWin* tl) case MusEGui::TopWin::TOPLEVELTYPE_LAST_ENTRY: //to avoid a warning break; } - toplevels.erase(i); + toplevels.erase(i); if (mustUpdateScoreMenus) arrangerView->updateScoreMenus(); updateWindowMenu(); return; } } - printf("topLevelDeleted: top level %p not found\n", tl); - //assert(false); + printf("topLevelDeleting: top level %p not found\n", tl); } - - //--------------------------------------------------------- // kbAccel //--------------------------------------------------------- @@ -2180,7 +2290,7 @@ void MusE::kbAccel(int key) MusEGlobal::song->setPlay(true); } - // p4.0.10 Tim. Normally each editor window handles these, to inc by the editor's raster snap value. + // Normally each editor window handles these, to inc by the editor's raster snap value. // But users were asking for a global version - "they don't work when I'm in mixer or transport". // Since no editor claimed the key event, we don't know a specific editor's snap setting, // so adopt a policy where the arranger is the 'main' raster reference, I guess... @@ -2661,7 +2771,8 @@ MusE::lash_idle_cb () int ok = save (ss.toAscii(), false); if (ok) { project.setFile(ss.toAscii()); - setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); + setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(project.absoluteFilePath()))); addProject(ss.toAscii()); MusEGlobal::museProject = QFileInfo(ss.toAscii()).absolutePath(); } @@ -2751,16 +2862,22 @@ again: case MusEGui::TopWin::MASTER: case MusEGui::TopWin::WAVE: case MusEGui::TopWin::LMASTER: - tl->close(); - goto again; - + { + if(tl->isVisible()) // Don't keep trying to close, only if visible. + { + if(!tl->close()) + printf("MusE::clearSong TopWin did not close!\n"); + goto again; + } + } case MusEGui::TopWin::TOPLEVELTYPE_LAST_ENTRY: //to avoid a warning break; } } - microSleep(100000); + microSleep(100000); + _arranger->songIsClearing(); MusEGlobal::song->clear(true, clear_all); - microSleep(100000); + microSleep(100000); return false; } @@ -3077,21 +3194,32 @@ void MusE::focusChanged(QWidget*, QWidget* now) if (currentMenuSharingTopwin && (currentMenuSharingTopwin!=activeTopWin)) currentMenuSharingTopwin->storeInitialState(); - + // if the activated widget is a QMdiSubWindow containing some TopWin + if ( (dynamic_cast<QMdiSubWindow*>(ptr)!=0) && + (dynamic_cast<MusEGui::TopWin*>( ((QMdiSubWindow*)ptr)->widget() )!=0) ) + { + waitingForTopwin=(MusEGui::TopWin*) ((QMdiSubWindow*)ptr)->widget(); + return; + } while (ptr) { + if (MusEGlobal::heavyDebugMsg) + printf("focusChanged: at widget %p with type %s\n",ptr, typeid(*ptr).name()); + if ( (dynamic_cast<MusEGui::TopWin*>(ptr)!=0) || // *ptr is a TopWin or a derived class (ptr==this) ) // the main window is selected break; ptr=dynamic_cast<QWidget*>(ptr->parent()); //in the unlikely case that ptr is a QObject, this returns NULL, which stops the loop } + MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(ptr); // ptr is either NULL, this or the pointer to a TopWin - if (ptr!=this) // if the main win is selected, don't treat that as "none", but also don't handle it + + // if the main win or some deleting topwin is selected, + // don't treat that as "none", but also don't handle it + if (ptr!=this && (!win || !win->deleting()) ) { - MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(ptr); - // now 'win' is either NULL or the pointer to the active TopWin if (win!=activeTopWin) { @@ -3239,6 +3367,26 @@ void MusE::shareMenuAndToolbarChanged(MusEGui::TopWin* win, bool val) } } +void MusE::topwinMenuInited(MusEGui::TopWin* topwin) +{ + if (topwin==NULL) + return; + + if (topwin == waitingForTopwin) + { + if (waitingForTopwin->deleting()) + { + waitingForTopwin=NULL; + } + else + { + activeTopWin=waitingForTopwin; + waitingForTopwin=NULL; + emit activeTopWinChanged(activeTopWin); + } + } +} + void MusE::updateWindowMenu() { bool sep; @@ -3292,6 +3440,8 @@ void MusE::updateWindowMenu() void MusE::bringToFront(QWidget* widget) { MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(widget); + if (!win) return; + if (win->isMdiWin()) { win->show(); @@ -3455,4 +3605,19 @@ void MusE::tileSubWindows() } } +QString MusE::projectTitle() const +{ + return MusEGui::projectTitleFromFilename(project.fileName()); +} + +QString MusE::projectPath() const +{ + return MusEGui::projectPathFromFilename(project.absoluteFilePath()); +} + +QString MusE::projectExtension() const +{ + return MusEGui::projectExtensionFromFilename(project.fileName()); +} + } //namespace MusEGui diff --git a/muse2/muse/app.h b/muse2/muse/app.h index 46e9f99b..184581dc 100644 --- a/muse2/muse/app.h +++ b/muse2/muse/app.h @@ -43,6 +43,7 @@ class QToolBar; class QToolButton; class QProgressDialog; class QMdiArea; +class QTimer; namespace MusECore { class AudioOutput; @@ -91,7 +92,7 @@ class TopWin; class Transport; class VisibleTracks; -#define MENU_ADD_SYNTH_ID_BASE 0x1000 +#define MENU_ADD_SYNTH_ID_BASE 0x8000 //--------------------------------------------------------- @@ -128,6 +129,7 @@ class MusE : public QMainWindow TopWin* activeTopWin; TopWin* currentMenuSharingTopwin; + TopWin* waitingForTopwin; std::list<QToolBar*> requiredToolbars; //always displayed std::list<QToolBar*> optionalToolbars; //only displayed when no toolbar-sharing window is active @@ -213,6 +215,10 @@ class MusE : public QMainWindow MidiTransformerDialog* midiTransformerDialog; QMenu* openRecent; + //QTimer* hackishSongOpenTimer; + //QString hackishSongOpenFilename; + //bool hackishSongOpenUseTemplate; + bool readMidi(FILE*); void read(MusECore::Xml& xml, bool skipConfig, bool isTemplate); void processTrack(MusECore::MidiTrack* track); @@ -327,13 +333,15 @@ class MusE : public QMainWindow void arrangeSubWindowsColumns(); void tileSubWindows(); + //void hackishSongOpenTimerTimeout(); + public slots: bool saveAs(); void bounceToFile(MusECore::AudioOutput* ao = 0); void closeEvent(QCloseEvent*e); void loadProjectFile(const QString&); void loadProjectFile(const QString&, bool songTemplate, bool loadAll); - void toplevelDeleted(MusEGui::TopWin* tl); + void toplevelDeleting(MusEGui::TopWin* tl); void loadTheme(const QString&); void loadStyleSheetFile(const QString&); bool seqRestart(); @@ -371,12 +379,14 @@ class MusE : public QMainWindow void addMdiSubWindow(QMdiSubWindow*); void shareMenuAndToolbarChanged(MusEGui::TopWin*, bool); + void topwinMenuInited(MusEGui::TopWin*); void updateWindowMenu(); public: MusE(int argc, char** argv); ~MusE(); + void loadDefaultSong(int argc, char** argv); Arranger* arranger() const { return _arranger; } QRect configGeometryMain; QProgressDialog *progress; @@ -384,10 +394,13 @@ class MusE : public QMainWindow void kbAccel(int); void changeConfig(bool writeFlag); void seqStop(); - bool seqStart(); + bool seqStart(); void setHeartBeat(); void importController(int, MusECore::MidiPort*, int); QString projectName() { return project.fileName(); } + QString projectTitle() const; + QString projectPath() const; + QString projectExtension() const; QWidget* mixer1Window(); QWidget* mixer2Window(); QWidget* transportWindow(); diff --git a/muse2/muse/arranger/alayout.cpp b/muse2/muse/arranger/alayout.cpp index a892356c..119da498 100644 --- a/muse2/muse/arranger/alayout.cpp +++ b/muse2/muse/arranger/alayout.cpp @@ -117,7 +117,7 @@ void TLLayout::setGeometry(const QRect &rect) QSize s1 = li[1]->sizeHint(); QSize s2 = li[2]->sizeHint(); - QSize s3 = li[3]->sizeHint(); + //QSize s3 = li[3]->sizeHint(); QSize s4 = li[4]->sizeHint(); QSize s5 = li[5]->sizeHint(); diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index 89245d64..cb024070 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -152,7 +152,7 @@ Arranger::Arranger(ArrangerView* parent, const char* name) toolbar->addWidget(cursorPos); const char* rastval[] = { - QT_TRANSLATE_NOOP("@default", "Off"), QT_TRANSLATE_NOOP("@default", "Bar"), "1/2", "1/4", "1/8", "1/16" + QT_TRANSLATE_NOOP("MusEGui::Arranger", "Off"), QT_TRANSLATE_NOOP("MusEGui::Arranger", "Bar"), "1/2", "1/4", "1/8", "1/16" }; label = new QLabel(tr("Snap")); label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); @@ -569,27 +569,40 @@ void Arranger::songChanged(int type) // Is it simply a midi controller value adjustment? Forget it. if(type != SC_MIDI_CONTROLLER) { - unsigned endTick = MusEGlobal::song->len(); - int offset = AL::sigmap.ticksMeasure(endTick); - hscroll->setRange(-offset, endTick + offset); //DEBUG - canvas->setOrigin(-offset, 0); - time->setOrigin(-offset, 0); - - int bar, beat; - unsigned tick; - AL::sigmap.tickValues(endTick, &bar, &beat, &tick); - if (tick || beat) - ++bar; - lenEntry->blockSignals(true); - lenEntry->setValue(bar); - lenEntry->blockSignals(false); - - if(type & SC_SONG_TYPE) // p4.0.7 Tim. + // TEST p4.0.36 Try these, may need more/less. + if(type & ( SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | + SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED)) + { + unsigned endTick = MusEGlobal::song->len(); + int offset = AL::sigmap.ticksMeasure(endTick); + hscroll->setRange(-offset, endTick + offset); //DEBUG + canvas->setOrigin(-offset, 0); + time->setOrigin(-offset, 0); + + int bar, beat; + unsigned tick; + AL::sigmap.tickValues(endTick, &bar, &beat, &tick); + if (tick || beat) + ++bar; + lenEntry->blockSignals(true); + lenEntry->setValue(bar); + lenEntry->blockSignals(false); + } + + if(type & SC_SONG_TYPE) setMode(MusEGlobal::song->mtype()); - trackSelectionChanged(); - canvas->partsChanged(); - typeBox->setCurrentIndex(int(MusEGlobal::song->mtype())); + if(type & SC_SELECTION) // TEST p4.0.36 Try this alone, may need more. + trackSelectionChanged(); + + // Keep this light, partsChanged is a heavy move! TEST p4.0.36 Try these, may need more. + if(type & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | + SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED | + SC_SIG | SC_TEMPO)) // Maybe sig. Requires tempo. + canvas->partsChanged(); + + //typeBox->setCurrentIndex(int(MusEGlobal::song->mtype())); // REMOVE Tim. Redundant. + if (type & SC_SIG) time->redraw(); if (type & SC_TEMPO) @@ -616,6 +629,14 @@ void Arranger::songChanged(int type) } } } + + // TEST p4.0.36 Try this + if(type & ( //SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED | + SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED | + SC_EVENT_INSERTED | SC_EVENT_REMOVED | SC_EVENT_MODIFIED)) //| + //SC_SIG | SC_TEMPO)) // Maybe sig. and tempo. No, moved above. + canvas->redraw(); + } updateTrackInfo(type); diff --git a/muse2/muse/arranger/arranger.h b/muse2/muse/arranger/arranger.h index d4193c01..35a3fe36 100644 --- a/muse2/muse/arranger/arranger.h +++ b/muse2/muse/arranger/arranger.h @@ -187,6 +187,7 @@ class Arranger : public QWidget { int selectionSize() { return canvas->selectionSize(); } void setGlobalTempo(int); void clear(); + void songIsClearing() { canvas->songIsClearing(); } unsigned cursorValue() { return cursVal; } diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp index 51fc3bb0..1bb45863 100644 --- a/muse2/muse/arranger/arrangerview.cpp +++ b/muse2/muse/arranger/arrangerview.cpp @@ -37,7 +37,7 @@ #include <QMessageBox> #include <QMimeData> #include <QPushButton> -#include <QResizeEvent> +//#include <QResizeEvent> #include <QScrollArea> #include <QScrollBar> #include <QSettings> @@ -129,6 +129,7 @@ ArrangerView::ArrangerView(QWidget* parent) connect(muse, SIGNAL(configChanged()), arranger, SLOT(configChanged())); connect(arranger, SIGNAL(setUsedTool(int)), editTools, SLOT(set(int))); connect(arranger, SIGNAL(selectionChanged()), SLOT(selectionChanged())); + connect(MusEGlobal::song, SIGNAL(songChanged(int)), visTracks, SLOT(updateVisibleTracksButtons())); @@ -167,8 +168,8 @@ ArrangerView::ArrangerView(QWidget* parent) scoreSubmenu = new QMenu(tr("Score"), this); scoreSubmenu->setIcon(QIcon(*scoreIconSet)); - scoreAllInOneSubsubmenu = new QMenu(tr("all parts in one staff"), this); - scoreOneStaffPerTrackSubsubmenu = new QMenu(tr("one staff per part"), this); + scoreAllInOneSubsubmenu = new QMenu(tr("all tracks in one staff"), this); + scoreOneStaffPerTrackSubsubmenu = new QMenu(tr("one staff per track"), this); scoreSubmenu->addMenu(scoreAllInOneSubsubmenu); scoreSubmenu->addMenu(scoreOneStaffPerTrackSubsubmenu); @@ -193,6 +194,10 @@ ArrangerView::ArrangerView(QWidget* parent) strGlobalInsertAction = new QAction(tr("Global Insert"), this); strGlobalSplitAction = new QAction(tr("Global Split"), this); + strGlobalCutSelAction = new QAction(tr("Global Cut - selected tracks"), this); + strGlobalInsertSelAction = new QAction(tr("Global Insert - selected tracks"), this); + strGlobalSplitSelAction = new QAction(tr("Global Split - selected tracks"), this); + //------------------------------------------------------------- @@ -246,7 +251,11 @@ ArrangerView::ArrangerView(QWidget* parent) menuStructure->addAction(strGlobalCutAction); menuStructure->addAction(strGlobalInsertAction); menuStructure->addAction(strGlobalSplitAction); - + menuStructure->addSeparator(); + menuStructure->addAction(strGlobalCutSelAction); + menuStructure->addAction(strGlobalInsertSelAction); + menuStructure->addAction(strGlobalSplitSelAction); + QMenu* functions_menu = menuBar()->addMenu(tr("Functions")); @@ -341,6 +350,9 @@ ArrangerView::ArrangerView(QWidget* parent) connect(strGlobalCutAction, SIGNAL(activated()), SLOT(globalCut())); connect(strGlobalInsertAction, SIGNAL(activated()), SLOT(globalInsert())); connect(strGlobalSplitAction, SIGNAL(activated()), SLOT(globalSplit())); + connect(strGlobalCutSelAction, SIGNAL(activated()), SLOT(globalCutSel())); + connect(strGlobalInsertSelAction, SIGNAL(activated()), SLOT(globalInsertSel())); + connect(strGlobalSplitSelAction, SIGNAL(activated()), SLOT(globalSplitSel())); @@ -351,7 +363,7 @@ ArrangerView::ArrangerView(QWidget* parent) connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged())); connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged())); - + MusEGlobal::muse->topwinMenuInited(this); // work around for probable QT/WM interaction bug. // for certain window managers, e.g xfce, this window is @@ -368,7 +380,7 @@ ArrangerView::~ArrangerView() void ArrangerView::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); emit closed(); e->accept(); } @@ -629,7 +641,7 @@ void ArrangerView::clearScoreMenuMappers() void ArrangerView::populateAddTrack() { - QActionGroup *grp = MusEGui::populateAddTrack(addTrack); + QActionGroup *grp = MusEGui::populateAddTrack(addTrack, true); connect(addTrack, SIGNAL(triggered(QAction *)), SLOT(addNewTrack(QAction *))); trackMidiAction = grp->actions()[0]; @@ -731,4 +743,9 @@ void ArrangerView::globalCut() { MusECore::globalCut(); } void ArrangerView::globalInsert() { MusECore::globalInsert(); } void ArrangerView::globalSplit() { MusECore::globalSplit(); } +// variants only applicable for selected tracks +void ArrangerView::globalCutSel() { MusECore::globalCut(true); } +void ArrangerView::globalInsertSel() { MusECore::globalInsert(true); } +void ArrangerView::globalSplitSel() { MusECore::globalSplit(true); } + } // namespace MusEGui diff --git a/muse2/muse/arranger/arrangerview.h b/muse2/muse/arranger/arrangerview.h index d52c5cc4..0dac67e4 100644 --- a/muse2/muse/arranger/arrangerview.h +++ b/muse2/muse/arranger/arrangerview.h @@ -89,7 +89,8 @@ class ArrangerView : public TopWin QMenu* master; QAction *strGlobalCutAction, *strGlobalInsertAction, *strGlobalSplitAction; - QAction *trackMidiAction, *trackDrumAction, *trackNewStyleDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; + QAction *strGlobalCutSelAction, *strGlobalInsertSelAction, *strGlobalSplitSelAction; + QAction *trackMidiAction, *trackDrumAction, *trackNewStyleDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; QAction *trackAInputAction, *trackAAuxAction; QAction *editCutAction, *editCopyAction, *editCopyRangeAction; QAction *editPasteAction, *editPasteCloneAction, *editPasteDialogAction, *editPasteCloneDialogAction; @@ -119,11 +120,14 @@ class ArrangerView : public TopWin void globalCut(); void globalInsert(); void globalSplit(); - void cmd(int); + void globalCutSel(); + void globalInsertSel(); + void globalSplitSel(); + void cmd(int); void addNewTrack(QAction* action); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); void closed(); public slots: diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index 987a7e9a..3889928f 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -3,7 +3,7 @@ // Linux Music Editor // $Id: pcanvas.cpp,v 1.48.2.26 2009/11/22 11:08:33 spamatica Exp $ // (C) Copyright 1999 Werner Schweer (ws@seh.de) -// (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -54,6 +54,7 @@ #include "shortcuts.h" #include "gconfig.h" #include "app.h" +#include "functions.h" #include "filedialog.h" #include "marker/marker.h" #include "mpevent.h" @@ -68,6 +69,8 @@ //#define ABS(x) (x>=0?x:-x) #define ABS(x) (abs(x)) +#define EDITING_FINISHED_TIMEOUT 50 /* in milliseconds */ + using std::set; namespace MusEGui { @@ -181,6 +184,8 @@ void PartCanvas::returnPressed() MusEGlobal::audio->msgChangePart(oldPart, newPart, true, true, false); editMode = false; + + editingFinishedTime.start(); } } @@ -298,12 +303,9 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp QPoint newpos = raster(QPoint(nx, ny)); selectItem(ci, true); - MusECore::UndoOp operation=moveItem(ci, newpos, dtype); - if (operation.type != MusECore::UndoOp::DoNothing) - { + bool result=moveItem(operations, ci, newpos, dtype); + if (result) ci->move(newpos); - operations.push_back(operation); - } if(moving.size() == 1) { itemReleased(curItem, newpos); @@ -322,37 +324,41 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp //--------------------------------------------------------- // Changed by T356. -MusECore::UndoOp PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) +bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& newpos, DragType t) { - MusECore::UndoOp result; NPart* npart = (NPart*) item; MusECore::Part* spart = npart->part(); MusECore::Track* track = npart->track(); + MusECore::Track* dtrack=NULL; unsigned dtick = newpos.x(); unsigned ntrack = y2pitch(item->mp().y()); MusECore::Track::TrackType type = track->type(); if (tracks->index(track) == ntrack && (dtick == spart->tick())) { - return MusECore::UndoOp(MusECore::UndoOp::DoNothing); + return false; } if (ntrack >= tracks->size()) { ntrack = tracks->size(); if (MusEGlobal::debugMsg) printf("PartCanvas::moveItem - add new track\n"); - MusECore::Track* newTrack = MusEGlobal::song->addTrack(type); // Add at end of list. + dtrack = MusEGlobal::song->addTrack(operations, type); // Add at end of list. + if (type == MusECore::Track::WAVE) { MusECore::WaveTrack* st = (MusECore::WaveTrack*) track; - MusECore::WaveTrack* dt = (MusECore::WaveTrack*) newTrack; + MusECore::WaveTrack* dt = (MusECore::WaveTrack*) dtrack; dt->setChannels(st->channels()); } emit tracklistChanged(); } - MusECore::Track* dtrack = tracks->index(ntrack); - if (dtrack->type() != type) { - QMessageBox::critical(this, QString("MusE"), - tr("Cannot copy/move/clone to different Track-Type")); - return MusECore::UndoOp(MusECore::UndoOp::DoNothing); + else + { + dtrack = tracks->index(ntrack); + if (dtrack->type() != type) { + QMessageBox::critical(this, QString("MusE"), + tr("Cannot copy/move/clone to different Track-Type")); + return false; + } } - + MusECore::Part* dpart; bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->events()->arefCount() > 1)); @@ -392,23 +398,25 @@ MusECore::UndoOp PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragTyp if (t == MOVE_COPY || t == MOVE_CLONE) { // These will not increment ref count, and will not chain clones... - // TODO: is comment this still correct (by flo93)? i doubt it! - result=MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart); + // TODO: is this comment still correct (by flo93)? i doubt it! + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart)); } else if (t == MOVE_MOVE) { dpart->setSelected(spart->selected()); // These will increment ref count if not a clone, and will chain clones... // TODO: is this comment still correct (by flo93)? i doubt it! - result=MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false); + operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false)); spart->setSelected(false); } - // else // will never happen -> result will always be defined + // else // will never happen -> operations will never be empty if (MusEGlobal::song->len() < (dpart->lenTick() + dpart->tick())) - MusEGlobal::song->setLen(dpart->lenTick() + dpart->tick()); - - return result; + operations.push_back( MusECore::UndoOp(MusECore::UndoOp::ModifySongLen, + dpart->lenTick() + dpart->tick(), + MusEGlobal::song->len() ) ); + + return true; } //--------------------------------------------------------- @@ -427,6 +435,13 @@ QPoint PartCanvas::raster(const QPoint& p) const return QPoint(x, y); } + +void PartCanvas::songIsClearing() +{ + curItem=NULL; + items.clearDelete(); +} + //--------------------------------------------------------- // partsChanged //--------------------------------------------------------- @@ -434,6 +449,10 @@ QPoint PartCanvas::raster(const QPoint& p) const void PartCanvas::partsChanged() { //items.clear(); + int sn = -1; + if (curItem) sn=curItem->part()->sn(); + curItem=NULL; + items.clearDelete(); for (MusECore::iTrack t = tracks->begin(); t != tracks->end(); ++t) { MusECore::PartList* pl = (*t)->parts(); @@ -441,6 +460,10 @@ void PartCanvas::partsChanged() MusECore::Part* part = i->second; NPart* np = new NPart(part); items.add(np); + + if (np->part()->sn() == sn) + curItem=np; + if (i->second->selected()) { selectItem(np, true); } @@ -647,6 +670,8 @@ QMenu* PartCanvas::genItemPopup(CItem* item) act_split->setData(2); QAction *act_glue = partPopup->addAction(QIcon(*glueIcon), tr("glue")); act_glue->setData(3); + QAction *act_superglue = partPopup->addAction(QIcon(*glueIcon), tr("super glue (merge selection)")); + act_superglue->setData(6); QAction *act_declone = partPopup->addAction(tr("de-clone")); act_declone->setData(15); @@ -736,6 +761,9 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) case 5: copy(pl); break; + case 6: + MusECore::merge_selected_parts(); + break; case 14: // wave edit emit startEditor(pl, 4); @@ -756,7 +784,7 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) // Indicate undo, and do port controller values but not clone parts. // changed by flo93: removed start and endUndo, instead changed first bool to true MusEGlobal::audio->msgChangePart(spart, dpart, true, true, false); - break; // Has to be break here, right? + break; } case 16: // Export to file { @@ -784,7 +812,7 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt) for (MusECore::iEvent e = el->begin(); e != el->end(); ++e) { MusECore::Event event = e->second; - MusECore::SndFileR f = event.sndFile(); + MusECore::SndFileR f = event.sndFile(); if (f.isNull()) continue; str.append(QString("\n@") + QString().setNum(event.tick()) + QString(" len:") + @@ -858,8 +886,8 @@ void PartCanvas::mousePress(QMouseEvent* event) default: if (item) emit trackChanged(item->part()->track()); - else - emit trackChanged(NULL); + //else -- don't see the point of removing track selection, commenting out (rj) + // emit trackChanged(NULL); break; case CutTool: if (item) splitItem(item, pt); @@ -952,11 +980,14 @@ void PartCanvas::keyPress(QKeyEvent* event) // } if (editMode) { + // this will probably never happen, as edit mode has been set + // to "false" some usec ago by returnPressed, called by editingFinished. if ( key == Qt::Key_Return || key == Qt::Key_Enter ) { //returnPressed(); commented out by flo return; } + // the below CAN indeed happen. else if ( key == Qt::Key_Escape ) { lineEditor->hide(); @@ -964,6 +995,11 @@ void PartCanvas::keyPress(QKeyEvent* event) return; } } + // if returnPressed, called by editingFinished, was executed + // a short time ago, ignore this keypress if it was enter or return + if (editingFinishedTime.elapsed() < EDITING_FINISHED_TIMEOUT && + (key == Qt::Key_Return || key == Qt::Key_Enter) ) + return; if (event->modifiers() & Qt::ShiftModifier) key += Qt::SHIFT; @@ -1160,7 +1196,7 @@ void PartCanvas::keyPress(QKeyEvent* event) //If we're at topmost, leave if (!track) { - printf("no track above!\n"); + //printf("no track above!\n"); return; } int middle = curItem->x() + curItem->part()->lenTick()/2; @@ -1295,17 +1331,25 @@ void PartCanvas::keyPress(QKeyEvent* event) curItem = newItem; selectItem(newItem, true); - //Check if we've hit the upper or lower boundaries of the window. If so, set a new position + //Check if we've hit the left, right, upper or lower boundaries of the window. If so, scroll to new position. if (newItem->x() < mapxDev(0)) { - int curpos = pos[0]; - setPos(0,newItem->x(),true); - setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled + emit horizontalScroll(rmapx(newItem->x() - xorg) - 10); // Leave some room. + } + else if (newItem->x() + newItem->width() > mapxDev(width())) { + int mx = rmapx(newItem->x()); + int newx = mx + rmapx(newItem->width()) - width(); + emit horizontalScroll( (newx > mx ? mx - 10 : newx + 10) - rmapx(xorg) ); + } + + if (newItem->y() < mapyDev(0)) { + int my = rmapy(newItem->y()); + int newy = my + rmapy(newItem->height()) - height(); + emit verticalScroll( (newy < my ? my - 10 : newy + 10) - rmapy(yorg) ); } - else if (newItem->x() > mapxDev(width())) { - int curpos = pos[0]; - setPos(0,newItem->x(),true); - setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled + else if (newItem->y() + newItem->height() > mapyDev(height())) { + emit verticalScroll( rmapy(newItem->y() + newItem->height() - yorg) - height() + 10); } + redraw(); } } @@ -2267,9 +2311,9 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev //else // color_brightness=64; // otherwise use dark color if (brightness >= 12000 && !pt->selected()) - color_brightness=64; // 96; // too bright: use dark color + color_brightness=54; // 96; // too bright: use dark color else - color_brightness=190; //160; // too dark: use lighter color + color_brightness=200; //160; // too dark: use lighter color } else color_brightness=80; @@ -3175,9 +3219,13 @@ void PartCanvas::viewDropEvent(QDropEvent* event) if (!track) { // we need to create a track for this drop if (text.endsWith(".mpt", Qt::CaseInsensitive)) { - track = MusEGlobal::song->addTrack(MusECore::Track::MIDI); // Add at end of list. + MusECore::Undo operations; + track = MusEGlobal::song->addTrack(operations, MusECore::Track::MIDI); // Add at end of list. + MusEGlobal::song->applyOperationGroup(operations); } else { - track = MusEGlobal::song->addTrack(MusECore::Track::WAVE); // Add at end of list. + MusECore::Undo operations; + track = MusEGlobal::song->addTrack(operations, MusECore::Track::WAVE); // Add at end of list. + MusEGlobal::song->applyOperationGroup(operations); } } if (track->type() == MusECore::Track::WAVE && @@ -3602,7 +3650,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, MusECore::AudioTra { double y; if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume - y = dbToVal(cl->curVal()); // represent volume between 0 and 1 + //printf("log conversion val=%f min=%f max=%f\n", cl->curVal(), min, max); + y = logToVal(cl->curVal(), min, max); // represent volume between 0 and 1 if (y < 0) y = 0.0; } else @@ -3615,7 +3664,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, MusECore::AudioTra { double y = ic->second.val; if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume - y = dbToVal(y); // represent volume between 0 and 1 + //printf("log conversion val=%f min=%f max=%f\n", cl->curVal(), min, max); + y = logToVal(y, min, max); // represent volume between 0 and 1 if (y < 0) y = 0.0; } else @@ -3714,7 +3764,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo { double y; if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume - y = dbToVal(cl->curVal()); // represent volume between 0 and 1 + y = logToVal(cl->curVal(), min, max); // represent volume between 0 and 1 if (y < 0) y = 0.0; } else @@ -3727,7 +3777,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo { double y = ic->second.val; if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume - y = dbToVal(y); // represent volume between 0 and 1 + y = logToVal(y, min, max); // represent volume between 0 and 1 if (y < 0) y = 0; } else @@ -3919,7 +3969,8 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint) automation.currentCtrlList->range(&min,&max); double cvval; if (automation.currentCtrlList->valueType() == MusECore::VAL_LOG ) { // use db scale for volume - cvval = valToDb(yfraction); + printf("log conversion val=%f min=%f max=%f\n", yfraction, min, max); + cvval = valToLog(yfraction, min, max); //printf("calc yfraction = %f v=%f ",yfraction,cvval); if (cvval< min) cvval=min; if (cvval>max) cvval=max; @@ -3952,13 +4003,45 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint) } -double PartCanvas::dbToVal(double inDb) +//--------------------------------------------------------- +// +// logToVal +// - represent logarithmic value on linear scale from 0 to 1 +// +//--------------------------------------------------------- +double PartCanvas::logToVal(double inLog, double min, double max) { - return (20.0*MusECore::fast_log10(inDb)+60.0) / 70.0; + //printf("logToVal inLog %f :", inLog); + if (inLog < min) inLog = min; + if (inLog > max) inLog = max; + double linMin = 20.0*MusECore::fast_log10(min); + double linMax = 20.0*MusECore::fast_log10(max); + double linVal = 20.0*MusECore::fast_log10(inLog); + + double outVal = (linVal-linMin) / (linMax - linMin); + // printf("inLog %f outVal %f linVal %f min %f max %f dbMin %f dbMax %f\n", inLog, outVal, linVal, min, max, linMin, linMax); + + return outVal; } -double PartCanvas::valToDb(double inV) + +//--------------------------------------------------------- +// +// valToLog +// - represent value from 0 to 1 as logarithmic value between min and max +// +//--------------------------------------------------------- +double PartCanvas::valToLog(double inV, double min, double max) { - return exp10((inV*70.0-60.0)/20.0); + double linMin = 20.0*MusECore::fast_log10(min); + double linMax = 20.0*MusECore::fast_log10(max); + + double linVal = (inV * (linMax - linMin)) + linMin; + double outVal = exp10((linVal)/20.0); + + //printf("::valToLog inV %f outVal %f linVal %f min %f max %f\n", inV, outVal, linVal, min, max); + if (outVal > max) outVal = max; + if (outVal < min) outVal = min; + return outVal; } //--------------------------------------------------------- diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index 8a108055..34395688 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -26,6 +26,7 @@ #include <QVector> #include <set> +#include <QTime> #include "song.h" #include "canvas.h" @@ -93,6 +94,8 @@ class PartCanvas : public Canvas { NPart* editPart; int curColorIndex; bool editMode; + + QTime editingFinishedTime; AutomationObject automation; @@ -116,7 +119,7 @@ class PartCanvas : public Canvas { virtual void newItem(CItem*,bool); virtual bool deleteItem(CItem*); virtual void moveCanvasItems(CItemList&, int, int, DragType); - virtual MusECore::UndoOp moveItem(CItem*, const QPoint&, DragType); + virtual bool moveItem(MusECore::Undo& operations, CItem*, const QPoint&, DragType); virtual void updateSong(DragType, int); virtual void startDrag(CItem*, DragType); @@ -145,8 +148,8 @@ class PartCanvas : public Canvas { void checkAutomation(MusECore::Track * t, const QPoint& pointer, bool addNewCtrl); void processAutomationMovements(QPoint pos, bool addPoint); - double dbToVal(double inDb); - double valToDb(double inV); + double logToVal(double inLog, double min, double max); + double valToLog(double inV, double min, double max); protected: virtual void drawCanvas(QPainter&, const QRect&); @@ -177,9 +180,11 @@ class PartCanvas : public Canvas { virtual ~PartCanvas(); void partsChanged(); void cmd(int); + void songIsClearing(); + public slots: - void redirKeypress(QKeyEvent* e) { keyPress(e); } - void controllerChanged(MusECore::Track *t); + void redirKeypress(QKeyEvent* e) { keyPress(e); } + void controllerChanged(MusECore::Track *t); }; } // namespace MusEGui diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index c209ba9c..f5edc8cf 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -63,6 +63,7 @@ #include "config.h" #include "popupmenu.h" #include "filedialog.h" +#include "menutitleitem.h" #ifdef DSSI_SUPPORT #include "dssihost.h" @@ -397,7 +398,7 @@ void TList::paint(const QRect& r) countVisible++; } //int count = ((MusECore::AudioTrack*)track)->controller()->size(); //commented out by flo: gives a "unused variable" warning - s.sprintf(" %d(%d) visible",countVisible, countAll); + s.sprintf(" %d(%d) %s",countVisible, countAll, tr("visible").toAscii().data()); } @@ -584,19 +585,23 @@ void TList::mouseDoubleClickEvent(QMouseEvent* ev) //--------------------------------------------------------- // portsPopupMenu //--------------------------------------------------------- - void TList::portsPopupMenu(MusECore::Track* t, int x, int y) { switch(t->type()) { case MusECore::Track::MIDI: case MusECore::Track::DRUM: case MusECore::Track::NEW_DRUM: + // FINDMICHJETZT: this is a notice for flo's experimental + // branch! don't forget NEW_DRUM here! + // please don't remove this. i'll do it when + // the time is there. case MusECore::Track::AUDIO_SOFTSYNTH: { MusECore::MidiTrack* track = (MusECore::MidiTrack*)t; //QPopupMenu* p = MusECore::midiPortsPopup(0); MusECore::MidiDevice* md = 0; + int potential_new_port_no=-1; int port = -1; if(t->type() == MusECore::Track::AUDIO_SOFTSYNTH) { @@ -609,25 +614,158 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y) port = track->outPort(); QMenu* p = MusECore::midiPortsPopup(this, port); // 0, port); + + if (t->type()==MusECore::Track::MIDI || t->type()==MusECore::Track::DRUM) //FINDMICHJETZT + { + // extend that menu a bit + + + // find first free port number + // do not permit numbers already used in other tracks! + // except if it's only used in this track. + int no; + for (no=0;no<MIDI_PORTS;no++) + if (MusEGlobal::midiPorts[no].device()==NULL) + { + MusECore::ciTrack it; + for (it=MusEGlobal::song->tracks()->begin(); it!=MusEGlobal::song->tracks()->end(); it++) + { + MusECore::MidiTrack* mt=dynamic_cast<MusECore::MidiTrack*>(*it); + if (mt && mt!=t && mt->outPort()==no) + break; + } + if (it == MusEGlobal::song->tracks()->end()) + break; + } + + if (no==MIDI_PORTS) + { + delete p; + printf("THIS IS VERY UNLIKELY TO HAPPEN: no free midi ports! you have used all %i!\n",MIDI_PORTS); + break; + } + + + potential_new_port_no=no; + typedef std::map<std::string, int > asmap; + typedef std::map<std::string, int >::iterator imap; + + asmap mapALSA; + asmap mapJACK; + + int aix = 0x10000000; + int jix = 0x20000000; + for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) + { + if((*i)->deviceType() == MusECore::MidiDevice::ALSA_MIDI) + { + // don't add devices which are used somewhere + int j; + for (j=0;j<MIDI_PORTS;j++) + if (MusEGlobal::midiPorts[j].device() == *i) + break; + + if (j==MIDI_PORTS) mapALSA.insert( std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), aix) ); + + ++aix; + } + else if((*i)->deviceType() == MusECore::MidiDevice::JACK_MIDI) + { + // don't add devices which are used somewhere + int j; + for (j=0;j<MIDI_PORTS;j++) + if (MusEGlobal::midiPorts[j].device() == *i) + break; + + if (j==MIDI_PORTS) mapJACK.insert( std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), jix) ); + ++jix; + } + } + + if (!mapALSA.empty() || !mapJACK.empty()) + { + QMenu* pup = p->addMenu(tr("Unused Devices")); + QAction* act; + + + if (!mapALSA.empty()) + { + pup->addAction(new MusEGui::MenuTitleItem("ALSA:", pup)); + + for(imap i = mapALSA.begin(); i != mapALSA.end(); ++i) + { + int idx = i->second; + QString s(i->first.c_str()); + MusECore::MidiDevice* md = MusEGlobal::midiDevices.find(s, MusECore::MidiDevice::ALSA_MIDI); + if(md) + { + if(md->deviceType() != MusECore::MidiDevice::ALSA_MIDI) + continue; + + act = pup->addAction(md->name()); + act->setData(idx); + } + } + } + + if (!mapALSA.empty() && !mapJACK.empty()) + pup->addSeparator(); + + if (!mapJACK.empty()) + { + pup->addAction(new MusEGui::MenuTitleItem("JACK:", pup)); + + for(imap i = mapJACK.begin(); i != mapJACK.end(); ++i) + { + int idx = i->second; + QString s(i->first.c_str()); + MusECore::MidiDevice* md = MusEGlobal::midiDevices.find(s, MusECore::MidiDevice::JACK_MIDI); + if(md) + { + if(md->deviceType() != MusECore::MidiDevice::JACK_MIDI) + continue; + + act = pup->addAction(md->name()); + act->setData(idx); + } + } + } + } + } + + QAction* act = p->exec(mapToGlobal(QPoint(x, y)), 0); if(!act) { delete p; break; } - + + QString acttext=act->text(); int n = act->data().toInt(); delete p; if(n < 0) // Invalid item. break; - if(n >= MIDI_PORTS) // Show port config dialog. + if(n == MIDI_PORTS) // Show port config dialog. { MusEGlobal::muse->configMidiPorts(); break; } + else if (n & 0x30000000) + { + int typ; + if (n & 0x10000000) + typ = MusECore::MidiDevice::ALSA_MIDI; + else + typ = MusECore::MidiDevice::JACK_MIDI; + + MusECore::MidiDevice* sdev = MusEGlobal::midiDevices.find(acttext, typ); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[potential_new_port_no], sdev); + n=potential_new_port_no; + } // Changed by T356. //track->setOutPort(n); //MusEGlobal::audio->msgSetTrackOutPort(track, n); @@ -892,16 +1030,24 @@ void TList::moveSelection(int n) if (t == tracks->end()) { --t; break; - } } - } + // skip over hidden tracks + if (!(*t)->isVisible()) { + n++; + } + } + } else { while (n++ != 0) { if (t == tracks->begin()) break; --t; + // skip over hidden tracks + if (!(*t)->isVisible()) { + n--; } } + } (*s)->setSelected(false); (*t)->setSelected(true); @@ -1048,7 +1194,7 @@ void TList::mousePressEvent(QMouseEvent* ev) if(act) { t = MusEGlobal::song->addNewTrack(act); // Add at end of list. - if(t) + if(t && t->isVisible()) { MusEGlobal::song->deselectTracks(); t->setSelected(true); @@ -1063,13 +1209,13 @@ void TList::mousePressEvent(QMouseEvent* ev) //delete synp; delete p; } - else if (button == Qt::LeftButton) { + /*else if (button == Qt::LeftButton) { if (!ctrl) { MusEGlobal::song->deselectTracks(); emit selectionChanged(0); } - } + }*/ return; } @@ -1107,7 +1253,8 @@ void TList::mousePressEvent(QMouseEvent* ev) return; } - mode = START_DRAG; + + mode = NORMAL; switch (col) { case COL_CLEF: @@ -1136,8 +1283,8 @@ void TList::mousePressEvent(QMouseEvent* ev) } delete p; } - break; + case COL_AUTOMATION: { if (!t->isMidiTrack()) { @@ -1173,6 +1320,8 @@ void TList::mousePressEvent(QMouseEvent* ev) case COL_RECORD: { + mode = START_DRAG; + bool val = !(t->recordFlag()); if (button == Qt::LeftButton) { if (!t->isMidiTrack()) { @@ -1211,6 +1360,7 @@ void TList::mousePressEvent(QMouseEvent* ev) } break; case COL_NONE: + mode = START_DRAG; break; case COL_CLASS: if (t->isMidiTrack()) @@ -1231,9 +1381,10 @@ void TList::mousePressEvent(QMouseEvent* ev) //MusEGlobal::audio->msgUpdateSoloStates(); // p4.0.14 //MusEGlobal::song->update(SC_ROUTE); // - break; + case COL_MUTE: + mode = START_DRAG; // p3.3.29 if ((button == Qt::RightButton) || (((QInputEvent*)ev)->modifiers() & Qt::ShiftModifier)) t->setOff(!t->off()); @@ -1247,11 +1398,13 @@ void TList::mousePressEvent(QMouseEvent* ev) MusEGlobal::song->update(SC_MUTE); break; case COL_SOLO: + mode = START_DRAG; MusEGlobal::audio->msgSetSolo(t, !t->solo()); MusEGlobal::song->update(SC_SOLO); break; case COL_NAME: + mode = START_DRAG; if (button == Qt::LeftButton) { if (!ctrl) { MusEGlobal::song->deselectTracks(); @@ -1367,11 +1520,13 @@ void TList::mousePressEvent(QMouseEvent* ev) break; case COL_TIMELOCK: + mode = START_DRAG; t->setLocked(!t->locked()); break; case COL_OCHANNEL: { + mode = START_DRAG; // or not? (flo) int delta = 0; if (button == Qt::RightButton) delta = 1; @@ -1437,6 +1592,9 @@ void TList::mousePressEvent(QMouseEvent* ev) } } break; + + default: + mode = START_DRAG; } redraw(); } diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp index fd90c2c2..0b1574cc 100644 --- a/muse2/muse/audio.cpp +++ b/muse2/muse/audio.cpp @@ -25,8 +25,6 @@ #include <cmath> #include <errno.h> -#include <QSocketNotifier> - #include "app.h" #include "song.h" #include "node.h" @@ -51,10 +49,18 @@ namespace MusEGlobal { MusECore::Audio* audio; MusECore::AudioDevice* audioDevice; // current audio device in use -extern unsigned int volatile midiExtSyncTicks; // p3.3.25 +extern unsigned int volatile midiExtSyncTicks; } namespace MusECore { + + +void initAudio() +{ + MusEGlobal::audio = new Audio(); +} + + extern double curTime(); //static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; @@ -166,8 +172,11 @@ Audio::Audio() exit(-1); } sigFd = filedes[1]; - QSocketNotifier* ss = new QSocketNotifier(filedes[0], QSocketNotifier::Read); - MusEGlobal::song->connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int))); + sigFdr = filedes[0]; + + // Moved to MusE::MusE + //QSocketNotifier* ss = new QSocketNotifier(filedes[0], QSocketNotifier::Read); + //MusEGlobal::song->connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int))); } //--------------------------------------------------------- @@ -182,7 +191,9 @@ bool Audio::start() //process(MusEGlobal::segmentSize); // warm up caches state = STOP; _loopCount = 0; - MusEGlobal::muse->setHeartBeat(); + + MusEGlobal::muse->setHeartBeat(); + if (MusEGlobal::audioDevice) { //_running = true; //MusEGlobal::audioDevice->start(); @@ -221,9 +232,11 @@ bool Audio::start() // shall we really stop JACK transport and locate to // saved position? - MusEGlobal::audioDevice->stopTransport(); + MusEGlobal::audioDevice->stopTransport(); + //MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos().frame()); - MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos()); + MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos()); + return true; } @@ -531,6 +544,26 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames) // Pre-process the metronome. ((AudioTrack*)metronome)->preProcessAlways(); + // Process Aux tracks first. + for(ciTrack it = tl->begin(); it != tl->end(); ++it) + { + if((*it)->isMidiTrack()) + continue; + track = (AudioTrack*)(*it); + if(!track->processed() && track->type() == Track::AUDIO_AUX) + { + //printf("Audio::process1 Do aux: track:%s\n", track->name().toLatin1().constData()); + channels = track->channels(); + // Just a dummy buffer. + float* buffer[channels]; + float data[frames * channels]; + for (int i = 0; i < channels; ++i) + buffer[i] = data + i * frames; + //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1()); + track->copyData(samplePos, channels, -1, -1, frames, buffer); + } + } + OutputList* ol = MusEGlobal::song->outputs(); for (ciAudioOutput i = ol->begin(); i != ol->end(); ++i) (*i)->process(samplePos, offset, frames); @@ -548,8 +581,11 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames) track = (AudioTrack*)(*it); // Ignore unprocessed tracks which have an output route, because they will be processed by // whatever track(s) they are routed to. - if(!track->processed() && track->noOutRoute() && (track->type() != Track::AUDIO_OUTPUT)) + //if(!track->processed() && track->noOutRoute() && (track->type() != Track::AUDIO_OUTPUT)) + // No, do all. + if(!track->processed() && (track->type() != Track::AUDIO_OUTPUT)) { + //printf("Audio::process1 track:%s\n", track->name().toLatin1().constData()); channels = track->channels(); // Just a dummy buffer. float* buffer[channels]; diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h index 8d89be78..3c4eb17d 100644 --- a/muse2/muse/audio.h +++ b/muse2/muse/audio.h @@ -166,7 +166,9 @@ class Audio { int fromThreadFdw, fromThreadFdr; // message pipe int sigFd; // pipe fd for messages to gui - + //QSocketNotifier* _socketNotifier; + int sigFdr; + // record values: Pos startRecordPos; Pos endRecordPos; @@ -189,8 +191,12 @@ class Audio { public: Audio(); - virtual ~Audio() {} + virtual ~Audio() { } + // Access to message pipe (like from gui namespace), otherwise audio would need to depend on gui. + int getFromThreadFdw() { return sigFd; } + int getFromThreadFdr() { return sigFdr; } + void process(unsigned frames); bool sync(int state, unsigned frame); void shutdown(); diff --git a/muse2/muse/audioprefetch.cpp b/muse2/muse/audioprefetch.cpp index 9406911f..1fcb7cef 100644 --- a/muse2/muse/audioprefetch.cpp +++ b/muse2/muse/audioprefetch.cpp @@ -39,7 +39,11 @@ MusECore::AudioPrefetch* audioPrefetch; namespace MusECore { -// Added by Tim. p3.3.20 +void initAudioPrefetch() +{ + MusEGlobal::audioPrefetch = new AudioPrefetch("Prefetch"); +} + //#define AUDIOPREFETCH_DEBUG enum { PREFETCH_TICK, PREFETCH_SEEK @@ -140,6 +144,7 @@ void AudioPrefetch::msgTick() { PrefetchMsg msg; msg.id = PREFETCH_TICK; + msg.pos = 0; // seems to be unused, was uninitalized. while (sendMsg1(&msg, sizeof(msg))) { printf("AudioPrefetch::msgTick(): send failed!\n"); } diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp index 7de92434..aceacc75 100644 --- a/muse2/muse/audiotrack.cpp +++ b/muse2/muse/audiotrack.cpp @@ -42,10 +42,10 @@ namespace MusECore { -bool AudioAux::_isVisible=true; -bool AudioInput::_isVisible=true; -bool AudioOutput::_isVisible=true; -bool AudioGroup::_isVisible = true; +bool AudioAux::_isVisible=false; +bool AudioInput::_isVisible=false; +bool AudioOutput::_isVisible=false; +bool AudioGroup::_isVisible =false; bool WaveTrack::_isVisible=true; // By T356. For caching jack in/out routing names BEFORE file save. @@ -107,7 +107,7 @@ AudioTrack::AudioTrack(TrackType t) _automationType = AUTO_OFF; //setChannels(1); setChannels(2); - addController(new CtrlList(AC_VOLUME,"Volume",0.0,3.16 /* roughly 10 db */, VAL_LOG)); + addController(new CtrlList(AC_VOLUME,"Volume",0.001,3.163 /* roughly 10 db */, VAL_LOG)); addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0, VAL_LINEAR)); addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0, VAL_LINEAR, true /*dont show in arranger */)); @@ -1610,8 +1610,40 @@ void AudioAux::read(Xml& xml) // getData //--------------------------------------------------------- -bool AudioAux::getData(unsigned /*pos*/, int ch, unsigned /*samples*/, float** data) +bool AudioAux::getData(unsigned pos, int ch, unsigned samples, float** data) { + // Make sure all the aux-supporting tracks are processed first so aux data is gathered. p4.0.37 + TrackList* tl = MusEGlobal::song->tracks(); + AudioTrack* track; + for(ciTrack it = tl->begin(); it != tl->end(); ++it) + { + if((*it)->isMidiTrack()) + continue; + track = (AudioTrack*)(*it); + // If there are any Aux route paths to the track, defer processing until the second main track processing pass. + if(!track->processed() && track->hasAuxSend() && !track->auxRefCount()) + { + int chans = track->channels(); + // Just a dummy buffer. + float* buff[chans]; + float buff_data[samples * chans]; + for (int i = 0; i < chans; ++i) + buff[i] = buff_data + i * samples; + + //printf("AudioAux::getData name:%s\n calling copyData on:%s auxRefCount:%d\n", + // name().toLatin1().constData(), track->name().toLatin1().constData(), track->auxRefCount()); + + track->copyData(pos, chans, -1, -1, samples, buff); + + /* float* buff[ch]; + float buff_data[samples * ch]; + for (int i = 0; i < ch; ++i) + buff[i] = buff_data + i * samples; + //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1()); + track->copyData(pos, ch, -1, -1, samples, buff); */ + } + } + for (int i = 0; i < ch; ++i) data[i] = buffer[i % channels()]; return true; diff --git a/muse2/muse/cliplist/cliplist.cpp b/muse2/muse/cliplist/cliplist.cpp index a4702137..60041dae 100644 --- a/muse2/muse/cliplist/cliplist.cpp +++ b/muse2/muse/cliplist/cliplist.cpp @@ -32,6 +32,7 @@ #include "wave.h" #include "xml.h" #include "ui_cliplisteditorbase.h" +#include "app.h" namespace MusEGui { @@ -168,6 +169,7 @@ ClipListEdit::ClipListEdit(QWidget* parent) connect(editor->len, SIGNAL(valueChanged(const MusECore::Pos&)), SLOT(lenChanged(const MusECore::Pos&))); updateList(); + MusEGlobal::muse->topwinMenuInited(this); } ClipListEdit::~ClipListEdit() @@ -194,7 +196,7 @@ void ClipListEdit::updateList() void ClipListEdit::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } diff --git a/muse2/muse/cliplist/cliplist.h b/muse2/muse/cliplist/cliplist.h index b490663c..0972df97 100644 --- a/muse2/muse/cliplist/cliplist.h +++ b/muse2/muse/cliplist/cliplist.h @@ -73,7 +73,7 @@ class ClipListEdit : public TopWin { void clicked(QTreeWidgetItem*, int); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public: ClipListEdit(QWidget* parent); diff --git a/muse2/muse/cobject.cpp b/muse2/muse/cobject.cpp index 59a9463e..50586d45 100644 --- a/muse2/muse/cobject.cpp +++ b/muse2/muse/cobject.cpp @@ -50,6 +50,7 @@ bool TopWin::initInited=false; TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlags f) : QMainWindow(parent, f) { + _isDeleting = false; if (initInited==false) initConfiguration(); @@ -77,7 +78,10 @@ TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlag mdisubwin=NULL; _sharesToolsAndMenu=_defaultSubwin[_type] ? _sharesWhenSubwin[_type] : _sharesWhenFree[_type]; if (_defaultSubwin[_type]) + { setIsMdiWin(true); + _savedToolbarState=_toolbarNonsharedInit[_type]; + } if (_sharesToolsAndMenu) menuBar()->hide(); @@ -85,8 +89,11 @@ TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlag subwinAction->setChecked(isMdiWin()); shareAction->setChecked(_sharesToolsAndMenu); fullscreenAction->setEnabled(!isMdiWin()); - - resize(_widthInit[_type], _heightInit[_type]); + + if (mdisubwin) + mdisubwin->resize(_widthInit[_type], _heightInit[_type]); + else + resize(_widthInit[_type], _heightInit[_type]); } @@ -96,6 +103,8 @@ TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlag void TopWin::readStatus(MusECore::Xml& xml) { + int x=0, y=0, width=800, height=600; + for (;;) { MusECore::Xml::Token token = xml.parse(); @@ -106,17 +115,24 @@ void TopWin::readStatus(MusECore::Xml& xml) switch (token) { case MusECore::Xml::TagStart: - if (tag == "geometry_state") - { - if (!restoreGeometry(QByteArray::fromHex(xml.parse1().toAscii()))) - fprintf(stderr,"ERROR: couldn't restore geometry. however, this is probably not really a problem.\n"); - } + if (tag == "x") + x=xml.parseInt(); + else if (tag == "y") + y=xml.parseInt(); + else if (tag == "width") + width=xml.parseInt(); + else if (tag == "height") + height=xml.parseInt(); else if (tag == "toolbars") { if (!sharesToolsAndMenu()) { if (!restoreState(QByteArray::fromHex(xml.parse1().toAscii()))) - fprintf(stderr,"ERROR: couldn't restore toolbars. however, this is not really a problem.\n"); + { + fprintf(stderr,"ERROR: couldn't restore toolbars. trying default configuration...\n"); + if (!restoreState(_toolbarNonsharedInit[_type])) + fprintf(stderr,"ERROR: couldn't restore default toolbars. this is not really a problem.\n"); + } } else { @@ -139,7 +155,20 @@ void TopWin::readStatus(MusECore::Xml& xml) case MusECore::Xml::TagEnd: if (tag == "topwin") + { + if (mdisubwin) + { + mdisubwin->move(x, y); + mdisubwin->resize(width, height); + } + else + { + move(x,y); + resize(width,height); + } + return; + } default: break; @@ -159,7 +188,22 @@ void TopWin::writeStatus(int level, MusECore::Xml& xml) const // changing it won't break muse, but it may break proper // restoring of the positions xml.intTag(level, "is_subwin", isMdiWin()); - xml.strTag(level, "geometry_state", saveGeometry().toHex().data()); + + if (mdisubwin) + { + xml.intTag(level, "x", mdisubwin->x()); + xml.intTag(level, "y", mdisubwin->y()); + xml.intTag(level, "width", mdisubwin->width()); + xml.intTag(level, "height", mdisubwin->height()); + } + else + { + xml.intTag(level, "x", x()); + xml.intTag(level, "y", y()); + xml.intTag(level, "width", width()); + xml.intTag(level, "height", height()); + } + xml.intTag(level, "shares_menu", sharesToolsAndMenu()); if (!sharesToolsAndMenu()) @@ -359,8 +403,17 @@ void TopWin::shareToolsAndMenu(bool val) void TopWin::storeInitialState() const { - _widthInit[_type] = width(); - _heightInit[_type] = height(); + if (mdisubwin) + { + _widthInit[_type] = mdisubwin->width(); + _heightInit[_type] = mdisubwin->height(); + } + else + { + _widthInit[_type] = width(); + _heightInit[_type] = height(); + } + if (sharesToolsAndMenu()) { if (muse->getCurrentMenuSharingTopwin() == this) @@ -519,4 +572,15 @@ void TopWin::resize(const QSize& s) resize(s.width(), s.height()); } +TopWin* ToplevelList::findType(TopWin::ToplevelType type) const +{ + for (ciToplevel i = begin(); i != end(); ++i) + { + if((*i)->type() == type) + return (*i); + } + return 0; +} + + } // namespace MusEGui diff --git a/muse2/muse/cobject.h b/muse2/muse/cobject.h index c1c45039..f6ea2ce1 100644 --- a/muse2/muse/cobject.h +++ b/muse2/muse/cobject.h @@ -62,7 +62,8 @@ class TopWin : public QMainWindow ToplevelType type() const { return _type; } static QString typeName(ToplevelType t); - + bool deleting() const { return _isDeleting; } + virtual void readStatus(MusECore::Xml&); virtual void writeStatus(int, MusECore::Xml&) const; @@ -118,6 +119,11 @@ class TopWin : public QMainWindow QByteArray _savedToolbarState; + // Set if close has been called on a TopWin having the WA_DeleteOnClose attribute. + // The TopWins and any children should ignore any signals such as songChanged + // which may cause a crash while deleting. + bool _isDeleting; + void initTopwinState(); private slots: @@ -131,13 +137,25 @@ class TopWin : public QMainWindow void shareToolsAndMenu(bool); void restoreMainwinState(); void storeInitialState() const; - + }; -typedef std::list <TopWin*> ToplevelList; -typedef ToplevelList::iterator iToplevel; -typedef ToplevelList::const_iterator ciToplevel; +//--------------------------------------------------------- +// ToplevelList +//--------------------------------------------------------- + +//typedef std::list <TopWin*> ToplevelList; +//typedef ToplevelList::iterator iToplevel; +//typedef ToplevelList::const_iterator ciToplevel; + +typedef std::list<TopWin*>::iterator iToplevel; +typedef std::list<TopWin*>::const_iterator ciToplevel; + +class ToplevelList : public std::list<TopWin* > { + public: + TopWin* findType(TopWin::ToplevelType) const; + }; } // namespace MusEGui diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp index 26f96bf1..5376734c 100644 --- a/muse2/muse/conf.cpp +++ b/muse2/muse/conf.cpp @@ -220,7 +220,7 @@ static void readPortChannel(Xml& xml, int midiPort) // readConfigMidiPort //--------------------------------------------------------- -static void readConfigMidiPort(Xml& xml) +static void readConfigMidiPort(Xml& xml, bool skipConfig) { int idx = 0; QString device; @@ -234,11 +234,9 @@ static void readConfigMidiPort(Xml& xml) // FIXME: TODO: Make this user-configurable! QString instrument("GM"); + int rwFlags = 3; int openFlags = 1; - bool thruFlag = false; - //int dic = 0; - //int doc = 0; - int dic = -1; // p4.0.17 + int dic = -1; int doc = -1; MidiSyncInfo tmpSi; @@ -251,6 +249,19 @@ static void readConfigMidiPort(Xml& xml) QString tag = xml.s1(); switch (token) { case Xml::TagStart: + + // skipConfig added so it doesn't overwrite midi ports. p4.0.41 Tim. + // Try to keep the controller information. But, this may need to be moved below. + // Also may want to try to keep sync info, but that's a bit risky, so let's not for now. + if (tag == "channel") { + readPortChannel(xml, idx); + break; + } + else if (skipConfig){ + xml.skip(tag); + break; + } + if (tag == "name") device = xml.parse1(); else if (tag == "type") @@ -262,6 +273,8 @@ static void readConfigMidiPort(Xml& xml) } else if (tag == "openFlags") openFlags = xml.parseInt(); + else if (tag == "rwFlags") // Jack midi devs need this. p4.0.41 + rwFlags = xml.parseInt(); else if (tag == "defaultInChans") dic = xml.parseInt(); else if (tag == "defaultOutChans") @@ -270,16 +283,15 @@ static void readConfigMidiPort(Xml& xml) tmpSi.read(xml); else if (tag == "instrument") { instrument = xml.parse1(); - // Moved by Tim. - //MusEGlobal::midiPorts[idx].setInstrument( + //MusEGlobal::midiPorts[idx].setInstrument( // Moved below // registerMidiInstrument(instrument) // ); } else if (tag == "midithru") - thruFlag = xml.parseInt(); // obsolete - else if (tag == "channel") { - readPortChannel(xml, idx); - } + xml.parseInt(); // obsolete + //else if (tag == "channel") { + // readPortChannel(xml, idx); // Moved above + // } else xml.unknown("MidiDevice"); break; @@ -290,6 +302,10 @@ static void readConfigMidiPort(Xml& xml) break; case Xml::TagEnd: if (tag == "midiport") { + + if(skipConfig) // p4.0.41 + return; + //if (idx > MIDI_PORTS) { if (idx < 0 || idx >= MIDI_PORTS) { fprintf(stderr, "bad midi port %d (>%d)\n", @@ -305,9 +321,8 @@ static void readConfigMidiPort(Xml& xml) if(!dev && type == MidiDevice::JACK_MIDI) { if(MusEGlobal::debugMsg) - fprintf(stderr, "readConfigMidiPort: creating jack midi device %s\n", device.toLatin1().constData()); - //dev = MidiJackDevice::createJackMidiDevice(device, openFlags); - dev = MidiJackDevice::createJackMidiDevice(device); // p3.3.55 + fprintf(stderr, "readConfigMidiPort: creating jack midi device %s with rwFlags:%d\n", device.toLatin1().constData(), rwFlags); + dev = MidiJackDevice::createJackMidiDevice(device, rwFlags); } if(MusEGlobal::debugMsg && !dev) @@ -315,7 +330,7 @@ static void readConfigMidiPort(Xml& xml) MidiPort* mp = &MusEGlobal::midiPorts[idx]; - mp->setInstrument(registerMidiInstrument(instrument)); // By Tim. + mp->setInstrument(registerMidiInstrument(instrument)); if(dic != -1) // p4.0.17 Leave them alone unless set by song. mp->setDefaultInChannels(dic); if(doc != -1) @@ -480,7 +495,7 @@ static void loadConfigMetronom(Xml& xml) // readSeqConfiguration //--------------------------------------------------------- -static void readSeqConfiguration(Xml& xml) +static void readSeqConfiguration(Xml& xml, bool skipConfig) { for (;;) { Xml::Token token = xml.parse(); @@ -492,7 +507,7 @@ static void readSeqConfiguration(Xml& xml) if (tag == "metronom") loadConfigMetronom(xml); else if (tag == "midiport") - readConfigMidiPort(xml); + readConfigMidiPort(xml, skipConfig); else if (tag == "rcStop") MusEGlobal::rcStopNote = xml.parseInt(); else if (tag == "rcEnable") @@ -542,7 +557,7 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig midiport configuration and VOLUME. */ if (tag == "sequencer") { - readSeqConfiguration(xml); + readSeqConfiguration(xml, readOnlySequencer); break; } else if (readOnlySequencer) { @@ -580,8 +595,10 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MidiTrack::setVisible((bool)xml.parseInt()); else if (tag == "inputTracksVisible") AudioInput::setVisible((bool)xml.parseInt()); - else if (tag == "outputTracksVisible") + else if (tag == "outputTracksVisible") { + printf("output track set from config!\n"); AudioOutput::setVisible((bool)xml.parseInt()); + } else if (tag == "synthTracksVisible") SynthI::setVisible((bool)xml.parseInt()); else if (tag == "bigtimeVisible") @@ -624,7 +641,18 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.geometryTransport = readGeometry(xml, tag); else if (tag == "geometryBigTime") MusEGlobal::config.geometryBigTime = readGeometry(xml, tag); - + else if (tag == "Mixer") { + if(mixers == 0) + MusEGlobal::config.mixer1.read(xml); + else + MusEGlobal::config.mixer2.read(xml); + ++mixers; + } + else if (tag == "geometryMain") + MusEGlobal::config.geometryMain = readGeometry(xml, tag); + + // don't insert else if(...) clauses between + // this line and "Global config stuff begins here". else if (!doReadGlobalConfig) { xml.skip(tag); break; @@ -636,9 +664,6 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig // ---- Global config stuff begins here ---- - else if (tag == "geometryMain") - MusEGlobal::config.geometryMain = readGeometry(xml, tag); - else if (tag == "theme") MusEGlobal::config.style = xml.parse1(); else if (tag == "styleSheetFile") @@ -851,20 +876,6 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.canvasBgPixmap = xml.parse1(); else if (tag == "canvasCustomBgList") MusEGlobal::config.canvasCustomBgList = xml.parse1().split(";", QString::SkipEmptyParts); - - //else if (tag == "mixer1") - // MusEGlobal::config.mixer1.read(xml); - //else if (tag == "mixer2") - // MusEGlobal::config.mixer2.read(xml); - else if (tag == "Mixer") - { - if(mixers == 0) - MusEGlobal::config.mixer1.read(xml); - else - MusEGlobal::config.mixer2.read(xml); - ++mixers; - } - else if (tag == "bigtimeForegroundcolor") MusEGlobal::config.bigTimeForegroundColor = readColor(xml); else if (tag == "bigtimeBackgroundcolor") @@ -936,8 +947,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.minControlProcessPeriod = xml.parseUInt(); else if (tag == "guiRefresh") MusEGlobal::config.guiRefresh = xml.parseInt(); - else if (tag == "userInstrumentsDir") - MusEGlobal::config.userInstrumentsDir = xml.parse1(); + else if (tag == "userInstrumentsDir") // Obsolete + MusEGlobal::config.userInstrumentsDir = xml.parse1(); // Keep for compatibility else if (tag == "startMode") MusEGlobal::config.startMode = xml.parseInt(); else if (tag == "startSong") @@ -956,6 +967,10 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig MusEGlobal::config.leftMouseButtonCanDecrease = xml.parseInt(); else if (tag == "rangeMarkerWithoutMMB") MusEGlobal::config.rangeMarkerWithoutMMB = xml.parseInt(); + else if (tag == "addHiddenTracks") + MusEGlobal::config.addHiddenTracks = xml.parseInt(); + else if (tag == "unhideTracks") + MusEGlobal::config.unhideTracks = xml.parseInt(); // ---- the following only skips obsolete entries ---- else if ((tag == "arranger") || (tag == "geometryPianoroll") || (tag == "geometryDrumedit")) @@ -1179,7 +1194,6 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo) if (dev) { xml.strTag(level, "name", dev->name()); - // p3.3.38 //if(dynamic_cast<MidiJackDevice*>(dev)) if(dev->deviceType() != MidiDevice::ALSA_MIDI) //xml.intTag(level, "type", MidiDevice::JACK_MIDI); @@ -1189,6 +1203,9 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo) // openFlags was read before, but never written here. //xml.intTag(level, "record", dev->rwFlags() & 0x2 ? 1 : 0); xml.intTag(level, "openFlags", dev->openFlags()); + + if(dev->deviceType() == MidiDevice::JACK_MIDI) + xml.intTag(level, "rwFlags", dev->rwFlags()); // Need this. Jack midi devs are created by app. p4.0.41 } mport->syncInfo().write(level, xml); // write out registered controller for all channels @@ -1255,9 +1272,8 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "dummyAudioBufSize", MusEGlobal::config.dummyAudioBufSize); xml.intTag(level, "dummyAudioSampleRate", MusEGlobal::config.dummyAudioSampleRate); xml.uintTag(level, "minControlProcessPeriod", MusEGlobal::config.minControlProcessPeriod); - xml.intTag(level, "guiRefresh", MusEGlobal::config.guiRefresh); - xml.strTag(level, "userInstrumentsDir", MusEGlobal::config.userInstrumentsDir); + // Removed by Orcan. 20101220 //xml.strTag(level, "helpBrowser", config.helpBrowser); xml.intTag(level, "extendedMidi", MusEGlobal::config.extendedMidi); @@ -1294,6 +1310,17 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "leftMouseButtonCanDecrease", MusEGlobal::config.leftMouseButtonCanDecrease); xml.intTag(level, "rangeMarkerWithoutMMB", MusEGlobal::config.rangeMarkerWithoutMMB); + xml.intTag(level, "unhideTracks", MusEGlobal::config.unhideTracks); + xml.intTag(level, "addHiddenTracks", MusEGlobal::config.addHiddenTracks); + + xml.intTag(level, "waveTracksVisible", MusECore::WaveTrack::visible()); + xml.intTag(level, "auxTracksVisible", MusECore::AudioAux::visible()); + xml.intTag(level, "groupTracksVisible", MusECore::AudioGroup::visible()); + xml.intTag(level, "midiTracksVisible", MusECore::MidiTrack::visible()); + xml.intTag(level, "inputTracksVisible", MusECore::AudioInput::visible()); + xml.intTag(level, "outputTracksVisible", MusECore::AudioOutput::visible()); + xml.intTag(level, "synthTracksVisible", MusECore::SynthI::visible()); + //for (int i = 0; i < 6; ++i) { for (int i = 0; i < NUM_FONTS; ++i) { char buffer[32]; @@ -1348,7 +1375,6 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.colorTag(level, "auxTrackBg", MusEGlobal::config.auxTrackBg); xml.colorTag(level, "synthTrackBg", MusEGlobal::config.synthTrackBg); - // Removed by Tim. p3.3.6 //xml.intTag(level, "txSyncPort", txSyncPort); //xml.intTag(level, "rxSyncPort", rxSyncPort); xml.intTag(level, "mtctype", MusEGlobal::mtcType); @@ -1375,11 +1401,8 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "bigtimeVisible", MusEGlobal::config.bigTimeVisible); xml.intTag(level, "transportVisible", MusEGlobal::config.transportVisible); - //xml.intTag(level, "mixerVisible", MusEGlobal::config.mixerVisible); // Obsolete xml.intTag(level, "mixer1Visible", MusEGlobal::config.mixer1Visible); xml.intTag(level, "mixer2Visible", MusEGlobal::config.mixer2Visible); - //MusEGlobal::config.mixer1.write(level, xml, "mixer1"); - //MusEGlobal::config.mixer2.write(level, xml, "mixer2"); MusEGlobal::config.mixer1.write(level, xml); MusEGlobal::config.mixer2.write(level, xml); @@ -1432,20 +1455,9 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "midiFilterCtrl3", MusEGlobal::midiFilterCtrl3); xml.intTag(level, "midiFilterCtrl4", MusEGlobal::midiFilterCtrl4); - xml.intTag(level, "waveTracksVisible", MusECore::WaveTrack::visible()); - xml.intTag(level, "auxTracksVisible", MusECore::AudioAux::visible()); - xml.intTag(level, "groupTracksVisible", MusECore::AudioGroup::visible()); - xml.intTag(level, "midiTracksVisible", MusECore::MidiTrack::visible()); - xml.intTag(level, "inputTracksVisible", MusECore::AudioInput::visible()); - xml.intTag(level, "outputTracksVisible", MusECore::AudioOutput::visible()); - xml.intTag(level, "synthTracksVisible", MusECore::SynthI::visible()); - // Removed by Tim. p3.3.6 - //xml.intTag(level, "txDeviceId", txDeviceId); //xml.intTag(level, "rxDeviceId", rxDeviceId); - // Changed by Tim. p3.3.6 - //xml.intTag(level, "txSyncPort", txSyncPort); /* // To keep old muse versions happy... @@ -1467,8 +1479,6 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const } */ - // Added by Tim. p3.3.6 - //xml.tag(level++, "midiSyncInfo"); //for(iMusECore::MidiDevice id = MusECore::MusEGlobal::midiDevices.begin(); id != MusECore::MusEGlobal::midiDevices.end(); ++id) //{ @@ -1496,8 +1506,6 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const xml.intTag(level, "bigtimeVisible", viewBigtimeAction->isChecked()); xml.intTag(level, "transportVisible", viewTransportAction->isChecked()); - //xml.intTag(level, "markerVisible", viewMarkerAction->isChecked()); // Obsolete (done by song's toplevel list) - //xml.intTag(level, "mixerVisible", menuView->isItemChecked(aid1)); // Obsolete xml.geometryTag(level, "geometryMain", this); // FINDME: maybe remove this? do we want // the main win to jump around when loading? @@ -1506,18 +1514,13 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const if (bigtime) xml.geometryTag(level, "geometryBigTime", bigtime); - //if (audioMixer) - // xml.geometryTag(level, "geometryMixer", audioMixer); // Obsolete xml.intTag(level, "mixer1Visible", viewMixerAAction->isChecked()); xml.intTag(level, "mixer2Visible", viewMixerBAction->isChecked()); if (mixer1) - //mixer1->write(level, xml, "mixer1"); mixer1->write(level, xml); if (mixer2) - //mixer2->write(level, xml, "mixer2"); mixer2->write(level, xml); - //_arranger->writeStatus(level, xml); // Obsolete. done by song's toplevel list. arrangerview also handles arranger. writeSeqConfiguration(level, xml, true); MusEGui::write_function_dialog_config(level, xml); @@ -1658,18 +1661,12 @@ namespace MusEGlobal { // write //--------------------------------------------------------- -//void MixerConfig::write(MusECore::Xml& xml, const char* name) void MixerConfig::write(int level, MusECore::Xml& xml) -//void MixerConfig::write(int level, MusECore::Xml& xml, const char* name) { - //xml.stag(QString(name)); - //xml.tag(level++, name.toLatin1().constData()); xml.tag(level++, "Mixer"); - //xml.tag(level++, name); - + xml.strTag(level, "name", name); - //xml.tag("geometry", geometry); xml.qrectTag(level, "geometry", geometry); xml.intTag(level, "showMidiTracks", showMidiTracks); @@ -1682,19 +1679,14 @@ void MixerConfig::write(int level, MusECore::Xml& xml) xml.intTag(level, "showAuxTracks", showAuxTracks); xml.intTag(level, "showSyntiTracks", showSyntiTracks); - //xml.etag(name); - //xml.etag(level, name.toLatin1().constData()); xml.etag(level, "Mixer"); - //xml.etag(level, name); } //--------------------------------------------------------- // read //--------------------------------------------------------- -//void MixerConfig::read(QDomNode node) void MixerConfig::read(MusECore::Xml& xml) -//void MixerConfig::read(MusECore::Xml& xml, const QString& name) { for (;;) { MusECore::Xml::Token token(xml.parse()); diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp index 315e686e..d45dd370 100644 --- a/muse2/muse/confmport.cpp +++ b/muse2/muse/confmport.cpp @@ -183,22 +183,25 @@ void MPConfig::changeDefOutputRoutes(QAction* act) MusEGlobal::audio->msgUpdateSoloStates(); MusEGlobal::song->update(SC_ROUTE); #else - int ch = 0; - for( ; ch < MIDI_CHANNELS; ++ch) - if(defch & (1 << ch)) break; - - MusEGlobal::audio->msgIdle(true); - for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) - { - // Leave drum track channel at current setting. - if((*it)->type() == MusECore::Track::DRUM) - (*it)->setOutPortAndUpdate(no); - else - (*it)->setOutPortAndChannelAndUpdate(no, ch); - } - MusEGlobal::audio->msgIdle(false); - MusEGlobal::audio->msgUpdateSoloStates(); - MusEGlobal::song->update(SC_MIDI_TRACK_PROP); + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + if(defch & (1 << ch)) + { + MusEGlobal::audio->msgIdle(true); + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + { + // Leave drum track channel at current setting. + if((*it)->type() == MusECore::Track::DRUM) + (*it)->setOutPortAndUpdate(no); + else + (*it)->setOutPortAndChannelAndUpdate(no, ch); + } + MusEGlobal::audio->msgIdle(false); + MusEGlobal::audio->msgUpdateSoloStates(); + MusEGlobal::song->update(SC_MIDI_TRACK_PROP); + + // Stop at the first output channel found. + break; + } #endif } } @@ -730,7 +733,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) //act = pup->addAction(tr("Create") + QT_TRANSLATE_NOOP("@default", " Jack") + tr(" output")); //act = pup->addAction(tr("Create") + QT_TRANSLATE_NOOP("@default", " Jack") + tr(" combo")); // ... or keep it simple and let the user click on the green lights instead. - act = pup->addAction(tr("Create") + QT_TRANSLATE_NOOP("@default", " Jack") + tr(" device")); + act = pup->addAction(tr("Create Jack device")); act->setData(0); typedef std::map<std::string, int > asmap; @@ -776,7 +779,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) //if(!mapALSA.empty()) { pup->addSeparator(); - pup->addAction(new MusEGui::MenuTitleItem(QT_TRANSLATE_NOOP("@default", "ALSA:"), pup)); + pup->addAction(new MusEGui::MenuTitleItem("ALSA:", pup)); for(imap i = mapALSA.begin(); i != mapALSA.end(); ++i) { @@ -791,7 +794,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) if(md->deviceType() != MusECore::MidiDevice::ALSA_MIDI) continue; - act = pup->addAction(QT_TRANSLATE_NOOP("@default", md->name())); + act = pup->addAction(md->name()); act->setData(idx); act->setCheckable(true); act->setChecked(md == dev); @@ -802,7 +805,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) if(!mapSYNTH.empty()) { pup->addSeparator(); - pup->addAction(new MusEGui::MenuTitleItem(QT_TRANSLATE_NOOP("@default", "SYNTH:"), pup)); + pup->addAction(new MusEGui::MenuTitleItem("SYNTH:", pup)); for(imap i = mapSYNTH.begin(); i != mapSYNTH.end(); ++i) { @@ -817,7 +820,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) if(md->deviceType() != MusECore::MidiDevice::SYNTH_MIDI) continue; - act = pup->addAction(QT_TRANSLATE_NOOP("@default", md->name())); + act = pup->addAction(md->name()); act->setData(idx); act->setCheckable(true); act->setChecked(md == dev); @@ -828,7 +831,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) //if(!mapJACK.empty()) { pup->addSeparator(); - pup->addAction(new MusEGui::MenuTitleItem(QT_TRANSLATE_NOOP("@default", "JACK:"), pup)); + pup->addAction(new MusEGui::MenuTitleItem("JACK:", pup)); for(imap i = mapJACK.begin(); i != mapJACK.end(); ++i) { @@ -843,7 +846,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item) if(md->deviceType() != MusECore::MidiDevice::JACK_MIDI) continue; - act = pup->addAction(QT_TRANSLATE_NOOP("@default", md->name())); + act = pup->addAction(md->name()); act->setData(idx); act->setCheckable(true); act->setChecked(md == dev); @@ -902,8 +905,105 @@ void MPConfig::rbClicked(QTableWidgetItem* item) sdev = 0; } + int allch = (1 << MIDI_CHANNELS) - 1; + MusECore::MidiTrackList* mtl = MusEGlobal::song->midis(); + + // Remove track routes to/from an existing port already using the selected device... + if(sdev) + { + for(int i = 0; i < MIDI_PORTS; ++i) + { + if(MusEGlobal::midiPorts[i].device() == sdev) + { + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + MusEGlobal::audio->msgRemoveRoute(MusECore::Route(i, allch), MusECore::Route(*it, allch)); + + // Turn on if and when multiple output routes are supported. + #if 0 + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + + //MusEGlobal::audio->msgUpdateSoloStates(); + //MusEGlobal::song->update(SC_ROUTE); + #endif + + break; + } + } + } + + // Remove all track routes to/from this port... + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + // Remove all routes from this port to the tracks. + MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + // Turn on if and when multiple output routes are supported. + #if 0 + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + + //MusEGlobal::audio->msgUpdateSoloStates(); + //MusEGlobal::song->update(SC_ROUTE); + #endif + MusEGlobal::midiSeq->msgSetMidiDevice(port, sdev); MusEGlobal::muse->changeConfig(true); // save configuration file + + // Add all track routes to/from this port... + if(sdev) + { + int chbits = MusEGlobal::midiPorts[no].defaultInChannels(); + // Do not add input routes to synths. + if(!sdev->isSynti()) + { + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + { + // Remove all routes from this port to the tracks first. + //MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + // Now connect all the specified routes. + if(chbits) + MusEGlobal::audio->msgAddRoute(MusECore::Route(no, chbits), MusECore::Route(*it, chbits)); + } + } + chbits = MusEGlobal::midiPorts[no].defaultOutChannels(); + // Turn on if and when multiple output routes are supported. + #if 0 + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + { + // Remove all routes from this port to the tracks first. + //MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + // Now connect all the specified routes. + if(chbits) + MusEGlobal::audio->msgAddRoute(MusECore::Route(no, chbits), MusECore::Route(*it, chbits)); + } + //MusEGlobal::audio->msgUpdateSoloStates(); + //MusEGlobal::song->update(SC_ROUTE); + #else + for(int ch = 0; ch < MIDI_CHANNELS; ++ch) + if(chbits & (1 << ch)) + { + MusEGlobal::audio->msgIdle(true); + for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) + { + // Leave drum track channel at current setting. + if((*it)->type() == MusECore::Track::DRUM) + (*it)->setOutPortAndUpdate(no); + else + (*it)->setOutPortAndChannelAndUpdate(no, ch); + } + MusEGlobal::audio->msgIdle(false); + //MusEGlobal::audio->msgUpdateSoloStates(); + //MusEGlobal::song->update(SC_MIDI_TRACK_PROP); + + // Stop at the first output channel found. + break; + } + #endif + } + + //MusEGlobal::audio->msgUpdateSoloStates(); + ////MusEGlobal::song->update(SC_ROUTE); + + MusEGlobal::audio->msgUpdateSoloStates(); MusEGlobal::song->update(); } } @@ -1061,7 +1161,8 @@ MPConfig::MPConfig(QWidget* parent) //popup = 0; instrPopup = 0; defpup = 0; - _showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first. + //_showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first. + _showAliases = 0; // 0: Show first aliases, if available. QStringList columnnames; columnnames << tr("Port") @@ -1125,8 +1226,7 @@ void MPConfig::songChanged(int flags) // Is it simply a midi controller value adjustment? Forget it. //if(flags == SC_MIDI_CONTROLLER) // return; - // No need for anything but this, yet. - if(!(flags & SC_CONFIG)) + if(!(flags & (SC_CONFIG | SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED))) return; // Get currently selected index... @@ -1299,32 +1399,29 @@ void MPConfig::songChanged(int flags) synthList->clear(); for (std::vector<MusECore::Synth*>::iterator i = MusEGlobal::synthis.begin(); i != MusEGlobal::synthis.end(); ++i) { - //s = (*i)->baseName(); - //s = (*i)->name(); - QTreeWidgetItem* item = new QTreeWidgetItem(synthList); - //item->setText(0, s); item->setText(0, QString((*i)->baseName())); + item->setText(1, MusECore::synthType2String((*i)->synthType())); s.setNum((*i)->instances()); - item->setText(1, s); - item->setTextAlignment(1, Qt::AlignHCenter); - //item->setText(2, QString((*i)->baseName())); - item->setText(2, QString((*i)->name())); + item->setText(2, s); + //item->setTextAlignment(2, Qt::AlignHCenter); + item->setText(3, QString((*i)->name())); - item->setText(3, QString((*i)->version())); - item->setText(4, QString((*i)->description())); + item->setText(4, QString((*i)->version())); + item->setText(5, QString((*i)->description())); } instanceList->clear(); MusECore::SynthIList* sl = MusEGlobal::song->syntis(); for (MusECore::iSynthI si = sl->begin(); si != sl->end(); ++si) { QTreeWidgetItem* iitem = new QTreeWidgetItem(instanceList); iitem->setText(0, (*si)->name()); + iitem->setText(1, MusECore::synthType2String((*si)->synth()->synthType())); if ((*si)->midiPort() == -1) s = tr("<none>"); else s.setNum((*si)->midiPort() + 1); - iitem->setText(1, s); - iitem->setTextAlignment(1, Qt::AlignHCenter); + iitem->setText(2, s); + //iitem->setTextAlignment(2, Qt::AlignHCenter); } synthList->resizeColumnToContents(1); mdevView->resizeColumnsToContents(); @@ -1345,7 +1442,10 @@ void MPConfig::addInstanceClicked() QTreeWidgetItem* item = synthList->currentItem(); if (item == 0) return; - MusECore::SynthI *si = MusEGlobal::song->createSynthI(item->text(0), item->text(2)); // Add at end of list. + // Add at end of list. + MusECore::SynthI *si = MusEGlobal::song->createSynthI(item->text(0), + item->text(3), + MusECore::string2SynthType(item->text(1))); if(!si) return; @@ -1374,8 +1474,9 @@ void MPConfig::removeInstanceClicked() MusECore::SynthIList* sl = MusEGlobal::song->syntis(); MusECore::iSynthI ii; for (ii = sl->begin(); ii != sl->end(); ++ii) { - if ((*ii)->iname() == item->text(0)) - break; + if( (*ii)->iname() == item->text(0) && + MusECore::synthType2String((*ii)->synth()->synthType()) == item->text(1) ) + break; } if (ii == sl->end()) { printf("synthesizerConfig::removeInstanceClicked(): synthi not found\n"); diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index f592d4d3..9896de9a 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -227,13 +227,11 @@ CtrlCanvas::CtrlCanvas(MidiEditor* e, QWidget* parent, int xmag, connect(MusEGlobal::song, SIGNAL(posChanged(int, unsigned, bool)), this, SLOT(setPos(int, unsigned, bool))); setMouseTracking(true); - if (editor->parts()->empty()) { - curPart = 0; - curTrack = 0; - } - else { + curPart = 0; + curTrack = 0; + if (!editor->parts()->empty()) setCurTrackAndPart(); - } + connect(MusEGlobal::song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); connect(MusEGlobal::muse, SIGNAL(configChanged()), SLOT(configChanged())); @@ -474,6 +472,9 @@ void CtrlCanvas::configChanged() void CtrlCanvas::songChanged(int type) { + if(editor->deleting()) // Ignore while while deleting to prevent crash. + return; + //printf("CtrlCanvas::songChanged type:%x\n", type); // Is it simply a midi controller value adjustment? Forget it. if(type == SC_MIDI_CONTROLLER) @@ -1947,7 +1948,7 @@ void CtrlCanvas::drawOverlay(QPainter& p) //p.setFont(MusEGlobal::config.fonts[3]); //p.setPen(Qt::black); //p.drawText(width()/2-100,height()/2-10, "Use shift + pencil or line tool to draw new events"); - p.drawText(2 , y * 2, tr("Use pencil or line tool to draw new events")); + p.drawText(2 , y * 2, tr("Drawing hint: Hold Ctrl to affect only existing events")); } } @@ -1998,7 +1999,7 @@ void CtrlCanvas::draw(QPainter& p, const QRect& rect) // draw line tool //--------------------------------------------------- - if (drawLineMode && (tool == MusEGui::DrawTool)) { + if ((tool == MusEGui::DrawTool) && drawLineMode) { p.setPen(Qt::black); p.drawLine(line1x, line1y, line2x, line2y); } diff --git a/muse2/muse/ctrl/ctrlcanvas.h b/muse2/muse/ctrl/ctrlcanvas.h index 79910b94..1fcaf1d8 100644 --- a/muse2/muse/ctrl/ctrlcanvas.h +++ b/muse2/muse/ctrl/ctrlcanvas.h @@ -177,6 +177,8 @@ class CtrlCanvas : public MusEGui::View { void updateItems(); void updateSelections(); + //virtual void closeEvent(QCloseEvent*); + private slots: void songChanged(int type); void configChanged(); diff --git a/muse2/muse/ctrl/ctrlpanel.cpp b/muse2/muse/ctrl/ctrlpanel.cpp index ed83bab8..e46f949c 100644 --- a/muse2/muse/ctrl/ctrlpanel.cpp +++ b/muse2/muse/ctrl/ctrlpanel.cpp @@ -162,6 +162,9 @@ CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, CtrlCanvas* c, const char* void CtrlPanel::heartBeat() { + if(editor->deleting()) // Ignore while while deleting to prevent crash. + return; + inHeartBeat = true; if(_track && _ctrl && _dnum != -1) diff --git a/muse2/muse/dialogs.cpp b/muse2/muse/dialogs.cpp index d88977ff..54a080bf 100644 --- a/muse2/muse/dialogs.cpp +++ b/muse2/muse/dialogs.cpp @@ -71,6 +71,22 @@ void init_function_dialogs(QWidget* parent) paste_events_dialog = new PasteEventsDialog(parent); } +void retranslate_function_dialogs() +{ + gatetime_dialog->retranslateUi(gatetime_dialog); + velocity_dialog->retranslateUi(velocity_dialog); + quantize_dialog->retranslateUi(quantize_dialog); + erase_dialog->retranslateUi(erase_dialog); + del_overlaps_dialog->retranslateUi(del_overlaps_dialog); + set_notelen_dialog->retranslateUi(set_notelen_dialog); + move_notes_dialog->retranslateUi(move_notes_dialog); + transpose_dialog->retranslateUi(transpose_dialog); + crescendo_dialog->retranslateUi(crescendo_dialog); + legato_dialog->retranslateUi(legato_dialog); + paste_dialog->retranslateUi(paste_dialog); + paste_events_dialog->retranslateUi(paste_events_dialog); +} + void read_function_dialog_config(MusECore::Xml& xml) { if (erase_dialog==NULL) diff --git a/muse2/muse/dialogs.h b/muse2/muse/dialogs.h index 08830fe0..f2d28f8c 100644 --- a/muse2/muse/dialogs.h +++ b/muse2/muse/dialogs.h @@ -59,6 +59,7 @@ extern PasteDialog* paste_dialog; extern PasteEventsDialog* paste_events_dialog; void init_function_dialogs(QWidget* parent); +void retranslate_function_dialogs(); void read_function_dialog_config(MusECore::Xml& xml); void write_function_dialog_config(int level, MusECore::Xml& xml); diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp index eae695db..4687f17f 100644 --- a/muse2/muse/driver/alsamidi.cpp +++ b/muse2/muse/driver/alsamidi.cpp @@ -39,6 +39,8 @@ #include "part.h" #include "gconfig.h" +#include <QApplication> + namespace MusECore { static int alsaSeqFdi = -1; @@ -46,6 +48,7 @@ static int alsaSeqFdo = -1; snd_seq_t* alsaSeq = 0; static snd_seq_addr_t musePort; +static snd_seq_addr_t announce_adr; //--------------------------------------------------------- // MidiAlsaDevice @@ -83,42 +86,55 @@ QString MidiAlsaDevice::open() QString estr; int wer = 0; int rer = 0; + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca(&pinfo); + //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); + snd_seq_port_info_set_addr(pinfo, &adr); + + int cap = snd_seq_port_info_get_capability(pinfo); // subscribe for writing if (_openFlags & 1) { - snd_seq_port_subscribe_set_sender(subs, &musePort); - snd_seq_port_subscribe_set_dest(subs, &adr); - // Not already subscribed (or error)? Then try subscribing. - if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) - { - //int error = snd_seq_subscribe_port(alsaSeq, subs); - wer = snd_seq_subscribe_port(alsaSeq, subs); - //if (error < 0) - if(wer < 0) - //return QString("Play: ")+QString(snd_strerror(error)); - estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" ")); - } - if(!wer) + if(cap & SND_SEQ_PORT_CAP_SUBS_WRITE) + { + snd_seq_port_subscribe_set_sender(subs, &musePort); + snd_seq_port_subscribe_set_dest(subs, &adr); + // Not already subscribed (or error)? Then try subscribing. + if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) + { + //int error = snd_seq_subscribe_port(alsaSeq, subs); + wer = snd_seq_subscribe_port(alsaSeq, subs); + //if (error < 0) + if(wer < 0) + //return QString("Play: ")+QString(snd_strerror(error)); + estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" ")); + } + } + if(!wer && (cap & SND_SEQ_PORT_CAP_WRITE)) _writeEnable = true; } // subscribe for reading if (_openFlags & 2) { - snd_seq_port_subscribe_set_dest(subs, &musePort); - snd_seq_port_subscribe_set_sender(subs, &adr); - // Not already subscribed (or error)? Then try subscribing. - if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) - { - //int error = snd_seq_subscribe_port(alsaSeq, subs); - rer = snd_seq_subscribe_port(alsaSeq, subs); - //if (error < 0) - if(rer < 0) - //return QString("Rec: ") + QString(snd_strerror(error)); - estr += (QString("Rec: ") + QString(snd_strerror(rer))); - } - if(!rer) + if(cap & SND_SEQ_PORT_CAP_SUBS_READ) + { + snd_seq_port_subscribe_set_dest(subs, &musePort); + snd_seq_port_subscribe_set_sender(subs, &adr); + // Not already subscribed (or error)? Then try subscribing. + if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) + { + //int error = snd_seq_subscribe_port(alsaSeq, subs); + rer = snd_seq_subscribe_port(alsaSeq, subs); + //if (error < 0) + if(rer < 0) + //return QString("Rec: ") + QString(snd_strerror(error)); + estr += (QString("Rec: ") + QString(snd_strerror(rer))); + } + } + if(!rer && (cap & SND_SEQ_PORT_CAP_READ)) _readEnable = true; } @@ -139,6 +155,16 @@ void MidiAlsaDevice::close() // Allocated on stack, no need to call snd_seq_port_subscribe_free() later. snd_seq_port_subscribe_alloca(&subs); + int wer = 0; + int rer = 0; + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca(&pinfo); + //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); + snd_seq_port_info_set_addr(pinfo, &adr); + + int cap = snd_seq_port_info_get_capability(pinfo); + // This function appears to be called only by MidiPort::setMidiDevice(), // which closes then opens the device. // Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags. @@ -158,37 +184,49 @@ void MidiAlsaDevice::close() //if (_openFlags & 1) { //if (!(_openFlags & 1)) { - snd_seq_port_subscribe_set_sender(subs, &musePort); - snd_seq_port_subscribe_set_dest(subs, &adr); - - // Already subscribed? Then unsubscribe. - if(!snd_seq_get_port_subscription(alsaSeq, subs)) - { - if(!snd_seq_unsubscribe_port(alsaSeq, subs)) - _writeEnable = false; - else - printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for writing\n"); + if(cap & SND_SEQ_PORT_CAP_SUBS_WRITE) + { + snd_seq_port_subscribe_set_sender(subs, &musePort); + snd_seq_port_subscribe_set_dest(subs, &adr); + + // Already subscribed? Then unsubscribe. + if(!snd_seq_get_port_subscription(alsaSeq, subs)) + { + wer = snd_seq_unsubscribe_port(alsaSeq, subs); + //if(!wer) + // _writeEnable = false; + //else + if(wer < 0) + printf("MidiAlsaDevice::close Error unsubscribing alsa midi port %d:%d for writing: %s\n", adr.client, adr.port, snd_strerror(wer)); + } + //else + //_writeEnable = false; } - else - _writeEnable = false; + _writeEnable = false; } //if (_openFlags & 2) { //if (!(_openFlags & 2)) { - snd_seq_port_subscribe_set_dest(subs, &musePort); - snd_seq_port_subscribe_set_sender(subs, &adr); - - // Already subscribed? Then unsubscribe. - if(!snd_seq_get_port_subscription(alsaSeq, subs)) - { - if(!snd_seq_unsubscribe_port(alsaSeq, subs)) - _readEnable = false; - else - printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for reading\n"); - } - else - _readEnable = false; + if(cap & SND_SEQ_PORT_CAP_SUBS_READ) + { + snd_seq_port_subscribe_set_dest(subs, &musePort); + snd_seq_port_subscribe_set_sender(subs, &adr); + + // Already subscribed? Then unsubscribe. + if(!snd_seq_get_port_subscription(alsaSeq, subs)) + { + rer = snd_seq_unsubscribe_port(alsaSeq, subs); + //if(!rer) + // _readEnable = false; + //else + if(rer < 0) + printf("MidiAlsaDevice::close Error unsubscribing alsa midi port %d:%d for reading: %s\n", adr.client, adr.port, snd_strerror(rer)); + } + //else + // _readEnable = false; + } + _readEnable = false; } } @@ -208,18 +246,18 @@ void MidiAlsaDevice::writeRouting(int level, Xml& xml) const { if(!r->name().isEmpty()) { - s = QT_TRANSLATE_NOOP("@default", "Route"); + s = "Route"; if(r->channel != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); + s += QString(" channel=\"%1\"").arg(r->channel); xml.tag(level++, s.toLatin1().constData()); xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData()); - s = QT_TRANSLATE_NOOP("@default", "dest"); + s = "dest"; if(r->type == Route::MIDI_DEVICE_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType()); + s += QString(" devtype=\"%1\"").arg(r->device->deviceType()); else if(r->type != Route::TRACK_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); + s += QString(" type=\"%1\"").arg(r->type); + s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); xml.tag(level, s.toLatin1().constData()); xml.etag(level--, "Route"); @@ -696,6 +734,13 @@ bool initMidiAlsa() snd_seq_client_info_set_client(cinfo, -1); while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) { + const char* cname = snd_seq_client_info_get_name(cinfo); + //printf( "ALSA client name: %s\n", cname); + + // Put Midi Through and user clients after others. Insert other unwanted clients here: // p4.0.41 + if(snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT || strcmp("Midi Through", cname) == 0) + continue; + snd_seq_port_info_t *pinfo; snd_seq_port_info_alloca(&pinfo); snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); @@ -703,6 +748,8 @@ bool initMidiAlsa() while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) { unsigned int capability = snd_seq_port_info_get_capability(pinfo); + if (capability & SND_SEQ_PORT_CAP_NO_EXPORT) // Ignore ports like "qjackctl" or "port". p4.0.41 + continue; if ((capability & outCap) == 0) { const char *name = snd_seq_port_info_get_name(pinfo); if (strcmp("Timer", name) == 0 || @@ -724,29 +771,52 @@ bool initMidiAlsa() adr.client, adr.port, flags, capability); MusEGlobal::midiDevices.add(dev); - - /* - // Experimental... Need to list 'sensible' devices first and ignore unwanted ones... - // Add instance last in midi device list. - for(int i = 0; i < MIDI_PORTS; ++i) - { - MidiPort* mp = &MusEGlobal::midiPorts[i]; - if(mp->device() == 0) - { - // midiSeq might not be initialzed yet! - //MusEGlobal::midiSeq->msgSetMidiDevice(mp, dev); - mp->setMidiDevice(dev); - - //muse->changeConfig(true); // save configuration file - //update(); - break; - } } - */ - + } + + snd_seq_client_info_set_client(cinfo, -1); // Reset + while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) { + const char* cname = snd_seq_client_info_get_name(cinfo); + //printf( "ALSA client name: %s\n", cname); + + // Put Midi Through and user clients after others. Insert other unwanted clients here: // p4.0.41 + if( !(snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT || strcmp("Midi Through", cname) == 0) ) + continue; + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca(&pinfo); + snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); + snd_seq_port_info_set_port(pinfo, -1); + + while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) { + unsigned int capability = snd_seq_port_info_get_capability(pinfo); + if (capability & SND_SEQ_PORT_CAP_NO_EXPORT) // Ignore ports like "qjackctl" or "port". p4.0.41 + continue; + if ((capability & outCap) == 0) { + const char *name = snd_seq_port_info_get_name(pinfo); + if (strcmp("Timer", name) == 0 || + strcmp("Announce", name) == 0 || + strcmp("Receiver", name) == 0) + continue; + } + snd_seq_addr_t adr = *snd_seq_port_info_get_addr(pinfo); + MidiAlsaDevice* dev = new MidiAlsaDevice(adr, QString(snd_seq_port_info_get_name(pinfo))); + int flags = 0; + if (capability & outCap) + flags |= 1; + if (capability & inCap) + flags |= 2; + dev->setrwFlags(flags); + if (MusEGlobal::debugMsg) + printf("ALSA port add: <%s>, %d:%d flags %d 0x%0x\n", + snd_seq_port_info_get_name(pinfo), + adr.client, adr.port, + flags, capability); + MusEGlobal::midiDevices.add(dev); } } - + + //snd_seq_set_client_name(alsaSeq, "MusE Sequencer"); snd_seq_set_client_name(alsaSeq, MusEGlobal::audioDevice->clientName()); @@ -781,14 +851,14 @@ bool initMidiAlsa() // alsa port changes //----------------------------------------- - snd_seq_addr_t aadr; - aadr.client = SND_SEQ_CLIENT_SYSTEM; - aadr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; + //snd_seq_addr_t aadr; + announce_adr.client = SND_SEQ_CLIENT_SYSTEM; + announce_adr.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; snd_seq_port_subscribe_t* subs; snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_dest(subs, &musePort); - snd_seq_port_subscribe_set_sender(subs, &aadr); + snd_seq_port_subscribe_set_sender(subs, &announce_adr); error = snd_seq_subscribe_port(alsaSeq, subs); if (error < 0) { printf("Alsa: Subscribe System failed: %s", snd_strerror(error)); @@ -805,12 +875,35 @@ bool initMidiAlsa() void exitMidiAlsa() { if(alsaSeq) - { - int error = snd_seq_close(alsaSeq); // FIXME Hm, this did not get rid of a buch of valgrind leaks. - if(error < 0) + { + int error = 0; + snd_seq_port_subscribe_t* subs; + // Allocated on stack, no need to call snd_seq_port_subscribe_free() later. + snd_seq_port_subscribe_alloca(&subs); + + snd_seq_port_info_t *pinfo; + snd_seq_port_info_alloca(&pinfo); + //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); + snd_seq_port_info_set_addr(pinfo, &announce_adr); + + snd_seq_port_subscribe_set_dest(subs, &musePort); + snd_seq_port_subscribe_set_sender(subs, &announce_adr); + + // Already subscribed? Then unsubscribe. + if(!snd_seq_get_port_subscription(alsaSeq, subs)) { - fprintf(stderr, "Could not close ALSA sequencer: %s\n", snd_strerror(error)); - } + error = snd_seq_unsubscribe_port(alsaSeq, subs); + if(error < 0) + printf("MusE: exitMidiAlsa: Error unsubscribing alsa midi Announce port %d:%d for reading: %s\n", announce_adr.client, announce_adr.port, snd_strerror(error)); + } + + error = snd_seq_delete_simple_port(alsaSeq, musePort.port); + if(error < 0) + fprintf(stderr, "MusE: Could not delete ALSA simple port: %s\n", snd_strerror(error)); + + error = snd_seq_close(alsaSeq); + if(error < 0) + fprintf(stderr, "MusE: Could not close ALSA sequencer: %s\n", snd_strerror(error)); } } @@ -850,7 +943,9 @@ void alsaScanMidiPorts() snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) { - unsigned int capability = snd_seq_port_info_get_capability(pinfo); + unsigned int capability = snd_seq_port_info_get_capability(pinfo); + if (capability & SND_SEQ_PORT_CAP_NO_EXPORT) // Ignore ports like "qjackctl" or "port". p4.0.41 + continue; if (((capability & outCap) == 0) && ((capability & inCap) == 0)) continue; @@ -900,6 +995,8 @@ void alsaScanMidiPorts() // // check for devices to add // + // TODO: Possibly auto-add them to available midi ports. p4.0.41 + // for (std::list<AlsaPort>::iterator k = portList.begin(); k != portList.end(); ++k) { iMidiDevice i = MusEGlobal::midiDevices.begin(); // printf("ALSA port: <%s>\n", k->name); @@ -920,6 +1017,8 @@ void alsaScanMidiPorts() // printf("add device\n"); } } + + } //--------------------------------------------------------- diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index 733353d8..421152a7 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -735,7 +735,11 @@ void JackAudioDevice::connectJackMidiPorts() { RouteList* rl = md->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + if(r->type != Route::JACK_ROUTE) + continue; connect(port, r->jackPort); + } } } @@ -748,7 +752,11 @@ void JackAudioDevice::connectJackMidiPorts() { RouteList* rl = md->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) + { + if(r->type != Route::JACK_ROUTE) + continue; connect(r->jackPort, port); + } } } } @@ -939,6 +947,8 @@ void JackAudioDevice::graphChanged() for (int i = 0;i < 20;i++) { erased = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; if (irl->channel != channel) continue; QString name = irl->name(); @@ -977,6 +987,8 @@ void JackAudioDevice::graphChanged() while (*pn) { bool found = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; if (irl->channel != channel) continue; QString name = irl->name(); @@ -1027,6 +1039,8 @@ void JackAudioDevice::graphChanged() for (int i = 0; i < 20 ; i++) { erased = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; if (irl->channel != channel) continue; QString name = irl->name(); @@ -1064,6 +1078,8 @@ void JackAudioDevice::graphChanged() while (*pn) { bool found = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; if (irl->channel != channel) continue; QString name = irl->name(); @@ -1139,6 +1155,8 @@ void JackAudioDevice::graphChanged() { erased = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1181,6 +1199,8 @@ void JackAudioDevice::graphChanged() while (*pn) { bool found = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1239,6 +1259,8 @@ void JackAudioDevice::graphChanged() { erased = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1280,6 +1302,8 @@ void JackAudioDevice::graphChanged() while (*pn) { bool found = false; for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { + if(irl->type != Route::JACK_ROUTE) + continue; //if (irl->channel != channel) // continue; QString name = irl->name(); @@ -1482,6 +1506,8 @@ void JackAudioDevice::start(int /*priority*/) RouteList* rl = ai->inRoutes(); void* port = ai->jackPort(ch); for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) { + if(ir->type != Route::JACK_ROUTE) + continue; if (ir->channel == ch) connect(ir->jackPort, port); } @@ -1495,6 +1521,8 @@ void JackAudioDevice::start(int /*priority*/) RouteList* rl = ai->outRoutes(); void* port = ai->jackPort(ch); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { + if(r->type != Route::JACK_ROUTE) + continue; if (r->channel == ch) { connect(port, r->jackPort); } @@ -1603,6 +1631,107 @@ int JackAudioDevice::frameDelay() const #endif //--------------------------------------------------------- +// getJackPorts +//--------------------------------------------------------- + +void JackAudioDevice::getJackPorts(const char** ports, std::list<QString>& name_list, bool midi, bool physical, int aliases) + { + if (JACK_DEBUG) + printf("JackAudioDevice::getJackPorts()\n"); + //std::list<QString> clientList; + //if(!checkJackClient(_client)) return clientList; + //if(!checkJackClient(_client)) return; + QString qname; + //const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; + //const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); + //const char** ports = jack_get_ports(_client, 0, type, jflags); + + QString cname(jack_get_client_name(_client)); + + for (const char** p = ports; p && *p; ++p) { + jack_port_t* port = jack_port_by_name(_client, *p); + //int flags = jack_port_flags(port); + //if (!(flags & JackPortIsInput)) + // continue; + //char buffer[128]; + + int port_flags = jack_port_flags(port); + //printf("JackAudioDevice::getJackPorts port: %s flags: %d\n", *p, port_flags); + + // Ignore our own client ports. + if(jack_port_is_mine(_client, port)) + { + if(MusEGlobal::debugMsg) + printf("JackAudioDevice::getJackPorts ignoring own port: %s\n", *p); + continue; + } + + int nsz = jack_port_name_size(); + char buffer[nsz]; + + bool mthrough = false; + + if(midi) + { + strncpy(buffer, *p, nsz); + char a2[nsz]; + char* al[2]; + al[0] = buffer; + al[1] = a2; + int na = jack_port_get_aliases(port, al); + if(na >= 1) + { + qname = QString(al[0]); + //printf("Checking port name for: %s\n", (QString("alsa_pcm:") + cname + QString("/")).toLatin1().constData()); + // Ignore our own ALSA client! + if(qname.startsWith(QString("alsa_pcm:") + cname + QString("/"))) + continue; + // Put Midi Through after all others. + mthrough = qname.startsWith(QString("alsa_pcm:Midi-Through/")); + //if((physical && mthrough) || (!physical && !mthrough)) + //if(physical && mthrough) + // continue; + } + } + // Put physical/terminal ports before others. + bool is_phys = (port_flags & (JackPortIsTerminal | JackPortIsPhysical)) && !mthrough; + if((physical && !is_phys) || (!physical && is_phys)) + continue; + + + strncpy(buffer, *p, nsz); + if((aliases == 0) || (aliases == 1)) + { + char a2[nsz]; + char* al[2]; + al[0] = buffer; + al[1] = a2; + int na = jack_port_get_aliases(port, al); + int a = aliases; + if(a >= na) + { + a = na; + if(a > 0) + a--; + } + qname = QString(al[a]); + } + else + qname = QString(buffer); + + //clientList.push_back(QString(buffer)); + name_list.push_back(qname); + } + + // p3.3.37 + //if(ports) + //free(ports); + // jack_free(ports); // p4.0.29 + + //return clientList; + } + +//--------------------------------------------------------- // outputPorts //--------------------------------------------------------- @@ -1612,9 +1741,11 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases) printf("JackAudioDevice::outputPorts()\n"); std::list<QString> clientList; if(!checkJackClient(_client)) return clientList; - QString qname; const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput); + + /* + QString qname; for (const char** p = ports; p && *p; ++p) { jack_port_t* port = jack_port_by_name(_client, *p); //int flags = jack_port_flags(port); @@ -1666,12 +1797,15 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases) //clientList.push_back(QString(buffer)); clientList.push_back(qname); } - - // p3.3.37 - if(ports) - //free(ports); - jack_free(ports); // p4.0.29 + */ + if(ports) + { + getJackPorts(ports, clientList, midi, true, aliases); // Get physical ports first. + getJackPorts(ports, clientList, midi, false, aliases); // Get non-physical ports last. + jack_free(ports); + } + return clientList; } @@ -1683,11 +1817,14 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases) { if (JACK_DEBUG) printf("JackAudioDevice::inputPorts()\n"); + std::list<QString> clientList; if(!checkJackClient(_client)) return clientList; - QString qname; const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); + + /* + QString qname; for (const char** p = ports; p && *p; ++p) { jack_port_t* port = jack_port_by_name(_client, *p); //int flags = jack_port_flags(port); @@ -1739,12 +1876,15 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases) //clientList.push_back(QString(buffer)); clientList.push_back(qname); } - - // p3.3.37 - if(ports) - //free(ports); - jack_free(ports); // p4.0.29 + */ + if(ports) + { + getJackPorts(ports, clientList, midi, true, aliases); // Get physical ports first. + getJackPorts(ports, clientList, midi, false, aliases); // Get non-physical ports last. + jack_free(ports); + } + return clientList; } diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h index bd78d481..c4d37db9 100644 --- a/muse2/muse/driver/jackaudio.h +++ b/muse2/muse/driver/jackaudio.h @@ -50,6 +50,7 @@ class JackAudioDevice : public AudioDevice { // Free-running frame counter incremented always in process. jack_nframes_t _frameCounter; + void getJackPorts(const char** ports, std::list<QString>& name_list, bool midi, bool physical, int aliases); static int processAudio(jack_nframes_t frames, void*); public: diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp index fa23d336..7a12b92d 100644 --- a/muse2/muse/driver/jackmidi.cpp +++ b/muse2/muse/driver/jackmidi.cpp @@ -276,10 +276,10 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const if(!r->name().isEmpty()) { xml.tag(level++, "Route"); - s = QT_TRANSLATE_NOOP("@default", "source"); + s = "source"; if(r->type != Route::TRACK_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); + s += QString(" type=\"%1\"").arg(r->type); + s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); xml.tag(level, s.toLatin1().constData()); xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData()); xml.etag(level--, "Route"); @@ -291,18 +291,18 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const { if(!r->name().isEmpty()) { - s = QT_TRANSLATE_NOOP("@default", "Route"); + s = "Route"; if(r->channel != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); + s += QString(" channel=\"%1\"").arg(r->channel); xml.tag(level++, s.toLatin1().constData()); xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData()); - s = QT_TRANSLATE_NOOP("@default", "dest"); + s = "dest"; if(r->type == Route::MIDI_DEVICE_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType()); + s += QString(" devtype=\"%1\"").arg(r->device->deviceType()); else if(r->type != Route::TRACK_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); + s += QString(" type=\"%1\"").arg(r->type); + s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); xml.tag(level, s.toLatin1().constData()); diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp index 92120dbb..2e4e6d35 100644 --- a/muse2/muse/dssihost.cpp +++ b/muse2/muse/dssihost.cpp @@ -99,6 +99,7 @@ static void scanDSSILib(QFileInfo& fi) // ddskrjo removed const for argument // That way we cover all bases - effect plugins and synths. // Non-synths will show up in the ladspa effect dialog, while synths will show up here... // There should be nothing left out... + // TIP: Until we add programs to plugins, comment these four checks to load dssi effects as synths, in order to have programs. if(descr->run_synth || descr->run_synth_adding || descr->run_multiple_synths || @@ -498,6 +499,9 @@ bool DssiSynthIF::init(DssiSynth* s) int inports = synth->_inports; if(inports != 0) { + posix_memalign((void**)&audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize); + memset(audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize); + audioInBuffers = new float*[inports]; for(int k = 0; k < inports; ++k) { @@ -723,6 +727,7 @@ DssiSynthIF::DssiSynthIF(SynthI* s) controls = 0; controlsOut = 0; audioInBuffers = 0; + audioInSilenceBuf = 0; audioOutBuffers = 0; } @@ -785,6 +790,9 @@ DssiSynthIF::~DssiSynthIF() delete[] audioInBuffers; } + if(audioInSilenceBuf) + free(audioInSilenceBuf); + if(audioOutBuffers) { for(unsigned long i = 0; i < synth->_outports; ++i) @@ -1420,7 +1428,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t // getData //--------------------------------------------------------- -MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MPEventList* el, MusECore::iMPEvent i, unsigned pos, int ports, unsigned n, float** buffer) +MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MPEventList* el, MusECore::iMPEvent start_event, unsigned pos, int ports, unsigned nframes, float** buffer) { //#ifdef DSSI_DEBUG // fprintf(stderr, "DssiSynthIF::getData elsize:%d pos:%d ports:%d samples:%d processed already?:%d\n", el->size(), pos, ports, n, synti->processed()); @@ -1440,19 +1448,11 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP // All ports must be connected to something! unsigned long nop, k; - // First, copy the given input buffers to our local input buffers. - //np = portsin > synth->_inports ? synth->_inports : portsin; - //for(k = 0; k < np; ++k) - // memcpy(audioInBuffers[k], inbuffer[k], sizeof(float) * n); - //for(; k < portsin; ++k) - // memset(audioInBuffers[k], 0, sizeof(float) * n); // Watch our limits. //willyfoobar-2011-02-13 //old code//np = ports > synth->_outports ? synth->_outports : ports; nop = ((unsigned long) ports) > synth->_outports ? synth->_outports : ((unsigned long) ports); - // TODO Number of inports requested? - //nip = ((unsigned long) iports) > synth->_inports ? synth->_inports : ((unsigned long) iports); const DSSI_Descriptor* dssi = synth->dssi; const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin; @@ -1484,18 +1484,109 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP // Note for dssi-vst this MUST equal MusEGlobal::audio period. It doesn't like broken-up runs (it stutters), // even with fixed sizes. Could be a Wine + Jack thing, wanting a full Jack buffer's length. //unsigned long fixedsize = 2048; - unsigned long fixedsize = n; + unsigned long fixedsize = nframes; // For now, the fixed size is clamped to the MusEGlobal::audio buffer size. // TODO: We could later add slower processing over several cycles - // so that users can select a small MusEGlobal::audio period but a larger control period. - if(fixedsize > n) - fixedsize = n; + if(fixedsize > nframes) + fixedsize = nframes; unsigned long min_per = MusEGlobal::config.minControlProcessPeriod; - if(min_per > n) - min_per = n; + if(min_per > nframes) + min_per = nframes; + + // + // p4.0.38 Handle inputs... + // + if(!((MusECore::AudioTrack*)synti)->noInRoute()) + { + RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes(); + iRoute i = irl->begin(); + if(i->track->isMidiTrack()) + { + //if(MusEGlobal::debugMsg) + //printf("DssiSynthIF::getData: Error: First route is a midi track route!\n"); + } + else + { + int ch = i->channel == -1 ? 0 : i->channel; + int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel; + int chs = i->channels == -1 ? 0 : i->channels; + + if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports) + { + //printf("DssiSynthIF::getData calling copyData on %s ch:%d remch:%d chs:%d\n", i->track->name().toLatin1().constData(), ch, remch, chs); + + int h = remch + chs; + for(int j = remch; j < h; ++j) + { + //printf(" setting used idx:%d\n", j); + synth->iUsedIdx[j] = true; + } + + ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); + } + } + + ++i; + for(; i != irl->end(); ++i) + { + if(i->track->isMidiTrack()) + { + //if(MusEGlobal::debugMsg) + // printf("DssiSynthIF::getData: Error: Route is a midi track route!\n"); + continue; + } + + int ch = i->channel == -1 ? 0 : i->channel; + int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel; + int chs = i->channels == -1 ? 0 : i->channels; + if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports) + { + //printf("DssiSynthIF::getData calling addData on %s ch:%d remch:%d chs:%d\n", i->track->name().toLatin1().constData(), ch, remch, chs); + + bool u1 = synth->iUsedIdx[remch]; + if(chs >= 2) + { + bool u2 = synth->iUsedIdx[remch + 1]; + if(u1 && u2) + ((MusECore::AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); + else + if(!u1 && !u2) + ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); + else + { + if(u1) + ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]); + else + ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]); + + if(u2) + ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]); + else + ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]); + } + } + else + { + if(u1) + ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]); + else + ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]); + } + + int h = remch + chs; + for(int j = remch; j < h; ++j) + { + //printf(" setting used idx:%d\n", j); + synth->iUsedIdx[j] = true; + } + } + } + } + // Process automation control values now. // TODO: This needs to be respect frame resolution. Put this inside the sample loop below. if(MusEGlobal::automation && synti && synti->automationType() != AUTO_OFF && id() != -1) @@ -1507,11 +1598,11 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP } } - while(sample < n) + while(sample < nframes) { //unsigned long nsamp = n; //unsigned long nsamp = n - sample; - unsigned long nsamp = usefixedrate ? fixedsize : n - sample; + unsigned long nsamp = usefixedrate ? fixedsize : nframes - sample; bool found = false; unsigned long frame = 0; unsigned long index = 0; @@ -1525,7 +1616,7 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP // The events happened in the last period or even before that. Shift into this period with + n. This will sync with MusEGlobal::audio. // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame. //evframe = (pos + frameOffset > v.frame + n) ? 0 : v.frame - pos - frameOffset + n; - evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n; + evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes; // Protection. Observed this condition. Why? Supposed to be linear timestamps. if(found && evframe < frame) { @@ -1545,7 +1636,7 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP //if(v.frame < startPos || v.frame >= (endPos + frameOffset) //if(evframe < sample || evframe >= n //if(evframe < sample || evframe >= (n + frameOffset) - if(evframe >= n + if(evframe >= nframes //|| (found && v.frame != frame) //|| (!usefixedrate && found && !v.unique && v.frame != frame) //|| (found && !v.unique && evframe != frame) @@ -1567,6 +1658,31 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP index = v.idx; // Set the ladspa control port value. controls[v.idx].val = v.value; + + // Need to update the automation value, otherwise it overwrites later with the last MusEGlobal::automation value. + if(id() != -1) + { + // Since we are now in the audio thread context, there's no need to send a message, + // just modify directly. + //MusEGlobal::audio->msgSetPluginCtrlVal(_track, genACnum(_id, k), controls[k].val); + synti->setPluginCtrlVal(genACnum(id(), v.idx), v.value); + + // Record automation. + // NO! Take care of this immediately in the OSC control handler, because we don't want + // any delay. + // OTOH Since this is the actual place and time where the control ports values + // are set, best to reflect what happens here to automation. + // However for dssi-vst it might be best to handle it that way. + + //AutomationType at = _track->automationType(); + // TODO: Taken from our native gui control handlers. + // This may need modification or may cause problems - + // we don't have the luxury of access to the dssi gui controls ! + //if(at == AUTO_WRITE || (MusEGlobal::audio->isPlaying() && at == AUTO_TOUCH)) + // enableController(k, false); + //_track->recordAutomation(id, v.value); + } + } // Process automation control values now. @@ -1583,8 +1699,8 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP if(found && !usefixedrate) //nsamp = frame - sample + 1; nsamp = frame - sample; - if(sample + nsamp >= n) // Safety check. - nsamp = n - sample; + if(sample + nsamp >= nframes) // Safety check. + nsamp = nframes - sample; //printf("DssiSynthIF::getData n:%d frame:%lu sample:%lu nsamp:%lu pos:%d fOffset:%d syncFrame:%lu loopcount:%d\n", // n, frame, sample, nsamp, pos, frameOffset, syncFrame, loopcount); // REMOVE Tim. @@ -1596,10 +1712,10 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP nevents = 0; // Process event list events... - for(; i != el->end(); ++i) + for(; start_event != el->end(); ++start_event) { //if(i->time() >= (endPos + frameOffset)) // NOTE: frameOffset? Tested, examined printouts of times: Seems OK for playback. - if(i->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again... + if(start_event->time() >= (pos + sample + nsamp + frameOffset)) // frameOffset? Test again... break; #ifdef DSSI_DEBUG @@ -1611,40 +1727,40 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP if(synti->midiPort() != -1) { MusECore::MidiPort* mp = &MusEGlobal::midiPorts[synti->midiPort()]; - if(i->type() == MusECore::ME_CONTROLLER) + if(start_event->type() == MusECore::ME_CONTROLLER) { - int da = i->dataA(); - int db = i->dataB(); + int da = start_event->dataA(); + int db = start_event->dataB(); db = mp->limitValToInstrCtlRange(da, db); - if(!mp->setHwCtrlState(i->channel(), da, db)) + if(!mp->setHwCtrlState(start_event->channel(), da, db)) continue; } else - if(i->type() == MusECore::ME_PITCHBEND) + if(start_event->type() == MusECore::ME_PITCHBEND) { - int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, i->dataA()); - if(!mp->setHwCtrlState(i->channel(), MusECore::CTRL_PITCH, da)) + int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, start_event->dataA()); + if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PITCH, da)) continue; } else - if(i->type() == MusECore::ME_PROGRAM) + if(start_event->type() == MusECore::ME_PROGRAM) { - if(!mp->setHwCtrlState(i->channel(), MusECore::CTRL_PROGRAM, i->dataA())) + if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PROGRAM, start_event->dataA())) continue; } } // Returns false if the event was not filled. It was handled, but some other way. - if(processEvent(*i, &events[nevents])) + if(processEvent(*start_event, &events[nevents])) { // Time-stamp the event. p4.0.15 Tim. - int ft = i->time() - frameOffset - pos; + int ft = start_event->time() - frameOffset - pos; if(ft < 0) ft = 0; //if (ft >= (int)MusEGlobal::segmentSize) if (ft >= int(sample + nsamp)) { - printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", i->time(), pos, frameOffset, ft, sample, nsamp); + printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp); ///if (ft > (int)MusEGlobal::segmentSize) //ft = MusEGlobal::segmentSize - 1; ft = sample + nsamp - 1; @@ -1696,61 +1812,6 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP } } - /* - // - // p3.3.39 Handle inputs... - // - //if((MusEGlobal::song->bounceTrack != this) && !noInRoute()) - if(!((MusECore::AudioTrack*)synti)->noInRoute()) - { - RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes(); - iRoute i = irl->begin(); - if(!i->track->isMidiTrack()) - { - //if(MusEGlobal::debugMsg) - printf("DssiSynthIF::getData: Error: First route is a midi track route!\n"); - } - else - { - int ch = i->channel == -1 ? 0 : i->channel; - int remch = i->remoteChannel == -1 ? 0 : i->remoteChannel; - int chs = i->channels == -1 ? 0 : i->channels; - - // TODO: - //if(ch >= synth->_inports) - //iUsedIdx[ch] = true; - //if(chs == 2) - // iUsedIdx[ch + 1] = true; - - //((MusECore::AudioTrack*)i->track)->copyData(framePos, channels, nframe, bp); - ((MusECore::AudioTrack*)i->track)->copyData(pos, ports, - //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0, - i->channel, - i->channels, - n, bp); - } - - //unsigned pos, int ports, unsigned n, float** buffer - - ++i; - for(; i != irl->end(); ++i) - { - if(i->track->isMidiTrack()) - { - //if(MusEGlobal::debugMsg) - printf("DssiSynthIF::getData: Error: Route is a midi track route!\n"); - continue; - } - //((MusECore::AudioTrack*)i->track)->addData(framePos, channels, nframe, bp); - ((MusECore::AudioTrack*)i->track)->addData(framePos, channels, - //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0, - i->channel, - i->channels, - nframe, bp); - } - } - */ - k = 0; // Connect the given buffers directly to the ports, up to a max of synth ports. for(; k < nop; ++k) @@ -1758,9 +1819,21 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP // Connect the remaining ports to some local buffers (not used yet). for(; k < synth->_outports; ++k) descr->connect_port(handle, synth->oIdx[k], audioOutBuffers[k] + sample); - // Just connect all inputs to some local buffers (not used yet). TODO: Support inputs. + // Connect all inputs either to some local buffers, or a silence buffer. for(k = 0; k < synth->_inports; ++k) - descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample); + { + //printf(" k:%d synth->iIdx[k]:%d\n", k, synth->iIdx[k]); + if(synth->iUsedIdx[k]) + { + synth->iUsedIdx[k] = false; // Reset + descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample); + } + else + { + //printf(" input used size:%ld idx:%ld = %d silencing...\n", synth->iUsedIdx.size(), k, synth->iUsedIdx[k]); + descr->connect_port(handle, synth->iIdx[k], audioInSilenceBuf + sample); + } + } // Run the synth for a period of time. This processes events and gets/fills our local buffers... if(synth->dssi->run_synth) @@ -1772,10 +1845,10 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP snd_seq_event_t* ev = events; synth->dssi->run_multiple_synths(1, &handle, nsamp, &ev, &nevents); } + // TIP: Until we add programs to plugins, uncomment these four checks to load dssi effects as synths, in order to have programs. //else //if(synth->dssi->LADSPA_Plugin->run) //{ - // // Just a test, worked OK. // synth->dssi->LADSPA_Plugin->run(handle, nsamp); //} @@ -1783,14 +1856,13 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP loopcount++; // REMOVE Tim. } - return i; + return start_event; } //--------------------------------------------------------- // putEvent //--------------------------------------------------------- -//bool DssiSynthIF::putEvent(const MidiEvent& ev) bool DssiSynthIF::putEvent(const MusECore::MidiPlayEvent& ev) { #ifdef DSSI_DEBUG @@ -2033,16 +2105,37 @@ int DssiSynthIF::oscControl(unsigned long port, float value) fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\n", cport); } - MusECore::ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport); - if(ip != synth->port2MidiCtlMap.end()) + // Record automation: + // Take care of this immediately, because we don't want the silly delay associated with + // processing the fifo one-at-a-time in the apply(). + // NOTE: With some vsts we don't receive control events until the user RELEASES a control. + // So the events all arrive at once when the user releases a control. + // That makes this pretty useless... But what the heck... + if(id() != -1) { + //int id = genACnum(_id, cport); + unsigned long pid = genACnum(id(), cport); + AutomationType at = synti->automationType(); + + // TODO: Taken from our native gui control handlers. + // This may need modification or may cause problems - + // we don't have the luxury of access to the dssi gui controls ! + if(at == AUTO_WRITE || (MusEGlobal::audio->isPlaying() && at == AUTO_TOUCH)) + enableController(cport, false); + + synti->recordAutomation(pid, value); + } + + //MusECore::ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport); + //if(ip != synth->port2MidiCtlMap.end()) + //{ // TODO: TODO: Update midi MusE's midi controller knobs, sliders, boxes etc with a call to the midi port's setHwCtrlState() etc. // But first we need a ladspa2MidiValue() function! ... // // //float val = ladspa2MidiValue(ld, i, ?, ?); - } + //} return 0; } @@ -2064,8 +2157,8 @@ int DssiSynthIF::oscMidi(int a, int b, int c) { MusECore::MidiPlayEvent event(0, port, channel, a, b, c); - #ifdef DSSI_DEBUG - printf(stderr, "DssiSynthIF::oscMidi midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB()); + #ifdef DSSI_DEBUG + printf("DssiSynthIF::oscMidi midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB()); #endif MusEGlobal::midiPorts[port].sendEvent(event); @@ -2329,7 +2422,8 @@ QString DssiSynthIF::name() const { return synti->nam QString DssiSynthIF::lib() const { return synth ? synth->completeBaseName() : QString(); } QString DssiSynthIF::dirPath() const { return synth ? synth->absolutePath() : QString(); } QString DssiSynthIF::fileName() const { return synth ? synth->fileName() : QString(); } -MusECore::AudioTrack* DssiSynthIF::track() { return (MusECore::AudioTrack*)synti; } +QString DssiSynthIF::titlePrefix() const { return QString(); } +MusECore::AudioTrack* DssiSynthIF::track() { return (MusECore::AudioTrack*)synti; } void DssiSynthIF::enableController(unsigned long i, bool v) { controls[i].enCtrl = v; } bool DssiSynthIF::controllerEnabled(unsigned long i) const { return controls[i].enCtrl; } bool DssiSynthIF::controllerEnabled2(unsigned long i) const { return controls[i].en2Ctrl; } diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h index 9b00b642..2836d72e 100644 --- a/muse2/muse/dssihost.h +++ b/muse2/muse/dssihost.h @@ -76,7 +76,8 @@ class DssiSynth : public Synth { unsigned long _portCount, _inports, _outports, _controlInPorts, _controlOutPorts; std::vector<unsigned long> iIdx; // Audio input index to port number. std::vector<unsigned long> oIdx; // Audio output index to port number. - std::vector<bool> iUsedIdx; // During process, tells whether an audio input port was used by any input routes. + //std::vector<bool> iUsedIdx; // During process, tells whether an audio input port was used by any input routes. + std::vector<int> iUsedIdx; // During process, tells whether an audio input port was used by any input routes. std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input. MusECore::MidiCtl2LadspaPortMap midiCtl2PortMap; // Maps midi controller numbers to DSSI port numbers. MusECore::MidiCtl2LadspaPortMap port2MidiCtlMap; // Maps DSSI port numbers to midi controller numbers. @@ -88,6 +89,8 @@ class DssiSynth : public Synth { public: DssiSynth(QFileInfo&, const DSSI_Descriptor*); // removed const for QFileInfo virtual ~DssiSynth(); + virtual Type synthType() const { return DSSI_SYNTH; } + virtual void incInstances(int); virtual SynthIF* createSIF(SynthI*); @@ -122,6 +125,7 @@ class DssiSynthIF : public SynthIF, public PluginIBase float** audioInBuffers; float** audioOutBuffers; + float* audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence. public: DssiSynthIF(SynthI* s); @@ -195,6 +199,7 @@ class DssiSynthIF : public SynthIF, public PluginIBase QString lib() const; QString dirPath() const; QString fileName() const; + QString titlePrefix() const; MusECore::AudioTrack* track(); void enableController(unsigned long /*i*/, bool v = true); bool controllerEnabled(unsigned long /*i*/) const; diff --git a/muse2/muse/exportmidi.cpp b/muse2/muse/exportmidi.cpp index b892e808..4a9c1f6d 100644 --- a/muse2/muse/exportmidi.cpp +++ b/muse2/muse/exportmidi.cpp @@ -149,15 +149,28 @@ void MusE::exportMidi() return; MusECore::MidiFile mf(fp); - MusECore::MidiTrackList* tl = MusEGlobal::song->midis(); - int ntracks = tl->size(); + //MusECore::MidiTrackList* tl = MusEGlobal::song->midis(); + MusECore::TrackList* tl = MusEGlobal::song->tracks(); // Changed to full track list so user can rearrange tracks. + //int ntracks = tl->size(); MusECore::MidiFileTrackList* mtl = new MusECore::MidiFileTrackList; int i = 0; - for (MusECore::iMidiTrack im = tl->begin(); im != tl->end(); ++im, ++i) { - MusECore::MidiTrack* track = *im; - MusECore::MidiFileTrack* mft = new MusECore::MidiFileTrack; - mtl->push_back(mft); + MusECore::MidiFileTrack* mft = 0; + //for (MusECore::iMidiTrack im = tl->begin(); im != tl->end(); ++im, ++i) { + for (MusECore::ciTrack im = tl->begin(); im != tl->end(); ++im) { + + if(!(*im)->isMidiTrack()) + continue; + + MusECore::MidiTrack* track = (MusECore::MidiTrack*)(*im); + + //MusECore::MidiFileTrack* mft = new MusECore::MidiFileTrack; + if (i == 0 || (i != 0 && MusEGlobal::config.smfFormat != 0)) // Changed to single track. Tim + { + mft = new MusECore::MidiFileTrack; + mtl->push_back(mft); + } + MusECore::MPEventList* l = &(mft->events); int port = track->outPort(); int channel = track->outChannel(); @@ -200,14 +213,17 @@ void MusE::exportMidi() //--------------------------------------------------- // Write Coment // - QString comment = track->comment(); - if (!comment.isEmpty()) { - int len = comment.length(); - MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)(comment.toLatin1().constData()), len); - ev.setA(0x1); - l->add(ev); - } - + //if (MusEGlobal::config.smfFormat == 0) // Only for smf 0 added by Tim. FIXME: Is this correct? See below. + { + QString comment = track->comment(); + if (!comment.isEmpty()) { + int len = comment.length(); + MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)(comment.toLatin1().constData()), len); + ev.setA(0x1); + l->add(ev); + } + } + //--------------------------------------------------- // Write Songtype SYSEX: GM/GS/XG // @@ -287,27 +303,38 @@ void MusE::exportMidi() // track name //----------------------------------- - if (!track->name().isEmpty()) { - QByteArray ba = track->name().toLatin1(); - const char* name = ba.constData(); - int len = strlen(name); - MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)name, len+1); - ev.setA(0x3); // Meta Sequence/Track Name - l->add(ev); - } - + if (i == 0 || (i != 0 && MusEGlobal::config.smfFormat != 0)) + { + if (!track->name().isEmpty()) { + QByteArray ba = track->name().toLatin1(); + const char* name = ba.constData(); + int len = strlen(name); + MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)name, len+1); + ev.setA(0x3); // Meta Sequence/Track Name + l->add(ev); + } + } + //----------------------------------- // track comment //----------------------------------- - if (!track->comment().isEmpty()) { - QByteArray ba = track->comment().toLatin1(); - const char* comment = ba.constData(); - int len = strlen(comment); - MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)comment, len+1); - ev.setA(0xf); // Meta Text - l->add(ev); - } + // FIXME: What are these 0x0F? All I found was that they are unspecified part of the sixteen text meta events. + // So why not use 0x01? And do we include it for all tracks, or only above 1? Tim. + //if (i == 0 || (i != 0 && MusEGlobal::config.smfFormat != 0)) + //if (i != 0 && MusEGlobal::config.smfFormat != 0) + if (MusEGlobal::config.smfFormat != 0) + { + if (!track->comment().isEmpty()) { + QByteArray ba = track->comment().toLatin1(); + const char* comment = ba.constData(); + int len = strlen(comment); + MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)comment, len+1); + ev.setA(0xf); // Meta Text + l->add(ev); + } + } + MusECore::PartList* parts = track->parts(); for (MusECore::iPart p = parts->begin(); p != parts->end(); ++p) { MusECore::MidiPart* part = (MusECore::MidiPart*) (p->second); @@ -315,7 +342,6 @@ void MusE::exportMidi() for (MusECore::iEvent i = evlist->begin(); i != evlist->end(); ++i) { MusECore::Event ev = i->second; int tick = ev.tick() + part->tick(); - switch (ev.type()) { case MusECore::Note: { @@ -400,11 +426,19 @@ void MusE::exportMidi() } } } + ++i; + } mf.setDivision(MusEGlobal::config.midiDivision); mf.setMType(MusEGlobal::song->mtype()); - mf.setTrackList(mtl, ntracks); + //mf.setTrackList(mtl, ntracks); + mf.setTrackList(mtl, i); mf.write(); + + // TESTING: Cleanup. I did not valgrind this feature in last memleak fixes, but I suspect it leaked. + //for(MusECore::iMidiFileTrack imft = mtl->begin(); imft != mtl->end(); ++imft) + // delete *imft; + //delete mtl; } } // namespace MusEGui diff --git a/muse2/muse/functions.cpp b/muse2/muse/functions.cpp index e0f9690c..77825f52 100644 --- a/muse2/muse/functions.cpp +++ b/muse2/muse/functions.cpp @@ -55,7 +55,7 @@ #include <QDrag> #include <QMessageBox> #include <QClipboard> - +#include <QSet> using namespace std; @@ -177,8 +177,9 @@ bool quantize_notes(const set<Part*>& parts) { if (!MusEGui::quantize_dialog->exec()) return false; - - quantize_notes(parts, MusEGui::quantize_dialog->range, (MusEGlobal::config.division*4)/(1<<MusEGui::quantize_dialog->raster_power2), +// (1<<MusEGui::quantize_dialog->raster_power2) + int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index]; + quantize_notes(parts, MusEGui::quantize_dialog->range, (MusEGlobal::config.division*4)/raster, MusEGui::quantize_dialog->quant_len, MusEGui::quantize_dialog->strength, MusEGui::quantize_dialog->swing, MusEGui::quantize_dialog->threshold); @@ -306,8 +307,9 @@ bool quantize_notes() parts=get_all_selected_parts(); else parts=get_all_parts(); - - quantize_notes(parts, MusEGui::quantize_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, (config.division*4)/(1<<MusEGui::quantize_dialog->raster_power2), + + int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index]; + quantize_notes(parts, MusEGui::quantize_dialog->range & FUNCTION_RANGE_ONLY_BETWEEN_MARKERS, (config.division*4)/raster, MusEGui::quantize_dialog->quant_len, MusEGui::quantize_dialog->strength, MusEGui::quantize_dialog->swing, MusEGui::quantize_dialog->threshold); @@ -1276,34 +1278,22 @@ void shrink_parts(int raster) MusEGlobal::song->applyOperationGroup(operations); } -void internal_schedule_expand_part(Part* part, int raster, Undo& operations) -{ - EventList* events=part->events(); - unsigned len=part->lenTick(); - - for (iEvent ev=events->begin(); ev!=events->end(); ev++) - if (ev->second.endTick() > len) - len=ev->second.endTick(); - - if (raster) len=ceil((float)len/raster)*raster; - - if (len > part->lenTick()) - { - MidiPart* new_part = new MidiPart(*(MidiPart*)part); - new_part->setLenTick(len); - operations.push_back(UndoOp(UndoOp::ModifyPart, part, new_part, true, false)); - } -} void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations) { + QSet<const Part*> already_done; + + for (Undo::iterator op_it=operations.begin(); op_it!=operations.end();op_it++) + if (op_it->type==UndoOp::ModifyPart || op_it->type==UndoOp::DeletePart) + already_done.insert(op_it->nPart); + unsigned old_len=part->lenTick(); if (old_len!=new_len) { Part* part_it=part; do { - if (part_it->lenTick()==old_len) + if (part_it->lenTick()==old_len && !already_done.contains(part_it)) { MidiPart* new_part = new MidiPart(*(MidiPart*)part_it); new_part->setLenTick(new_len); @@ -1393,4 +1383,81 @@ void clean_parts() MusEGlobal::song->applyOperationGroup(operations); } +bool merge_selected_parts() +{ + set<Part*> temp = get_all_selected_parts(); + return merge_parts(temp); +} + +bool merge_parts(const set<Part*>& parts) +{ + set<Track*> tracks; + for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) + tracks.insert( (*it)->track() ); + + Undo operations; + + // process tracks separately + for (set<Track*>::iterator t_it=tracks.begin(); t_it!=tracks.end(); t_it++) + { + Track* track=*t_it; + + unsigned begin=MAXINT, end=0; + Part* first_part=NULL; + + // find begin of the first and end of the last part + for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) + if ((*it)->track()==track) + { + Part* p=*it; + if (p->tick() < begin) + { + begin=p->tick(); + first_part=p; + } + + if (p->endTick() > end) + end=p->endTick(); + } + + if (begin==MAXINT || end==0) + { + printf("THIS SHOULD NEVER HAPPEN: begin==MAXINT || end==0 in merge_parts()\n"); + continue; // skip the actual work, as we cannot work under errornous conditions. + } + + // create and prepare the new part + Part* new_part = track->newPart(first_part); + new_part->setTick(begin); + new_part->setLenTick(end-begin); + + EventList* new_el = new_part->events(); + new_el->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it + // so we must decrement it first :/ + new_el->clear(); + + // copy all events from the source parts into the new part + for (set<Part*>::iterator p_it=parts.begin(); p_it!=parts.end(); p_it++) + if ((*p_it)->track()==track) + { + EventList* old_el= (*p_it)->events(); + for (iEvent ev_it=old_el->begin(); ev_it!=old_el->end(); ev_it++) + { + Event new_event=ev_it->second; + new_event.setTick( new_event.tick() + (*p_it)->tick() - new_part->tick() ); + new_el->add(new_event); + } + } + + // delete all the source parts + for (set<Part*>::iterator it=parts.begin(); it!=parts.end(); it++) + if ((*it)->track()==track) + operations.push_back( UndoOp(UndoOp::DeletePart, *it) ); + // and add the new one + operations.push_back( UndoOp(UndoOp::AddPart, new_part) ); + } + + return MusEGlobal::song->applyOperationGroup(operations); +} + } // namespace MusECore diff --git a/muse2/muse/functions.h b/muse2/muse/functions.h index 2cf9c245..c81dd2bc 100644 --- a/muse2/muse/functions.h +++ b/muse2/muse/functions.h @@ -102,6 +102,8 @@ void shrink_parts(int raster=-1); //negative values mean "config.division" void expand_parts(int raster=-1); void schedule_resize_all_same_len_clone_parts(Part* part, unsigned new_len, Undo& operations); void clean_parts(); +bool merge_selected_parts(); +bool merge_parts(const std::set<Part*>& parts); } // namespace MusECore diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp index a19d9ed8..a6abbb93 100644 --- a/muse2/muse/gconfig.cpp +++ b/muse2/muse/gconfig.cpp @@ -131,8 +131,8 @@ GlobalConfigValues config = { -60.0, // double minSlider; false, // use Jack freewheel 20, // int guiRefresh; - QString(""), // userInstrumentsDir - //QString(""), // helpBrowser; // Obsolete + QString(""), // userInstrumentsDir // Obsolete. Must keep for compatibility. + //QString(""), // helpBrowser; // Obsolete true, // extendedMidi 384, // division for smf export QString(""), // copyright string for smf export @@ -191,7 +191,11 @@ GlobalConfigValues config = { false, // popupsDefaultStayOpen false, // leftMouseButtonCanDecrease false, // rangeMarkerWithoutMMB - MusECore::DONT_REC_MUTED_OR_HIDDEN + MusECore::DONT_REC_MUTED_OR_HIDDEN, + true, // addHiddenTracks + true // unhideTracks }; +//GlobalConfigValues globalConfig = config; + } // namespace MusEGlobal diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h index 24fd787a..f611687f 100644 --- a/muse2/muse/gconfig.h +++ b/muse2/muse/gconfig.h @@ -121,7 +121,7 @@ struct GlobalConfigValues { double minSlider; bool freewheelMode; int guiRefresh; - QString userInstrumentsDir; + QString userInstrumentsDir; // Obsolete. Must keep for compatibility. bool extendedMidi; // extended smf format int midiDivision; // division for smf export @@ -178,6 +178,8 @@ struct GlobalConfigValues { bool leftMouseButtonCanDecrease; bool rangeMarkerWithoutMMB; MusECore::newDrumRecordCondition_t newDrumRecordCondition; + bool addHiddenTracks; + bool unhideTracks; }; diff --git a/muse2/muse/globals.cpp b/muse2/muse/globals.cpp index fad6472e..d50ea1eb 100644 --- a/muse2/muse/globals.cpp +++ b/muse2/muse/globals.cpp @@ -116,21 +116,13 @@ bool loadDSSI = true; bool usePythonBridge = false; bool useLASH = true; -/* const char* midi_file_pattern[] = { - QT_TRANSLATE_NOOP("@default", "Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2)"), - QT_TRANSLATE_NOOP("@default", "Midi (*.mid *.MID *.mid.gz *.mid.bz2)"), - QT_TRANSLATE_NOOP("@default", "Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "Midi (*.mid *.MID *.mid.gz *.mid.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; -*/ -const QStringList midi_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2);;") + - QString("Midi (*.mid *.MID *.mid.gz *.mid.bz2);;") + - QString("Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2);;") + - QString("All Files (*)")).split(";;"); //FIXME: By T356 01/19/2010 // If saving as a compressed file (gz or bz2), @@ -148,80 +140,46 @@ const char* midi_file_save_pattern[] = { "All Files (*)", 0 }; -QStringList midi_file_save_pattern = - QStringList::split(";;", QT_TRANSLATE_NOOP("@default", - QString("Midi (*.mid);;") + - QString("gzip compressed Midi (*.mid.gz);;") + - QString("bzip2 compressed Midi (*.mid.bz2);;") + - QString("Karaoke (*.kar);;") + - QString("gzip compressed karaoke (*.kar.gz);;") + - QString("bzip2 compressed karaoke (*.kar.bz2);;") + - QString("All Files (*)")) ); */ -/* const char* midi_file_save_pattern[] = { - QT_TRANSLATE_NOOP("@default", "Midi (*.mid)"), - QT_TRANSLATE_NOOP("@default", "Karaoke (*.kar)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "Midi (*.mid)"), + QT_TRANSLATE_NOOP("file_patterns", "Karaoke (*.kar)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; -*/ -const QStringList midi_file_save_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Midi (*.mid);;") + - QString("Karaoke (*.kar);;") + - QString("All Files (*)")).split(";;"); -/* const char* med_file_pattern[] = { - QT_TRANSLATE_NOOP("@default", "med Files (*.med *.med.gz *.med.bz2)"), - QT_TRANSLATE_NOOP("@default", "Uncompressed med Files (*.med)"), - QT_TRANSLATE_NOOP("@default", "gzip compressed med Files (*.med.gz)"), - QT_TRANSLATE_NOOP("@default", "bzip2 compressed med Files (*.med.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "all known files (*.med *.med.gz *.med.bz2 *.mid *.midi *.kar)"), + QT_TRANSLATE_NOOP("file_patterns", "med Files (*.med *.med.gz *.med.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "Uncompressed med Files (*.med)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed med Files (*.med.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed med Files (*.med.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "mid Files (*.mid *.midi *.kar *.MID *.MIDI *.KAR)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; const char* med_file_save_pattern[] = { - QT_TRANSLATE_NOOP("@default", "Uncompressed med Files (*.med)"), - QT_TRANSLATE_NOOP("@default", "gzip compressed med Files (*.med.gz)"), - QT_TRANSLATE_NOOP("@default", "bzip2 compressed med Files (*.med.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "Uncompressed med Files (*.med)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed med Files (*.med.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed med Files (*.med.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), + 0 + }; +const char* project_create_file_save_pattern[] = { + QT_TRANSLATE_NOOP("file_patterns", "Uncompressed med Files (*.med)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed med Files (*.med.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed med Files (*.med.bz2)"), 0 }; -*/ -const QStringList med_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("all known files (*.med *.med.gz *.med.bz2 *.mid *.midi *.kar);;") + - QString("med Files (*.med *.med.gz *.med.bz2);;") + - QString("Uncompressed med Files (*.med);;") + - QString("gzip compressed med Files (*.med.gz);;") + - QString("bzip2 compressed med Files (*.med.bz2);;") + - QString("mid Files (*.mid *.midi *.kar);;") + - QString("All Files (*)")).split(";;"); -const QStringList med_file_save_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Uncompressed med Files (*.med);;") + - QString("gzip compressed med Files (*.med.gz);;") + - QString("bzip2 compressed med Files (*.med.bz2);;") + - QString("All Files (*)")).split(";;"); -/* const char* image_file_pattern[] = { - QT_TRANSLATE_NOOP("@default", "(*.jpg *.gif *.png)"), - QT_TRANSLATE_NOOP("@default", "(*.jpg)"), - QT_TRANSLATE_NOOP("@default", "(*.gif)"), - QT_TRANSLATE_NOOP("@default", "(*.png)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "(*.jpg *.gif *.png)"), + QT_TRANSLATE_NOOP("file_patterns", "(*.jpg)"), + QT_TRANSLATE_NOOP("file_patterns", "(*.gif)"), + QT_TRANSLATE_NOOP("file_patterns", "(*.png)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; -*/ -const QStringList image_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("(*.jpg *.gif *.png);;") + - QString("(*.jpg);;") + - QString("(*.gif);;") + - QString("(*.png);;") + - QString("All Files (*)")).split(";;"); // Not used. /* @@ -232,84 +190,62 @@ const char* ctrl_file_pattern[] = { }; */ -/* const char* part_file_pattern[] = { - //QT_TRANSLATE_NOOP("@default", "part Files (*.mpt)"), - QT_TRANSLATE_NOOP("@default", "part Files (*.mpt *.mpt.gz *.mpt.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "part Files (*.mpt *.mpt.gz *.mpt.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; const char* part_file_save_pattern[] = { - QT_TRANSLATE_NOOP("@default", "part Files (*.mpt)"), - QT_TRANSLATE_NOOP("@default", "gzip compressed part Files (*.mpt.gz)"), - QT_TRANSLATE_NOOP("@default", "bzip2 compressed part Files (*.mpt.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "part Files (*.mpt)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed part Files (*.mpt.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed part Files (*.mpt.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; -*/ -const QStringList part_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("part Files (*.mpt *.mpt.gz *.mpt.bz2);;") + - QString("All Files (*)")).split(";;"); - -const QStringList part_file_save_pattern = - QT_TRANSLATE_NOOP("@default", - QString("part Files (*.mpt);;") + - QString("gzip compressed part Files (*.mpt.gz);;") + - QString("bzip2 compressed part Files (*.mpt.bz2);;") + - QString("All Files (*)")).split(";;"); /* const char* plug_file_pattern[] = { - QT_TRANSLATE_NOOP("@default", "part Files (*.pre)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "part Files (*.pre)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; */ -/* + const char* preset_file_pattern[] = { - QT_TRANSLATE_NOOP("@default", "Presets (*.pre *.pre.gz *.pre.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "Presets (*.pre *.pre.gz *.pre.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; const char* preset_file_save_pattern[] = { - QT_TRANSLATE_NOOP("@default", "Presets (*.pre)"), - QT_TRANSLATE_NOOP("@default", "gzip compressed presets (*.pre.gz)"), - QT_TRANSLATE_NOOP("@default", "bzip2 compressed presets (*.pre.bz2)"), - QT_TRANSLATE_NOOP("@default", "All Files (*)"), + QT_TRANSLATE_NOOP("file_patterns", "Presets (*.pre)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed presets (*.pre.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed presets (*.pre.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), 0 }; -*/ -const QStringList preset_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Presets (*.pre *.pre.gz *.pre.bz2);;") + - QString("All Files (*)")).split(";;"); - -const QStringList preset_file_save_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Presets (*.pre);;") + - QString("gzip compressed presets (*.pre.gz);;") + - QString("bzip2 compressed presets (*.pre.bz2);;") + - QString("All Files (*)")).split(";;"); - -const QStringList drum_map_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Presets (*.map *.map.gz *.map.bz2);;") + - QString("All Files (*)")).split(";;"); -const QStringList drum_map_file_save_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Presets (*.map);;") + - QString("gzip compressed presets (*.map.gz);;") + - QString("bzip2 compressed presets (*.map.bz2);;") + - QString("All Files (*)")).split(";;"); - -const QStringList audio_file_pattern = - QT_TRANSLATE_NOOP("@default", - QString("Wave/Binary (*.wav *.ogg *.bin);;") + - QString("Wave (*.wav *.ogg);;") + - QString("Binary (*.bin);;") + - QString("All Files (*)")).split(";;"); + +const char* drum_map_file_pattern[] = { + QT_TRANSLATE_NOOP("file_patterns", "Presets (*.map *.map.gz *.map.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), + 0 +}; + +const char* drum_map_file_save_pattern[] = { + QT_TRANSLATE_NOOP("file_patterns", "Presets (*.map)"), + QT_TRANSLATE_NOOP("file_patterns", "gzip compressed presets (*.map.gz)"), + QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed presets (*.map.bz2)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), + 0 +}; + +const char* audio_file_pattern[] = { + QT_TRANSLATE_NOOP("file_patterns", "Wave/Binary (*.wav *.ogg *.bin)"), + QT_TRANSLATE_NOOP("file_patterns", "Wave (*.wav *.ogg)"), + QT_TRANSLATE_NOOP("file_patterns", "Binary (*.bin)"), + QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"), + 0 +}; ///Qt::ButtonState globalKeyState; Qt::KeyboardModifiers globalKeyState; diff --git a/muse2/muse/globals.h b/muse2/muse/globals.h index c0a3395a..7563c171 100644 --- a/muse2/muse/globals.h +++ b/muse2/muse/globals.h @@ -34,7 +34,6 @@ class QString; class QAction; class QActionGroup; -class QStringList; class QTimer; namespace MusEGui { @@ -91,33 +90,20 @@ extern bool realTimeScheduling; extern int realTimePriority; extern int midiRTPrioOverride; -/* -extern const char* midi_file_pattern[]; //!< File name pattern for midi files -extern const char* midi_file_save_pattern[]; //!< File name pattern for saving midi files -extern const char* med_file_pattern[]; //!< File name pattern for muse project files -extern const char* med_file_save_pattern[]; //!< File name pattern for saving muse project files -extern const char* image_file_pattern[]; //!< File name pattern for image files (gfx) -//extern const char* ctrl_file_pattern[]; //!< File name pattern for controller-files -extern const char* part_file_pattern[]; //!< File name pattern for part files -extern const char* part_file_save_pattern[]; //!< File name pattern for saving part files -//extern const char* plug_file_pattern[]; //!< File name pattern for plugin files -extern const char* preset_file_pattern[]; //!< File name pattern for plugin files -extern const char* preset_file_save_pattern[]; //!< File name pattern for saving plugin files -*/ - -extern const QStringList midi_file_pattern; -extern const QStringList midi_file_save_pattern; -extern const QStringList med_file_pattern; -extern const QStringList med_file_save_pattern; -extern const QStringList image_file_pattern; -//extern const QStringList ctrl_file_pattern; -extern const QStringList part_file_pattern; -extern const QStringList part_file_save_pattern; -extern const QStringList preset_file_pattern; -extern const QStringList preset_file_save_pattern; -extern const QStringList drum_map_file_pattern; -extern const QStringList drum_map_file_save_pattern; -extern const QStringList audio_file_pattern; +extern const char* midi_file_pattern[]; +extern const char* midi_file_save_pattern[]; +extern const char* med_file_pattern[]; +extern const char* med_file_save_pattern[]; +extern const char* project_create_file_save_pattern[]; +extern const char* image_file_pattern[]; +//extern const char* ctrl_file_pattern[]; +extern const char* part_file_pattern[]; +extern const char* part_file_save_pattern[]; +extern const char* preset_file_pattern[]; +extern const char* preset_file_save_pattern[]; +extern const char* drum_map_file_pattern[]; +extern const char* drum_map_file_save_pattern[]; +extern const char* audio_file_pattern[]; ///extern Qt::ButtonState globalKeyState; extern Qt::KeyboardModifiers globalKeyState; diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index 1298b2d2..144d876d 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -20,6 +20,8 @@ // //========================================================= +#include <list> + #include "helper.h" #include "part.h" #include "track.h" @@ -28,6 +30,22 @@ #include "icons.h" #include "synth.h" #include "functions.h" +#include "gconfig.h" + +#include "driver/jackmidi.h" +#include "route.h" +#include "mididev.h" +#include "globaldefs.h" +#include "audio.h" +#include "audiodev.h" +#include "midiseq.h" + +#include <QApplication> +#include <QDir> +#include <QFileInfo> +#include <QFileDialog> +#include <QString> +//#include <QTemporaryFile> #ifdef DSSI_SUPPORT #include "dssihost.h" @@ -165,237 +183,544 @@ QMenu* populateAddSynth(QWidget* parent) //typedef std::multimap<std::string, int, addSynth_cmp_str >::iterator imap; typedef std::multimap<std::string, int >::iterator imap; - MusECore::MessSynth* synMESS = 0; - QMenu* synpMESS = 0; - asmap mapMESS; - - #ifdef DSSI_SUPPORT - MusECore::DssiSynth* synDSSI = 0; - QMenu* synpDSSI = 0; - asmap mapDSSI; - #endif - #ifdef VST_SUPPORT - MusECore::VstSynth* synVST = 0; - QMenu* synpVST = 0; - asmap mapVST; - #endif + int ntypes = MusECore::Synth::SYNTH_TYPE_END; + asmap smaps[ntypes]; + QMenu* mmaps[ntypes]; + for(int itype = 0; itype < ntypes; ++itype) + mmaps[itype] = 0; - // Not necessary, but what the heck. - QMenu* synpOther = 0; - asmap mapOther; + MusECore::Synth* synth; + MusECore::Synth::Type type; - //const int synth_base_id = 0x1000; int ii = 0; for(std::vector<MusECore::Synth*>::iterator i = MusEGlobal::synthis.begin(); i != MusEGlobal::synthis.end(); ++i) { - synMESS = dynamic_cast<MusECore::MessSynth*>(*i); - if(synMESS) - { - mapMESS.insert( std::pair<std::string, int> (std::string(synMESS->description().toLower().toLatin1().constData()), ii) ); - } - else - { - - #ifdef DSSI_SUPPORT - synDSSI = dynamic_cast<MusECore::DssiSynth*>(*i); - if(synDSSI) - { - mapDSSI.insert( std::pair<std::string, int> (std::string(synDSSI->description().toLower().toLatin1().constData()), ii) ); - } - else - #endif - - { - #ifdef VST_SUPPORT - synVST = dynamic_cast<MusECore::VstSynth*>(*i); - if(synVST) - { - mapVST.insert( std::pair<std::string, int> (std::string(synVST->description().toLower().toLatin1().constData()), ii) ); - } - else - #endif - - { - mapOther.insert( std::pair<std::string, int> (std::string((*i)->description().toLower().toLatin1().constData()), ii) ); - } - } - } + synth = *i; + type = synth->synthType(); + if(type >= ntypes) + continue; + smaps[type].insert( std::pair<std::string, int> (std::string(synth->description().toLower().toLatin1().constData()), ii) ); ++ii; } int sz = MusEGlobal::synthis.size(); - for(imap i = mapMESS.begin(); i != mapMESS.end(); ++i) - { - int idx = i->second; - if(idx > sz) // Sanity check - continue; - MusECore::Synth* s = MusEGlobal::synthis[idx]; - if(s) + for(int itype = 0; itype < ntypes; ++itype) + { + for(imap i = smaps[itype].begin(); i != smaps[itype].end(); ++i) { - // No MESS sub-menu yet? Create it now. - if(!synpMESS) - synpMESS = new QMenu(parent); - QAction* sM = synpMESS->addAction(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">"); - sM->setData(MENU_ADD_SYNTH_ID_BASE + idx); - } - } - - #ifdef DSSI_SUPPORT - for(imap i = mapDSSI.begin(); i != mapDSSI.end(); ++i) - { - int idx = i->second; - if(idx > sz) - continue; - MusECore::Synth* s = MusEGlobal::synthis[idx]; - if(s) - { - // No DSSI sub-menu yet? Create it now. - if(!synpDSSI) - synpDSSI = new QMenu(parent); - //synpDSSI->insertItem(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">", MENU_ADD_SYNTH_ID_BASE + idx); - QAction* sD = synpDSSI->addAction(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">"); - sD->setData(MENU_ADD_SYNTH_ID_BASE + idx); - } - } - #endif - - #ifdef VST_SUPPORT - for(imap i = mapVST.begin(); i != mapVST.end(); ++i) - { - int idx = i->second; - if(idx > sz) - continue; - Synth* s = MusEGlobal::synthis[idx]; - if(s) - { - // No VST sub-menu yet? Create it now. - if(!synpVST) - synpVST = new QMenu(parent); - QAction* sV = synpVST->addAction(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">"); - sV->setData(MENU_ADD_SYNTH_ID_BASE + idx); - } - } - #endif - - for(imap i = mapOther.begin(); i != mapOther.end(); ++i) - { - int idx = i->second; - if(idx > sz) - continue; - MusECore::Synth* s = MusEGlobal::synthis[idx]; - // No Other sub-menu yet? Create it now. - if(!synpOther) - synpOther = new QMenu(parent); - //synpOther->insertItem(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">", MENU_ADD_SYNTH_ID_BASE + idx); - QAction* sO = synpOther->addAction(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">"); - sO->setData(MENU_ADD_SYNTH_ID_BASE + idx); - } - - if(synpMESS) - { - synpMESS->setIcon(*synthIcon); - synpMESS->setTitle(QT_TRANSLATE_NOOP("@default", "MESS")); - synp->addMenu(synpMESS); - } - - #ifdef DSSI_SUPPORT - if(synpDSSI) - { - synpDSSI->setIcon(*synthIcon); - synpDSSI->setTitle(QT_TRANSLATE_NOOP("@default", "DSSI")); - synp->addMenu(synpDSSI); - } - #endif - - #ifdef VST_SUPPORT - if(synpVST) - { - synpVST->setIcon(*synthIcon); - synpVST->setTitle(QT_TRANSLATE_NOOP("@default", "FST")); - synp->addMenu(synpVST); - } - #endif - - if(synpOther) - { - synpOther->setIcon(*synthIcon); - synpOther->setTitle(QObject::tr("Other")); - synp->addMenu(synpOther); + int idx = i->second; + if(idx > sz) // Sanity check + continue; + synth = MusEGlobal::synthis[idx]; + if(synth) + { + // No sub-menu yet? Create it now. + if(!mmaps[itype]) + { + mmaps[itype] = new QMenu(parent); + mmaps[itype]->setIcon(*synthIcon); + mmaps[itype]->setTitle(MusECore::synthType2String((MusECore::Synth::Type)itype)); + synp->addMenu(mmaps[itype]); + } + QAction* act = mmaps[itype]->addAction(synth->description() + " <" + synth->name() + ">"); + act->setData( MENU_ADD_SYNTH_ID_BASE * (itype + 1) + idx ); + } + } } - + return synp; } - //--------------------------------------------------------- // populateAddTrack // this is also used in "mixer" //--------------------------------------------------------- -QActionGroup* populateAddTrack(QMenu* addTrack) +QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll) { QActionGroup* grp = new QActionGroup(addTrack); + if (MusEGlobal::config.addHiddenTracks) + populateAll=true; + + if (populateAll || MusECore::MidiTrack::visible()) { + QAction* midi = addTrack->addAction(QIcon(*addtrack_addmiditrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Midi Track"))); + midi->setData(MusECore::Track::MIDI); + grp->addAction(midi); + } + if (populateAll || MusECore::MidiTrack::visible()) { + QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Drum Track"))); + drum->setData(MusECore::Track::DRUM); + grp->addAction(drum); + } + if (populateAll || MusECore::MidiTrack::visible()) { + QAction* newdrum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add New Style Drum Track"))); + newdrum->setData(MusECore::Track::NEW_DRUM); + grp->addAction(newdrum); + } + if (populateAll || MusECore::WaveTrack::visible()) { + QAction* wave = addTrack->addAction(QIcon(*addtrack_wavetrackIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Wave Track"))); + wave->setData(MusECore::Track::WAVE); + grp->addAction(wave); + } - QAction* midi = addTrack->addAction(QIcon(*addtrack_addmiditrackIcon), - QT_TRANSLATE_NOOP("@default", "Add Midi Track")); - midi->setData(MusECore::Track::MIDI); - grp->addAction(midi); + if (populateAll || MusECore::AudioOutput::visible()) { + QAction* aoutput = addTrack->addAction(QIcon(*addtrack_audiooutputIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Audio Output"))); + aoutput->setData(MusECore::Track::AUDIO_OUTPUT); + grp->addAction(aoutput); + } + if (populateAll || MusECore::AudioGroup::visible()) { + QAction* agroup = addTrack->addAction(QIcon(*addtrack_audiogroupIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Audio Group"))); + agroup->setData(MusECore::Track::AUDIO_GROUP); + grp->addAction(agroup); + } - QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), - QT_TRANSLATE_NOOP("@default", "Add Drum Track")); - drum->setData(MusECore::Track::DRUM); - grp->addAction(drum); + if (populateAll || MusECore::AudioInput::visible()) { + QAction* ainput = addTrack->addAction(QIcon(*addtrack_audioinputIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Audio Input"))); + ainput->setData(MusECore::Track::AUDIO_INPUT); + grp->addAction(ainput); + } + if (populateAll || MusECore::AudioAux::visible()) { + QAction* aaux = addTrack->addAction(QIcon(*addtrack_auxsendIcon), + qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Aux Send"))); + aaux->setData(MusECore::Track::AUDIO_AUX); + grp->addAction(aaux); + } - QAction* newdrum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), - QT_TRANSLATE_NOOP("@default", "Add New Style Drum Track")); - newdrum->setData(MusECore::Track::NEW_DRUM); - grp->addAction(newdrum); + if (populateAll || MusECore::SynthI::visible()) { + // Create a sub-menu and fill it with found synth types. Make addTrack the owner. + QMenu* synp = populateAddSynth(addTrack); + synp->setIcon(*synthIcon); + synp->setTitle(qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Synth"))); + // Add the sub-menu to the given menu. + addTrack->addMenu(synp); + } - QAction* wave = addTrack->addAction(QIcon(*addtrack_wavetrackIcon), - QT_TRANSLATE_NOOP("@default", "Add Wave Track")); - wave->setData(MusECore::Track::WAVE); - grp->addAction(wave); + //QObject::connect(addTrack, SIGNAL(triggered(QAction *)), MusEGlobal::song, SLOT(addNewTrack(QAction *))); + return grp; + } + +//--------------------------------------------------------- +// getFilterExtension +//--------------------------------------------------------- - QAction* aoutput = addTrack->addAction(QIcon(*addtrack_audiooutputIcon), - QT_TRANSLATE_NOOP("@default", "Add Audio Output")); - aoutput->setData(MusECore::Track::AUDIO_OUTPUT); - grp->addAction(aoutput); +QString getFilterExtension(const QString &filter) +{ + // + // Return the first extension found. Must contain at least one * character. + // + + int pos = filter.indexOf('*'); + if(pos == -1) + return QString(); + + QString filt; + int len = filter.length(); + ++pos; + for( ; pos < len; ++pos) + { + QChar c = filter[pos]; + if((c == ')') || (c == ';') || (c == ',') || (c == ' ')) + break; + filt += filter[pos]; + } + return filt; +} +QStringList localizedStringListFromCharArray(const char** array, const char* context) +{ + QStringList temp; + for (int i=0;array[i];i++) + temp << qApp->translate(context, array[i]); + + return temp; +} - QAction* agroup = addTrack->addAction(QIcon(*addtrack_audiogroupIcon), - QT_TRANSLATE_NOOP("@default", "Add Audio Group")); - agroup->setData(MusECore::Track::AUDIO_GROUP); - grp->addAction(agroup); +QString browseProjectFolder(QWidget* parent) +{ + QString path; + if(!MusEGlobal::config.projectBaseFolder.isEmpty()) + { + QDir d(MusEGlobal::config.projectBaseFolder); + path = d.absolutePath(); + } + + QString dir = QFileDialog::getExistingDirectory(parent, qApp->tr("Select project directory"), path); + if(dir.isEmpty()) + dir = MusEGlobal::config.projectBaseFolder; + // projDirLineEdit->setText(dir); + //return QFileDialog::getExistingDirectory(this, qApp.tr("Select project directory"), path); + return dir; +} +QString projectTitleFromFilename(QString filename) +{ + int idx; + idx = filename.lastIndexOf(".med.bz2", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".med.gz", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".med", -1, Qt::CaseInsensitive); + + if(idx != -1) + filename.truncate(idx); + + QFileInfo fi(filename); - QAction* ainput = addTrack->addAction(QIcon(*addtrack_audioinputIcon), - QT_TRANSLATE_NOOP("@default", "Add Audio Input")); - ainput->setData(MusECore::Track::AUDIO_INPUT); - grp->addAction(ainput); + //return fi.baseName(); + return fi.fileName(); +} + +QString projectPathFromFilename(QString filename) +{ + QFileInfo fi(filename); + return QDir::cleanPath(fi.absolutePath()); +} + +QString projectExtensionFromFilename(QString filename) +{ + int idx; + idx = filename.lastIndexOf(".med.bz2", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".med.gz", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".med", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".bz2", -1, Qt::CaseInsensitive); + if(idx == -1) + idx = filename.lastIndexOf(".gz", -1, Qt::CaseInsensitive); + + return (idx == -1) ? QString() : filename.right(filename.size() - idx); +} + +QString getUniqueUntitledName() +{ + QString filename("untitled"); + //QTemporaryFile tf(MusEGlobal::config.projectBaseFolder +"/" + s + "XXXXXX.med"); + //if(tf.open()) + // s = MusEGui::projectTitleFromFilename(tf.fileName()); + + QString fbase(MusEGlobal::config.projectBaseFolder); + + QString nfb = fbase; + if(MusEGlobal::config.projectStoreInFolder) + nfb += "/" + filename; + QFileInfo fi(nfb + "/" + filename + ".med"); // TODO p4.0.40 Check other extensions. + if(!fi.exists()) + //return filename; + return fi.filePath(); + + // Find a new filename + QString nfn = filename; + int idx; + for (idx=2; idx<10000; idx++) { + QString num = QString::number(idx); + nfn = filename + "_" + num; + nfb = fbase; + if(MusEGlobal::config.projectStoreInFolder) + nfb += "/" + nfn; + QFileInfo fi(nfb + "/" + nfn + ".med"); + if(!fi.exists()) + //break; + return fi.filePath(); + } + + //if(idx >= 10000) + printf("MusE error: Could not make untitled project name (10000 or more untitled projects in project dir - clean up!\n"); + + //return nfn; + + nfb = fbase; + if(MusEGlobal::config.projectStoreInFolder) + nfb += "/" + filename; + return nfb + "/" + filename + ".med"; +} - QAction* aaux = addTrack->addAction(QIcon(*addtrack_auxsendIcon), - QT_TRANSLATE_NOOP("@default", "Add Aux Send")); - aaux->setData(MusECore::Track::AUDIO_AUX); - grp->addAction(aaux); +#if 1 - // Create a sub-menu and fill it with found synth types. Make addTrack the owner. - QMenu* synp = populateAddSynth(addTrack); - synp->setIcon(*synthIcon); - synp->setTitle(QT_TRANSLATE_NOOP("@default", "Add Synth")); +// ------------------------------------------------------------------------------------------------------- +// populateMidiPorts() +// This version creats separate devices for input and output ports. +// It does not attempt to pair them together. +// ------------------------------------------------------------------------------------------------------- +void populateMidiPorts() +{ + if(!MusEGlobal::checkAudioDevice()) + return; - // Add the sub-menu to the given menu. - addTrack->addMenu(synp); + MusECore::MidiDevice* dev = 0; + + int port_num = 0; + + // If Jack is running, prefer Jack midi devices over ALSA. + if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::JACK_AUDIO) + { + std::list<QString> sl; + sl = MusEGlobal::audioDevice->inputPorts(true, 1); // Ask for second aliases. + for(std::list<QString>::iterator i = sl.begin(); i != sl.end(); ++i) + { + dev = MusECore::MidiJackDevice::createJackMidiDevice(*i, 1); + if(dev) + { + //printf("populateMidiPorts Created jack writeable device: %s\n", dev->name().toLatin1().constData()); + //dev->setOpenFlags(1); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + MusECore::Route srcRoute(dev, -1); + MusECore::Route dstRoute(*i, true, -1, MusECore::Route::JACK_ROUTE); + MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); + if(++port_num == MIDI_PORTS) + return; + } + } + + sl = MusEGlobal::audioDevice->outputPorts(true, 1); // Ask for second aliases. + for(std::list<QString>::iterator i = sl.begin(); i != sl.end(); ++i) + { + dev = MusECore::MidiJackDevice::createJackMidiDevice(*i, 2); + if(dev) + { + //printf("populateMidiPorts Created jack readable device: %s\n", dev->name().toLatin1().constData()); + //dev->setOpenFlags(2); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + MusECore::Route srcRoute(*i, false, -1, MusECore::Route::JACK_ROUTE); + MusECore::Route dstRoute(dev, -1); + MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); + if(++port_num == MIDI_PORTS) + return; + } + } + } + else + // If Jack is not running, use ALSA devices. + if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::DUMMY_AUDIO) + { + for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) + { + if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) + continue; + dev = *i; + // Select only sensible devices first - not thru etc. + //if( ... ) + // continue; - //QObject::connect(addTrack, SIGNAL(triggered(QAction *)), MusEGlobal::song, SLOT(addNewTrack(QAction *))); + //dev->setOpenFlags(1); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + + if(++port_num == MIDI_PORTS) + return; + } - return grp; + //for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) + //{ + // if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) + // continue; + // // Select the ones ignored in the first pass. + // if(! ... ) + // continue; + // + // dev->setOpenFlags(1); + // MusEGlobal::midiSeq->msgSetMidiDevice(port_num, dev); + // + // if(++port_num == MIDI_PORTS) + // return; + //} + } + + //MusEGlobal::muse->changeConfig(true); // save configuration file + //MusEGlobal::song->update(); + +} + +#else // this code is disabled + +DISABLED AND MAYBE OUT-OF-DATE CODE! +the code below is disabled for a longer period of time, +there were certain changes and merges. dunno if that code +works at all. before activating it again, intensively +verify whether its still okay! + +// ------------------------------------------------------------------------------------------------------- +// populateMidiPorts() +// This version worked somewhat well with system devices. +// But no, it is virtually impossible to tell from the names whether ports should be paired. +// There is too much room for error - what markers to look for ("capture_"/"playback_") etc. +// It works kind of OK with 'seq' Jack Midi ALSA devices, but not for 'raw' which have a different +// naming structure ("in-hw-0-0-0"/"out-hw-0-0-0"). +// It also fails to combine if the ports were named by a client app, for example another instance of MusE. +// ------------------------------------------------------------------------------------------------------- + +void populateMidiPorts() +{ + if(!MusEGlobal::checkAudioDevice()) + return; + + MusECore::MidiDevice* dev = 0; + + int port_num = 0; + + // If Jack is running, prefer Jack midi devices over ALSA. + if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::JACK_AUDIO) + { + std::list<QString> wsl; + std::list<QString> rsl; + //wsl = MusEGlobal::audioDevice->inputPorts(true, 1); // Ask for second aliases. + wsl = MusEGlobal::audioDevice->inputPorts(true, 0); // Ask for first aliases. + //rsl = MusEGlobal::audioDevice->outputPorts(true, 1); // Ask for second aliases. + rsl = MusEGlobal::audioDevice->outputPorts(true, 0); // Ask for first aliases. + + for(std::list<QString>::iterator wi = wsl.begin(); wi != wsl.end(); ++wi) + { + QString ws = *wi; + int y = ws.lastIndexOf("_"); + if(y >= 1) + { + int x = ws.lastIndexOf("_", y-1); + if(x >= 0) + ws.remove(x, y - x); + } + + + bool match_found = false; + for(std::list<QString>::iterator ri = rsl.begin(); ri != rsl.end(); ++ri) + { + QString rs = *ri; + int y = rs.lastIndexOf("_"); + if(y >= 1) + { + int x = rs.lastIndexOf("_", y-1); + if(x >= 0) + rs.remove(x, y - x); + } + + // Do we have a matching pair? + if(rs == ws) + { + // Would like to remove the client name, but no, we need it as a distinguishing identifier. + //int z = ws.indexOf(":"); + //if(z >= 0) + // ws.remove(0, z + 1); + + dev = MusECore::MidiJackDevice::createJackMidiDevice(ws, 3); + if(dev) + { + //printf("populateMidiPorts Created jack writeable/readable device: %s\n", dev->name().toLatin1().constData()); + //dev->setOpenFlags(1); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + MusECore::Route devRoute(dev, -1); + MusECore::Route wdstRoute(*wi, true, -1, MusECore::Route::JACK_ROUTE); + MusECore::Route rsrcRoute(*ri, false, -1, MusECore::Route::JACK_ROUTE); + MusEGlobal::audio->msgAddRoute(devRoute, wdstRoute); + MusEGlobal::audio->msgAddRoute(rsrcRoute, devRoute); + if(++port_num == MIDI_PORTS) + return; + } + + rsl.erase(ri); // Done with this read port. Remove. + match_found = true; + break; + } + } + + if(!match_found) + { + // No match was found. Create a single writeable device. + QString s = *wi; + // Would like to remove the client name, but no, we need it as a distinguishing identifier. + //int z = s.indexOf(":"); + //if(z >= 0) + // s.remove(0, z + 1); + dev = MusECore::MidiJackDevice::createJackMidiDevice(s, 1); + if(dev) + { + //printf("populateMidiPorts Created jack writeable device: %s\n", dev->name().toLatin1().constData()); + //dev->setOpenFlags(1); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + MusECore::Route srcRoute(dev, -1); + MusECore::Route dstRoute(*wi, true, -1, MusECore::Route::JACK_ROUTE); + MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); + if(++port_num == MIDI_PORTS) + return; + } } + } + + // Create the remaining readable ports as single readable devices. + for(std::list<QString>::iterator ri = rsl.begin(); ri != rsl.end(); ++ri) + { + QString s = *ri; + // Would like to remove the client name, but no, we need it as a distinguishing identifier. + //int z = s.indexOf(":"); + //if(z >= 0) + // s.remove(0, z + 1); + dev = MusECore::MidiJackDevice::createJackMidiDevice(s, 2); + if(dev) + { + //printf("populateMidiPorts Created jack readable device: %s\n", dev->name().toLatin1().constData()); + //dev->setOpenFlags(2); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + MusECore::Route srcRoute(*ri, false, -1, MusECore::Route::JACK_ROUTE); + MusECore::Route dstRoute(dev, -1); + MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); + if(++port_num == MIDI_PORTS) + return; + } + } + } + else + // If Jack is not running, use ALSA devices. + if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::DUMMY_AUDIO) + { + for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) + { + if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) + continue; + dev = *i; + // Select only sensible devices first - not thru etc. + //if( ... ) + // continue; + + //dev->setOpenFlags(1); + MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); + + if(++port_num == MIDI_PORTS) + return; + } + + //for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) + //{ + // if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) + // continue; + // // Select the ones ignored in the first pass. + // if(! ... ) + // continue; + // + // dev->setOpenFlags(1); + // MusEGlobal::midiSeq->msgSetMidiDevice(port_num, dev); + // + // if(++port_num == MIDI_PORTS) + // return; + //} + } + + //MusEGlobal::muse->changeConfig(true); // save configuration file + //MusEGlobal::song->update(); + +} +#endif // populateMidiPorts + } // namespace MusEGui + diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index a051cd15..ad531fae 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -25,6 +25,7 @@ #include <set> #include <QSet> +#include <QStringList> #include "drummap.h" @@ -52,7 +53,15 @@ QSet<Part*> parts_at_tick(unsigned tick, const QSet<Track*>& tracks); namespace MusEGui { QMenu* populateAddSynth(QWidget* parent); -QActionGroup* populateAddTrack(QMenu* addTrack); +QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll=false); +QStringList localizedStringListFromCharArray(const char** array, const char* context); +QString getFilterExtension(const QString &filter); +QString browseProjectFolder(QWidget* parent = 0); +QString projectTitleFromFilename(QString filename); +QString projectPathFromFilename(QString filename); +QString projectExtensionFromFilename(QString filename); +QString getUniqueUntitledName(); +void populateMidiPorts(); } #endif diff --git a/muse2/muse/importmidi.cpp b/muse2/muse/importmidi.cpp index 86738fe4..bd3c8a9f 100644 --- a/muse2/muse/importmidi.cpp +++ b/muse2/muse/importmidi.cpp @@ -21,7 +21,6 @@ // //========================================================= -#include <assert.h> #include <errno.h> #include <values.h> @@ -418,7 +417,8 @@ void MusE::processTrack(MusECore::MidiTrack* track) i->second.dump(); } // all events should be processed: - assert(tevents->empty()); + if (!tevents->empty()) + printf("THIS SHOULD NEVER HAPPEN: not all events processed at the end of MusE::processTrack()!\n"); } //--------------------------------------------------------- diff --git a/muse2/muse/instruments/editinstrument.cpp b/muse2/muse/instruments/editinstrument.cpp index 742e0626..b90b872e 100644 --- a/muse2/muse/instruments/editinstrument.cpp +++ b/muse2/muse/instruments/editinstrument.cpp @@ -407,27 +407,10 @@ void EditInstrument::saveAs() if(!QDir(MusEGlobal::museUserInstruments).exists()) { - if(QMessageBox::question(this, - tr("MusE:"), - tr("The user instrument directory\n%1\ndoes not exist yet. Create it now?\n").arg(MusEGlobal::museUserInstruments) + - tr("(You can change the user instruments directory at Settings->Global Settings->Midi)"), - QMessageBox::Ok | QMessageBox::Default, - QMessageBox::Cancel | QMessageBox::Escape, - Qt::NoButton) == QMessageBox::Ok) - { - if(QDir().mkdir(MusEGlobal::museUserInstruments)) - printf("Created user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); - else - { - printf("Unable to create user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); - QMessageBox::critical(this, tr("MusE:"), tr("Unable to create user instrument directory '%1'").arg(MusEGlobal::museUserInstruments)); - //return; - path = MusEGlobal::museUser; - } - } - else - // return; - path = MusEGlobal::museUser; + printf("MusE Error! User instrument directory: %s does not exist. Should be created at startup!\n", MusEGlobal::museUserInstruments.toLatin1().constData()); + + //path = MusEGlobal::museUser; + //path = MusEGlobal::configPath; } //if (instrument->filePath().isEmpty()) @@ -699,27 +682,10 @@ void EditInstrument::fileSaveAs() if(!QDir(MusEGlobal::museUserInstruments).exists()) { - if(QMessageBox::question(this, - tr("MusE:"), - tr("The user instrument directory\n%1\ndoes not exist yet. Create it now?\n").arg(MusEGlobal::museUserInstruments) + - tr("(You can change the user instruments directory at Settings->Global Settings->Midi)"), - QMessageBox::Ok | QMessageBox::Default, - QMessageBox::Cancel | QMessageBox::Escape, - Qt::NoButton) == QMessageBox::Ok) - { - if(QDir().mkdir(MusEGlobal::museUserInstruments)) - printf("Created user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); - else - { - printf("Unable to create user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); - QMessageBox::critical(this, tr("MusE:"), tr("Unable to create user instrument directory '%1'").arg(MusEGlobal::museUserInstruments)); - //return; - path = MusEGlobal::museUser; - } - } - else - // return; - path = MusEGlobal::museUser; + printf("MusE Error! User instrument directory: %s does not exist. Should be created at startup!\n", MusEGlobal::museUserInstruments.toLatin1().constData()); + + //path = MusEGlobal::museUser; + //path = MusEGlobal::configPath; } path += QString("/%1.idf").arg(so); diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index c479ebc6..a01903ae 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -932,15 +932,11 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru return "<unknown>"; } -} // namespace MusECore - -namespace MusEGui { - //--------------------------------------------------------- // populatePatchPopup //--------------------------------------------------------- -void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* menu, int chan, MType songType, bool drum) +void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MType songType, bool drum) { menu->clear(); int mask = 0; @@ -952,7 +948,7 @@ void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* men if(drumchan) { int id = (0xff << 16) + (0xff << 8) + 0x00; // First patch - QAction* act = menu->addAction(MusECore::gmdrumname); + QAction* act = menu->addAction(gmdrumname); //act->setCheckable(true); act->setData(id); return; @@ -961,16 +957,16 @@ void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* men break; case MT_UNKNOWN: mask = 7; break; } - if (midiInstrument->groups()->size() > 1) { - for (MusECore::ciPatchGroup i = midiInstrument->groups()->begin(); i != midiInstrument->groups()->end(); ++i) { - MusECore::PatchGroup* pgp = *i; + if (pg.size() > 1) { + for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) { + PatchGroup* pgp = *i; //QMenu* pm = menu->addMenu(pgp->name); - PopupMenu* pm = new PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here. + MusEGui::PopupMenu* pm = new MusEGui::PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here. menu->addMenu(pm); pm->setFont(MusEGlobal::config.fonts[0]); - const MusECore::PatchList& pl = pgp->patches; - for (MusECore::ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { - const MusECore::Patch* mp = *ipl; + const PatchList& pl = pgp->patches; + for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { + const Patch* mp = *ipl; if ((mp->typ & mask) && ((drum && songType != MT_GM) || (mp->drum == drumchan)) ) @@ -985,11 +981,11 @@ void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* men } } } - else if (midiInstrument->groups()->size() == 1 ){ + else if (pg.size() == 1 ){ // no groups - const MusECore::PatchList& pl = midiInstrument->groups()->front()->patches; - for (MusECore::ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { - const MusECore::Patch* mp = *ipl; + const PatchList& pl = pg.front()->patches; + for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { + const Patch* mp = *ipl; if (mp->typ & mask) { int id = ((mp->hbank & 0xff) << 16) + ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff); @@ -999,6 +995,7 @@ void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* men } } } - } -} // namespace MusEGui + } + +} // namespace MusECore diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index 3a645d7f..385e67b4 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -143,7 +143,7 @@ class MidiInstrument { virtual void reset(int, MType); virtual QString getPatchName(int,int,MType,bool); //virtual void populatePatchPopup(QMenu*, int, MType, bool); - //virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool); + virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool); void read(Xml&); void write(int level, Xml&); @@ -171,8 +171,8 @@ extern void removeMidiInstrument(const MidiInstrument* instr); } // namespace MusECore -namespace MusEGui { -extern void populatePatchPopup(MusECore::MidiInstrument*, PopupMenu*, int, MType, bool); -} +//namespace MusEGui { +//extern void populatePatchPopup(MusECore::MidiInstrument*, PopupMenu*, int, MType, bool); +//} #endif diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp index 32a328a8..cc52d26e 100644 --- a/muse2/muse/liste/editevent.cpp +++ b/muse2/muse/liste/editevent.cpp @@ -871,20 +871,17 @@ void EditCtrlDialog::instrPopup() int port = track->outPort(); MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument(); - ///instr->populatePatchPopup(pop, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); //QMenu* pup = new QMenu(this); MusEGui::PopupMenu* pup = new MusEGui::PopupMenu(this); - populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); - ///if(pop->actions().count() == 0) - /// return; if(pup->actions().count() == 0) { delete pup; return; } - ///QAction* rv = pop->exec(patchName->mapToGlobal(QPoint(10,5))); QAction* rv = pup->exec(patchName->mapToGlobal(QPoint(10,5))); if (rv) { val = rv->data().toInt(); diff --git a/muse2/muse/liste/listedit.cpp b/muse2/muse/liste/listedit.cpp index eadfa68c..6795cedb 100644 --- a/muse2/muse/liste/listedit.cpp +++ b/muse2/muse/liste/listedit.cpp @@ -45,6 +45,7 @@ #include "event.h" #include "midiport.h" #include "midictrl.h" +#include "app.h" namespace MusEGui { @@ -183,7 +184,8 @@ static QString midiMetaComment(const MusECore::Event& ev) void ListEdit::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -193,6 +195,9 @@ void ListEdit::closeEvent(QCloseEvent* e) void ListEdit::songChanged(int type) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (type == 0) return; if (type & (SC_PART_REMOVED | SC_PART_MODIFIED @@ -465,6 +470,8 @@ QString EventListItem::text(int col) const ListEdit::ListEdit(MusECore::PartList* pl) : MidiEditor(TopWin::LISTE, 0, pl) { + selectedTick=0; + insertItems = new QActionGroup(this); insertItems->setExclusive(false); insertNote = new QAction(QIcon(*note1Icon), tr("insert Note"), insertItems); @@ -587,7 +594,6 @@ ListEdit::ListEdit(MusECore::PartList* pl) mainGrid->setColumnStretch(0, 100); mainGrid->addWidget(liste, 1, 0, 2, 1); connect(MusEGlobal::song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); - songChanged(-1); if(pl->empty()) { @@ -605,10 +611,14 @@ ListEdit::ListEdit(MusECore::PartList* pl) curPartId = -1; } } + + songChanged(-1); initShortcuts(); setWindowTitle("MusE: List Editor"); + + MusEGlobal::muse->topwinMenuInited(this); } //--------------------------------------------------------- diff --git a/muse2/muse/liste/listedit.h b/muse2/muse/liste/listedit.h index 7548fc86..1c0c1bd9 100644 --- a/muse2/muse/liste/listedit.h +++ b/muse2/muse/liste/listedit.h @@ -86,7 +86,7 @@ class ListEdit : public MidiEditor { void songChanged(int); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public: ListEdit(MusECore::PartList*); diff --git a/muse2/muse/main.cpp b/muse2/muse/main.cpp index 27a8926e..d946bf00 100644 --- a/muse2/muse/main.cpp +++ b/muse2/muse/main.cpp @@ -24,6 +24,8 @@ #include <QApplication> #include <QDir> #include <QFile> +#include <QFileInfo> +#include <QFileInfoList> #include <QKeyEvent> #include <QMessageBox> #include <QLocale> @@ -31,6 +33,8 @@ #include <QTimer> #include <QTranslator> #include <QIcon> +#include <QString> +#include <QStringList> #include <sys/mman.h> #include <alsa/asoundlib.h> @@ -41,6 +45,7 @@ #include "audiodev.h" #include "gconfig.h" #include "globals.h" +#include "helper.h" #include "icons.h" #include "sync.h" #include "functions.h" @@ -267,9 +272,38 @@ int main(int argc, char* argv[]) if (! cPath.exists()) cPath.mkpath("."); + // Create user templates dir if it doesn't exist + QDir utemplDir = QDir(MusEGlobal::configPath + QString("/templates")); + if(!utemplDir.exists()) + { + utemplDir.mkpath("."); + // Support old versions: Copy existing templates over. + QDir old_utemplDir = QDir(QString(getenv("HOME")) + QString("/templates")); + // printf(" old templates dir:%s\n", (QString(getenv("HOME")) + QString("/templates")).toLatin1().constData()); + if(old_utemplDir.exists()) + { + //printf(" found old templates dir\n"); + // We really just want these, even though it's possible other filenames were saved. + // Another application might have used that directory. + QStringList flt; flt << "*.med" << "*.med.gz" << "*.med.bz2" << "*.mid" << "*.midi" << "*.kar"; + old_utemplDir.setNameFilters(flt); + + QFileInfoList fil = old_utemplDir.entryInfoList(); + QFileInfo fi; + foreach(fi, fil) + { + QString fn = fi.fileName(); + QFile f(fi.absoluteFilePath()); + f.copy(utemplDir.absolutePath() + "/" + fn); + //printf(" copy old template to:%s result:%d\n", QString(utemplPath.absolutePath() + "/" + fn).toLatin1().constData(), rv); + } + } + } + QFile cConf (MusEGlobal::configName); QFile cConfTempl (MusEGlobal::museGlobalShare + QString("/templates/MusE.cfg")); - if (! cConf.exists()) + bool cConfExists = cConf.exists(); + if (!cConfExists) { printf ("creating new config...\n"); if (cConfTempl.copy(MusEGlobal::configName)) @@ -303,10 +337,51 @@ int main(int argc, char* argv[]) MusEGui::init_function_dialogs(MusEGlobal::muse); MusEGui::initShortCuts(); + MusECore::readConfiguration(); - MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; + // Need to put a sane default here because we can't use ~ in the file name string. + if(!cConfExists) + MusEGlobal::config.projectBaseFolder = MusEGlobal::museUser + QString("/MusE"); + //MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; + + // Create user instruments dir if it doesn't exist + { + QString uinstrPath = MusEGlobal::configPath + QString("/instruments"); + QDir uinstrDir = QDir(uinstrPath); + if(!uinstrDir.exists()) + uinstrDir.mkpath("."); + + if(!MusEGlobal::config.userInstrumentsDir.isEmpty() && MusEGlobal::config.userInstrumentsDir != uinstrPath) // Only if it is different. + { + // Support old versions: Copy existing instruments over. + QDir old_uinstrDir(MusEGlobal::config.userInstrumentsDir); + //printf(" old instruments dir:%s\n", MusEGlobal::config.userInstrumentsDir.toLatin1().constData()); + if(old_uinstrDir.exists()) + { + //printf(" found old instruments dir\n"); + QStringList flt; flt << "*.idf"; + old_uinstrDir.setNameFilters(flt); + + QFileInfoList fil = old_uinstrDir.entryInfoList(); + QFileInfo fi; + foreach(fi, fil) + { + QString fn = fi.fileName(); + QFile f(fi.absoluteFilePath()); + QFile newf(uinstrDir.absolutePath() + "/" + fn); + if(!newf.exists()) + { + f.copy(newf.fileName()); + //printf(" copy old instrument to:%s result:%d\n", newf.fileName().toLatin1().constData(), rv); + } + } + } + } + MusEGlobal::museUserInstruments = uinstrPath; + } + if (MusEGlobal::config.useDenormalBias) printf("Denormal protection enabled.\n"); // SHOW MUSE SPLASH SCREEN @@ -324,7 +399,7 @@ int main(int argc, char* argv[]) stimer->start(6000); } } - + int i; QString optstr("ahvdDmMsP:Y:l:py"); @@ -393,6 +468,7 @@ int main(int argc, char* argv[]) } */ + AL::initDsp(); if (MusEGlobal::debugMsg) @@ -438,8 +514,7 @@ int main(int argc, char* argv[]) else MusEGlobal::realTimeScheduling = MusEGlobal::audioDevice->isRealtime(); - - // What unreliable nonsense. With Jack2 this reports true even if it is not running realtime. + // ??? With Jack2 this reports true even if it is not running realtime. // Jack says: "Cannot use real-time scheduling (RR/10)(1: Operation not permitted)". The kernel is non-RT. // I cannot seem to find a reliable answer to the question, even with dummy audio and system calls. //if (MusEGlobal::debugMsg) @@ -448,11 +523,7 @@ int main(int argc, char* argv[]) MusEGlobal::useJackTransport.setValue(true); // setup the prefetch fifo length now that the segmentSize is known - // Changed by Tim. p3.3.17 - // Changed to 4 *, JUST FOR TEST!!! MusEGlobal::fifoLength = 131072 / MusEGlobal::segmentSize; - //MusEGlobal::fifoLength = (131072 / MusEGlobal::segmentSize) * 4; - argc -= optind; ++argc; @@ -486,7 +557,9 @@ int main(int argc, char* argv[]) printf("locale de\n"); MusEGlobal::hIsB = false; } - + + MusEGui::retranslate_function_dialogs(); + if (MusEGlobal::loadPlugins) MusECore::initPlugins(); @@ -496,7 +569,6 @@ int main(int argc, char* argv[]) if(MusEGlobal::loadDSSI) MusECore::initDSSI(); - // p3.3.39 MusECore::initOSC(); MusEGui::initIcons(); @@ -515,21 +587,19 @@ int main(int argc, char* argv[]) ++it; } } - + MusEGlobal::muse = new MusEGui::MusE(argc, &argv[optind]); app.setMuse(MusEGlobal::muse); MusEGlobal::muse->setWindowIcon(*MusEGui::museIcon); - - // Added by Tim. p3.3.22 if (!MusEGlobal::debugMode) { if (mlockall(MCL_CURRENT | MCL_FUTURE)) perror("WARNING: Cannot lock memory:"); } MusEGlobal::muse->show(); - MusEGlobal::muse->seqStart(); - + MusEGlobal::muse->seqStart(); + #ifdef HAVE_LASH { MusEGui::lash_client = 0; @@ -540,14 +610,28 @@ int main(int argc, char* argv[]) MusEGui::lash_client = lash_init (lash_args, muse_name, lash_flags, LASH_PROTOCOL(2,0)); lash_alsa_client_id (MusEGui::lash_client, snd_seq_client_id (MusECore::alsaSeq)); if (!noAudio) { - // p3.3.38 - //char *jack_name = ((JackAudioDevice*)MusEGlobal::audioDevice)->getJackName(); const char *jack_name = MusEGlobal::audioDevice->clientName(); lash_jack_client_name (MusEGui::lash_client, jack_name); } } } #endif /* HAVE_LASH */ + + //-------------------------------------------------- + // Auto-fill the midi ports, if appropriate. p4.0.41 + //-------------------------------------------------- + if(argc < 2 && MusEGlobal::config.startMode == 1) + { + MusEGui::populateMidiPorts(); + //MusEGlobal::muse->changeConfig(true); // save configuration file + //MusEGlobal::song->update(); + } + + //-------------------------------------------------- + // Load the default song. + //-------------------------------------------------- + MusEGlobal::muse->loadDefaultSong(argc, &argv[optind]); // p4.0.41 + QTimer::singleShot(100, MusEGlobal::muse, SLOT(showDidYouKnowDialog())); int rv = app.exec(); diff --git a/muse2/muse/marker/markerview.cpp b/muse2/muse/marker/markerview.cpp index bc9e48b9..39ce4fc0 100644 --- a/muse2/muse/marker/markerview.cpp +++ b/muse2/muse/marker/markerview.cpp @@ -26,6 +26,7 @@ #include "markerview.h" #include "xml.h" #include "globals.h" +#include "app.h" #include "sync.h" #include "icons.h" #include "song.h" @@ -157,7 +158,7 @@ void MarkerItem::setTick(unsigned v) void MarkerView::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); emit closed(); e->accept(); } @@ -296,6 +297,8 @@ MarkerView::MarkerView(QWidget* parent) updateList(); + MusEGlobal::muse->topwinMenuInited(this); + // work around for probable QT/WM interaction bug. // for certain window managers, e.g xfce, this window is // is displayed although not specifically set to show(); diff --git a/muse2/muse/marker/markerview.h b/muse2/muse/marker/markerview.h index b50ab7a4..06e22daf 100644 --- a/muse2/muse/marker/markerview.h +++ b/muse2/muse/marker/markerview.h @@ -96,7 +96,7 @@ class MarkerView : public TopWin { void songChanged(int); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); void closed(); public: diff --git a/muse2/muse/master/lmaster.cpp b/muse2/muse/master/lmaster.cpp index bf31cc91..f461e1d3 100644 --- a/muse2/muse/master/lmaster.cpp +++ b/muse2/muse/master/lmaster.cpp @@ -27,6 +27,7 @@ #include "xml.h" #include "song.h" #include "globals.h" +#include "app.h" #include "audio.h" //#include "posedit.h" //#include "sigedit.h" @@ -122,7 +123,9 @@ namespace MusEGui { void LMaster::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -132,6 +135,9 @@ void LMaster::closeEvent(QCloseEvent* e) void LMaster::songChanged(int type) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (type & (SC_SIG | SC_TEMPO | SC_KEY )) updateList(); } @@ -281,6 +287,7 @@ LMaster::LMaster() connect(keyButton, SIGNAL(clicked()), SLOT(insertKey())); initShortcuts(); + MusEGlobal::muse->topwinMenuInited(this); } //--------------------------------------------------------- diff --git a/muse2/muse/master/lmaster.h b/muse2/muse/master/lmaster.h index 6bc90019..33b40f30 100644 --- a/muse2/muse/master/lmaster.h +++ b/muse2/muse/master/lmaster.h @@ -173,7 +173,7 @@ class LMaster : public MidiEditor { void configChanged(); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); void seekTo(int tick); public: diff --git a/muse2/muse/master/master.cpp b/muse2/muse/master/master.cpp index 50c3f518..02bef8a1 100644 --- a/muse2/muse/master/master.cpp +++ b/muse2/muse/master/master.cpp @@ -27,6 +27,8 @@ #include <QEvent> #include <QMouseEvent> #include <QPainter> +#include <QList> +#include <QPair> #include "globals.h" #include "master.h" @@ -52,6 +54,8 @@ Master::Master(MidiEditor* e, QWidget* parent, int xmag, int ymag) pos[0] = 0; pos[1] = 0; pos[2] = 0; + drag = DRAG_OFF; + tool = MusEGui::PointerTool; // should be overridden soon anyway, but to be sure... setFocusPolicy(Qt::StrongFocus); // Tim. setMouseTracking(true); connect(MusEGlobal::song, SIGNAL(posChanged(int, unsigned, bool)), this, SLOT(setPos(int, unsigned, bool))); @@ -288,8 +292,8 @@ void Master::viewMouseReleaseEvent(QMouseEvent*) bool Master::deleteVal1(unsigned int x1, unsigned int x2) { - bool songChanged = false; - + QList< QPair<int,int> > stuff_to_do; + MusECore::TempoList* tl = &MusEGlobal::tempomap; for (MusECore::iTEvent i = tl->begin(); i != tl->end(); ++i) { if (i->first < x1) @@ -300,11 +304,17 @@ bool Master::deleteVal1(unsigned int x1, unsigned int x2) ++ii; if (ii != tl->end()) { int tempo = ii->second->tempo; - MusEGlobal::audio->msgDeleteTempo(i->first, tempo, false); - songChanged = true; + // changed by flo: postpone the actual delete operation + // to avoid race conditions and invalidating the iterator + //MusEGlobal::audio->msgDeleteTempo(i->first, tempo, false); + stuff_to_do.append(QPair<int,int>(i->first, tempo)); } } - return songChanged; + + for (QList< QPair<int,int> >::iterator it=stuff_to_do.begin(); it!=stuff_to_do.end(); it++) + MusEGlobal::audio->msgDeleteTempo(it->first, it->second, false); + + return !stuff_to_do.empty(); } void Master::deleteVal(int x1, int x2) diff --git a/muse2/muse/master/masteredit.cpp b/muse2/muse/master/masteredit.cpp index e9d669e1..f6169766 100644 --- a/muse2/muse/master/masteredit.cpp +++ b/muse2/muse/master/masteredit.cpp @@ -37,6 +37,7 @@ #include "doublelabel.h" ///#include "sigedit.h" #include "globals.h" +#include "app.h" #include <values.h> @@ -59,7 +60,9 @@ int MasterEdit::_rasterInit = 0; void MasterEdit::closeEvent(QCloseEvent* e) { - emit deleted(static_cast<TopWin*>(this)); + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -69,6 +72,9 @@ void MasterEdit::closeEvent(QCloseEvent* e) void MasterEdit::songChanged(int type) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (type & SC_TEMPO) { int tempo = MusEGlobal::tempomap.tempo(MusEGlobal::song->cpos()); curTempo->blockSignals(true); @@ -154,7 +160,7 @@ MasterEdit::MasterEdit() info->addWidget(tempo); const char* rastval[] = { - QT_TRANSLATE_NOOP("@default", "Off"), "Bar", "1/2", "1/4", "1/8", "1/16" + QT_TRANSLATE_NOOP("MusEGui::MasterEdit", "Off"), QT_TRANSLATE_NOOP("MusEGui::MasterEdit", "Bar"), "1/2", "1/4", "1/8", "1/16" }; rasterLabel = new MusEGui::LabelCombo(tr("Snap"), 0); rasterLabel->setFocusPolicy(Qt::NoFocus); @@ -264,6 +270,7 @@ MasterEdit::MasterEdit() connect(canvas, SIGNAL(timeChanged(unsigned)), SLOT(setTime(unsigned))); initTopwinState(); + MusEGlobal::muse->topwinMenuInited(this); } //--------------------------------------------------------- diff --git a/muse2/muse/master/masteredit.h b/muse2/muse/master/masteredit.h index fdf8dd71..835ca879 100644 --- a/muse2/muse/master/masteredit.h +++ b/muse2/muse/master/masteredit.h @@ -91,7 +91,7 @@ class MasterEdit : public MidiEditor { // void tempoChanged(double); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public: MasterEdit(); diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp index d5ed119d..85a47ead 100644 --- a/muse2/muse/midi.cpp +++ b/muse2/muse/midi.cpp @@ -25,7 +25,6 @@ #include <cmath> #include <errno.h> #include <values.h> -#include <assert.h> #include "song.h" #include "midi.h" @@ -1055,7 +1054,7 @@ void Audio::processMidi() { int pitch = ctl & 0x7f; // pitch is now the incoming pitch pitch = track->map_drum_in(pitch); // pitch is now the mapped (recorded) pitch - event.setA(ctl & ~0xff | pitch); // map the drum ctrl's value accordingly + event.setA((ctl & ~0xff) | pitch); // map the drum ctrl's value accordingly if (MusEGlobal::config.newDrumRecordCondition & MusECore::DONT_REC_HIDDEN && track->drummap_hidden()[pitch] ) diff --git a/muse2/muse/midictrl.cpp b/muse2/muse/midictrl.cpp index 11849ce7..c477297e 100644 --- a/muse2/muse/midictrl.cpp +++ b/muse2/muse/midictrl.cpp @@ -21,7 +21,6 @@ // //========================================================= -#include <assert.h> #include <stdio.h> #include "midictrl.h" @@ -241,7 +240,7 @@ QString midiCtrlName(int ctrl, bool fullyQualified) //--------------------------------------------------------- MidiController::MidiController() - : _name(QString(QT_TRANSLATE_NOOP("@default", "Velocity"))) + : _name(QString("Velocity")) { _num = CTRL_VELOCITY; _minVal = 0; diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp index d024422c..bc8bbdb0 100644 --- a/muse2/muse/midiedit/dcanvas.cpp +++ b/muse2/muse/midiedit/dcanvas.cpp @@ -78,18 +78,18 @@ DEvent::DEvent(MusECore::Event e, MusECore::Part* p, int instr) // addItem //--------------------------------------------------------- -void DrumCanvas::addItem(MusECore::Part* part, MusECore::Event& event) +CItem* DrumCanvas::addItem(MusECore::Part* part, MusECore::Event& event) { if (signed(event.tick())<0) { printf("ERROR: trying to add event before current part!\n"); - return; + return NULL; } int instr=pitch_and_track_to_instrument(event.pitch(), part->track()); if (instr<0) { if (heavyDebugMsg) printf("trying to add event which is hidden or not in any part known to me\n"); - return; + return NULL; } DEvent* ev = new DEvent(event, part, instr); @@ -104,6 +104,8 @@ void DrumCanvas::addItem(MusECore::Part* part, MusECore::Event& event) //part = newPart; part->setLenTick(part->lenTick()+diff); } + + return ev; } //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/dcanvas.h b/muse2/muse/midiedit/dcanvas.h index 9053b3bf..0fd4c9e0 100644 --- a/muse2/muse/midiedit/dcanvas.h +++ b/muse2/muse/midiedit/dcanvas.h @@ -124,7 +124,7 @@ class DrumCanvas : public EventCanvas { void dragEnterEvent(QDragEnterEvent* event); void dragMoveEvent(QDragMoveEvent*); void dragLeaveEvent(QDragLeaveEvent*); - virtual void addItem(MusECore::Part*, MusECore::Event&); + virtual CItem* addItem(MusECore::Part*, MusECore::Event&); virtual void resizeEvent(QResizeEvent*); virtual void curPartChanged(); int getNextStep(unsigned int pos, int basicStep, int stepSize=1); diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index 58875b4d..7adab525 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -53,6 +53,7 @@ #include "vscale.h" #include "swidget.h" #include "globals.h" +#include "app.h" #include "icons.h" #include "filedialog.h" #include "drummap.h" @@ -139,6 +140,8 @@ void DrumEdit::setHeaderToolTips() void DrumEdit::closeEvent(QCloseEvent* e) { + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + QSettings settings("MusE", "MusE-qt"); //settings.setValue("Drumedit/geometry", saveGeometry()); settings.setValue("Drumedit/windowState", saveState()); @@ -149,7 +152,7 @@ void DrumEdit::closeEvent(QCloseEvent* e) _dlistWidthInit = *it; //There are only 2 values stored in the sizelist, size of dlist widget and dcanvas widget it++; _dcanvasWidthInit = *it; - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -590,6 +593,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un initTopwinState(); + MusEGlobal::muse->topwinMenuInited(this); } //--------------------------------------------------------- @@ -598,6 +602,9 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un void DrumEdit::songChanged1(int bits) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (bits & SC_SOLO) { toolbar->setSolo(canvas->track()->solo()); @@ -1007,12 +1014,15 @@ void DrumEdit::cmd(int cmd) 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: + { + int raster = MusEGui::rasterVals[MusEGui::quantize_dialog->raster_index]; if (quantize_dialog->exec()) quantize_notes(partlist_to_set(parts()), quantize_dialog->range, - (MusEGlobal::config.division*4)/(1<<quantize_dialog->raster_power2), + (MusEGlobal::config.division*4)/raster, /* 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 08f485e7..59590d34 100644 --- a/muse2/muse/midiedit/drumedit.h +++ b/muse2/muse/midiedit/drumedit.h @@ -170,7 +170,7 @@ class DrumEdit : public MidiEditor { virtual void updateHScrollRange(); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public: DrumEdit(MusECore::PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT); diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index 9941f7e5..3eeb4f84 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: ecanvas.cpp,v 1.8.2.6 2009/05/03 04:14:00 terminator356 Exp $ // (C) Copyright 2001 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -151,6 +152,17 @@ void EventCanvas::songChanged(int flags) if (flags & ~SC_SELECTION) { //items.clear(); + bool curItemNeedsRestore=false; + MusECore::Event storedEvent; + int partSn; + if (curItem) + { + curItemNeedsRestore=true; + storedEvent=curItem->event(); + partSn=curItem->part()->sn(); + } + curItem=NULL; + items.clearDelete(); start_tick = MAXINT; end_tick = 0; @@ -177,7 +189,15 @@ void EventCanvas::songChanged(int flags) break; if (e.isNote()) { - addItem(part, e); + CItem* temp = addItem(part, e); + + if (temp && curItemNeedsRestore && e==storedEvent && part->sn()==partSn) + { + if (curItem!=NULL) + printf("THIS SHOULD NEVER HAPPEN: curItemNeedsRestore=true, event fits, but there was already a fitting event!?\n"); + + curItem=temp; + } } } } @@ -308,54 +328,54 @@ void EventCanvas::keyPress(QKeyEvent* event) } // Select items by key (PianoRoll & DrumEditor) else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) { - iCItem i, iRightmost; - CItem* rightmost = NULL; - //Get the rightmost selected note (if any) - for (i = items.begin(); i != items.end(); ++i) { - if (i->second->isSelected()) { - iRightmost = i; rightmost = i->second; - } - } - if (rightmost) { - iCItem temp = iRightmost; temp++; - //If so, deselect current note and select the one to the right - if (temp != items.end()) { - if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) - deselectAll(); - - iRightmost++; - iRightmost->second->setSelected(true); - updateSelection(); - } - } - //if (rightmost && mapx(rightmost->event().tick()) > width()) for some reason this doesn't this doesnt move the event in view - // emit followEvent(rightmost->x()); - + rciCItem i; + for (i = items.rbegin(); i != items.rend(); ++i) + if (i->second->isSelected()) + break; + + if(i == items.rend()) + i = items.rbegin(); + + if(i != items.rbegin()) + --i; + if(i->second) + { + if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) + deselectAll(); + CItem* sel = i->second; + sel->setSelected(true); + updateSelection(); + if (sel->x() + sel->width() > mapxDev(width())) + { + int mx = rmapx(sel->x()); + int newx = mx + rmapx(sel->width()) - width(); + // Leave a bit of room for the specially-drawn drum notes. But good for piano too. + emit horizontalScroll( (newx > mx ? mx - 10: newx + 10) - rmapx(xorg) ); + } + } } //Select items by key: (PianoRoll & DrumEditor) else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) { - iCItem i, iLeftmost; - CItem* leftmost = NULL; - if (items.size() > 0 ) { - for (i = items.end(), i--; i != items.begin(); i--) { - if (i->second->isSelected()) { - iLeftmost = i; leftmost = i->second; - } - } - if (leftmost) { - if (iLeftmost != items.begin()) { - //Add item - if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) - deselectAll(); - - iLeftmost--; - iLeftmost->second->setSelected(true); - updateSelection(); - } - } - //if (leftmost && mapx(leftmost->event().tick())< 0 ) for some reason this doesn't this doesnt move the event in view - // emit followEvent(leftmost->x()); - } + ciCItem i; + for (i = items.begin(); i != items.end(); ++i) + if (i->second->isSelected()) + break; + + if(i == items.end()) + i = items.begin(); + + if(i != items.begin()) + --i; + if(i->second) + { + if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) + deselectAll(); + CItem* sel = i->second; + sel->setSelected(true); + updateSelection(); + if (sel->x() <= mapxDev(0)) + emit horizontalScroll(rmapx(sel->x() - xorg) - 10); // Leave a bit of room. + } } else if (key == shortcuts[SHRT_INC_PITCH].key) { modifySelected(NoteInfo::VAL_PITCH, 1); diff --git a/muse2/muse/midiedit/ecanvas.h b/muse2/muse/midiedit/ecanvas.h index 2c783332..ad19480e 100644 --- a/muse2/muse/midiedit/ecanvas.h +++ b/muse2/muse/midiedit/ecanvas.h @@ -72,7 +72,7 @@ class EventCanvas : public Canvas { bool _setCurPartIfOnlyOneEventIsSelected; void updateSelection(); - virtual void addItem(MusECore::Part*, MusECore::Event&) = 0; + virtual CItem* addItem(MusECore::Part*, MusECore::Event&) = 0; // Added by T356. virtual QPoint raster(const QPoint&) const; virtual MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType) = 0; diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index 82a75f7f..8c2a7a87 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -56,6 +56,7 @@ #include "tb1.h" #include "utils.h" #include "globals.h" +#include "app.h" #include "gconfig.h" #include "icons.h" #include "audio.h" @@ -118,7 +119,7 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name, mapper->setMapping(editPasteAction, PianoCanvas::CMD_PASTE); connect(editPasteAction, SIGNAL(triggered()), mapper, SLOT(map())); - editPasteDialogAction = menuEdit->addAction(QIcon(*editpasteIconSet), tr("&Paste (with dialog)")); + editPasteDialogAction = menuEdit->addAction(QIcon(*editpasteIconSet), tr("Paste (with dialog)")); mapper->setMapping(editPasteDialogAction, PianoCanvas::CMD_PASTE_DIALOG); connect(editPasteDialogAction, SIGNAL(triggered()), mapper, SLOT(map())); @@ -532,6 +533,7 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name, } initTopwinState(); + MusEGlobal::muse->topwinMenuInited(this); } //--------------------------------------------------------- @@ -540,6 +542,8 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name, void PianoRoll::songChanged1(int bits) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; if (bits & SC_SOLO) { @@ -815,15 +819,19 @@ void PianoRoll::removeCtrl(CtrlEdit* ctrl) //--------------------------------------------------------- // closeEvent +// Save state. +// Disconnect signals which may cause crash due to Qt deferred deletion on close. //--------------------------------------------------------- void PianoRoll::closeEvent(QCloseEvent* e) { + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + QSettings settings("MusE", "MusE-qt"); //settings.setValue("Pianoroll/geometry", saveGeometry()); settings.setValue("Pianoroll/windowState", saveState()); - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } diff --git a/muse2/muse/midiedit/pianoroll.h b/muse2/muse/midiedit/pianoroll.h index 0b90b1e6..9b73fc1b 100644 --- a/muse2/muse/midiedit/pianoroll.h +++ b/muse2/muse/midiedit/pianoroll.h @@ -176,7 +176,7 @@ class PianoRoll : public MidiEditor { void updateTrackInfo(); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public slots: virtual void updateHScrollRange(); diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp index e2a05bda..2c32a1cf 100644 --- a/muse2/muse/midiedit/prcanvas.cpp +++ b/muse2/muse/midiedit/prcanvas.cpp @@ -29,6 +29,8 @@ #include <QDragMoveEvent> #include <QDropEvent> #include <QMouseEvent> +#include <QList> +#include <QPair> #include <set> @@ -74,11 +76,11 @@ NEvent::NEvent(MusECore::Event& e, MusECore::Part* p, int y) : MusEGui::CItem(e, // addItem //--------------------------------------------------------- -void PianoCanvas::addItem(MusECore::Part* part, MusECore::Event& event) +CItem* PianoCanvas::addItem(MusECore::Part* part, MusECore::Event& event) { if (signed(event.tick())<0) { printf("ERROR: trying to add event before current part!\n"); - return; + return NULL; } NEvent* ev = new NEvent(event, part, pitch2y(event.pitch())); @@ -93,6 +95,8 @@ void PianoCanvas::addItem(MusECore::Part* part, MusECore::Event& event) //part = newPart; part->setLenTick(part->lenTick()+diff); } + + return ev; } //--------------------------------------------------------- @@ -1086,6 +1090,7 @@ void PianoCanvas::curPartChanged() void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int delta) { + QList< QPair<MusECore::EventList*,MusECore::Event> > already_done; MusEGlobal::audio->msgIdle(true); MusEGlobal::song->startUndo(); for (MusEGui::iCItem i = items.begin(); i != items.end(); ++i) { @@ -1097,6 +1102,10 @@ void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int delta) continue; MusECore::MidiPart* part = (MusECore::MidiPart*)(e->part()); + + if (already_done.contains(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event))) + continue; + MusECore::Event newEvent = event.clone(); switch (type) { @@ -1151,6 +1160,8 @@ void PianoCanvas::modifySelected(MusEGui::NoteInfo::ValType type, int delta) // Indicate do not do port controller values and clone parts. //MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part)); MusEGlobal::song->addUndo(MusECore::UndoOp(MusECore::UndoOp::ModifyEvent, newEvent, event, part, false, false)); + + already_done.append(QPair<MusECore::EventList*,MusECore::Event>(part->events(), event)); } MusEGlobal::song->endUndo(SC_EVENT_MODIFIED); MusEGlobal::audio->msgIdle(false); diff --git a/muse2/muse/midiedit/prcanvas.h b/muse2/muse/midiedit/prcanvas.h index e9bd654d..35e4975f 100644 --- a/muse2/muse/midiedit/prcanvas.h +++ b/muse2/muse/midiedit/prcanvas.h @@ -82,7 +82,7 @@ class PianoCanvas : public EventCanvas { virtual void dragEnterEvent(QDragEnterEvent* event); virtual void dragMoveEvent(QDragMoveEvent*); virtual void dragLeaveEvent(QDragLeaveEvent*); - virtual void addItem(MusECore::Part*, MusECore::Event&); + virtual CItem* addItem(MusECore::Part*, MusECore::Event&); int y2pitch(int) const; int pitch2y(int) const; diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 2d24fa54..ff1893ce 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -88,10 +88,6 @@ QString IntToQStr(int i); -#define APPLY_TO_SELECTED_STRING tr("Apply to selected notes:") -#define APPLY_TO_NEW_STRING tr("Apply to new notes:") - - //PIXELS_PER_NOTEPOS must be greater or equal to 3*NOTE_XLEN + 2*NOTE_SHIFT //because if tick 0 is at x=0: the notes can be shifted by NOTE_SHIFT. //additionally, they can be moved by NOTE_XLEN (collision avoiding) @@ -170,6 +166,15 @@ QColor* mycolors; // array [NUM_MYCOLORS] set<QString> ScoreEdit::names; +int ScoreCanvas::_quant_power2_init=3; +int ScoreCanvas::_pixels_per_whole_init=300; +int ScoreCanvas::note_velo_init=64; +int ScoreCanvas::note_velo_off_init=64; +int ScoreCanvas::new_len_init=0; +ScoreCanvas::coloring_mode_t ScoreCanvas::coloring_mode_init=COLOR_MODE_BLACK; +bool ScoreCanvas::preamble_contains_timesig_init=true; +bool ScoreCanvas::preamble_contains_keysig_init=true; + //--------------------------------------------------------- // ScoreEdit @@ -223,6 +228,8 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) xscroll->setMinimum(0); yscroll->setMinimum(0); + xscroll->setValue(0); + yscroll->setValue(0); menu_mapper=new QSignalMapper(this); connect(menu_mapper, SIGNAL(mapped(int)), SLOT(menu_command(int))); @@ -295,14 +302,28 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) len_actions->addAction(n32_action); len_actions->addAction(nlast_action); - nlast_action->setChecked(true); - menu_command(CMD_NOTELEN_LAST); + switch (ScoreCanvas::new_len_init) + { + case 0: nlast_action->setChecked(true); menu_command(CMD_NOTELEN_LAST); break; + case 1: n1_action->setChecked(true); menu_command(CMD_NOTELEN_1); break; + case 2: n2_action->setChecked(true); menu_command(CMD_NOTELEN_2); break; + case 4: n4_action->setChecked(true); menu_command(CMD_NOTELEN_4); break; + case 8: n8_action->setChecked(true); menu_command(CMD_NOTELEN_8); break; + case 16: n16_action->setChecked(true); menu_command(CMD_NOTELEN_16); break; + case 32: n32_action->setChecked(true); menu_command(CMD_NOTELEN_32); break; + default: + cerr << "ERROR: THIS SHOULD NEVER HAPPEN. newLen is invalid in ScoreEdit::ScoreEdit.\n" << + " (newLen="<<ScoreCanvas::new_len_init<<"; the only valid values are 0,1,2,4,8,16 and 32)\n" << + " however, don't worry, this is no major problem, using 0 instead" << endl; + nlast_action->setChecked(true); + menu_command(CMD_NOTELEN_LAST); + } note_settings_toolbar->addSeparator(); - apply_velo_to_label = new QLabel(APPLY_TO_NEW_STRING, note_settings_toolbar); - int w1 = apply_velo_to_label->fontMetrics().width(APPLY_TO_NEW_STRING); - int w2 = apply_velo_to_label->fontMetrics().width(APPLY_TO_SELECTED_STRING); + apply_velo_to_label = new QLabel(tr("Apply to new notes:"), note_settings_toolbar); + int w1 = apply_velo_to_label->fontMetrics().width(tr("Apply to new notes:")); + int w2 = apply_velo_to_label->fontMetrics().width(tr("Apply to selected notes:")); if (w1>w2) apply_velo_to_label->setFixedWidth(w1+5); else @@ -318,7 +339,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) connect(velo_spinbox, SIGNAL(editingFinished()), SLOT(velo_box_changed())); connect(this,SIGNAL(velo_changed(int)), score_canvas, SLOT(set_velo(int))); note_settings_toolbar->addWidget(velo_spinbox); - velo_spinbox->setValue(64); + velo_spinbox->setValue(ScoreCanvas::note_velo_init); note_settings_toolbar->addWidget(new QLabel(tr("Off-Velocity:"), note_settings_toolbar)); velo_off_spinbox = new QSpinBox(this); @@ -329,7 +350,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) connect(velo_off_spinbox, SIGNAL(editingFinished()), SLOT(velo_off_box_changed())); connect(this,SIGNAL(velo_off_changed(int)), score_canvas, SLOT(set_velo_off(int))); note_settings_toolbar->addWidget(velo_off_spinbox); - velo_off_spinbox->setValue(64); + velo_off_spinbox->setValue(ScoreCanvas::note_velo_off_init); @@ -338,13 +359,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) quant_toolbar->addWidget(new QLabel(tr("Quantisation:"), quant_toolbar)); quant_combobox = new QComboBox(this); quant_combobox->addItem("2"); // if you add or remove items from - quant_combobox->addItem("4"); // here, also change quant_mapper[] - quant_combobox->addItem("8"); // in ScoreCanvas::set_quant()! + quant_combobox->addItem("4"); // here, also change all code regarding + quant_combobox->addItem("8"); // _quant_power2 and _quant_power2_init quant_combobox->addItem("16"); // and MAX_QUANT_POWER (must be log2(largest_value)) quant_combobox->addItem("32"); + quant_combobox->setCurrentIndex(score_canvas->quant_power2()-1); + // the above is intendedly executed BEFORE connecting. otherwise this would + // destroy pixels_per_whole_init! connect(quant_combobox, SIGNAL(currentIndexChanged(int)), score_canvas, SLOT(set_quant(int))); quant_toolbar->addWidget(quant_combobox); - quant_combobox->setCurrentIndex(2); + quant_toolbar->addSeparator(); @@ -355,7 +379,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) connect(px_per_whole_spinbox, SIGNAL(valueChanged(int)), score_canvas, SLOT(set_pixels_per_whole(int))); connect(score_canvas, SIGNAL(pixels_per_whole_changed(int)), px_per_whole_spinbox, SLOT(setValue(int))); quant_toolbar->addWidget(px_per_whole_spinbox); - px_per_whole_spinbox->setValue(300); + px_per_whole_spinbox->setValue(ScoreCanvas::_pixels_per_whole_init); QMenu* edit_menu = menuBar()->addMenu(tr("&Edit")); @@ -456,8 +480,18 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) menu_mapper->setMapping(color_velo_action, CMD_COLOR_VELO); menu_mapper->setMapping(color_part_action, CMD_COLOR_PART); - color_black_action->setChecked(true); - menu_command(CMD_COLOR_BLACK); + switch (ScoreCanvas::coloring_mode_init) + { + case 0: color_black_action->setChecked(true); menu_command(CMD_COLOR_BLACK); break; + case 1: color_velo_action->setChecked(true); menu_command(CMD_COLOR_VELO); break; + case 2: color_part_action->setChecked(true); menu_command(CMD_COLOR_PART); break; + default: + cerr << "ERROR: THIS SHOULD NEVER HAPPEN. noteColor is invalid in ScoreEdit::ScoreEdit.\n" << + " (noteColor="<<ScoreCanvas::coloring_mode_init<<"; the only valid values are 0,1 and 2)\n" << + " however, don't worry, this is no major problem, using 0 instead" << endl; + color_black_action->setChecked(true); + menu_command(CMD_COLOR_BLACK); + } QMenu* preamble_menu = settings_menu->addMenu(tr("Set up &preamble")); preamble_keysig_action = preamble_menu->addAction(tr("Display &key signature")); @@ -468,8 +502,8 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) preamble_keysig_action->setCheckable(true); preamble_timesig_action->setCheckable(true); - preamble_keysig_action->setChecked(true); - preamble_timesig_action->setChecked(true); + preamble_keysig_action->setChecked(ScoreCanvas::preamble_contains_keysig_init); + preamble_timesig_action->setChecked(ScoreCanvas::preamble_contains_timesig_init); QAction* set_name_action = settings_menu->addAction(tr("Set Score &name"), menu_mapper, SLOT(map())); menu_mapper->setMapping(set_name_action, CMD_SET_NAME); @@ -505,6 +539,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos) apply_velo=true; initTopwinState(); + MusEGlobal::muse->topwinMenuInited(this); } void ScoreEdit::init_shortcuts() @@ -589,7 +624,7 @@ bool ScoreEdit::set_name(QString newname, bool emit_signal, bool emergency_name) ScoreEdit::~ScoreEdit() { - + names.erase(name); } void ScoreEdit::velo_box_changed() @@ -604,16 +639,19 @@ void ScoreEdit::velo_off_box_changed() void ScoreEdit::song_changed(int flags) { + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (flags & (SC_SELECTION | SC_EVENT_MODIFIED | SC_EVENT_REMOVED)) { map<MusECore::Event*, MusECore::Part*> selection=get_events(score_canvas->get_all_parts(),1); if (selection.empty()) { - apply_velo_to_label->setText(APPLY_TO_NEW_STRING); + apply_velo_to_label->setText(tr("Apply to new notes:")); } else { - apply_velo_to_label->setText(APPLY_TO_SELECTED_STRING); + apply_velo_to_label->setText(tr("Apply to selected notes:")); int velo=-1; int velo_off=-1; @@ -659,6 +697,7 @@ void ScoreEdit::canvas_height_changed(int height) void ScoreEdit::viewport_height_changed(int height) { int val=score_canvas->canvas_height() - height; + // FINDMICHJETZT canvas_height() is uninitalized! if (val<0) val=0; yscroll->setPageStep(height * PAGESTEP); yscroll->setMaximum(val); @@ -671,11 +710,14 @@ void ScoreEdit::viewport_height_changed(int height) void ScoreEdit::closeEvent(QCloseEvent* e) { + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + names.erase(name); + QSettings settings("MusE", "MusE-qt"); //settings.setValue("ScoreEdit/geometry", saveGeometry()); settings.setValue("ScoreEdit/windowState", saveState()); - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -688,8 +730,8 @@ void ScoreEdit::menu_command(int cmd) { bool ok; QString newname = QInputDialog::getText(this, tr("Enter the new score title"), - tr("Enter the new score title"), QLineEdit::Normal, - name, &ok); + tr("Enter the new score title"), QLineEdit::Normal, + name, &ok); if (ok) { if (!set_name(newname)) @@ -1055,7 +1097,23 @@ void ScoreEdit::read_configuration(MusECore::Xml& xml) switch (token) { case MusECore::Xml::TagStart: - if (tag == "topwin") + if (tag=="quantPowerInit") + ScoreCanvas::_quant_power2_init=xml.parseInt(); + else if (tag=="pxPerWholeInit") + ScoreCanvas::_pixels_per_whole_init=xml.parseInt(); + else if (tag=="newNoteVeloInit") + ScoreCanvas::note_velo_init=xml.parseInt(); + else if (tag=="newNoteVeloOffInit") + ScoreCanvas::note_velo_off_init=xml.parseInt(); + else if (tag=="newLenInit") + ScoreCanvas::new_len_init=xml.parseInt(); + else if (tag=="noteColorInit") + ScoreCanvas::coloring_mode_init=(ScoreCanvas::coloring_mode_t)xml.parseInt(); + else if (tag=="preambleContainsKeysig") + ScoreCanvas::preamble_contains_keysig_init=xml.parseInt(); + else if (tag=="preambleContainsTimesig") + ScoreCanvas::preamble_contains_timesig_init=xml.parseInt(); + else if (tag == "topwin") TopWin::readConfiguration(SCORE, xml); else xml.unknown("ScoreEdit"); @@ -1075,7 +1133,18 @@ void ScoreEdit::read_configuration(MusECore::Xml& xml) void ScoreEdit::write_configuration(int level, MusECore::Xml& xml) { xml.tag(level++, "scoreedit"); + + xml.intTag(level, "quantPowerInit", ScoreCanvas::_quant_power2_init); + xml.intTag(level, "pxPerWholeInit", ScoreCanvas::_pixels_per_whole_init); + xml.intTag(level, "newNoteVeloInit", ScoreCanvas::note_velo_init); + xml.intTag(level, "newNoteVeloOffInit", ScoreCanvas::note_velo_off_init); + xml.intTag(level, "newLenInit", ScoreCanvas::new_len_init); + xml.intTag(level, "noteColorInit", ScoreCanvas::coloring_mode_init); + xml.intTag(level, "preambleContainsKeysig", ScoreCanvas::preamble_contains_keysig_init); + xml.intTag(level, "preambleContainsTimesig", ScoreCanvas::preamble_contains_timesig_init); + TopWin::writeConfiguration(SCORE, level, xml); + xml.etag(level, "scoreedit"); } @@ -1212,22 +1281,20 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi dragged_event_part=NULL; last_len=384; - new_len=-1; + new_len=-1; // will be initalized with new_len_init by ScoreEdit::ScoreEdit(); - set_quant(2); //this is actually unneccessary, as while - //initalizing the quant_combobox, this gets - //called again. but for safety... - set_pixels_per_whole(300); //same as above. but safety rocks + _quant_power2=_quant_power2_init; // ScoreEdit relies on this to be done! + _pixels_per_whole_init = _pixels_per_whole_init; - set_velo(64); - set_velo_off(64); + note_velo=note_velo_init; + note_velo_off_init=note_velo_off_init; dragging_staff=false; - coloring_mode=COLOR_MODE_BLACK; - preamble_contains_keysig=true; - preamble_contains_timesig=true; + coloring_mode=coloring_mode_init; + preamble_contains_keysig=preamble_contains_keysig_init; + preamble_contains_timesig=preamble_contains_timesig_init; x_scroll_speed=0; @@ -1454,6 +1521,9 @@ void ScoreCanvas::fully_recalculate() void ScoreCanvas::song_changed(int flags) { + if(parent && parent->deleting()) // Ignore while while deleting to prevent crash. + return; + if (flags & (SC_PART_MODIFIED | SC_PART_REMOVED | SC_PART_INSERTED | SC_TRACK_REMOVED)) { update_parts(); @@ -1503,7 +1573,7 @@ int ScoreCanvas::canvas_width() int ScoreCanvas::canvas_height() { - return staves.rbegin()->y_bottom; + return staves.empty() ? 0 : staves.rbegin()->y_bottom; } int ScoreCanvas::viewport_width() @@ -1532,7 +1602,7 @@ void color_image(QImage& img, const QColor& color) { uchar* ptr=img.bits(); //int bytes=img.byteCount(); - int bytes=img.bytesPerLine() * img.height(); // By Tim. For older Qt versions. Tested OK on Qt4.5. + int bytes=img.bytesPerLine() * img.height(); // By Tim. For older Qt versions. Tested OK on Qt4.5. int r,g,b; color.getRgb(&r,&g,&b); @@ -2793,6 +2863,7 @@ void ScoreCanvas::draw_note_lines(QPainter& p, int y, bool reserve_akkolade_spac { int xbegin = reserve_akkolade_space ? AKKOLADE_LEFTMARGIN+AKKOLADE_WIDTH+AKKOLADE_RIGHTMARGIN : 0; int xend=width(); + // FINDMICHJETZT y is uninitalized! p.setPen(Qt::black); @@ -4183,7 +4254,7 @@ void ScoreCanvas::pos_changed(int index, unsigned tick, bool scroll) { switch (MusEGlobal::song->follow()) { - case MusECore::Song::NO: break; + case MusECore::Song::NO: break; case MusECore::Song::JUMP: goto_tick(tick,false); break; case MusECore::Song::CONTINUOUS: goto_tick(tick,true); break; } @@ -4277,16 +4348,16 @@ void ScoreCanvas::menu_command(int cmd) { switch (cmd) { - case CMD_COLOR_BLACK: coloring_mode=COLOR_MODE_BLACK; redraw(); break; - case CMD_COLOR_PART: coloring_mode=COLOR_MODE_PART; redraw(); break; - case CMD_COLOR_VELO: coloring_mode=COLOR_MODE_VELO; redraw(); break; - case CMD_NOTELEN_1: new_len=TICKS_PER_WHOLE/ 1; break; - case CMD_NOTELEN_2: new_len=TICKS_PER_WHOLE/ 2; break; - case CMD_NOTELEN_4: new_len=TICKS_PER_WHOLE/ 4; break; - case CMD_NOTELEN_8: new_len=TICKS_PER_WHOLE/ 8; break; - 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; + case CMD_COLOR_BLACK: coloring_mode_init=coloring_mode=COLOR_MODE_BLACK; redraw(); break; + case CMD_COLOR_PART: coloring_mode_init=coloring_mode=COLOR_MODE_PART; redraw(); break; + case CMD_COLOR_VELO: coloring_mode_init=coloring_mode=COLOR_MODE_VELO; redraw(); break; + case CMD_NOTELEN_1: new_len_init= 1; new_len=TICKS_PER_WHOLE/ 1; break; + case CMD_NOTELEN_2: new_len_init= 2; new_len=TICKS_PER_WHOLE/ 2; break; + case CMD_NOTELEN_4: new_len_init= 4; new_len=TICKS_PER_WHOLE/ 4; break; + case CMD_NOTELEN_8: new_len_init= 8; new_len=TICKS_PER_WHOLE/ 8; break; + case CMD_NOTELEN_16: new_len_init=16; new_len=TICKS_PER_WHOLE/16; break; + case CMD_NOTELEN_32: new_len_init=32; new_len=TICKS_PER_WHOLE/32; break; + case CMD_NOTELEN_LAST: new_len_init= 0; new_len=-1; break; default: cerr << "ERROR: ILLEGAL FUNCTION CALL: ScoreCanvas::menu_command called with unknown command ("<<cmd<<")"<<endl; @@ -4296,23 +4367,24 @@ void ScoreCanvas::menu_command(int cmd) void ScoreCanvas::preamble_keysig_slot(bool state) { preamble_contains_keysig=state; + preamble_contains_keysig_init=state; redraw(); } void ScoreCanvas::preamble_timesig_slot(bool state) { preamble_contains_timesig=state; + preamble_contains_timesig_init=state; redraw(); } void ScoreCanvas::set_quant(int val) { - int quant_mapper[]={1,2,3,4,5}; - - if ((val>=0) && (val<signed(sizeof(quant_mapper)/sizeof(*quant_mapper)))) + if ((val>=0) && (val<5)) { int old_len=quant_len(); - _quant_power2=quant_mapper[val]; + _quant_power2=val+1; + _quant_power2_init=_quant_power2; set_pixels_per_whole(pixels_per_whole() * quant_len() / old_len ); @@ -4339,6 +4411,7 @@ void ScoreCanvas::set_pixels_per_whole(int val) // zero!) _pixels_per_whole=val; + _pixels_per_whole_init=val; for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++) it->calc_item_pos(); @@ -4380,6 +4453,7 @@ void ScoreCanvas::maybe_close_if_empty() void ScoreCanvas::set_velo(int velo) { note_velo=velo; + note_velo_init=velo; if (parent->get_apply_velo()) modify_velocity(get_all_parts(),1, 0,velo); @@ -4388,6 +4462,7 @@ void ScoreCanvas::set_velo(int velo) void ScoreCanvas::set_velo_off(int velo) { note_velo_off=velo; + note_velo_off_init=velo; if (parent->get_apply_velo()) modify_off_velocity(get_all_parts(),1, 0,velo); @@ -4583,13 +4658,9 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo /* BUGS and potential bugs * o tied notes don't work properly when there's a key-change in * between, for example, when a cis is tied to a des - * o schedule_all_same_len_parts: if there are two clones A and B, - * and both A and B get scheduled to be expanded (because we - * have one event from A and one event from B), this causes a bug, - * because after A (and B) got resized, the B-resize is invalid! - * o when changing toolbarstate when sharing and immediately after that + * > o when changing toolbarstate when sharing and immediately after that * changing "share" status, the changed state isn't stored - * o arranger state and mixer state aren't stored (says tim) + * (could be solved by storing the current window when quitting/saving whatever) * ? pasting in editors sometimes fails oO? ( ERROR: reading eventlist * from clipboard failed. ignoring this one... ) [ not reproducible ] * @@ -4597,9 +4668,16 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * o drum controllers * update ctrlcanvas/panel * test! + * o drum editor is buggy. propagate_drum_map may operate on old values + * ("BUGGY! problem is: while changing entries, ourDrumMap + may be reallocated which causes abort()s and/or bugs.") * o don't mix DRUM and NEW_DRUM in drumeditor! + * o quantize must round UP, not down when at 0.5 * o my record flag handling * o option for disabling old-style / new-style drum tracks? + * ! o using super glue while a score editor displaying the glued parts + * is open lets muse segfault. this may or may not be fixed in + * the release branch :/ * * > o drum editor: channel-stuff * o clearly state in the changelog: when having multiple drumeditors open, @@ -4611,6 +4689,11 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * ask the user if he wants to proceed, and then set maintained_automatically to false * o offer some way to set maintained_automatically to true again * o move generation and deletion of ourDrumMap from DCanvas to DrumEditor and remove ugly wrapper functions + * > o fix valgrind problems (the two "FINDMICHJETZT" lines in scoreedit.cpp) + * > o add a songposition scrollbar-toolbar (in different sizes) + * this might be equivalent to "redo transport menu" (below). + * > o add toolbar(s) for tempo- etc spinboxes from the transport window + * * * o find and fix FINDMICHJETZT * o fix all segfaults and non-working stuff! @@ -4626,9 +4709,9 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * o all places where i added doubleclick-edits: only react on left-click double clicks! * o support "new style" reordering with old style drum tracks as well * (not swapping but inserting!) + * o support edge-scrolling when opening a lasso * o add "dotted quarter" quantize option (for 6/8 beat) * o ticks-to-quarter spinboxes - * o newly created windows have to be focussed! * o mirror most menus to an additional right-click context menu to avoid the long mouse pointer * journey to the menu bar. try to find a way which does not involve duplicate code! * o implement borland-style maximize: free windows do not cover the main menu, even when maximized @@ -4651,6 +4734,7 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * o thin out: remove unneeded ctrl messages * * less important stuff + * o allow "fixating" toolbars? * o quantize-templates (everything is forced into a specified * rhythm) * o part-templates (you specify some notes and a control-chord; @@ -4662,8 +4746,6 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * calc_pos_add_list must be called before calc_item_pos then, * and calc_item_pos must respect the pos_add_list instead of * keeping its own pos_add variable (which is only an optimisation) - * o support edge-scrolling when opening a lasso - * o save more configuration stuff (quant, color) * * really unimportant nice-to-haves * o support in-song clef-changes @@ -4676,10 +4758,6 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo * * * stuff for the other muse developers - * o update translations - * o remove ambiguous translation: "offset"="zeitversatz" - * this is ambigous in mod. note len and WRONG in mod. velo dialogs - * * o process accurate timesignatures from muse's list (has to be implemented first in muse) * ( (2+2+3)/4 or (3+2+2)/4 instead of 7/4 ) */ diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index 0d1432b8..7a16d19f 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -184,7 +184,7 @@ class ScoreEdit : public TopWin void clipboard_changed(); signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); void name_changed(); void velo_changed(int); void velo_off_changed(int); @@ -275,6 +275,9 @@ class FloEvent tick=ti; source_event=event; source_part=part; + + num=denom=0xdeadbeef; //unused, but valgrind complains if uninited + key=MusECore::KEY_C; } FloEvent(unsigned ti, typeEnum t, int num_, int denom_) { @@ -284,6 +287,9 @@ class FloEvent tick=ti; source_event=NULL; source_part=NULL; + + len=vel=pitch=0xdeadbeef; //unused, but valgrind complains if uninited + key=MusECore::KEY_C; } FloEvent(unsigned ti, typeEnum t, MusECore::key_enum k) { @@ -292,6 +298,8 @@ class FloEvent tick=ti; source_event=NULL; source_part=NULL; + + pitch=vel=len=num=denom=0xdeadbeef; //unused, but valgrind complains if uninited } }; class FloItem @@ -345,6 +353,7 @@ class FloItem begin_tick=beg; source_event=event; source_part=part; + is_active=false; } FloItem(typeEnum t, int num_, int denom_) @@ -659,8 +668,20 @@ class ScoreCanvas : public MusEGui::View void move_staff_below(list<staff_t>::iterator dest, list<staff_t>::iterator src); void cleanup_staves(); void maybe_close_if_empty(); - + +// defaults ---------------------------------------------------------- + public: + enum coloring_mode_t {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO}; + static int _quant_power2_init; + static int _pixels_per_whole_init; + static int note_velo_init, note_velo_off_init; + static int new_len_init; + static coloring_mode_t coloring_mode_init; + static bool preamble_contains_timesig_init; + static bool preamble_contains_keysig_init; + // member variables --------------------------------------------------- + private: int _quant_power2; int _pixels_per_whole; @@ -737,7 +758,7 @@ class ScoreCanvas : public MusEGui::View bool srec; bool held_notes[128]; - enum {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO} coloring_mode; + coloring_mode_t coloring_mode; bool preamble_contains_keysig; bool preamble_contains_timesig; @@ -767,38 +788,38 @@ class ScoreCanvas : public MusEGui::View void add_new_parts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&); - public slots: - void x_scroll_event(int); - void y_scroll_event(int); - void song_changed(int); - void fully_recalculate(); - void goto_tick(int,bool); - void pos_changed(int i, unsigned u, bool b); - void heartbeat_timer_event(); - - void set_tool(int); - void set_quant(int); - void menu_command(int); - void preamble_keysig_slot(bool); - void preamble_timesig_slot(bool); - void set_pixels_per_whole(int); + public slots: + void x_scroll_event(int); + void y_scroll_event(int); + void song_changed(int); + void fully_recalculate(); + void goto_tick(int,bool); + void pos_changed(int i, unsigned u, bool b); + void heartbeat_timer_event(); - void set_velo(int); - void set_velo_off(int); + void set_tool(int); + void set_quant(int); + void menu_command(int); + void preamble_keysig_slot(bool); + void preamble_timesig_slot(bool); + void set_pixels_per_whole(int); - void set_steprec(bool); - - void update_parts(); //re-populates the set<MusECore::Part*>s from the set<int>s + void set_velo(int); + void set_velo_off(int); + + void set_steprec(bool); + + void update_parts(); //re-populates the set<MusECore::Part*>s from the set<int>s signals: - void xscroll_changed(int); - void yscroll_changed(int); - void viewport_width_changed(int); - void canvas_width_changed(int); - void preamble_width_changed(int); - void viewport_height_changed(int); - void canvas_height_changed(int); - void pixels_per_whole_changed(int); - void pos_add_changed(); + void xscroll_changed(int); + void yscroll_changed(int); + void viewport_width_changed(int); + void canvas_width_changed(int); + void preamble_width_changed(int); + void viewport_height_changed(int); + void canvas_height_changed(int); + void pixels_per_whole_changed(int); + void pos_add_changed(); protected: virtual void draw(QPainter& p, const QRect& rect); diff --git a/muse2/muse/midifile.cpp b/muse2/muse/midifile.cpp index a94644ff..1fc7e114 100644 --- a/muse2/muse/midifile.cpp +++ b/muse2/muse/midifile.cpp @@ -23,7 +23,6 @@ #include <errno.h> #include <values.h> -#include <assert.h> #include "song.h" #include "midi.h" @@ -568,9 +567,9 @@ void MidiFile::writeEvent(const MidiPlayEvent* event) int nstat = event->type(); // we dont save meta data into smf type 0 files: - - if (MusEGlobal::config.smfFormat == 0 && nstat == ME_META) - return; + // Oct 16, 2011: Apparently it is legal to do that. Part of fix for bug tracker 3293339. + //if (MusEGlobal::config.smfFormat == 0 && nstat == ME_META) + // return; nstat |= c; // @@ -621,24 +620,45 @@ bool MidiFile::write() writeLong(6); // header len writeShort(MusEGlobal::config.smfFormat); if (MusEGlobal::config.smfFormat == 0) { - writeShort(1); + /* + //writeShort(1); // Removed. Bug tracker 3293339 MidiFileTrack dst; for (iMidiFileTrack i = _tracks->begin(); i != _tracks->end(); ++i) { MPEventList* sl = &((*i)->events); for (iMPEvent ie = sl->begin(); ie != sl->end(); ++ie) + { + // ALERT: Observed a problem here, apparently some of the events are being added too fast. + // The dump below tells me some of the events (sysex/meta) are missing from the list! + // Apparently it's a timing problem. Very puzzling. + // Attempting wild-guess fix now to eliminate multiple MidiFileTracks in MusE::exportMidi()... + // Nope. Didn't help. Now that it's a single MidiFileTrack, try skipping this section altogether... + // Yes that appears to have fixed it. Weird. What's the difference - the local 'dst' variable ? + // Or are there still lurking problems, or something more fundamentally wrong with Event or MPEvent? + printf("MidiFile::write adding event to dst:\n"); // REMOVE Tim. + ie->dump(); // REMOVE Tim. dst.events.add(*ie); + } } writeShort(1); writeShort(_division); writeTrack(&dst); + */ + + writeShort(1); + //writeShort(_division); + //if(!_tracks->empty()) + // writeTrack(*(_tracks->begin())); + } else { + + writeShort(ntracks); - + } writeShort(_division); for (ciMidiFileTrack i = _tracks->begin(); i != _tracks->end(); ++i) writeTrack(*i); - } +/// } return (ferror(fp) != 0); } diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp index 71a90fe7..b7d1d7b7 100644 --- a/muse2/muse/midiport.cpp +++ b/muse2/muse/midiport.cpp @@ -24,6 +24,7 @@ //#include "config.h" #include <QMenu> +#include <QApplication> #include "mididev.h" #include "midiport.h" @@ -331,18 +332,18 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort) { MusECore::MidiDevice* md = MusEGlobal::midiPorts[pi].device(); //if(md && !md->isSynti() && (md->rwFlags() & 1)) - //if(md && (md->rwFlags() & 1)) - if(md && (md->rwFlags() & 1 || md->isSynti()) ) + if(md && (md->rwFlags() & 1)) + //if(md && (md->rwFlags() & 1 || md->isSynti()) ) // Revert. Hm, why synths? Only writeable ports. p4.0.41 break; } if(pi == MIDI_PORTS) { - act = p->addAction(p->tr("Warning: No output devices!")); + act = p->addAction(qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Warning: No output devices!"))); act->setCheckable(false); act->setData(-1); p->addSeparator(); } - act = p->addAction(QIcon(*MusEGui::settings_midiport_softsynthsIcon), p->tr("Open midi config...")); + act = p->addAction(QIcon(*MusEGui::settings_midiport_softsynthsIcon), qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Open midi config..."))); act->setCheckable(false); act->setData(MIDI_PORTS); p->addSeparator(); @@ -351,8 +352,12 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort) for (int i = 0; i < MIDI_PORTS; ++i) { MidiPort* port = &MusEGlobal::midiPorts[i]; + MusECore::MidiDevice* md = port->device(); + //if(md && !(md->rwFlags() & 1 || md->isSynti()) && (i != checkPort)) + if(md && !(md->rwFlags() & 1) && (i != checkPort)) // Only writeable ports, or current one. + continue; name.sprintf("%d:%s", port->portno()+1, port->portname().toLatin1().constData()); - if(port->device() || (i == checkPort)) + if(md || (i == checkPort)) { act = p->addAction(name); act->setData(i); @@ -360,12 +365,12 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort) act->setChecked(i == checkPort); } - if(!port->device()) + if(!md) { if(!subp) // No submenu yet? Create it now. { subp = new QMenu(p); - subp->setTitle(subp->tr("Empty ports")); + subp->setTitle(qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Empty ports"))); //subp->addAction(new MusEGui::MenuTitleItem("Empty Ports", subp)); } //act = subp->addAction(name); // No need for all those "<None>" names. diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp index e31db7c7..1e46db11 100644 --- a/muse2/muse/midiseq.cpp +++ b/muse2/muse/midiseq.cpp @@ -44,6 +44,7 @@ #include "synth.h" #include "song.h" #include "gconfig.h" +#include <lo/lo_osc_types.h> namespace MusEGlobal { MusECore::MidiSeq* midiSeq; @@ -54,6 +55,12 @@ namespace MusECore { int MidiSeq::ticker = 0; +void initMidiSequencer() +{ + //MusEGlobal::midiSeq = new MidiSeq(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0, "Midi"); + MusEGlobal::midiSeq = new MidiSeq("Midi"); +} + //--------------------------------------------------------- // readMsg //--------------------------------------------------------- @@ -819,16 +826,16 @@ void MidiSeq::msgMsg(int id) void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device) { - MusECore::AudioMsg msg; - msg.id = MusECore::SEQM_IDLE; - msg.a = true; - Thread::sendMsg(&msg); - - port->setMidiDevice(device); + MusECore::AudioMsg msg; + msg.id = MusECore::SEQM_IDLE; + msg.a = true; + Thread::sendMsg(&msg); + + port->setMidiDevice(device); - msg.id = MusECore::SEQM_IDLE; - msg.a = false; - Thread::sendMsg(&msg); + msg.id = MusECore::SEQM_IDLE; + msg.a = false; + Thread::sendMsg(&msg); } // This does not appear to be used anymore. Was called in Audio::process1, now Audio::processMidi is called directly. p4.0.15 Tim. diff --git a/muse2/muse/mixer/amixer.cpp b/muse2/muse/mixer/amixer.cpp index f9ede36c..34c8190b 100644 --- a/muse2/muse/mixer/amixer.cpp +++ b/muse2/muse/mixer/amixer.cpp @@ -169,7 +169,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MusEGlobal::MixerConfig* c) setWindowIcon(*museIcon); QMenu* menuConfig = menuBar()->addMenu(tr("&Create")); - MusEGui::populateAddTrack(menuConfig); + MusEGui::populateAddTrack(menuConfig,true); connect(menuConfig, SIGNAL(triggered(QAction *)), MusEGlobal::song, SLOT(addNewTrack(QAction *))); QMenu* menuView = menuBar()->addMenu(tr("&View")); diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index 10f281fb..9c393a1a 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -147,6 +147,7 @@ void AudioStrip::songChanged(int val) // Set the strip label's font. //label->setFont(MusEGlobal::config.fonts[1]); setLabelFont(); + setLabelText(); // Adjust minimum volume slider and label values. slider->setRange(MusEGlobal::config.minSlider-0.1, 10.0); @@ -203,7 +204,17 @@ void AudioStrip::songChanged(int val) pre->setChecked(src->prefader()); pre->blockSignals(false); } - } + + // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track! + // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels. + int rc = track->auxRefCount(); + int n = auxKnob.size(); + for (int idx = 0; idx < n; ++idx) + { + auxKnob[idx]->setEnabled( rc == 0 ); + auxLabel[idx]->setEnabled( rc == 0 ); + } + } if (val & SC_AUX) { int n = auxKnob.size(); for (int idx = 0; idx < n; ++idx) { @@ -333,11 +344,14 @@ void AudioStrip::updateOffState() stereo->setEnabled(val); label->setEnabled(val); + // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track! + // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels. + bool ae = track->auxRefCount() == 0 && val; int n = auxKnob.size(); for (int i = 0; i < n; ++i) { - auxKnob[i]->setEnabled(val); - auxLabel[i]->setEnabled(val); + auxKnob[i]->setEnabled(ae); + auxLabel[i]->setEnabled(ae); } if (pre) @@ -348,12 +362,12 @@ void AudioStrip::updateOffState() solo->setEnabled(val); if (mute) mute->setEnabled(val); - if (autoType) - autoType->setEnabled(val); - if (iR) - iR->setEnabled(val); - if (oR) - oR->setEnabled(val); + //if (autoType) + // autoType->setEnabled(val); + //if (iR) + // iR->setEnabled(val); + //if (oR) + // oR->setEnabled(val); if (off) { off->blockSignals(true); off->setChecked(track->off()); @@ -799,6 +813,12 @@ AudioStrip::AudioStrip(QWidget* parent, MusECore::AudioTrack* at) double val = MusECore::fast_log10(t->auxSend(idx))*20.0; ak->setValue(val); al->setValue(val); + + // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track! + // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels. + int rc = track->auxRefCount(); + ak->setEnabled( rc == 0 ); + al->setEnabled( rc == 0 ); } } else { diff --git a/muse2/muse/mixer/mstrip.cpp b/muse2/muse/mixer/mstrip.cpp index 2e51feb9..dc495aa6 100644 --- a/muse2/muse/mixer/mstrip.cpp +++ b/muse2/muse/mixer/mstrip.cpp @@ -448,9 +448,8 @@ void MidiStrip::updateOffState() // TODO: Disabled for now. //if (autoType) // autoType->setEnabled(val); - if (iR) - iR->setEnabled(val); - // TODO: Disabled for now. + //if (iR) + // iR->setEnabled(val); //if (oR) // oR->setEnabled(val); if (off) { @@ -504,6 +503,7 @@ void MidiStrip::songChanged(int val) // Set the strip label's font. //label->setFont(MusEGlobal::config.fonts[1]); setLabelFont(); + setLabelText(); } } diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp index 5f5e5e39..146d981c 100644 --- a/muse2/muse/mixer/strip.cpp +++ b/muse2/muse/mixer/strip.cpp @@ -29,6 +29,8 @@ #include <QColor> #include <QVBoxLayout> #include <QFrame> +#include <QMouseEvent> +#include <QMenu> #include "globals.h" #include "gconfig.h" @@ -165,7 +167,8 @@ void Strip::setLabelText() //gradient.setColorAt(0, c.darker()); //gradient.setColorAt(0, c); //gradient.setColorAt(1, c.darker()); - gradient.setColorAt(0, c.lighter()); + gradient.setColorAt(0, c); + gradient.setColorAt(0.5, c.lighter()); gradient.setColorAt(1, c); //palette.setBrush(QPalette::Button, gradient); //palette.setBrush(QPalette::Window, gradient); @@ -307,6 +310,23 @@ void Strip::resizeEvent(QResizeEvent* ev) setLabelText(); setLabelFont(); } - + +void Strip::mousePressEvent(QMouseEvent* ev) +{ + if (ev->button() == Qt::RightButton) { + QMenu* menu = new QMenu; + menu->addAction(tr("Remove track?")); + QPoint pt = QCursor::pos(); + QAction* act = menu->exec(pt, 0); + if (!act) + { + delete menu; + return; + } + MusEGlobal::song->removeTrack0(track); + MusEGlobal::audio->msgUpdateSoloStates(); + } +} + } // namespace MusEGui diff --git a/muse2/muse/mixer/strip.h b/muse2/muse/mixer/strip.h index 5b3b541b..d0cde1a6 100644 --- a/muse2/muse/mixer/strip.h +++ b/muse2/muse/mixer/strip.h @@ -73,6 +73,7 @@ class Strip : public QFrame { MusEGui::ComboBox* autoType; void setLabelText(); virtual void resizeEvent(QResizeEvent*); + virtual void mousePressEvent(QMouseEvent *); private slots: void recordToggled(bool); diff --git a/muse2/muse/mpevent.cpp b/muse2/muse/mpevent.cpp index f72af528..8b65bce1 100644 --- a/muse2/muse/mpevent.cpp +++ b/muse2/muse/mpevent.cpp @@ -18,7 +18,6 @@ // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// //========================================================= #include "mpevent.h" @@ -42,6 +41,7 @@ MEvent::MEvent(unsigned t, int port, int tpe, const unsigned char* data, int len edata.setData(data, len); _type = tpe; _loopNum = 0; + setChannel(0); } MEvent::MEvent(unsigned tick, int port, int channel, const Event& e) diff --git a/muse2/muse/mplugins/mitplugin.cpp b/muse2/muse/mplugins/mitplugin.cpp index 48e30bb6..d4d7dd70 100644 --- a/muse2/muse/mplugins/mitplugin.cpp +++ b/muse2/muse/mplugins/mitplugin.cpp @@ -48,7 +48,7 @@ void MusE::startMidiInputPlugin(int id) QAction* act; if (id == 0) { if (!MusEGlobal::mitPluginTranspose) { - MusEGlobal::mitPluginTranspose = new MusEGui::MITPluginTranspose(); + MusEGlobal::mitPluginTranspose = new MITPluginTranspose(); MusECore::mitPlugins.push_back(MusEGlobal::mitPluginTranspose); connect(MusEGlobal::mitPluginTranspose, SIGNAL(hideWindow()), SLOT(hideMitPluginTranspose())); @@ -58,7 +58,7 @@ void MusE::startMidiInputPlugin(int id) } else if (id == 1) { if (!midiInputTransform) { - midiInputTransform = new MusEGui::MidiInputTransformDialog(); + midiInputTransform = new MidiInputTransformDialog(); connect(midiInputTransform, SIGNAL(hideWindow()), SLOT(hideMidiInputTransform())); } @@ -67,7 +67,7 @@ void MusE::startMidiInputPlugin(int id) } else if (id == 2) { if (!midiFilterConfig) { - midiFilterConfig = new MusEGui::MidiFilterConfig(); + midiFilterConfig = new MidiFilterConfig(); connect(midiFilterConfig, SIGNAL(hideWindow()), SLOT(hideMidiFilterConfig())); } @@ -76,7 +76,7 @@ void MusE::startMidiInputPlugin(int id) } else if (id == 3) { if (!midiRemoteConfig) { - midiRemoteConfig = new MusEGui::MRConfig(); + midiRemoteConfig = new MRConfig(); connect(midiRemoteConfig, SIGNAL(hideWindow()), SLOT(hideMidiRemoteConfig())); } @@ -134,7 +134,7 @@ void MusE::hideMidiRhythmGenerator() void MusE::startMidiTransformer() { if (midiTransformerDialog == 0) - midiTransformerDialog = new MusEGui::MidiTransformerDialog; + midiTransformerDialog = new MidiTransformerDialog; midiTransformerDialog->show(); } diff --git a/muse2/muse/mplugins/rhythm.cpp b/muse2/muse/mplugins/rhythm.cpp index 78dfeee5..7c51227c 100644 --- a/muse2/muse/mplugins/rhythm.cpp +++ b/muse2/muse/mplugins/rhythm.cpp @@ -29,6 +29,8 @@ #include "rhythm.h" +namespace MusEGui { + //--------------------------------------------------------- // RhythmGen //--------------------------------------------------------- @@ -525,5 +527,7 @@ RhythmGenerator::~RhythmGenerator() { // no need to delete child widgets, Qt does it all for us } + #endif +} // namespace MusEGui diff --git a/muse2/muse/mplugins/rhythm.h b/muse2/muse/mplugins/rhythm.h index d60e7993..de6c178b 100644 --- a/muse2/muse/mplugins/rhythm.h +++ b/muse2/muse/mplugins/rhythm.h @@ -34,17 +34,22 @@ #include <QMainWindow> +#define MAX_GROUPS 5 +#define MAX_KEYS 20 + class QCloseEvent; +namespace MusECore { +class Xml; +} + +namespace MusEGui { + class tTrack; class tEventWin; class tSong; class tBarInfo; -#define MAX_GROUPS 5 -#define MAX_KEYS 20 - -class Xml; #if 0 //--------------------------------------------------------- @@ -59,8 +64,8 @@ struct tRhyGroup { listen = 0; contrib = 0; } -// void write(int, Xml&); -// void read(Xml&); +// void write(int, MusECore::Xml&); +// void read(MusECore::Xml&); }; //--------------------------------------------------------- @@ -71,8 +76,8 @@ struct tRhyGroups { tRhyGroup g[MAX_GROUPS]; tRhyGroup& operator [] (int i) { return g[i]; } -// void write(int, Xml&); -// void read(Xml&); +// void write(int, MusECore::Xml&); +// void read(MusECore::Xml&); }; //--------------------------------------------------------- @@ -123,8 +128,8 @@ class tRhythm void GenInit(long start_clock); void GenerateEvent(tTrack *track, long clock, short vel, short len); - void write(int, Xml&); - void read(Xml&); + void write(int, MusECore::Xml&); + void read(MusECore::Xml&); }; #endif @@ -209,5 +214,7 @@ class RhythmGen : public QMainWindow, public Ui::RhythmBase // bool OnClose(); }; +} // namespace MusEGui + #endif diff --git a/muse2/muse/node.cpp b/muse2/muse/node.cpp index db11b7bd..cb77f939 100644 --- a/muse2/muse/node.cpp +++ b/muse2/muse/node.cpp @@ -4,6 +4,7 @@ // $Id: node.cpp,v 1.36.2.25 2009/12/20 05:00:35 terminator356 Exp $ // // (C) Copyright 2000-2004 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -22,10 +23,11 @@ //========================================================= #include <cmath> -#include <assert.h> #include <sndfile.h> #include <stdlib.h> +#include <QString> + #include "node.h" #include "globals.h" #include "gconfig.h" @@ -45,7 +47,6 @@ //#define NODE_DEBUG //#define FIFO_DEBUG -// Added by Tim. p3.3.18 //#define METRONOME_DEBUG namespace MusECore { @@ -163,10 +164,19 @@ void Track::updateInternalSoloStates() void MidiTrack::updateInternalSoloStates() { - if(this == _tmpSoloChainTrack) - return; - - Track::updateInternalSoloStates(); + if(_nodeTraversed) // Anti circular mechanism. + { + fprintf(stderr, "MidiTrack::updateInternalSoloStates %s :\n MusE Warning: Please check your routes: Circular path found!\n", name().toLatin1().constData()); + return; + } + //if(this == _tmpSoloChainTrack) + // return; + + _nodeTraversed = true; + + Track::updateInternalSoloStates(); + + _nodeTraversed = false; // Reset. } @@ -176,40 +186,61 @@ void MidiTrack::updateInternalSoloStates() void AudioTrack::updateInternalSoloStates() { - if(this == _tmpSoloChainTrack) - return; - - Track::updateInternalSoloStates(); - - if(_tmpSoloChainDoIns) + if(_nodeTraversed) // Anti circular mechanism. + { + fprintf(stderr, "AudioTrack::updateInternalSoloStates %s :\n MusE Warning: Please check your routes: Circular path found!\n", name().toLatin1().constData()); + return; + } + //if(this == _tmpSoloChainTrack) + // return; + + _nodeTraversed = true; + + Track::updateInternalSoloStates(); + + if(_tmpSoloChainDoIns) + { + if(type() == AUDIO_SOFTSYNTH) + { + const MusECore::MidiTrackList* ml = MusEGlobal::song->midis(); + for(MusECore::ciMidiTrack im = ml->begin(); im != ml->end(); ++im) { - if(type() == AUDIO_SOFTSYNTH) - { - const MusECore::MidiTrackList* ml = MusEGlobal::song->midis(); - for(MusECore::ciMidiTrack im = ml->begin(); im != ml->end(); ++im) - { - MusECore::MidiTrack* mt = *im; - if(mt->outPort() >= 0 && mt->outPort() == ((SynthI*)this)->midiPort()) - mt->updateInternalSoloStates(); - } - } - - const RouteList* rl = inRoutes(); - for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - if(ir->type == Route::TRACK_ROUTE) - ir->track->updateInternalSoloStates(); - } + MusECore::MidiTrack* mt = *im; + if(mt->outPort() >= 0 && mt->outPort() == ((SynthI*)this)->midiPort()) + mt->updateInternalSoloStates(); } - else - { - const RouteList* rl = outRoutes(); - for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + } + + const RouteList* rl = inRoutes(); + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + if(ir->type == Route::TRACK_ROUTE) + ir->track->updateInternalSoloStates(); + else + // Support Midi Port -> Audio Input solo chains. p4.0.37 Tim. + if(ir->type == Route::MIDI_PORT_ROUTE) + { + const MidiTrackList* ml = MusEGlobal::song->midis(); + for(ciMidiTrack im = ml->begin(); im != ml->end(); ++im) { - if(ir->type == Route::TRACK_ROUTE) - ir->track->updateInternalSoloStates(); + MidiTrack* mt = *im; + if(mt->outPort() == ir->midiPort && ((1 << mt->outChannel()) & ir->channel) ) + mt->updateInternalSoloStates(); } - } + } + } + } + else + { + const RouteList* rl = outRoutes(); + for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) + { + if(ir->type == Route::TRACK_ROUTE) + ir->track->updateInternalSoloStates(); + } + } + + _nodeTraversed = false; // Reset. } @@ -222,6 +253,8 @@ void MidiTrack::updateSoloStates(bool noDec) if(noDec && !_solo) return; + _nodeTraversed = true; // Anti circular mechanism. + _tmpSoloChainTrack = this; _tmpSoloChainDoIns = false; _tmpSoloChainNoDec = noDec; @@ -245,6 +278,8 @@ void MidiTrack::updateSoloStates(bool noDec) } } } + + _nodeTraversed = false; // Reset. } @@ -257,6 +292,8 @@ void AudioTrack::updateSoloStates(bool noDec) if(noDec && !_solo) return; + _nodeTraversed = true; // Anti circular mechanism. + _tmpSoloChainTrack = this; _tmpSoloChainNoDec = noDec; updateSoloState(); @@ -302,6 +339,8 @@ void AudioTrack::updateSoloStates(bool noDec) ir->track->updateInternalSoloStates(); } } + + _nodeTraversed = false; // Reset. } @@ -328,7 +367,6 @@ void Track::setOff(bool val) // copyData //--------------------------------------------------------- -//void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer) { //Changed by T356. 12/12/09. @@ -337,60 +375,51 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s // Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing. // Previously only WaveTrack used them. (Changed WaveTrack as well). + #ifdef NODE_DEBUG + printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().toLatin1().constData(), processed()); + #endif + if(srcStartChan == -1) srcStartChan = 0; - int srcChans = (srcChannels == -1) ? channels() : srcChannels; + int trackChans = channels(); + int srcChans = (srcChannels == -1) ? trackChans : srcChannels; int srcTotalOutChans = totalOutChannels(); if(channels() == 1) srcTotalOutChans = 1; - #ifdef NODE_DEBUG - printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().toLatin1().constData(), processed()); - #endif - // Special consideration for metronome: It is not part of the track list, // and it has no in or out routes, yet multiple output tracks may call addData on it ! // We can't tell how many output tracks call it, so we can only assume there might be more than one. // Not strictly necessary here because only addData is ever called, but just to be consistent... - //bool usedirectbuf = (outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT); - bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); + //bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); int i; - // p3.3.38 - //float* buffer[srcChannels]; float* buffer[srcTotalOutChans]; + float data[nframes * srcTotalOutChans]; - - //float data[nframes * srcChannels]; - //for(i = 0; i < srcChannels; ++i) - // buffer[i] = data + i * nframes; - // precalculate stereo volume double vol[2]; double _volume = volume(); double _pan = pan(); vol[0] = _volume * (1.0 - _pan); vol[1] = _volume * (1.0 + _pan); - float meter[srcChans]; + float meter[trackChans]; // Have we been here already during this process cycle? if(processed()) { // If there is only one (or no) output routes, it's an error - we've been called more than once per process cycle! + // No, this is no longer an error, it's deliberate. Processing no longer done in 'chains', now done randomly. p4.0.37 #ifdef NODE_DEBUG - if(usedirectbuf) - printf("MusE: AudioTrack::copyData Error! One or no out routes, but already processed! Copying local buffers anyway...\n"); + printf("MusE: AudioTrack::copyData name:%s already processed _haveData:%d\n", name().toLatin1().constData(), _haveData); #endif // Is there already some data gathered from a previous call during this process cycle? if(_haveData) { // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. - //for(i = 0; i < srcChannels; ++i) - // buffer[i] = outBuffers[i]; - // p3.3.38 for(i = 0; i < srcTotalOutChans; ++i) buffer[i] = outBuffers[i]; } @@ -414,29 +443,16 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s { // First time here during this process cycle. - // Point the input buffers at a temporary stack buffer. - //float data[nframes * srcChannels]; - //for(i = 0; i < srcChannels; ++i) - // buffer[i] = data + i * nframes; - // p3.3.38 - float data[nframes * srcTotalOutChans]; - for(i = 0; i < srcTotalOutChans; ++i) - buffer[i] = data + i * nframes; - - // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc. - // For ex. if this is an audio input, Jack will set the pointers for us in AudioInput::getData! - // p3.3.29 1/27/10 Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times, - // so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is ! - //if(!getData(pos, srcChannels, nframes, buffer) || off() || (isMute() && !_prefader)) - //if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader)) - // p3.3.38 - if(off() || !getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader)) - { + _haveData = false; // Reset. + _processed = true; // Set this now. + + if(off()) + { #ifdef NODE_DEBUG - printf("MusE: AudioTrack::copyData name:%s dstChannels:%d zeroing buffers\n", name().toLatin1().constData(), dstChannels); + printf("MusE: AudioTrack::copyData name:%s dstChannels:%d Off, zeroing buffers\n", name().toLatin1().constData(), dstChannels); #endif - // No data was available. Zero the supplied buffers. + // Track is off. Zero the supplied buffers. unsigned int q; for(i = 0; i < dstChannels; ++i) { @@ -449,13 +465,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s memset(dstBuffer[i], 0, sizeof(float) * nframes); } - for(i = 0; i < srcChans; ++i) + _efxPipe->apply(0, nframes, 0); // Just process controls only, not audio (do not 'run'). + + for(i = 0; i < trackChans; ++i) { - //_meter[i] = 0; _meter[i] = 0.0; - - /* - if(!usedirectbuf) + /*if(!usedirectbuf) { if(MusEGlobal::config.useDenormalBias) { @@ -464,22 +479,49 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s } else memset(outBuffers[i], 0, sizeof(float) * nframes); - } - */ + } */ } - _haveData = false; - _processed = true; + //_haveData = false; + //_processed = true; + //_isProcessing = false; // Unblock. return; } + + // Point the input buffers at a temporary stack buffer. + for(i = 0; i < srcTotalOutChans; ++i) + buffer[i] = data + i * nframes; + + // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc. + // For ex. if this is an audio input, Jack will set the pointers for us in AudioInput::getData! + // Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times, + // so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is ! + if(!getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader)) + { + #ifdef NODE_DEBUG + printf("MusE: AudioTrack::copyData name:%s srcTotalOutChans:%d zeroing buffers\n", name().toLatin1().constData(), srcTotalOutChans); + #endif + + // No data was available. Track is not off. Zero the working buffers and continue on. + unsigned int q; + for(i = 0; i < srcTotalOutChans; ++i) + { + if(MusEGlobal::config.useDenormalBias) + { + for(q = 0; q < nframes; ++q) + buffer[i][q] = MusEGlobal::denormalBias; + } + else + memset(buffer[i], 0, sizeof(float) * nframes); + } + } //--------------------------------------------------- // apply plugin chain //--------------------------------------------------- - // p3.3.41 //fprintf(stderr, "AudioTrack::copyData %s efx apply srcChans:%d\n", name().toLatin1().constData(), srcChans); - _efxPipe->apply(srcChans, nframes, buffer); + _efxPipe->apply(trackChans, nframes, buffer); //--------------------------------------------------- // aux sends @@ -526,18 +568,16 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s if(_prefader) { - for(i = 0; i < srcChans; ++i) + for(i = 0; i < trackChans; ++i) { float* p = buffer[i]; meter[i] = 0.0; for(unsigned k = 0; k < nframes; ++k) { - double f = fabs(*p); + double f = fabs(*p++); if(f > meter[i]) meter[i] = f; - ++p; } - //_meter[i] = lrint(meter[i] * 32767.0); _meter[i] = meter[i]; if(_meter[i] > _peak[i]) _peak[i] = _meter[i]; @@ -571,20 +611,19 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s else memset(outBuffers[i], 0, sizeof(float) * nframes); } - } - */ + } */ + - _haveData = false; - _processed = true; + if(!_prefader) + for(i = 0; i < trackChans; ++i) // Must process ALL channels, even if unconnected. Only max 2 channels. + _meter[i] = 0.0; + return; } // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them. - if(!usedirectbuf) + //if(!usedirectbuf) { - //for(i = 0; i < srcChannels; ++i) - // AL::dsp->cpy(outBuffers[i], buffer[i], nframes); - // p3.3.38 for(i = 0; i < srcTotalOutChans; ++i) AL::dsp->cpy(outBuffers[i], buffer[i], nframes); } @@ -607,9 +646,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s else memset(dstBuffer[i], 0, sizeof(float) * nframes); } - _processed = true; return; } + // Force a source range to fit actual available total out channels. if((srcStartChan + srcChans) > srcTotalOutChans) srcChans = srcTotalOutChans - srcStartChan; @@ -619,132 +658,94 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s // postfader metering //--------------------------------------------------- - - if(srcChans == dstChannels) + #ifdef NODE_DEBUG + printf("MusE: AudioTrack::copyData trackChans:%d srcTotalOutChans:%d srcStartChan:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcStartChan, srcChans, dstChannels); + #endif + + if(!_prefader) { - if(_prefader) + for(int c = 0; c < trackChans; ++c) { - for(int c = 0; c < dstChannels; ++c) + meter[c] = 0.0; + double v = (trackChans == 1 ? _volume : vol[c]); + float* sp = buffer[c]; + for(unsigned k = 0; k < nframes; ++k) { - // p3.3.38 - //float* sp = buffer[c]; - float* sp = buffer[c + srcStartChan]; - - float* dp = dstBuffer[c]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ = (*sp++ * vol[c]); + float val = *sp++ * v; // If the track is mono pan has no effect on meters. + double f = fabs(val); + if(f > meter[c]) + meter[c] = f; } - } - else + _meter[c] = meter[c]; + if(_meter[c] > _peak[c]) + _peak[c] = _meter[c]; + } + } + + if(srcChans == dstChannels) + { + for(int c = 0; c < dstChannels; ++c) { - for(int c = 0; c < dstChannels; ++c) - { - meter[c] = 0.0; - - // p3.3.38 - //float* sp = buffer[c]; - float* sp = buffer[c + srcStartChan]; - - float* dp = dstBuffer[c]; - //printf("2 dstBuffer[c]=%d\n",long(dstBuffer[c])); - for(unsigned k = 0; k < nframes; ++k) - { - float val = *sp++ * vol[c]; - *dp++ = val; - double f = fabs(val); - if(f > meter[c]) - meter[c] = f; - } - //_meter[c] = lrint(meter[c] * 32767.0); - _meter[c] = meter[c]; - if(_meter[c] > _peak[c]) - _peak[c] = _meter[c]; - } + double v; + if(srcStartChan > 2) // Don't apply pan or volume to extra channels above 2. + //v = _volume; + v = 1.0; + else + if(srcChans >= 2) // If 2 channels apply pan normally. + v = vol[c]; + else + if(trackChans < 2) // If 1 channel and track is 1 channel, don't apply pan. + v = _volume; + else + v = vol[srcStartChan]; // Otherwise 1 channel but track is 2 channels. Apply the channel volume. + + float* sp = buffer[c + srcStartChan]; + float* dp = dstBuffer[c]; + for(unsigned k = 0; k < nframes; ++k) + //*dp++ = (*sp++ * vol[c]); + *dp++ = (*sp++ * v); } } else if(srcChans == 1 && dstChannels == 2) { - // p3.3.38 - //float* sp = buffer[0]; - float* sp = buffer[srcStartChan]; - - if(_prefader) + for(int c = 0; c < dstChannels; ++c) { - for(int c = 0; c < dstChannels; ++c) - { - float* dp = dstBuffer[c]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ = (*sp++ * vol[c]); - } - } - else - { - meter[0] = 0.0; - for(unsigned k = 0; k < nframes; ++k) - { - float val = *sp++; - double f = fabs(val) * _volume; - if(f > meter[0]) - meter[0] = f; - *(dstBuffer[0] + k) = val * vol[0]; - *(dstBuffer[1] + k) = val * vol[1]; - } - //_meter[0] = lrint(meter[0] * 32767.0); - _meter[0] = meter[0]; - if(_meter[0] > _peak[0]) - _peak[0] = _meter[0]; + double v; + if(srcStartChan > 2) // Don't apply pan or volume to extra channels above 2. + //v = _volume; + v = 1.0; + else + if(trackChans <= 1) // If track is mono apply pan. + v = vol[c]; + else + v = vol[srcStartChan]; // Otherwise track is stereo, apply the same channel volume to both. + + float* sp = buffer[srcStartChan]; + float* dp = dstBuffer[c]; + for(unsigned k = 0; k < nframes; ++k) + //*dp++ = (*sp++ * vol[c]); + *dp++ = (*sp++ * v); } } else if(srcChans == 2 && dstChannels == 1) { - // p3.3.38 - //float* sp1 = buffer[0]; - //float* sp2 = buffer[1]; + //double v1 = (srcStartChan > 2 ? _volume : vol[srcStartChan]); // Don't apply pan to extra channels above 2. + //double v2 = (srcStartChan > 2 ? _volume : vol[srcStartChan + 1]); // + double v1 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan]); // Don't apply pan or volume to extra channels above 2. + double v2 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan + 1]); // + float* dp = dstBuffer[0]; float* sp1 = buffer[srcStartChan]; float* sp2 = buffer[srcStartChan + 1]; - - if(_prefader) - { - float* dp = dstBuffer[0]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ = (*sp1++ * vol[0] + *sp2++ * vol[1]); - } - else - { - float* dp = dstBuffer[0]; - meter[0] = 0.0; - meter[1] = 0.0; - for(unsigned k = 0; k < nframes; ++k) - { - float val1 = *sp1++ * vol[0]; - float val2 = *sp2++ * vol[1]; - double f1 = fabs(val1); - if(f1 > meter[0]) - meter[0] = f1; - double f2 = fabs(val2); - if(f2 > meter[1]) - meter[1] = f2; - *dp++ = (val1 + val2); - } - //_meter[0] = lrint(meter[0] * 32767.0); - _meter[0] = meter[0]; - if(_meter[0] > _peak[0]) - _peak[0] = _meter[0]; - //_meter[1] = lrint(meter[1] * 32767.0); - _meter[1] = meter[1]; - if(_meter[1] > _peak[1]) - _peak[1] = _meter[1]; - } + for(unsigned k = 0; k < nframes; ++k) + //*dp++ = (*sp1++ * vol[0] + *sp2++ * vol[1]); + *dp++ = (*sp1++ * v1 + *sp2++ * v2); } - - _processed = true; } //--------------------------------------------------------- // addData //--------------------------------------------------------- -//void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer) void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer) { //Changed by T356. 12/12/09. @@ -753,21 +754,21 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr // Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing. // Previously only WaveTrack used them. (Changed WaveTrack as well). - //Added by Tim. p3.3.16 #ifdef NODE_DEBUG printf("MusE: AudioTrack::addData name:%s processed:%d\n", name().toLatin1().constData(), processed()); #endif - if (off()) - { - _processed = true; - return; - } + //if (off()) + //{ + // _processed = true; + // return; + //} if(srcStartChan == -1) srcStartChan = 0; - int srcChans = (srcChannels == -1) ? channels() : srcChannels; + int trackChans = channels(); + int srcChans = (srcChannels == -1) ? trackChans : srcChannels; int srcTotalOutChans = totalOutChannels(); if(channels() == 1) srcTotalOutChans = 1; @@ -775,18 +776,12 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr // Special consideration for metronome: It is not part of the track list, // and it has no in or out routes, yet multiple output tracks may call addData on it ! // We can't tell how many output tracks call it, so we can only assume there might be more than one. - //bool usedirectbuf = (outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT); - bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); + //bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); int i; - // p3.3.38 - //float* buffer[srcChannels]; float* buffer[srcTotalOutChans]; - - //float data[nframes * srcChannels]; - //for (i = 0; i < srcChannels; ++i) - // buffer[i] = data + i * nframes; + float data[nframes * srcTotalOutChans]; // precalculate stereo volume double vol[2]; @@ -794,105 +789,96 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr double _pan = pan(); vol[0] = _volume * (1.0 - _pan); vol[1] = _volume * (1.0 + _pan); - float meter[srcChans]; + //float meter[srcChans]; + float meter[trackChans]; // Have we been here already during this process cycle? if(processed()) { // If there is only one (or no) output routes, it's an error - we've been called more than once per process cycle! + // No, this is no longer an error, it's deliberate. Processing no longer done in 'chains', now done randomly. p4.0.37 #ifdef NODE_DEBUG - if(usedirectbuf) - printf("MusE: AudioTrack::addData Error! One or no out routes, but already processed! Copying local buffers anyway...\n"); + printf("MusE: AudioTrack::addData name:%s already processed _haveData:%d\n", name().toLatin1().constData(), _haveData); #endif // Is there already some data gathered from a previous call during this process cycle? if(_haveData) { // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. - //for(i = 0; i < srcChannels; ++i) - // buffer[i] = outBuffers[i]; - // p3.3.38 for(i = 0; i < srcTotalOutChans; ++i) buffer[i] = outBuffers[i]; } else + { // No data was available from a previous call during this process cycle. Nothing to add, just return. return; + } } else { // First time here during this process cycle. - // Point the input buffers at a temporary stack buffer. - //float data[nframes * srcChannels]; - //for(i = 0; i < srcChannels; ++i) - // buffer[i] = data + i * nframes; - // p3.3.38 - float data[nframes * srcTotalOutChans]; - for(i = 0; i < srcTotalOutChans; ++i) - buffer[i] = data + i * nframes; - + _haveData = false; // Reset. + _processed = true; // Set this now. - // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc. - // For ex. if this is an audio input, Jack will set the pointers for us. - //if(!getData(pos, srcChannels, nframes, buffer)) - // p3.3.38 - if(!getData(pos, srcTotalOutChans, nframes, buffer)) - { - // No data was available. Nothing to add, but zero our local buffers and the meters. - for(i = 0; i < srcChans; ++i) + if(off()) + { + #ifdef NODE_DEBUG + printf("MusE: AudioTrack::addData name:%s dstChannels:%d Track is Off \n", name().toLatin1().constData(), dstChannels); + #endif + + // Nothing to zero or add... + + _efxPipe->apply(0, nframes, 0); // Track is off. Just process controls only, not audio (do not 'run'). + + for(i = 0; i < trackChans; ++i) { - // If we're using local buffers, we must zero them so that the next thing requiring them - // during this process cycle will see zeros. - /* - if(!usedirectbuf) + _meter[i] = 0.0; + /*if(!usedirectbuf) { if(MusEGlobal::config.useDenormalBias) { - for(unsigned int q = 0; q < nframes; ++q) + for(q = 0; q < nframes; ++q) outBuffers[i][q] = MusEGlobal::denormalBias; - } - else + } + else memset(outBuffers[i], 0, sizeof(float) * nframes); - } - */ - - //_meter[i] = 0; - _meter[i] = 0.0; - } - - _haveData = false; - _processed = true; + } */ + } return; } - - /* - // p3.3.41 Added. - unsigned int q; - for(i = 0; i < srcChans; ++i) + + // Point the input buffers at a temporary stack buffer. + for(i = 0; i < srcTotalOutChans; ++i) + buffer[i] = data + i * nframes; + + // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc. + // For ex. if this is an audio input, Jack will set the pointers for us. + if(!getData(pos, srcTotalOutChans, nframes, buffer)) { - if(MusEGlobal::config.useDenormalBias) - { - for(q = 0; q < nframes; ++q) + // No data was available. Track is not off. Zero the working buffers and continue on. + unsigned int q; + for(i = 0; i < srcTotalOutChans; ++i) + { + if(MusEGlobal::config.useDenormalBias) { - if(q & 1) - buffer[i][q] -= MusEGlobal::denormalBias; - else - buffer[i][q] += MusEGlobal::denormalBias; - } - } - } - */ - + for(q = 0; q < nframes; ++q) + buffer[i][q] = MusEGlobal::denormalBias; + } + else + memset(buffer[i], 0, sizeof(float) * nframes); + } + } + //--------------------------------------------------- // apply plugin chain //--------------------------------------------------- - // p3.3.41 //fprintf(stderr, "AudioTrack::addData %s efx apply srcChans:%d nframes:%ld %e %e %e %e\n", // name().toLatin1().constData(), srcChans, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); - _efxPipe->apply(srcChans, nframes, buffer); - // p3.3.41 + + _efxPipe->apply(trackChans, nframes, buffer); + //fprintf(stderr, "AudioTrack::addData after efx: %e %e %e %e\n", // buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); @@ -941,18 +927,16 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr if(_prefader) { - for(i = 0; i < srcChans; ++i) + for(i = 0; i < trackChans; ++i) { float* p = buffer[i]; meter[i] = 0.0; for(unsigned k = 0; k < nframes; ++k) { - double f = fabs(*p); + double f = fabs(*p++); if(f > meter[i]) meter[i] = f; - ++p; } - //_meter[i] = lrint(meter[i] * 32767.0); _meter[i] = meter[i]; if(_meter[i] > _peak[i]) _peak[i] = _meter[i]; @@ -962,8 +946,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr if(isMute()) { // If we're using local buffers, we must zero them. - /* - if(!usedirectbuf) + /* if(!usedirectbuf) { for(i = 0; i < srcChannels; ++i) { @@ -975,20 +958,19 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr else memset(outBuffers[i], 0, sizeof(float) * nframes); } - } - */ + } */ - _haveData = false; - _processed = true; + if(!_prefader) + //for(i = 0; i < srcChans; ++i) + for(i = 0; i < trackChans; ++i) + _meter[i] = 0.0; + return; } // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them. - if(!usedirectbuf) + //if(!usedirectbuf) { - //for(i = 0; i < srcChannels; ++i) - // AL::dsp->cpy(outBuffers[i], buffer[i], nframes); - // p3.3.38 for(i = 0; i < srcTotalOutChans; ++i) AL::dsp->cpy(outBuffers[i], buffer[i], nframes); } @@ -1011,9 +993,9 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr else memset(dstBuffer[i], 0, sizeof(float) * nframes); } - _processed = true; return; } + // Force a source range to fit actual available total out channels. if((srcStartChan + srcChans) > srcTotalOutChans) srcChans = srcTotalOutChans - srcStartChan; @@ -1023,123 +1005,88 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr // postfader metering //--------------------------------------------------- - if(srcChans == dstChannels) + #ifdef NODE_DEBUG + printf("MusE: AudioTrack::addData trackChans:%d srcTotalOutChans:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcChans, dstChannels); + #endif + + if(!_prefader) { - if(_prefader) + for(int c = 0; c < trackChans; ++c) { - for(int c = 0; c < dstChannels; ++c) + meter[c] = 0.0; + double v = (trackChans == 1 ? _volume : vol[c]); + float* sp = buffer[c]; + for(unsigned k = 0; k < nframes; ++k) { - // p3.3.38 - //float* sp = buffer[c]; - float* sp = buffer[c + srcStartChan]; - - float* dp = dstBuffer[c]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ += (*sp++ * vol[c]); + float val = *sp++ * v; // If the track is mono pan has no effect on meters. + double f = fabs(val); + if(f > meter[c]) + meter[c] = f; } - } - else + _meter[c] = meter[c]; + if(_meter[c] > _peak[c]) + _peak[c] = _meter[c]; + } + } + + if(srcChans == dstChannels) + { + for(int c = 0; c < dstChannels; ++c) { - for(int c = 0; c < dstChannels; ++c) - { - meter[c] = 0.0; - // p3.3.38 - //float* sp = buffer[c]; - float* sp = buffer[c + srcStartChan]; - - float* dp = dstBuffer[c]; - for(unsigned k = 0; k < nframes; ++k) - { - float val = *sp++ * vol[c]; - *dp++ += val; - double f = fabs(val); - if (f > meter[c]) - meter[c] = f; - } - //_meter[c] = lrint(meter[c] * 32767.0); - _meter[c] = meter[c]; - if(_meter[c] > _peak[c]) - _peak[c] = _meter[c]; - } + double v; + if(srcStartChan > 2) // Don't apply pan or volume to extra channels above 2. + //v = _volume; + v = 1.0; + else + if(srcChans >= 2) // If 2 channels apply pan normally. + v = vol[c]; + else + if(trackChans < 2) // If 1 channel and track is 1 channel, don't apply pan. + v = _volume; + else + v = vol[srcStartChan]; // Otherwise 1 channel but track is 2 channels. Apply the channel volume. + + float* sp = buffer[c + srcStartChan]; + float* dp = dstBuffer[c]; + for(unsigned k = 0; k < nframes; ++k) + //*dp++ += (*sp++ * vol[c]); + *dp++ += (*sp++ * v); } } else if(srcChans == 1 && dstChannels == 2) { - // p3.3.38 - float* sp = buffer[srcStartChan]; - - if(_prefader) + for(int c = 0; c < dstChannels; ++c) { - for(int c = 0; c < dstChannels; ++c) - { - float* dp = dstBuffer[c]; - //float* sp = buffer[0]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ += (*sp++ * vol[c]); - } - } - else - { - //float* sp = buffer[0]; - meter[0] = 0.0; - for(unsigned k = 0; k < nframes; ++k) - { - float val = *sp++; - double f = fabs(val) * _volume; - if(f > meter[0]) - meter[0] = f; - *(dstBuffer[0] + k) += val * vol[0]; - *(dstBuffer[1] + k) += val * vol[1]; - } - //_meter[0] = lrint(meter[0] * 32767.0); - _meter[0] = meter[0]; - if(_meter[0] > _peak[0]) - _peak[0] = _meter[0]; + double v; + if(srcStartChan > 2) // Don't apply pan or volume to extra channels above 2. + //v = _volume; + v = 1.0; + else + if(trackChans <= 1) // If track is mono apply pan. + v = vol[c]; + else + v = vol[srcStartChan]; // Otherwise track is stereo, apply the same channel volume to both. + + float* sp = buffer[srcStartChan]; + float* dp = dstBuffer[c]; + for(unsigned k = 0; k < nframes; ++k) + //*dp++ += (*sp++ * vol[c]); + *dp++ += (*sp++ * v); } } else if(srcChans == 2 && dstChannels == 1) { - // p3.3.38 - //float* sp1 = buffer[0]; - //float* sp2 = buffer[1]; + //double v1 = (srcStartChan > 2 ? _volume : vol[srcStartChan]); // Don't apply pan to extra channels above 2. + //double v2 = (srcStartChan > 2 ? _volume : vol[srcStartChan + 1]); // + double v1 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan]); // Don't apply pan or volume to extra channels above 2. + double v2 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan + 1]); // float* sp1 = buffer[srcStartChan]; float* sp2 = buffer[srcStartChan + 1]; - - if(_prefader) - { - float* dp = dstBuffer[0]; - for(unsigned k = 0; k < nframes; ++k) - *dp++ += (*sp1++ * vol[0] + *sp2++ * vol[1]); - } - else - { - float* dp = dstBuffer[0]; - meter[0] = 0.0; - meter[1] = 0.0; - for(unsigned k = 0; k < nframes; ++k) - { - float val1 = *sp1++ * vol[0]; - float val2 = *sp2++ * vol[1]; - double f1 = fabs(val1); - if(f1 > meter[0]) - meter[0] = f1; - double f2 = fabs(val2); - if(f2 > meter[1]) - meter[1] = f2; - *dp++ += (val1 + val2); - } - //_meter[0] = lrint(meter[0] * 32767.0); - _meter[0] = meter[0]; - if(_meter[0] > _peak[0]) - _peak[0] = _meter[0]; - //_meter[1] = lrint(meter[1] * 32767.0); - _meter[1] = meter[1]; - if(_meter[1] > _peak[1]) - _peak[1] = _meter[1]; - } + float* dp = dstBuffer[0]; + for(unsigned k = 0; k < nframes; ++k) + //*dp++ += (*sp1++ * vol[0] + *sp2++ * vol[1]); + *dp++ += (*sp1++ * v1 + *sp2++ * v2); } - - _processed = true; } //--------------------------------------------------------- @@ -1301,15 +1248,12 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b printf(" calling copyData on %s...\n", ir->track->name().toLatin1().constData()); #endif - // p3.3.38 - //((AudioTrack*)ir->track)->copyData(pos, channels, nframes, buffer); ((AudioTrack*)ir->track)->copyData(pos, channels, //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0, ir->channel, ir->channels, nframes, buffer); - // p3.3.41 //fprintf(stderr, "AudioTrack::getData %s data: nframes:%ld %e %e %e %e\n", name().toLatin1().constData(), nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); ++ir; @@ -1321,8 +1265,6 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b if(ir->track->isMidiTrack()) continue; - // p3.3.38 - //((AudioTrack*)ir->track)->addData(pos, channels, nframes, buffer); ((AudioTrack*)ir->track)->addData(pos, channels, //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0, ir->channel, @@ -1345,12 +1287,11 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe void* jackPort = jackPorts[ch]; //float* jackbuf = 0; - //if (jackPort) { - // p3.3.41 Do not get buffers of unconnected client ports. Causes repeating leftover data, can be loud, or DC ! + // Do not get buffers of unconnected client ports. Causes repeating leftover data, can be loud, or DC ! if (jackPort && MusEGlobal::audioDevice->connections(jackPort)) { //buffer[ch] = MusEGlobal::audioDevice->getBuffer(jackPort, nframes); - // p3.3.41 If the client port buffer is also used by another channel (connected to the same jack port), + // If the client port buffer is also used by another channel (connected to the same jack port), // don't directly set pointer, copy the data instead. // Otherwise the next channel will interfere - it will overwrite the buffer ! // Verified symptoms: Can't use a splitter. Mono noise source on a stereo track sounds in mono. Etc... @@ -1367,8 +1308,6 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe { for (unsigned int i=0; i < nframes; i++) buffer[ch][i] += MusEGlobal::denormalBias; - - // p3.3.41 //fprintf(stderr, "AudioInput::getData %s Jack port %p efx apply channels:%d nframes:%ld %e %e %e %e\n", // name().toLatin1().constData(), jackPort, channels, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); } @@ -1385,8 +1324,6 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe memset(buffer[ch], 0, nframes * sizeof(float)); } - // p3.3.41 - //fprintf(stderr, "AudioInput::getData %s No Jack port efx apply channels:%d nframes:%ld %e %e %e %e\n", // name().toLatin1().constData(), channels, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); } } @@ -1525,7 +1462,7 @@ void AudioTrack::record() return; } if (_recFile) { - // Line removed by Tim. p3.3.8 Oct 28, 2009 + // Line removed by Tim. Oct 28, 2009 //_recFile->seek(pos, 0); // // Fix for recorded waves being shifted ahead by an amount @@ -1571,7 +1508,6 @@ void AudioTrack::record() if( (pos >= fr) && (!MusEGlobal::song->punchout() || (!MusEGlobal::song->loop() && pos < MusEGlobal::song->rPos().frame())) ) { pos -= fr; - // Added by Tim. p3.3.8 //int position = _recFile->seek(0, SEEK_CUR); //printf("AudioTrack::record loopcnt:%d lframe:%d newpos:%d curpos:%d start:%d end:%d\n", MusEGlobal::audio->loopCount(), MusEGlobal::audio->loopFrame(), pos, position, MusEGlobal::audio->getStartRecordPos().frame(), MusEGlobal::audio->getEndRecordPos().frame()); @@ -1615,7 +1551,6 @@ void AudioOutput::processInit(unsigned nframes) void AudioOutput::process(unsigned pos, unsigned offset, unsigned n) { - //Added by Tim. p3.3.16 #ifdef NODE_DEBUG printf("MusE: AudioOutput::process name:%s processed:%d\n", name().toLatin1().constData(), processed()); #endif @@ -1623,9 +1558,6 @@ void AudioOutput::process(unsigned pos, unsigned offset, unsigned n) for (int i = 0; i < _channels; ++i) { buffer1[i] = buffer[i] + offset; } - - // p3.3.38 - //copyData(pos, _channels, n, buffer1); copyData(pos, _channels, -1, -1, n, buffer1); } @@ -1667,17 +1599,13 @@ void AudioOutput::processWrite() putFifo(_channels, _nframes, buffer); } } - // Changed by Tim. p3.3.18 + // Changed by Tim. //if (MusEGlobal::audioClickFlag && MusEGlobal::song->click()) { if (sendMetronome() && MusEGlobal::audioClickFlag && MusEGlobal::song->click()) { - // Added by Tim. p3.3.18 #ifdef METRONOME_DEBUG printf("MusE: AudioOutput::processWrite Calling metronome->addData frame:%u channels:%d frames:%lu\n", MusEGlobal::audio->pos().frame(), _channels, _nframes); #endif - - // p3.3.38 - //metronome->addData(MusEGlobal::audio->pos().frame(), _channels, _nframes, buffer); metronome->addData(MusEGlobal::audio->pos().frame(), _channels, -1, -1, _nframes, buffer); } } @@ -1722,7 +1650,6 @@ Fifo::~Fifo() { for (int i = 0; i < nbuffer; ++i) { - // p3.3.45 if(buffer[i]->buffer) { //printf("Fifo::~Fifo freeing buffer\n"); @@ -1743,7 +1670,6 @@ Fifo::~Fifo() bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos) { - // Added by Tim. p3.3.17 #ifdef FIFO_DEBUG printf("FIFO::put segs:%d samples:%lu pos:%u\n", segs, samples, pos); #endif @@ -1766,7 +1692,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos) // Changed by Tim. p3.3.15 //b->buffer = new float[n]; posix_memalign((void**)&(b->buffer), 16, sizeof(float) * n); - // p3.3.45 if(!b->buffer) { printf("Fifo::put could not allocate buffer segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1775,7 +1700,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos) b->maxSize = n; } - // p3.3.45 if(!b->buffer) { printf("Fifo::put no buffer! segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1799,7 +1723,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos) bool Fifo::get(int segs, unsigned long samples, float** dst, unsigned* pos) { - // Added by Tim. p3.3.17 #ifdef FIFO_DEBUG printf("FIFO::get segs:%d samples:%lu\n", segs, samples); #endif @@ -1809,7 +1732,6 @@ bool Fifo::get(int segs, unsigned long samples, float** dst, unsigned* pos) return true; } FifoBuffer* b = buffer[ridx]; - // p3.3.45 if(!b->buffer) { printf("Fifo::get no buffer! segs:%d samples:%lu b->pos:%u\n", segs, samples, b->pos); @@ -1845,7 +1767,6 @@ void Fifo::remove() bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned pos) { - // Added by Tim. p3.3.17 #ifdef FIFO_DEBUG printf("Fifo::getWriteBuffer segs:%d samples:%lu pos:%u\n", segs, samples, pos); #endif @@ -1867,7 +1788,6 @@ bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned // Changed by Tim. p3.3.15 //b->buffer = new float[n]; posix_memalign((void**)&(b->buffer), 16, sizeof(float) * n); - // p3.3.45 if(!b->buffer) { printf("Fifo::getWriteBuffer could not allocate buffer segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1876,8 +1796,6 @@ bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned b->maxSize = n; } - - // p3.3.45 if(!b->buffer) { printf("Fifo::getWriteBuffer no buffer! segs:%d samples:%lu pos:%u\n", segs, samples, pos); diff --git a/muse2/muse/osc.cpp b/muse2/muse/osc.cpp index bc64575a..7daeb9ff 100644 --- a/muse2/muse/osc.cpp +++ b/muse2/muse/osc.cpp @@ -824,7 +824,7 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin } QString oscUrl; - oscUrl = QString("%1%2/%3/%4").arg(QString(QT_TRANSLATE_NOOP("@default", url))).arg(typ).arg(baseName).arg(label); + oscUrl = QString("%1%2/%3/%4").arg(QString( url)).arg(typ).arg(baseName).arg(label); #ifdef _USE_QPROCESS_FOR_GUI_ @@ -841,7 +841,8 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin arguments << oscUrl << filePath << name - << QString("channel-1"); + //<< QString("channel-1"); + << (titlePrefix() + label); #ifdef OSC_DEBUG fprintf(stderr, "OscIF::oscInitGui starting QProcess\n"); @@ -885,7 +886,8 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin oscUrl.toLatin1().constData(), filePath.toLatin1().constData(), name.toLatin1().constData(), - "channel 1", (void*)0); + //"channel 1", (void*)0); + label.toLatin1().constData(), (void*)0); // Should not return after execlp. If so it's an error. fprintf(stderr, "exec %s %s %s %s %s failed: %s\n", @@ -941,13 +943,13 @@ void OscIF::oscShowGui(bool v) } //for (int i = 0; i < 5; ++i) { - for (int i = 0; i < 10; ++i) { // Give it a wee bit more time? + for (int i = 0; i < 20; ++i) { // Give it a wee bit more time? if (_uiOscPath) break; sleep(1); } if (_uiOscPath == 0) { - printf("OscIF::oscShowGui(): no _uiOscPath. Error: Timeout - synth gui did not start within 10 seconds.\n"); + printf("OscIF::oscShowGui(): no _uiOscPath. Error: Timeout - synth gui did not start within 20 seconds.\n"); return; } @@ -1087,14 +1089,18 @@ bool OscDssiIF::oscInitGui() if(!_oscSynthIF) return false; - return OscIF::oscInitGui(QT_TRANSLATE_NOOP("@default", "dssi_synth"), _oscSynthIF->dssiSynth()->baseName(), + return OscIF::oscInitGui("dssi_synth", _oscSynthIF->dssiSynth()->baseName(), _oscSynthIF->dssiSynth()->name(), _oscSynthIF->dssiSynthI()->name(), _oscSynthIF->dssiSynth()->fileName(), _oscSynthIF->dssi_ui_filename()); } + +QString OscDssiIF::titlePrefix() const +{ + return _oscSynthIF ? _oscSynthIF->titlePrefix() : QString(); +} #endif // DSSI_SUPPORT - //--------------------------------------------------------- // OscEffectIF:: // oscSetPluginI @@ -1160,11 +1166,16 @@ bool OscEffectIF::oscInitGui() if(!_oscPluginI) return false; - return OscIF::oscInitGui(QT_TRANSLATE_NOOP("@default", "ladspa_efx"), _oscPluginI->plugin()->lib(false), + return OscIF::oscInitGui("ladspa_efx", _oscPluginI->plugin()->lib(false), _oscPluginI->plugin()->label(), _oscPluginI->label(), _oscPluginI->plugin()->fileName(), _oscPluginI->dssi_ui_filename()); } +QString OscEffectIF::titlePrefix() const +{ + return _oscPluginI ? _oscPluginI->titlePrefix() : QString(); +} + #else //OSC_SUPPORT void initOSC() {} diff --git a/muse2/muse/osc.h b/muse2/muse/osc.h index 30df03cb..e3f1a26d 100644 --- a/muse2/muse/osc.h +++ b/muse2/muse/osc.h @@ -74,6 +74,8 @@ class OscIF virtual bool oscInitGui() { return false; } virtual void oscShowGui(bool); virtual bool oscGuiVisible() const; + + virtual QString titlePrefix() const { return QString(); } }; class OscEffectIF : public OscIF @@ -95,6 +97,8 @@ class OscEffectIF : public OscIF virtual int oscConfigure(lo_arg**); virtual bool oscInitGui(); + + virtual QString titlePrefix() const; }; #ifdef DSSI_SUPPORT @@ -117,6 +121,8 @@ class OscDssiIF : public OscIF virtual int oscConfigure(lo_arg**); virtual bool oscInitGui(); + + virtual QString titlePrefix() const; }; #endif // DSSI_SUPPORT diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index 6407dadc..33519e11 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -23,7 +23,6 @@ //========================================================= #include <stdio.h> -#include <assert.h> #include <cmath> #include "song.h" @@ -39,7 +38,7 @@ namespace MusECore { -int Part::snGen; +int Part::snGen=0; //--------------------------------------------------------- // unchainClone @@ -751,6 +750,18 @@ WavePart::WavePart(const WavePart& p) : Part(p) Part::~Part() { + if (_prevClone!=this || _nextClone!=this) + { + printf("THIS MIGHT BE A HINT FOR BUGS: Part isn't unchained in ~Part()! i'll do that now. this is\n" + "not an actual bug, actually that manual unchain should be unneccessary if this was coded\n" + "properly. but as it wasn't, and the unchain was always done manually, this might be an\n" + "indicator that it have been forgotten. either your computer will explode in 3..2..1..now,\n" + "or you can ignore this message.\n" + "\n"); + + unchainClone(this); + } + _events->incRef(-1); if (_events->refCount() <= 0) delete _events; @@ -805,7 +816,8 @@ void PartList::remove(Part* part) break; } } - assert(i != end()); + if (i == end()) + printf("THIS SHOULD NEVER HAPPEN: could not find the part in PartList::remove()!\n"); } //--------------------------------------------------------- diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 63e65f2e..227a9daf 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -1573,65 +1573,60 @@ bool Pipeline::nativeGuiVisible(int idx) //--------------------------------------------------------- // apply +// If ports is 0, just process controllers only, not audio (do not 'run'). //--------------------------------------------------------- -//void Pipeline::apply(int ports, unsigned long nframes, float** buffer1) void Pipeline::apply(unsigned long ports, unsigned long nframes, float** buffer1) { // prepare a second set of buffers in case a plugin is not // capable of inPlace processing - - // Removed by Tim. p3.3.15 //float* buffer2[ports]; //float data[nframes * ports]; //for (int i = 0; i < ports; ++i) // buffer2[i] = data + i * nframes; - // p3.3.41 - //fprintf(stderr, "Pipeline::apply data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]); + //fprintf(stderr, "Pipeline::apply data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]); bool swap = false; for (iPluginI ip = begin(); ip != end(); ++ip) { PluginI* p = *ip; - if (p && p->on()) { - if (p->inPlaceCapable()) - { - if (swap) - //p->connect(ports, buffer2, buffer2); - //p->connect(ports, buffer, buffer); - p->apply(nframes, ports, buffer, buffer); // p4.0.21 - else - //p->connect(ports, buffer1, buffer1); - p->apply(nframes, ports, buffer1, buffer1); // - } - else - { - if (swap) - //p->connect(ports, buffer2, buffer1); - //p->connect(ports, buffer, buffer1); - p->apply(nframes, ports, buffer, buffer1); // - else - //p->connect(ports, buffer1, buffer2); - //p->connect(ports, buffer1, buffer); - p->apply(nframes, ports, buffer1, buffer); // - swap = !swap; - } - //p->apply(nframes); // Rem. p4.0.21 - } + + if(p) + { + //if (p && p->on()) { + if (p->on()) + { + //fprintf(stderr, "Pipeline::apply PluginI:%p on:%d\n", p, p->on()); + if (p->inPlaceCapable()) + { + if (swap) + p->apply(nframes, ports, buffer, buffer); + else + p->apply(nframes, ports, buffer1, buffer1); + } + else + { + if (swap) + p->apply(nframes, ports, buffer, buffer1); + else + p->apply(nframes, ports, buffer1, buffer); + swap = !swap; + } + } + else + { + p->apply(nframes, 0, 0, 0); // Do not process (run) audio, process controllers only. + } } - if (swap) + } + if (ports != 0 && swap) { - //for (int i = 0; i < ports; ++i) - for (unsigned long i = 0; i < ports; ++i) // p4.0.21 + for (unsigned long i = 0; i < ports; ++i) //memcpy(buffer1[i], buffer2[i], sizeof(float) * nframes); //memcpy(buffer1[i], buffer[i], sizeof(float) * nframes); AL::dsp->cpy(buffer1[i], buffer[i], nframes); } - - // p3.3.41 - //fprintf(stderr, "Pipeline::apply after data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]); - } //--------------------------------------------------------- @@ -2439,6 +2434,7 @@ void PluginI::showGui() if (_plugin) { if (_gui == 0) makeGui(); + _gui->setWindowTitle(titlePrefix() + name()); if (_gui->isVisible()) _gui->hide(); else @@ -2558,7 +2554,17 @@ void PluginI::enable2AllControllers(bool v) } //--------------------------------------------------------- +// titlePrefix +//--------------------------------------------------------- + +QString PluginI::titlePrefix() const +{ + return _track->name() + QString(": "); +} + +//--------------------------------------------------------- // apply +// If ports is 0, just process controllers only, not audio (do not 'run'). //--------------------------------------------------------- /* @@ -2653,7 +2659,6 @@ void PluginI::apply(unsigned long n) */ #if 1 -// p4.0.21 void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut) { // Process control value changes. @@ -2769,7 +2774,6 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** //controls[v.idx].val = v.value; controls[v.idx].tmpVal = v.value; - /* // Need to update the automation value, otherwise it overwrites later with the last MusEGlobal::automation value. if(_track && _id != -1) { @@ -2795,7 +2799,6 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** // enableController(k, false); //_track->recordAutomation(id, v.value); } - */ } // Now update the actual values from the temporary values... @@ -2813,20 +2816,23 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** nsamp = n - sample; //printf("PluginI::apply ports:%lu n:%lu frame:%lu sample:%lu nsamp:%lu syncFrame:%lu loopcount:%d\n", - // ports, n, frame, sample, nsamp, syncFrame, loopcount); // REMOVE Tim. + // ports, n, frame, sample, nsamp, syncFrame, loopcount); // Don't allow zero-length runs. This could/should be checked in the control loop instead. // Note this means it is still possible to get stuck in the top loop (at least for a while). if(nsamp == 0) continue; - connect(ports, sample, bufIn, bufOut); + if(ports != 0) + { + connect(ports, sample, bufIn, bufOut); - for(int i = 0; i < instances; ++i) - { - //fprintf(stderr, "PluginI::apply handle %d\n", i); - _plugin->apply(handle[i], nsamp); - } + for(int i = 0; i < instances; ++i) + { + //fprintf(stderr, "PluginI::apply handle %d\n", i); + _plugin->apply(handle[i], nsamp); + } + } sample += nsamp; loopcount++; // REMOVE Tim. @@ -3444,7 +3450,8 @@ PluginGui::PluginGui(MusECore::PluginIBase* p) params = 0; paramsOut = 0; plugin = p; - setWindowTitle(plugin->name()); + //setWindowTitle(plugin->name()); + setWindowTitle(plugin->titlePrefix() + plugin->name()); QToolBar* tools = addToolBar(tr("File Buttons")); @@ -3546,7 +3553,7 @@ PluginGui::PluginGui(MusECore::PluginIBase* p) gw[nobj].param = parameter; gw[nobj].type = -1; - if (strcmp(obj->metaObject()->className(), "Slider") == 0) { + if (strcmp(obj->metaObject()->className(), "MusEGui::Slider") == 0) { gw[nobj].type = GuiWidgets::SLIDER; ((Slider*)obj)->setId(nobj); ((Slider*)obj)->setCursorHoming(true); @@ -3561,7 +3568,7 @@ PluginGui::PluginGui(MusECore::PluginIBase* p) connect(obj, SIGNAL(sliderReleased(int)), SLOT(guiSliderReleased(int))); connect(obj, SIGNAL(sliderRightClicked(const QPoint &, int)), SLOT(guiSliderRightClicked(const QPoint &, int))); } - else if (strcmp(obj->metaObject()->className(), "DoubleLabel") == 0) { + else if (strcmp(obj->metaObject()->className(), "MusEGui::DoubleLabel") == 0) { gw[nobj].type = GuiWidgets::DOUBLE_LABEL; ((DoubleLabel*)obj)->setId(nobj); //for(int i = 0; i < nobj; i++) @@ -4106,16 +4113,18 @@ void PluginGui::save() void PluginGui::bypassToggled(bool val) { + setWindowTitle(plugin->titlePrefix() + plugin->name()); plugin->setOn(val); MusEGlobal::song->update(SC_ROUTE); } //--------------------------------------------------------- -// songChanged +// setOn //--------------------------------------------------------- void PluginGui::setOn(bool val) { + setWindowTitle(plugin->titlePrefix() + plugin->name()); onOff->blockSignals(true); onOff->setChecked(val); onOff->blockSignals(false); @@ -4208,11 +4217,11 @@ void PluginGui::updateControls() } - if(!MusEGlobal::automation) - return; - AutomationType at = plugin->track()->automationType(); - if(at == AUTO_OFF) - return; + //if(!MusEGlobal::automation) + // return; + //AutomationType at = plugin->track()->automationType(); + //if(at == AUTO_OFF) + // return; if (params) { //for (int i = 0; i < plugin->parameters(); ++i) { for (unsigned long i = 0; i < plugin->parameters(); ++i) { // p4.0.21 @@ -4611,9 +4620,9 @@ void PluginGui::guiSliderRightClicked(const QPoint &p, int idx) //--------------------------------------------------------- QWidget* PluginLoader::createWidget(const QString & className, QWidget * parent, const QString & name) { - if(className == QString("DoubleLabel")) + if(className == QString("MusEGui::DoubleLabel")) return new DoubleLabel(parent, name.toLatin1().constData()); - if(className == QString("Slider")) + if(className == QString("MusEGui::Slider")) return new Slider(parent, name.toLatin1().constData(), Qt::Horizontal); return QUiLoader::createWidget(className, parent, name); diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h index 717f98b6..044fd863 100644 --- a/muse2/muse/plugin.h +++ b/muse2/muse/plugin.h @@ -72,18 +72,6 @@ class Xml; class MidiController; -/* -//--------------------------------------------------------- -// PluginBase -//--------------------------------------------------------- - -class PluginBase -{ - protected: - void range(unsigned long i, float*, float*) const; -}; -*/ - //--------------------------------------------------------- // Plugin //--------------------------------------------------------- @@ -155,13 +143,11 @@ class Plugin { if (plugin && plugin->cleanup) plugin->cleanup(handle); } - //void connectPort(LADSPA_Handle handle, int port, float* value) { - void connectPort(LADSPA_Handle handle, unsigned long port, float* value) { // p4.0.21 + void connectPort(LADSPA_Handle handle, unsigned long port, float* value) { if(plugin) plugin->connect_port(handle, port, value); } - //void apply(LADSPA_Handle handle, int n) { - void apply(LADSPA_Handle handle, unsigned long n) { // p4.0.21 + void apply(LADSPA_Handle handle, unsigned long n) { if(plugin) plugin->run(handle, n); } @@ -170,12 +156,10 @@ class Plugin { int oscConfigure(LADSPA_Handle /*handle*/, const char* /*key*/, const char* /*value*/); #endif - //int ports() { return plugin ? plugin->PortCount : 0; } unsigned long ports() { return _portCount; } LADSPA_PortDescriptor portd(unsigned long k) const { return plugin ? plugin->PortDescriptors[k] : 0; - //return _portDescriptors[k]; } LADSPA_PortRangeHint range(unsigned long i) { @@ -184,8 +168,7 @@ class Plugin { return plugin->PortRangeHints[i]; } - //double defaultValue(unsigned long port) const; - float defaultValue(unsigned long port) const; // p4.0.21 + float defaultValue(unsigned long port) const; void range(unsigned long i, float*, float*) const; CtrlValueType ctrlValueType(unsigned long /*i*/) const; CtrlList::Mode ctrlMode(unsigned long /*i*/) const; @@ -202,20 +185,6 @@ class Plugin { unsigned long controlInPorts() const { return _controlInPorts; } unsigned long controlOutPorts() const { return _controlOutPorts; } bool inPlaceCapable() const { return _inPlaceCapable; } - - /* - bool isLog(int k) const { - LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; - return LADSPA_IS_HINT_LOGARITHMIC(r.HintDescriptor); - } - bool isBool(int k) const { - return LADSPA_IS_HINT_TOGGLED(plugin->PortRangeHints[pIdx[k]].HintDescriptor); - } - bool isInt(int k) const { - LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; - return LADSPA_IS_HINT_INTEGER(r.HintDescriptor); - } - */ }; typedef std::list<Plugin>::iterator iPlugin; @@ -266,21 +235,18 @@ class PluginIBase ~PluginIBase(); virtual bool on() const = 0; virtual void setOn(bool /*val*/) = 0; - //virtual int pluginID() = 0; - virtual unsigned long pluginID() = 0; // p4.0.21 + virtual unsigned long pluginID() = 0; virtual int id() = 0; virtual QString pluginLabel() const = 0; virtual QString name() const = 0; virtual QString lib() const = 0; virtual QString dirPath() const = 0; virtual QString fileName() const = 0; + virtual QString titlePrefix() const = 0; virtual AudioTrack* track() = 0; - //virtual void enableController(int /*i*/, bool /*v*/ = true) = 0; - //virtual bool controllerEnabled(int /*i*/) const = 0; - //virtual bool controllerEnabled2(int /*i*/) const = 0; - virtual void enableController(unsigned long /*i*/, bool /*v*/ = true) = 0; // p4.0.21 + virtual void enableController(unsigned long /*i*/, bool /*v*/ = true) = 0; virtual bool controllerEnabled(unsigned long /*i*/) const = 0; virtual bool controllerEnabled2(unsigned long /*i*/) const = 0; virtual void updateControllers() = 0; @@ -288,12 +254,7 @@ class PluginIBase virtual void writeConfiguration(int /*level*/, Xml& /*xml*/) = 0; virtual bool readConfiguration(Xml& /*xml*/, bool /*readPreset*/=false) = 0; - //virtual int parameters() const = 0; - //virtual void setParam(int /*i*/, double /*val*/) = 0; - //virtual double param(int /*i*/) const = 0; - //virtual const char* paramName(int /*i*/) = 0; - //virtual LADSPA_PortRangeHint range(int /*i*/) = 0; - virtual unsigned long parameters() const = 0; // p4.0.21 + virtual unsigned long parameters() const = 0; virtual unsigned long parametersOut() const = 0; virtual void setParam(unsigned long /*i*/, float /*val*/) = 0; virtual float param(unsigned long /*i*/) const = 0; @@ -307,8 +268,6 @@ class PluginIBase virtual CtrlList::Mode ctrlMode(unsigned long /*i*/) const = 0; QString dssi_ui_filename() const; - //virtual void showGui(bool) = 0; // p4.0.20 - //virtual void showNativeGui(bool) = 0; // MusEGui::PluginGui* gui() const { return _gui; } void deleteGui(); }; @@ -353,7 +312,6 @@ class PluginBase #define AUDIO_IN (LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT) #define AUDIO_OUT (LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT) -//class PluginI { class PluginI : public PluginIBase { Plugin* _plugin; int channel; @@ -365,10 +323,8 @@ class PluginI : public PluginIBase { Port* controls; Port* controlsOut; - //int controlPorts; - //int controlOutPorts; - unsigned long controlPorts; // p4.0.21 - unsigned long controlOutPorts; // + unsigned long controlPorts; + unsigned long controlOutPorts; ///PluginGui* _gui; bool _on; @@ -400,26 +356,17 @@ class PluginI : public PluginIBase { void setTrack(AudioTrack* t) { _track = t; } AudioTrack* track() { return _track; } - //int pluginID() { return _plugin->id(); } - unsigned long pluginID() { return _plugin->id(); } // p4.0.21 + unsigned long pluginID() { return _plugin->id(); } void setID(int i); int id() { return _id; } void updateControllers(); bool initPluginInstance(Plugin*, int channels); void setChannels(int); - //void connect(int ports, float** src, float** dst); - //void apply(int n); - //void connect(unsigned ports, float** src, float** dst); - //void apply(unsigned n); - void connect(unsigned long ports, unsigned long offset, float** src, float** dst); // p4.0.21 - void apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut); // - - //void enableController(int i, bool v = true) { controls[i].enCtrl = v; } - //bool controllerEnabled(int i) const { return controls[i].enCtrl; } - //void enable2Controller(int i, bool v = true) { controls[i].en2Ctrl = v; } - //bool controllerEnabled2(int i) const { return controls[i].en2Ctrl; } - void enableController(unsigned long i, bool v = true) { controls[i].enCtrl = v; } // p4.0.21 + void connect(unsigned long ports, unsigned long offset, float** src, float** dst); + void apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut); + + void enableController(unsigned long i, bool v = true) { controls[i].enCtrl = v; } bool controllerEnabled(unsigned long i) const { return controls[i].enCtrl; } void enable2Controller(unsigned long i, bool v = true) { controls[i].en2Ctrl = v; } bool controllerEnabled2(unsigned long i) const { return controls[i].en2Ctrl; } @@ -434,6 +381,7 @@ class PluginI : public PluginIBase { QString lib() const { return _plugin->lib(); } QString dirPath() const { return _plugin->dirPath(); } QString fileName() const { return _plugin->fileName(); } + QString titlePrefix() const; #ifdef OSC_SUPPORT OscEffectIF& oscIF() { return _oscif; } @@ -453,8 +401,7 @@ class PluginI : public PluginIBase { void writeConfiguration(int level, Xml& xml); bool readConfiguration(Xml& xml, bool readPreset=false); bool loadControl(Xml& xml); - //bool setControl(const QString& s, double val); - bool setControl(const QString& s, float val); // p4.0.21 + bool setControl(const QString& s, float val); void showGui(); void showGui(bool); bool isDssiPlugin() const { return _plugin->isDssiPlugin(); } @@ -464,20 +411,8 @@ class PluginI : public PluginIBase { bool guiVisible(); bool nativeGuiVisible(); - //int parameters() const { return controlPorts; } - //void setParam(int i, double val) { controls[i].tmpVal = val; } - //double param(int i) const { return controls[i].val; } - //double defaultValue(unsigned int param) const; - //const char* paramName(int i) { return _plugin->portName(controls[i].idx); } - //LADSPA_PortDescriptor portd(int i) const { return _plugin->portd(controls[i].idx); } - //void range(int i, float* min, float* max) const { _plugin->range(controls[i].idx, min, max); } - //bool isAudioIn(int k) { return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN; } - //bool isAudioOut(int k) { return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT; } - //LADSPA_PortRangeHint range(int i) { return _plugin->range(controls[i].idx); } - // p4.0.21 unsigned long parameters() const { return controlPorts; } unsigned long parametersOut() const { return controlOutPorts; } - //void setParam(unsigned i, float val) { controls[i].tmpVal = val; } void setParam(unsigned long i, float val); float param(unsigned long i) const { return controls[i].val; } float paramOut(unsigned long i) const { return controlsOut[i].val; } @@ -500,8 +435,6 @@ class PluginI : public PluginIBase { // chain of connected efx inserts //--------------------------------------------------------- -//const int PipelineDepth = 4; // Moved to globaldefs.h - class Pipeline : public std::vector<PluginI*> { float* buffer[MAX_CHANNELS]; @@ -525,8 +458,7 @@ class Pipeline : public std::vector<PluginI*> { void deleteAllGuis(); bool guiVisible(int); bool nativeGuiVisible(int); - //void apply(int ports, unsigned long nframes, float** buffer); - void apply(unsigned long ports, unsigned long nframes, float** buffer); // p4.0.21 + void apply(unsigned long ports, unsigned long nframes, float** buffer); void move(int idx, bool up); bool empty(int idx) const; void setChannels(int); @@ -537,11 +469,6 @@ typedef Pipeline::const_iterator ciPluginI; extern void initPlugins(); -//extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val); -//extern void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max); -//extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def); -//extern float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val); -// p4.0.21 extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, unsigned long port, float* val); extern void ladspaControlRange(const LADSPA_Descriptor* plugin, unsigned long port, float* min, float* max); extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, unsigned long port, int ctlnum, int* min, int* max, int* def); @@ -593,8 +520,7 @@ struct GuiWidgets { }; QWidget* widget; int type; - //int param; - unsigned long param; // p4.0.21 + unsigned long param; }; //--------------------------------------------------------- @@ -604,13 +530,11 @@ struct GuiWidgets { class PluginGui : public QMainWindow { Q_OBJECT - //PluginI* plugin; // plugin instance MusECore::PluginIBase* plugin; // plugin instance GuiParam* params; GuiParam* paramsOut; - //int nobj; - unsigned long nobj; // number of widgets in gw // p4.0.21 + unsigned long nobj; // number of widgets in gw GuiWidgets* gw; QAction* onOff; @@ -640,7 +564,6 @@ class PluginGui : public QMainWindow { void heartBeat(); public: - //PluginGui(MusECore::PluginI*); PluginGui(MusECore::PluginIBase*); ~PluginGui(); diff --git a/muse2/muse/remote/pyapi.cpp b/muse2/muse/remote/pyapi.cpp index 57b956ca..90818a44 100644 --- a/muse2/muse/remote/pyapi.cpp +++ b/muse2/muse/remote/pyapi.cpp @@ -1131,7 +1131,9 @@ bool Song::event(QEvent* _e) break; } case QPybridgeEvent::SONG_ADD_TRACK: - MusEGlobal::song->addTrack((Track::TrackType)e->getP1()); // Add at end of list. + MusECore::Undo operations; + MusEGlobal::song->addTrack(operations, (Track::TrackType)e->getP1()); // Add at end of list. + MusEGlobal::song->applyOperationGroup(operations); break; case QPybridgeEvent::SONG_CHANGE_TRACKNAME: { Track* t = this->findTrack(e->getS1()); diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp index f00c6d6c..1d494fb0 100644 --- a/muse2/muse/route.cpp +++ b/muse2/muse/route.cpp @@ -4,6 +4,7 @@ // $Id: route.cpp,v 1.18.2.3 2008/05/21 00:28:52 terminator356 Exp $ // // (C) Copyright 2003-2004 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -37,8 +38,6 @@ //#define ROUTE_DEBUG -//#define ROUTE_MIDIPORT_NAME_PREFIX "MusE MidiPort " - namespace MusECore { const QString ROUTE_MIDIPORT_NAME_PREFIX = "MusE MidiPort "; @@ -57,9 +56,7 @@ Route::Route(void* t, int ch) type = JACK_ROUTE; } -//Route::Route(AudioTrack* t, int ch) Route::Route(Track* t, int ch, int chans) -//Route::Route(Track* t, int ch) { track = t; midiPort = -1; @@ -69,7 +66,6 @@ Route::Route(Track* t, int ch, int chans) type = TRACK_ROUTE; } -//Route::Route(MidiJackDevice* d) Route::Route(MidiDevice* d, int ch) { device = d; @@ -77,19 +73,10 @@ Route::Route(MidiDevice* d, int ch) channel = ch; channels = -1; remoteChannel = -1; - /* - //if(dynamic_cast<MidiJackDevice*>(d)) - if(d->deviceType() == MidiDevice::JACK_MIDI) - type = JACK_MIDI_ROUTE; - else - //if(dynamic_cast<MidiAlsaDevice*>(d)) - if(d->deviceType() == MidiDevice::ALSA_MIDI) - type = ALSA_MIDI_ROUTE; - */ type = MIDI_DEVICE_ROUTE; } -Route::Route(int port, int ch) // p3.3.49 +Route::Route(int port, int ch) { track = 0; midiPort = port; @@ -99,16 +86,12 @@ Route::Route(int port, int ch) // p3.3.49 type = MIDI_PORT_ROUTE; } -//Route::Route(const QString& s, bool dst, int ch) Route::Route(const QString& s, bool dst, int ch, int rtype) { - //Route node(name2route(s, dst)); Route node(name2route(s, dst, rtype)); channel = node.channel; if(channel == -1) channel = ch; - //if(channels == -1) - // channels = chans; channels = node.channels; remoteChannel = node.remoteChannel; type = node.type; @@ -123,14 +106,6 @@ Route::Route(const QString& s, bool dst, int ch, int rtype) jackPort = node.jackPort; midiPort = -1; } - /* - else - if (type == JACK_MIDI_ROUTE) - device = node.device; - else - if (type == ALSA_MIDI_ROUTE) - device = node.device; - */ else if(type == MIDI_DEVICE_ROUTE) { @@ -138,10 +113,10 @@ Route::Route(const QString& s, bool dst, int ch, int rtype) midiPort = -1; } else - if(type == MIDI_PORT_ROUTE) // p3.3.49 + if(type == MIDI_PORT_ROUTE) { track = 0; - midiPort = node.midiPort; // + midiPort = node.midiPort; } } @@ -179,31 +154,20 @@ void addRoute(Route src, Route dst) // dst.type, dst.channel, dst.name().toLatin1().constData()); if (src.type == Route::JACK_ROUTE) { - //if (dst.type != TRACK_ROUTE) - //{ - // fprintf(stderr, "addRoute: bad route 1\n"); - // exit(-1); - // return; - //} - if (dst.type == Route::TRACK_ROUTE) { if (dst.track->type() != Track::AUDIO_INPUT) { fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().toLatin1().constData()); - //exit(-1); return; } if (dst.channel < 0) { fprintf(stderr, "addRoute: source is jack, dest:%s is track but invalid channel:%d\n", dst.track->name().toLatin1().constData(), dst.channel); - //exit(-1); return; } - //src.channel = src.dstChannel = dst.channel; src.channel = dst.channel; - //src.channels = dst.channels = 1; RouteList* inRoutes = dst.track->inRoutes(); for (ciRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { @@ -221,28 +185,11 @@ void addRoute(Route src, Route dst) inRoutes->push_back(src); } else - //if (dst.type == Route::JACK_MIDI_ROUTE) if (dst.type == Route::MIDI_DEVICE_ROUTE) - //if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 { - //MidiDevice *md = MusEGlobal::midiPorts[dst.midiPort].device(); - //if(dst.device->deviceType() == MidiDevice::JACK_MIDI) - //if(!md) - //{ - // fprintf(stderr, "addRoute: source is Jack, but no destination port device\n"); - // return; - //} - if(dst.device->deviceType() == MidiDevice::JACK_MIDI) - //if(md->deviceType() == MidiDevice::JACK_MIDI) { src.channel = dst.channel; - //src.channel = -1; - //src.channel = 0; - //src.channel = src.dstChannel = dst.channel; - //src.channels = dst.channels = 1; - //dst.channel = -1; - RouteList* routes = dst.device->inRoutes(); for (ciRoute i = routes->begin(); i != routes->end(); ++i) { @@ -262,45 +209,32 @@ void addRoute(Route src, Route dst) else { fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType()); - // exit(-1); return; } } else { fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type); - // exit(-1); return; } } else if (dst.type == Route::JACK_ROUTE) { - //if (src.type != TRACK_ROUTE) - //{ - // fprintf(stderr, "addRoute: bad route 3\n"); - // exit(-1); - // return; - //} - if (src.type == Route::TRACK_ROUTE) { if (src.track->type() != Track::AUDIO_OUTPUT) { fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n"); - // exit(-1); return; } if (src.channel < 0) { fprintf(stderr, "addRoute: destination is jack, source:%s is track but invalid channel:%d\n", src.track->name().toLatin1().constData(), src.channel); - // exit(-1); return; } RouteList* outRoutes = src.track->outRoutes(); - //dst.channel = dst.dstChannel = src.channel; dst.channel = src.channel; - //dst.channels = src.channels = 1; for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { @@ -318,17 +252,11 @@ void addRoute(Route src, Route dst) outRoutes->push_back(dst); } else - //if (src.type == Route::JACK_MIDI_ROUTE) if (src.type == Route::MIDI_DEVICE_ROUTE) { if(src.device->deviceType() == MidiDevice::JACK_MIDI) { dst.channel = src.channel; - //dst.channel = -1; - //src.channel = -1; - //dst.channel = dst.dstChannel = src.channel; - //dst.channels = src.channels = 1; - RouteList* routes = src.device->outRoutes(); for (ciRoute i = routes->begin(); i != routes->end(); ++i) { @@ -348,18 +276,16 @@ void addRoute(Route src, Route dst) else { fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType()); - // exit(-1); return; } } else { fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type); - // exit(-1); return; } } - else if(src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + else if(src.type == Route::MIDI_PORT_ROUTE) { if(dst.type != Route::TRACK_ROUTE) { @@ -367,66 +293,18 @@ void addRoute(Route src, Route dst) return; } - // p4.0.14 - /* - if(dst.track->type() == Track::AUDIO_INPUT) - { - if(src.channel < 1 || src.channel >= (1 << MIDI_CHANNELS)) - { - fprintf(stderr, "addRoute: source is midi port:%d, but channel mask:%d out of range\n", src.midiPort, src.channel); - return; - } - - MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort]; - //src.channel = dst.channel = -1; - RouteList* outRoutes = mp->outRoutes(); - iRoute ir = outRoutes->begin(); - for ( ; ir != outRoutes->end(); ++ir) - { - //if (*i == dst) // route already there - ir->dump(); - if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // Does a route to the track exist? - { - //#ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s out route already exists. ir->channel:%d |= dst.channel:%d\n", - src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, dst.channel); - //#endif - ir->channel |= dst.channel; // Bitwise OR the desired channel bit with the existing bit mask. - break; - //return; - } - } - if(ir == outRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. - outRoutes->push_back(dst); - - RouteList* inRoutes = dst.track->inRoutes(); - - ir = inRoutes->begin(); - for ( ; ir != inRoutes->end(); ++ir) - { - if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // Does a route to the midi port exist? - { - fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s in route already exists. ir->channel:%d |= src.channel:%d\n", - src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, src.channel); - ir->channel |= src.channel; // Bitwise OR the desired channel bit with the existing bit mask. - break; - } - } - if(ir == inRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. - inRoutes->push_back(src); - - return; - } - */ - MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort]; - // p4.0.17 Do not allow ports with synth midi devices to connect to audio ins! - if(dst.track->type() == Track::AUDIO_INPUT && mp->device() && mp->device()->isSynti()) - { - fprintf(stderr, "addRoute: destination is audio in, but source midi port:%d is synth device\n", src.midiPort); + // Do not allow ports with synth midi devices to connect to audio ins! p4.0.17 + //if(dst.track->type() == Track::AUDIO_INPUT && mp->device() && mp->device()->isSynti()) + //{ + // fprintf(stderr, "addRoute: destination is audio in, but source midi port:%d is synth device\n", src.midiPort); + // return; + //} + // Actually, do not allow synth ports to connect to any track. It may be useful in some cases, + // may be desired later, but for now it's just a routing hassle. p4.0.35 + if(mp->device() && mp->device()->isSynti()) return; - } if(dst.channel < 1 || dst.channel >= (1 << MIDI_CHANNELS)) { @@ -443,46 +321,39 @@ void addRoute(Route src, Route dst) src.channel = dst.channel; RouteList* outRoutes = mp->outRoutes(); - //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - iRoute ir = outRoutes->begin(); // p3.3.50 + iRoute ir = outRoutes->begin(); for ( ; ir != outRoutes->end(); ++ir) { - //if (*i == dst) // route already there - if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // p3.3.50 Does a route to the track exist? + if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // Does a route to the track exist? { - //#ifdef ROUTE_DEBUG - //fprintf(stderr, "addRoute: src midi port:%d dst track:%s route already exists.\n", src.midiPort, dst.track->name().toLatin1().constData()); - //#endif - ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + ir->channel |= dst.channel; // Bitwise OR the desired channel bit with the existing bit mask. break; - - //return; } } #ifdef ROUTE_DEBUG fprintf(stderr, "addRoute: src midi port:%d dst track name:%s pushing dst and src routes\n", src.midiPort, dst.track->name().toLatin1().constData()); #endif - if(ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + if(ir == outRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. outRoutes->push_back(dst); RouteList* inRoutes = dst.track->inRoutes(); - // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. + // Make sure only one single route, with a channel mask, can ever exist. ir = inRoutes->begin(); for ( ; ir != inRoutes->end(); ++ir) { - if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // p3.3.50 Does a route to the midi port exist? + if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // Does a route to the midi port exist? { - ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + ir->channel |= src.channel; // Bitwise OR the desired channel bit with the existing bit mask. break; } } - if(ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + if(ir == inRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. inRoutes->push_back(src); } - else if(dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + else if(dst.type == Route::MIDI_PORT_ROUTE) { if(src.type != Route::TRACK_ROUTE) { @@ -495,7 +366,6 @@ void addRoute(Route src, Route dst) return; } - //MidiDevice *md = MusEGlobal::midiPorts[dst.midiPort].device(); //if(!md) //{ @@ -506,24 +376,17 @@ void addRoute(Route src, Route dst) dst.channel = src.channel; RouteList* outRoutes = src.track->outRoutes(); - //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - iRoute ir = outRoutes->begin(); // p3.3.50 + iRoute ir = outRoutes->begin(); for ( ; ir != outRoutes->end(); ++ir) { - //if (*i == dst) // route already there - if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort) // p3.3.50 Does a route to the midi port exist? + if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort) // Does a route to the midi port exist? { - //#ifdef ROUTE_DEBUG - //fprintf(stderr, "addRoute: dst midi port:%d src track:%s route already exists.\n", dst.midiPort, src.track->name().toLatin1().constData()); - //#endif - //return; - - ir->channel |= dst.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + ir->channel |= dst.channel; // Bitwise OR the desired channel bit with the existing bit mask. break; } } - if(ir == outRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + if(ir == outRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. outRoutes->push_back(dst); MidiPort *mp = &MusEGlobal::midiPorts[dst.midiPort]; @@ -533,167 +396,97 @@ void addRoute(Route src, Route dst) #endif RouteList* inRoutes = mp->inRoutes(); - // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. + // Make sure only one single route, with a channel mask, can ever exist. ir = inRoutes->begin(); for ( ; ir != inRoutes->end(); ++ir) { - if (ir->type == Route::TRACK_ROUTE && ir->track == src.track) // p3.3.50 Does a route to the track exist? + if (ir->type == Route::TRACK_ROUTE && ir->track == src.track) // Does a route to the track exist? { - ir->channel |= src.channel; // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. + ir->channel |= src.channel; // Bitwise OR the desired channel bit with the existing bit mask. break; } } - if(ir == inRoutes->end()) // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with. + if(ir == inRoutes->end()) // Only if route not found, add the route, with the requested channel bits as mask to start with. inRoutes->push_back(src); - //inRoutes->insert(inRoutes->begin(), src); } else { - if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 + if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) { fprintf(stderr, "addRoute: source or destination are not track routes\n"); return; } - // Removed p3.3.49 - /* - //if ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) - if(src.type == Route::MIDI_DEVICE_ROUTE) - { - //src.channel = src.dstChannel = dst.dstChannel = dst.channel; - src.channel = dst.channel; - //src.channels = dst.channels = 1; - RouteList* outRoutes = src.device->outRoutes(); - #ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src name: %s looking for existing dest in out routes...\n", src.device->name().toLatin1().constData()); - #endif - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - { - if (*i == dst) // route already there - { - //#ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src Jack or ALSA midi route already exists.\n"); - //#endif - return; - } - } - #ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src midi dst name: %s pushing destination and source routes\n", dst.track->name().toLatin1().constData()); - #endif - - outRoutes->push_back(dst); - RouteList* inRoutes = dst.track->inRoutes(); - inRoutes->push_back(src); - } - else - */ + RouteList* outRoutes = src.track->outRoutes(); - { - ///if(dst.type == Route::MIDI_DEVICE_ROUTE) // Removed p3.3.49 - //{ - /// dst.channel = src.channel; - //src.channel = src.dstChannel = dst.dstChannel = dst.channel; - //src.channels = dst.channels = 1; - //} - //else - //{ - //src.channel = src.dstChannel = dst.dstChannel = dst.channel; - //src.channels = dst.channels = 1; - //} - - RouteList* outRoutes = src.track->outRoutes(); - - // - // Must enforce to ensure channel and channels are valid if defaults of -1 passed. - // - if(src.track->type() == Track::AUDIO_SOFTSYNTH) - { - if(src.channel == -1) - src.channel = 0; - if(src.channels == -1) - src.channels = src.track->channels(); - //if(dst.type == Route::TRACK_ROUTE) // p3.3.49 Removed - //{ - //if(dst.channel == -1) - // dst.channel = 0; - //if(dst.channels == -1) - // Yes, that's correct: dst channels = src track channels. - // dst.channels = src.track->channels(); - dst.channel = src.channel; - dst.channels = src.channels; - dst.remoteChannel = src.remoteChannel; - //} - } - //if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH) - //{ - // if(dst.channel == -1) - // dst.channel = 0; - // if(dst.channels == -1) - // Yes, that's correct: dst channels = src track channels. - // dst.channels = src.track->channels(); - //} - - for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - { - if (*i == dst) // route already there - // TODO: - //if (i->type == dst.type && i->channel == dst.channel) + // + // Must enforce to ensure channel and channels are valid if defaults of -1 passed. + // + if(src.track->type() == Track::AUDIO_SOFTSYNTH) + { + if(src.channel == -1) + src.channel = 0; + if(src.channels == -1) + src.channels = src.track->channels(); + dst.channel = src.channel; + dst.channels = src.channels; + dst.remoteChannel = src.remoteChannel; + } + + for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) + { + if (*i == dst) // route already there + // TODO: + //if (i->type == dst.type && i->channel == dst.channel) + { + //if(i->type == Route::TRACK_ROUTE) + { + //if(i->track == dst.track) { - //if(i->type == Route::TRACK_ROUTE) + //if(i->channels == dst.channels) { - //if(i->track == dst.track) - { - //if(i->channels == dst.channels) - { - //#ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src track route already exists.\n"); - //#endif - return; - } - //else - //{ - - //} - } + //#ifdef ROUTE_DEBUG + fprintf(stderr, "addRoute: src track route already exists.\n"); + //#endif + return; } - } - } - outRoutes->push_back(dst); - RouteList* inRoutes; - - // Removed p3.3.49 - /* - //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) - if(dst.type == Route::MIDI_DEVICE_ROUTE) - { - #ifdef ROUTE_DEBUG - fprintf(stderr, "addRoute: src track dst midi name: %s pushing destination and source routes\n", dst.device->name().toLatin1().constData()); - #endif - inRoutes = dst.device->inRoutes(); - } - else - */ - - { - #ifdef ROUTE_DEBUG - //fprintf(stderr, "addRoute: src track ch:%d chs:%d dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().toLatin1().constData()); - fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n", - src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData()); - //fprintf(stderr, "addRoute: src track ch:%d dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().toLatin1().constData()); - #endif - inRoutes = dst.track->inRoutes(); - } - - - // - // make sure AUDIO_AUX is processed last - // - if (src.track->type() == Track::AUDIO_AUX) - inRoutes->push_back(src); - else - inRoutes->insert(inRoutes->begin(), src); - } + //else + //{ + + //} + } + } + } + } + outRoutes->push_back(dst); + RouteList* inRoutes; + + #ifdef ROUTE_DEBUG + //fprintf(stderr, "addRoute: src track ch:%d chs:%d dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().toLatin1().constData()); + fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n", + src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData()); + //fprintf(stderr, "addRoute: src track ch:%d dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().toLatin1().constData()); + #endif + inRoutes = dst.track->inRoutes(); + + // + // make sure AUDIO_AUX is processed last + // + if (src.track->type() == Track::AUDIO_AUX) // REMOVE Tim. This special aux code may not be useful or needed now. + inRoutes->push_back(src); // + else + inRoutes->insert(inRoutes->begin(), src); + + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update the destination track's aux ref count, and all tracks it is routed to. + if(src.track->auxRefCount()) + //dst.track->updateAuxStates( src.track->auxRefCount() ); + src.track->updateAuxRoute( src.track->auxRefCount(), dst.track ); + else + if(src.track->type() == Track::AUDIO_AUX) + //dst.track->updateAuxStates( 1 ); + src.track->updateAuxRoute( 1, dst.track ); } } @@ -709,12 +502,6 @@ void removeRoute(Route src, Route dst) if (src.type == Route::JACK_ROUTE) { - //if (dst.type != TRACK_ROUTE) - //{ - // fprintf(stderr, "removeRoute: bad route 1\n"); - // exit(-1); - // return; - //} if(!dst.isValid()) { printf("removeRoute: source is jack, invalid destination\n"); @@ -726,7 +513,6 @@ void removeRoute(Route src, Route dst) if (dst.track->type() != Track::AUDIO_INPUT) { fprintf(stderr, "removeRoute: source is jack, destination is track but not audio input\n"); - // exit(-1); return; } RouteList* inRoutes = dst.track->inRoutes(); @@ -741,7 +527,6 @@ void removeRoute(Route src, Route dst) } } else - //if (dst.type == Route::JACK_MIDI_ROUTE) if (dst.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = dst.device->inRoutes(); @@ -758,18 +543,11 @@ void removeRoute(Route src, Route dst) else { fprintf(stderr, "removeRoute: source is jack, destination unknown\n"); - // exit(-1); return; } } else if (dst.type == Route::JACK_ROUTE) { - //if (src.type != TRACK_ROUTE) - //{ - // fprintf(stderr, "removeRoute: bad route 3\n"); - // exit(-1); - // return; - //} if(!src.isValid()) { printf("removeRoute: destination is jack, invalid source\n"); @@ -781,7 +559,6 @@ void removeRoute(Route src, Route dst) if (src.track->type() != Track::AUDIO_OUTPUT) { fprintf(stderr, "removeRoute: destination is jack, source is track but not audio output\n"); - // exit(-1); return; } RouteList* outRoutes = src.track->outRoutes(); @@ -795,7 +572,6 @@ void removeRoute(Route src, Route dst) } } else - //if (src.type == Route::JACK_MIDI_ROUTE) if (src.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = src.device->outRoutes(); @@ -811,11 +587,10 @@ void removeRoute(Route src, Route dst) else { fprintf(stderr, "removeRoute: destination is jack, source unknown\n"); - // exit(-1); return; } } - else if(src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + else if(src.type == Route::MIDI_PORT_ROUTE) { if(dst.type != Route::TRACK_ROUTE) { @@ -829,19 +604,18 @@ void removeRoute(Route src, Route dst) RouteList* outRoutes = mp->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { - //if (*i == dst) - if(i->type == Route::TRACK_ROUTE && i->track == dst.track) // p3.3.50 Is there a route to the track? + if(i->type == Route::TRACK_ROUTE && i->track == dst.track) // Is there a route to the track? { //printf("i->channel:%x dst.channel:%x\n", i->channel, dst.channel); - i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. + i->channel &= ~dst.channel; // Unset the desired channel bits. if(i->channel == 0) // Only if there are no channel bits set, erase the route. { //printf("erasing out route from midi port:%d\n", src.midiPort); outRoutes->erase(i); } - break; // For safety, keep looking and remove any more found. - // No, must break, else crash. There should only be one route anyway... + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... } } } @@ -853,22 +627,21 @@ void removeRoute(Route src, Route dst) RouteList* inRoutes = dst.track->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { - //if (*i == src) - if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort) // p3.3.50 Is there a route to the midi port? + if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort) // Is there a route to the midi port? { - i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. + i->channel &= ~src.channel; // Unset the desired channel bits. if(i->channel == 0) // Only if there are no channel bits set, erase the route. inRoutes->erase(i); - break; // For safety, keep looking and remove any more found. - // No, must break, else crash. There should only be one route anyway... + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... } } } else printf("removeRoute: source is midi port:%d but destination track invalid\n", src.midiPort); } - else if(dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + else if(dst.type == Route::MIDI_PORT_ROUTE) { if(src.type != Route::TRACK_ROUTE) { @@ -881,15 +654,14 @@ void removeRoute(Route src, Route dst) RouteList* outRoutes = src.track->outRoutes(); for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { - //if (*i == dst) - if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort) // p3.3.50 Is there a route to the midi port? + if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort) // Is there a route to the midi port? { - i->channel &= ~dst.channel; // p3.3.50 Unset the desired channel bits. + i->channel &= ~dst.channel; // Unset the desired channel bits. if(i->channel == 0) // Only if there are no channel bits set, erase the route. outRoutes->erase(i); - break; // For safety, keep looking and remove any more found. - // No, must break, else crash. There should only be one route anyway... + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... } } } @@ -902,15 +674,14 @@ void removeRoute(Route src, Route dst) RouteList* inRoutes = mp->inRoutes(); for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { - //if (*i == src) - if (i->type == Route::TRACK_ROUTE && i->track == src.track) // p3.3.50 Is there a route to the track? + if (i->type == Route::TRACK_ROUTE && i->track == src.track) // Is there a route to the track? { - i->channel &= ~src.channel; // p3.3.50 Unset the desired channel bits. + i->channel &= ~src.channel; // Unset the desired channel bits. if(i->channel == 0) // Only if there are no channel bits set, erase the route. inRoutes->erase(i); - break; // For safety, keep looking and remove any more found. - // No, must break, else crash. There should only be one route anyway... + break; // For safety, keep looking and remove any more found. + // No, must break, else crash. There should only be one route anyway... } } } @@ -919,87 +690,54 @@ void removeRoute(Route src, Route dst) } else { - if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) // p3.3.49 + if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE) { fprintf(stderr, "removeRoute: source and destination are not tracks\n"); return; } - // Removed p3.3.49 - /* - //if((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) - if(src.type == Route::MIDI_DEVICE_ROUTE) + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update the destination track's aux ref count, and all tracks it is routed to. + if(src.isValid() && dst.isValid()) { - if(src.isValid()) - { - RouteList* outRoutes = src.device->outRoutes(); - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - { - if (*i == dst) { - outRoutes->erase(i); - break; - } - } - } + if(src.track->auxRefCount()) + //dst.track->updateAuxStates( -src.track->auxRefCount() ); + src.track->updateAuxRoute( -src.track->auxRefCount(), dst.track ); else - printf("removeRoute: source is midi but invalid\n"); - - if(dst.isValid()) + if(src.track->type() == Track::AUDIO_AUX) + //dst.track->updateAuxStates( -1 ); + src.track->updateAuxRoute( -1, dst.track ); + } + + if(src.isValid()) + { + RouteList* outRoutes = src.track->outRoutes(); + for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) { - RouteList* inRoutes = dst.track->inRoutes(); - for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) - { - if (*i == src) { - inRoutes->erase(i); - break; - } - } + if (*i == dst) { + outRoutes->erase(i); + break; + } } - else - printf("removeRoute: source is midi but destination invalid\n"); - } + } else - */ + printf("removeRoute: source is track but invalid\n"); + if(dst.isValid()) { - if(src.isValid()) - { - RouteList* outRoutes = src.track->outRoutes(); - for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) - { - if (*i == dst) { - outRoutes->erase(i); - break; - } - } - } - else - printf("removeRoute: source is track but invalid\n"); + RouteList* inRoutes; - if(dst.isValid()) + inRoutes = dst.track->inRoutes(); + for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) { - RouteList* inRoutes; - - //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) - // Removed p3.3.49 - /* - if (dst.type == Route::MIDI_DEVICE_ROUTE) - inRoutes = dst.device->inRoutes(); - else - */ - - inRoutes = dst.track->inRoutes(); - for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i) - { - if (*i == src) { - inRoutes->erase(i); - break; - } - } - } - else - printf("removeRoute: source is track but destination invalid\n"); - } + if (*i == src) { + inRoutes->erase(i); + break; + } + } + } + else + printf("removeRoute: source is track but destination invalid\n"); } } @@ -1013,9 +751,19 @@ void removeRoute(Route src, Route dst) // So far it only works with MidiDevice <-> Jack. //--------------------------------------------------------- -// p3.3.55 void removeAllRoutes(Route src, Route dst) { + // TODO: Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update the destination track's aux ref count, and all tracks it is routed to. + /* if(src.isValid() && dst.isValid()) + { + if(src.track->auxRefCount()) + dst.track->updateAuxStates( -src.track->auxRefCount() ); + else + if(src.track->type() == Track::TrackType::AUDIO_AUX)) + dst.track->updateAuxStates( -1 ); + } */ + if(src.isValid()) { if(src.type == Route::MIDI_DEVICE_ROUTE) @@ -1052,22 +800,11 @@ static QString track2name(const Track* n) QString Route::name() const { - // p3.3.38 Removed - /* - QString s; - if ((type == TRACK_ROUTE) && (channel != -1)) { -// if (channel != -1) { - QString c; - c.setNum(channel+1); - s = c + ":"; - } - */ - if(type == MIDI_DEVICE_ROUTE) { if(device) { - // p3.3.55 Removed for unified jack in/out devices, the actual port names are now different from device name. + // For unified jack in/out devices, the actual port names are now different from device name. // Like this: device: "MyJackDevice1" -> inport: "MyJackDevice1_in" outport: "MyJackDevice1_out" /* if(device->deviceType() == MidiDevice::JACK_MIDI) @@ -1075,8 +812,7 @@ QString Route::name() const else */ - //if(device->deviceType() == MidiDevice::ALSA_MIDI) - return device->name(); + return device->name(); } return QWidget::tr("None"); } @@ -1084,16 +820,14 @@ QString Route::name() const if(type == JACK_ROUTE) { if (!MusEGlobal::checkAudioDevice()) return ""; - //return s + MusEGlobal::audioDevice->portName(jackPort); return MusEGlobal::audioDevice->portName(jackPort); } else - if(type == MIDI_PORT_ROUTE) // p3.3.49 + if(type == MIDI_PORT_ROUTE) { return ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort); } else - //return s + track2name(track); return track2name(track); } @@ -1106,7 +840,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) { // printf("name2route %s\n", rn.toLatin1().constData()); int channel = -1; - //int channel = 0; QString s(rn); // Support old route style in med files. Obsolete. if (rn[0].isNumber() && rn[1]==':') @@ -1117,8 +850,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) if(rtype == -1) { - //if(dst) - //{ if(MusEGlobal::checkAudioDevice()) { void* p = MusEGlobal::audioDevice->findPort(s.toLatin1().constData()); @@ -1149,7 +880,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) return Route(*i, channel); } - // p3.3.49 if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX) { bool ok = false; @@ -1160,8 +890,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) } else { - //if(dst) - //{ if(rtype == Route::TRACK_ROUTE) { TrackList* tl = MusEGlobal::song->tracks(); @@ -1178,8 +906,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) AudioTrack* track = (AudioTrack*)*i; if(track->name() == s) return Route(track, channel); - //return Route(track, channel, 1); - //return Route(track, channel, track->channels()); } } } @@ -1191,7 +917,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) for(iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i) { if((*i)->name() == s) - //if (jmd->name() == rn) return Route(*i, channel); /* @@ -1224,7 +949,7 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) } } else - if(rtype == Route::MIDI_PORT_ROUTE) // p3.3.49 + if(rtype == Route::MIDI_PORT_ROUTE) { if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX) { @@ -1238,7 +963,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype) printf(" name2route: <%s> not found\n", rn.toLatin1().constData()); return Route((Track*) 0, channel); - //return Route((Track*) 0, channel, 1); } //--------------------------------------------------------- @@ -1255,10 +979,6 @@ bool checkRoute(const QString& s, const QString& d) return false; if (src.type == Route::JACK_ROUTE) { - //if (dst.type != TRACK_ROUTE) { - // return false; - // } - if (dst.type == Route::TRACK_ROUTE) { if (dst.track->type() != Track::AUDIO_INPUT) { @@ -1274,12 +994,9 @@ bool checkRoute(const QString& s, const QString& d) } } else - //if (dst.type == Route::JACK_MIDI_ROUTE) if (dst.type == Route::MIDI_DEVICE_ROUTE) { - //src.channel = dst.channel; src.channel = -1; - //dst.channel = -1; RouteList* routes = dst.device->inRoutes(); for (ciRoute i = routes->begin(); i != routes->end(); ++i) { @@ -1293,10 +1010,6 @@ bool checkRoute(const QString& s, const QString& d) } else if (dst.type == Route::JACK_ROUTE) { - //if (src.type != TRACK_ROUTE) { - // return false; - // } - if (src.type == Route::TRACK_ROUTE) { if (src.track->type() != Track::AUDIO_OUTPUT) { @@ -1312,13 +1025,10 @@ bool checkRoute(const QString& s, const QString& d) } } else - //if (src.type == Route::JACK_MIDI_ROUTE) if (src.type == Route::MIDI_DEVICE_ROUTE) { RouteList* routes = src.device->outRoutes(); - //dst.channel = src.channel; dst.channel = -1; - //src.channel = -1; for (ciRoute i = routes->begin(); i != routes->end(); ++i) { if (*i == dst) { // route already there @@ -1329,7 +1039,7 @@ bool checkRoute(const QString& s, const QString& d) else return false; } - else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + else if (src.type == Route::MIDI_PORT_ROUTE) { RouteList* outRoutes = MusEGlobal::midiPorts[src.midiPort].outRoutes(); for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) @@ -1339,13 +1049,11 @@ bool checkRoute(const QString& s, const QString& d) } } } - //else if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 + //else if (dst.type == Route::MIDI_PORT_ROUTE) //{ //} else { - //RouteList* outRoutes = ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) ? - // src.device->outRoutes() : src.track->outRoutes(); RouteList* outRoutes = (src.type == Route::MIDI_DEVICE_ROUTE) ? src.device->outRoutes() : src.track->outRoutes(); for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i) @@ -1366,7 +1074,7 @@ void Route::read(Xml& xml) { QString s; int dtype = MidiDevice::ALSA_MIDI; - int port = -1; // p3.3.49 + int port = -1; unsigned char rtype = Route::TRACK_ROUTE; for (;;) @@ -1397,7 +1105,7 @@ void Route::read(Xml& xml) if(tag == "name") s = xml.s2(); else - if(tag == "mport") // p3.3.49 + if(tag == "mport") { port = xml.s2().toInt(); rtype = Route::MIDI_PORT_ROUTE; @@ -1409,7 +1117,7 @@ void Route::read(Xml& xml) #ifdef ROUTE_DEBUG printf("Route::read(): tag end type:%d channel:%d name:%s\n", rtype, channel, s.toLatin1().constData()); #endif - if(rtype == MIDI_PORT_ROUTE) // p3.3.49 + if(rtype == MIDI_PORT_ROUTE) { if(port >= 0 && port < MIDI_PORTS) { @@ -1462,7 +1170,6 @@ void Route::read(Xml& xml) MidiDevice* md = *imd; if(md->name() == s && md->deviceType() == dtype) { - // p3.3.45 // We found a device, but if it is not in use by the song (port is -1), ignore it. // This prevents loading and propagation of bogus routes in the med file. if(md->midiPort() == -1) @@ -1509,7 +1216,7 @@ void Song::readRoute(Xml& xml) case Xml::End: return; case Xml::TagStart: - // p3.3.38 2010/02/03 Support old routes in med files. Now obsolete! + // 2010/02/03 Support old routes in med files. Now obsolete! if (tag == "srcNode") src = xml.parse1(); else if (tag == "dstNode") @@ -1545,7 +1252,7 @@ void Song::readRoute(Xml& xml) if(tag == "remch") remch = xml.s2().toInt(); else - if(tag == "channelMask") // p3.3.50 New channel mask for midi port-track routes. + if(tag == "channelMask") // New channel mask for midi port-track routes. ch = xml.s2().toInt(); else printf("Song::readRoute(): unknown attribute:%s\n", tag.toLatin1().constData()); @@ -1564,17 +1271,17 @@ void Song::readRoute(Xml& xml) // Support new routes. if(sroute.isValid() && droute.isValid()) { - // p3.3.49 Support pre- 1.1-RC2 midi-device-to-track routes. Obsolete. Replaced with midi port routes. + // Support pre- 1.1-RC2 midi-device-to-track routes. Obsolete. Replaced with midi port routes. if(sroute.type == Route::MIDI_DEVICE_ROUTE && droute.type == Route::TRACK_ROUTE) { if(sroute.device->midiPort() >= 0 && sroute.device->midiPort() < MIDI_PORTS - && ch >= 0 && ch < MIDI_CHANNELS) // p3.3.50 + && ch >= 0 && ch < MIDI_CHANNELS) { sroute.midiPort = sroute.device->midiPort(); sroute.device = 0; sroute.type = Route::MIDI_PORT_ROUTE; - sroute.channel = 1 << ch; // p3.3.50 Convert to new bit-wise channel mask. + sroute.channel = 1 << ch; // Convert to new bit-wise channel mask. droute.channel = sroute.channel; addRoute(sroute, droute); @@ -1586,13 +1293,13 @@ void Song::readRoute(Xml& xml) else if(sroute.type == Route::TRACK_ROUTE && droute.type == Route::MIDI_DEVICE_ROUTE) { if(droute.device->midiPort() >= 0 && droute.device->midiPort() < MIDI_PORTS - && ch >= 0 && ch < MIDI_CHANNELS) // p3.3.50 + && ch >= 0 && ch < MIDI_CHANNELS) { droute.midiPort = droute.device->midiPort(); droute.device = 0; droute.type = Route::MIDI_PORT_ROUTE; - droute.channel = 1 << ch; // p3.3.50 Convert to new bit-wise channel mask. + droute.channel = 1 << ch; // Convert to new bit-wise channel mask. sroute.channel = droute.channel; addRoute(sroute, droute); @@ -1659,7 +1366,7 @@ void Route::dump() const printf("Route dump: jack audio port <%s> channel %d\n", MusEGlobal::audioDevice->portName(jackPort).toLatin1().constData(), channel); } else - if (type == MIDI_PORT_ROUTE) // p3.3.49 + if (type == MIDI_PORT_ROUTE) { printf("Route dump: midi port <%d> channel mask %d\n", midiPort, channel); } @@ -1672,8 +1379,6 @@ void Route::dump() const if(device->deviceType() == MidiDevice::JACK_MIDI) { if(MusEGlobal::checkAudioDevice()) - //printf("jack midi port device <%s> ", MusEGlobal::audioDevice->portName(device->clientPort()).toLatin1().constData()); - // p3.3.55 { printf("jack midi device <%s> ", device->name().toLatin1().constData()); if(device->inClientPort()) @@ -1730,36 +1435,16 @@ bool Route::operator==(const Route& a) const { //if (!MusEGlobal::checkAudioDevice()) return false; //return MusEGlobal::audioDevice->portName(jackPort) == MusEGlobal::audioDevice->portName(a.jackPort); - // p3.3.55 Simplified. - return jackPort == a.jackPort; + return jackPort == a.jackPort; // Simplified. } else - if (type == MIDI_PORT_ROUTE) // p3.3.49 + if (type == MIDI_PORT_ROUTE) { return midiPort == a.midiPort; } else if (type == MIDI_DEVICE_ROUTE) { - // p3.3.55 Changed for unified jack in/out devices, the actual port names are now different from device name. - // Like this: device: "MyJackDevice1" -> inport: "MyJackDevice1_in" outport: "MyJackDevice1_out" - /* - if(device && a.device && device->deviceType() == a.device->deviceType()) - { - if(device->deviceType() == MidiDevice::JACK_MIDI) - { - if (!MusEGlobal::checkAudioDevice()) return false; - return MusEGlobal::audioDevice->portName(device->clientPort()) == MusEGlobal::audioDevice->portName(a.device->clientPort()); - } - else - if(device->deviceType() == MidiDevice::ALSA_MIDI) - // TODO: OK ?? - return device->clientPort() == a.device->clientPort() && (channel == a.channel); - else - if(device->deviceType() == MidiDevice::SYNTH_MIDI) - return device->name() == a.device->name(); - } - */ return device == a.device; } } @@ -1767,4 +1452,56 @@ bool Route::operator==(const Route& a) const return false; } +/* +//--------------------------------------------------------- +// isCircularRoute +// Recursive. +// If dst is valid, start traversal from there, not from src. +// Returns true if circular. +//--------------------------------------------------------- + +bool isCircularRoutePath(Track* src, Track* dst) +{ + //if(isMidiTrack() || _type == AUDIO_AUX) + //if(isMidiTrack()) + // return; + + bool rv = false; + + if(dst) + { + src->setNodeTraversed(true); + rv = isCircularRoutePath(dst, NULL); + src->setNodeTraversed(false); + //if(rv) + // fprintf(stderr, " Circular route %s -> %s\n", src->name().toLatin1().constData(), dst->name().toLatin1().constData()); + return rv; + } + + if(src->nodeTraversed()) + return true; + + src->setNodeTraversed(true); + + //printf("isCircularRoute %s\n", src->name().toLatin1().constData()); + + RouteList* orl = src->outRoutes(); + for (iRoute i = orl->begin(); i != orl->end(); ++i) + { + if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) + continue; + Track* t = (*i).track; + //if(t->isMidiTrack()) + // continue; + rv = isCircularRoutePath(src, NULL); + if(rv) + break; + } + + src->setNodeTraversed(false); + return rv; +} +*/ + + } // namespace MusECore diff --git a/muse2/muse/route.h b/muse2/muse/route.h index 36b00d47..587369bc 100644 --- a/muse2/muse/route.h +++ b/muse2/muse/route.h @@ -4,6 +4,7 @@ // $Id: route.h,v 1.5.2.1 2008/05/21 00:28:52 terminator356 Exp $ // // (C) Copyright 2001 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -43,17 +44,15 @@ class Xml; //--------------------------------------------------------- struct Route { - enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2, MIDI_PORT_ROUTE=3 }; // p3.3.49 + enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2, MIDI_PORT_ROUTE=3 }; union { - //AudioTrack* track; Track* track; - //MidiJackDevice* device; MidiDevice* device; void* jackPort; }; - int midiPort; // p3.3.49 Midi port number. Best not to put this in the union to avoid problems? + int midiPort; // Midi port number. Best not to put this in the union to avoid problems? //snd_seq_addr_t alsaAdr; @@ -75,7 +74,7 @@ struct Route { Route(void* t, int ch=-1); Route(Track* t, int ch = -1, int chans = -1); Route(MidiDevice* d, int ch); - Route(int port, int ch); // p3.3.49 + Route(int port, int ch); Route(const QString&, bool dst, int ch, int rtype = -1); Route(); @@ -84,7 +83,7 @@ struct Route { bool isValid() const { return ((type == TRACK_ROUTE) && (track != 0)) || ((type == JACK_ROUTE) && (jackPort != 0)) || ((type == MIDI_DEVICE_ROUTE) && (device != 0)) || - ((type == MIDI_PORT_ROUTE) && (midiPort >= 0) && (midiPort < MIDI_PORTS)); // p3.3.49 + ((type == MIDI_PORT_ROUTE) && (midiPort >= 0) && (midiPort < MIDI_PORTS)); } void read(Xml& xml); void dump() const; @@ -106,6 +105,7 @@ extern void removeRoute(Route, Route); extern void removeAllRoutes(Route, Route); // p3.3.55 extern Route name2route(const QString&, bool dst, int rtype = -1); extern bool checkRoute(const QString&, const QString&); +//extern bool isCircularRoutePath(Track* src, Track* dst); // Recursive. //--------------------------------------------------------- // RouteMenuMap diff --git a/muse2/muse/shortcuts.cpp b/muse2/muse/shortcuts.cpp index 7563fd93..95df7292 100644 --- a/muse2/muse/shortcuts.cpp +++ b/muse2/muse/shortcuts.cpp @@ -42,7 +42,7 @@ ShortCut shortcuts[SHRT_NUM_OF_ELEMENTS]; void defShrt(int shrt, int key, const char* descr, int type, const char* xml) { shortcuts[shrt].key = key; - shortcuts[shrt].descr = QT_TRANSLATE_NOOP("@default", descr); + shortcuts[shrt].descr = descr; shortcuts[shrt].type = type; shortcuts[shrt].xml = xml; } @@ -51,279 +51,279 @@ void defShrt(int shrt, int key, const char* descr, int type, const char* xml) void initShortCuts() { //Global: - defShrt(SHRT_PLAY_SONG, Qt::Key_Enter, "Transport: Start playback from current location", GLOBAL_SHRT, "play"); - defShrt(SHRT_TOGGLE_METRO, Qt::Key_C, "Transport: Toggle metronome", GLOBAL_SHRT,"toggle_metro"); - defShrt(SHRT_STOP, Qt::Key_Insert,"Transport: Stop Playback", GLOBAL_SHRT, "stop"); - defShrt(SHRT_GOTO_START, Qt::Key_W, "Transport: Goto Start", GLOBAL_SHRT, "goto_start"); - defShrt(SHRT_PLAY_TOGGLE, Qt::Key_Space, "Transport: Play, Stop, Rewind", GLOBAL_SHRT, "play_toggle"); - defShrt(SHRT_GOTO_LEFT, Qt::Key_End, "Transport: Goto left marker" , GLOBAL_SHRT, "goto_left"); - defShrt(SHRT_GOTO_RIGHT, Qt::Key_PageDown, "Transport: Goto right marker" , GLOBAL_SHRT, "goto_right"); - defShrt(SHRT_TOGGLE_LOOP, Qt::Key_Slash, "Transport: Toggle Loop section", GLOBAL_SHRT, "toggle_loop"); - defShrt(SHRT_START_REC, Qt::Key_Asterisk, "Transport: Toggle Record", GLOBAL_SHRT, "toggle_rec"); - defShrt(SHRT_REC_CLEAR, Qt::Key_Backspace, "Transport: Clear all rec enabled tracks", GLOBAL_SHRT, "rec_clear"); - defShrt(SHRT_FULLSCREEN, Qt::CTRL + Qt::Key_F, "Toggle fullscreen", GLOBAL_SHRT, "fullscreen"); - - defShrt(SHRT_COPY, Qt::CTRL + Qt::Key_C, "Edit: Copy", INVIS_SHRT, "copy"); - defShrt(SHRT_COPY_RANGE, Qt::CTRL + Qt::SHIFT + Qt::Key_C, "Edit: Copy in range", GLOBAL_SHRT, "copy_range"); - defShrt(SHRT_UNDO, Qt::CTRL + Qt::Key_Z, "Edit: Undo", INVIS_SHRT, "undo"); - defShrt(SHRT_REDO, Qt::CTRL + Qt::Key_Y, "Edit: Redo", INVIS_SHRT, "redo"); - defShrt(SHRT_CUT, Qt::CTRL + Qt::Key_X, "Edit: Cut", INVIS_SHRT, "cut"); - defShrt(SHRT_PASTE, Qt::CTRL + Qt::Key_V, "Edit: Paste", INVIS_SHRT, "paste"); - defShrt(SHRT_PASTE_DIALOG, Qt::CTRL + Qt::SHIFT + Qt::Key_V, "Edit: Paste (with dialog)", GLOBAL_SHRT, "paste_dialog"); - defShrt(SHRT_DELETE, Qt::Key_Delete, "Edit: Delete", INVIS_SHRT, "delete"); + defShrt(SHRT_PLAY_SONG, Qt::Key_Enter, QT_TRANSLATE_NOOP("shortcuts", "Transport: Start playback from current location"), GLOBAL_SHRT, "play"); + defShrt(SHRT_TOGGLE_METRO, Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "Transport: Toggle metronome"), GLOBAL_SHRT,"toggle_metro"); + defShrt(SHRT_STOP, Qt::Key_Insert,QT_TRANSLATE_NOOP("shortcuts", "Transport: Stop Playback"), GLOBAL_SHRT, "stop"); + defShrt(SHRT_GOTO_START, Qt::Key_W, QT_TRANSLATE_NOOP("shortcuts", "Transport: Goto Start"), GLOBAL_SHRT, "goto_start"); + defShrt(SHRT_PLAY_TOGGLE, Qt::Key_Space, QT_TRANSLATE_NOOP("shortcuts", "Transport: Play, Stop, Rewind"), GLOBAL_SHRT, "play_toggle"); + defShrt(SHRT_GOTO_LEFT, Qt::Key_End, QT_TRANSLATE_NOOP("shortcuts", "Transport: Goto left marker") , GLOBAL_SHRT, "goto_left"); + defShrt(SHRT_GOTO_RIGHT, Qt::Key_PageDown, QT_TRANSLATE_NOOP("shortcuts", "Transport: Goto right marker") , GLOBAL_SHRT, "goto_right"); + defShrt(SHRT_TOGGLE_LOOP, Qt::Key_Slash, QT_TRANSLATE_NOOP("shortcuts", "Transport: Toggle Loop section"), GLOBAL_SHRT, "toggle_loop"); + defShrt(SHRT_START_REC, Qt::Key_Asterisk, QT_TRANSLATE_NOOP("shortcuts", "Transport: Toggle Record"), GLOBAL_SHRT, "toggle_rec"); + defShrt(SHRT_REC_CLEAR, Qt::Key_Backspace, QT_TRANSLATE_NOOP("shortcuts", "Transport: Clear all rec enabled tracks"), GLOBAL_SHRT, "rec_clear"); + defShrt(SHRT_FULLSCREEN, Qt::CTRL + Qt::Key_F, QT_TRANSLATE_NOOP("shortcuts", "Toggle fullscreen"), GLOBAL_SHRT, "fullscreen"); + + defShrt(SHRT_COPY, Qt::CTRL + Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "Edit: Copy"), INVIS_SHRT, "copy"); + defShrt(SHRT_COPY_RANGE, Qt::CTRL + Qt::SHIFT + Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "Edit: Copy in range"), GLOBAL_SHRT, "copy_range"); + defShrt(SHRT_UNDO, Qt::CTRL + Qt::Key_Z, QT_TRANSLATE_NOOP("shortcuts", "Edit: Undo"), INVIS_SHRT, "undo"); + defShrt(SHRT_REDO, Qt::CTRL + Qt::SHIFT + Qt::Key_Z, QT_TRANSLATE_NOOP("shortcuts", "Edit: Redo"), INVIS_SHRT, "redo"); + defShrt(SHRT_CUT, Qt::CTRL + Qt::Key_X, QT_TRANSLATE_NOOP("shortcuts", "Edit: Cut"), INVIS_SHRT, "cut"); + defShrt(SHRT_PASTE, Qt::CTRL + Qt::Key_V, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste"), INVIS_SHRT, "paste"); + defShrt(SHRT_PASTE_DIALOG, Qt::CTRL + Qt::SHIFT + Qt::Key_V, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste (with dialog)"), GLOBAL_SHRT, "paste_dialog"); + defShrt(SHRT_DELETE, Qt::Key_Delete, QT_TRANSLATE_NOOP("shortcuts", "Edit: Delete"), INVIS_SHRT, "delete"); //----------------------------------------------------------- // Arranger: - defShrt(SHRT_NEW, Qt::CTRL + Qt::Key_N, "File: New project", ARRANG_SHRT + DEDIT_SHRT, "new_project"); - defShrt(SHRT_OPEN, Qt::CTRL + Qt::Key_O, "File: Open from disk", ARRANG_SHRT + DEDIT_SHRT, "open_project"); - defShrt(SHRT_SAVE, Qt::CTRL + Qt::Key_S, "File: Save project", ARRANG_SHRT + DEDIT_SHRT, "save_project"); + defShrt(SHRT_NEW, Qt::CTRL + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "File: New project"), ARRANG_SHRT + DEDIT_SHRT, "new_project"); + defShrt(SHRT_OPEN, Qt::CTRL + Qt::Key_O, QT_TRANSLATE_NOOP("shortcuts", "File: Open from disk"), ARRANG_SHRT + DEDIT_SHRT, "open_project"); + defShrt(SHRT_SAVE, Qt::CTRL + Qt::Key_S, QT_TRANSLATE_NOOP("shortcuts", "File: Save project"), ARRANG_SHRT + DEDIT_SHRT, "save_project"); //----------------------------------------------------------- - defShrt(SHRT_OPEN_RECENT, Qt::CTRL + Qt::Key_1, "File: Open recent file", ARRANG_SHRT, "open_recent"); - defShrt(SHRT_SAVE_AS, 0 , "File: Save as", ARRANG_SHRT, "save_project_as"); - defShrt(SHRT_LOAD_TEMPLATE, 0 , "File: Load template", ARRANG_SHRT, "load_template"); -// defShrt(SHRT_CONFIG_PRINTER, Qt::CTRL + Qt::Key_P, "Configure printer", ARRANG_SHRT, "config_printer"); - defShrt(SHRT_IMPORT_MIDI, 0 , "File: Import midi file", ARRANG_SHRT, "import_midi"); - defShrt(SHRT_EXPORT_MIDI, 0 , "File: Export midi file", ARRANG_SHRT, "export_midi"); - defShrt(SHRT_IMPORT_PART, 0 , "File: Import midi part", ARRANG_SHRT, "import_part"); - defShrt(SHRT_IMPORT_AUDIO, 0 , "File: Import audio file", ARRANG_SHRT, "import_audio"); - defShrt(SHRT_QUIT, Qt::CTRL + Qt::Key_Q, "File: Quit MusE", ARRANG_SHRT, "quit"); -// defShrt(SHRT_DESEL_PARTS, Qt::CTRL + Qt::Key_B, "Deselect all parts", ARRANG_SHRT, "deselect_parts"); - defShrt(SHRT_SELECT_PRTSTRACK, Qt::CTRL+ Qt::ALT + Qt::Key_P, "Edit: Select parts on track", ARRANG_SHRT, "select_parts_on_track"); - defShrt(SHRT_OPEN_PIANO, Qt::CTRL + Qt::Key_E, "Open pianoroll", ARRANG_SHRT, "open_pianoroll"); - defShrt(SHRT_OPEN_DRUMS, Qt::CTRL + Qt::Key_D, "Open drumeditor", ARRANG_SHRT, "open_drumedit"); - defShrt(SHRT_OPEN_LIST, Qt::CTRL + Qt::Key_L, "Open listeditor", ARRANG_SHRT, "open_listedit"); - defShrt(SHRT_OPEN_WAVE, Qt::CTRL + Qt::Key_W, "Open waveeditor", ARRANG_SHRT, "open_waveedit"); - defShrt(SHRT_OPEN_GRAPHIC_MASTER, Qt::CTRL + Qt::Key_M, "Open graphical mastertrack editor", ARRANG_SHRT, "open_graph_master"); - defShrt(SHRT_OPEN_LIST_MASTER, Qt::CTRL + Qt::SHIFT + Qt::Key_M, "Open list mastertrack editor", ARRANG_SHRT, "open_list_master"); - defShrt(SHRT_OPEN_MIDI_TRANSFORM, Qt::CTRL + Qt::Key_T, "Open midi transformer", ARRANG_SHRT, "open_midi_transform"); - defShrt(SHRT_ADD_MIDI_TRACK, Qt::CTRL + Qt::Key_J, "Add midi track", ARRANG_SHRT, "add_midi_track"); - defShrt(SHRT_ADD_DRUM_TRACK, 0, "Add drum track", ARRANG_SHRT, "add_drum_track"); - defShrt(SHRT_ADD_NEW_STYLE_DRUM_TRACK, 0, "Add new style drum track", ARRANG_SHRT, "add_new_style_drum_track"); - defShrt(SHRT_ADD_WAVE_TRACK, 0, "Add wave track", ARRANG_SHRT, "add_wave_track"); - defShrt(SHRT_ADD_AUDIO_OUTPUT, 0, "Add audio output", ARRANG_SHRT, "add_audio_output"); - defShrt(SHRT_ADD_AUDIO_GROUP, 0, "Add audio group", ARRANG_SHRT, "add_audio_group"); - defShrt(SHRT_ADD_AUDIO_INPUT, 0, "Add audio input", ARRANG_SHRT, "add_audio_input"); - defShrt(SHRT_ADD_AUDIO_AUX , 0, "Add audio aux", ARRANG_SHRT, "add_audio_aux"); - defShrt(SHRT_GLOBAL_CUT, 0, "Structure: Global cut", ARRANG_SHRT, "global_cut"); - defShrt(SHRT_GLOBAL_INSERT, 0, "Structure: Global insert", ARRANG_SHRT, "global_insert"); - defShrt(SHRT_GLOBAL_SPLIT, 0, "Structure: Global split", ARRANG_SHRT, "global_split"); - defShrt(SHRT_CUT_EVENTS, 0, "Structure: Cut events", ARRANG_SHRT, "cut_events"); - //defShrt(SHRT_OPEN_MIXER, Qt::Key_F10, "View: Open mixer window", ARRANG_SHRT, "toggle_mixer"); - defShrt(SHRT_OPEN_MIXER, Qt::Key_F10, "View: Open mixer #1 window", ARRANG_SHRT, "toggle_mixer"); - defShrt(SHRT_OPEN_MIXER2, Qt::CTRL + Qt::Key_F10, "View: Open mixer #2 window", ARRANG_SHRT, "toggle_mixer2"); - defShrt(SHRT_OPEN_TRANSPORT, Qt::Key_F11, "View: Toggle transport window", ARRANG_SHRT, "toggle_transport"); - defShrt(SHRT_OPEN_BIGTIME, Qt::Key_F12, "View: Toggle bigtime window", ARRANG_SHRT, "toggle_bigtime"); - defShrt(SHRT_OPEN_MARKER, Qt::Key_F9, "View: Open marker window", ARRANG_SHRT, "marker_window"); - - defShrt(SHRT_FOLLOW_JUMP, 0, "Settings: Follow song by page", ARRANG_SHRT, "follow_jump"); - defShrt(SHRT_FOLLOW_NO, 0, "Settings: Follow song off", ARRANG_SHRT, "follow_no"); - defShrt(SHRT_FOLLOW_CONTINUOUS, 0, "Settings: Follow song continuous", ARRANG_SHRT, "follow_continuous"); - - defShrt(SHRT_GLOBAL_CONFIG, 0, "Settings: Global configuration", ARRANG_SHRT, "configure_global"); - defShrt(SHRT_CONFIG_SHORTCUTS, 0, "Settings: Configure shortcuts", ARRANG_SHRT, "configure_shortcuts"); - defShrt(SHRT_CONFIG_METRONOME, 0, "Settings: Configure metronome", ARRANG_SHRT, "configure_metronome"); - defShrt(SHRT_CONFIG_MIDISYNC, 0, "Settings: Midi sync configuration", ARRANG_SHRT, "configure_midi_sync"); - defShrt(SHRT_MIDI_FILE_CONFIG, 0, "Settings: Midi file import/export configuration", ARRANG_SHRT, "configure_midi_file"); - defShrt(SHRT_APPEARANCE_SETTINGS, 0, "Settings: Appearance settings", ARRANG_SHRT, "configure_appearance_settings"); - defShrt(SHRT_CONFIG_MIDI_PORTS, 0, "Settings: Midi ports / Soft Synth", ARRANG_SHRT, "configure_midi_ports"); - defShrt(SHRT_CONFIG_AUDIO_PORTS, 0, "Settings: Audio subsystem configuration", ARRANG_SHRT, "configure_audio_ports"); - //defShrt(SHRT_SAVE_GLOBAL_CONFIG, 0, "Save global configuration", ARRANG_SHRT, "configure_save_global"); - - defShrt(SHRT_MIDI_EDIT_INSTRUMENTS, 0, "Midi: Edit midi instruments", ARRANG_SHRT, "midi_edit_instruments"); - defShrt(SHRT_MIDI_INPUT_TRANSFORM, 0, "Midi: Open midi input transform", ARRANG_SHRT, "midi_open_input_transform"); - defShrt(SHRT_MIDI_INPUT_FILTER, 0, "Midi: Open midi input filter", ARRANG_SHRT, "midi_open_input_filter"); - defShrt(SHRT_MIDI_INPUT_TRANSPOSE, 0, "Midi: Midi input transpose", ARRANG_SHRT, "midi_open_input_transpose"); - defShrt(SHRT_MIDI_REMOTE_CONTROL, 0, "Midi: Midi remote control", ARRANG_SHRT, "midi_remote_control"); + defShrt(SHRT_OPEN_RECENT, Qt::CTRL + Qt::Key_1, QT_TRANSLATE_NOOP("shortcuts", "File: Open recent file"), ARRANG_SHRT, "open_recent"); + defShrt(SHRT_SAVE_AS, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Save as"), ARRANG_SHRT, "save_project_as"); + defShrt(SHRT_LOAD_TEMPLATE, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Load template"), ARRANG_SHRT, "load_template"); +// defShrt(SHRT_CONFIG_PRINTER, Qt::CTRL + Qt::Key_P, QT_TRANSLATE_NOOP("shortcuts", "Configure printer"), ARRANG_SHRT, "config_printer"); + defShrt(SHRT_IMPORT_MIDI, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Import midi file"), ARRANG_SHRT, "import_midi"); + defShrt(SHRT_EXPORT_MIDI, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Export midi file"), ARRANG_SHRT, "export_midi"); + defShrt(SHRT_IMPORT_PART, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Import midi part"), ARRANG_SHRT, "import_part"); + defShrt(SHRT_IMPORT_AUDIO, 0 , QT_TRANSLATE_NOOP("shortcuts", "File: Import audio file"), ARRANG_SHRT, "import_audio"); + defShrt(SHRT_QUIT, Qt::CTRL + Qt::Key_Q, QT_TRANSLATE_NOOP("shortcuts", "File: Quit MusE"), ARRANG_SHRT, "quit"); +// defShrt(SHRT_DESEL_PARTS, Qt::CTRL + Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Deselect all parts"), ARRANG_SHRT, "deselect_parts"); + defShrt(SHRT_SELECT_PRTSTRACK, Qt::CTRL+ Qt::ALT + Qt::Key_P, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select parts on track"), ARRANG_SHRT, "select_parts_on_track"); + defShrt(SHRT_OPEN_PIANO, Qt::CTRL + Qt::Key_E, QT_TRANSLATE_NOOP("shortcuts", "Open pianoroll"), ARRANG_SHRT, "open_pianoroll"); + defShrt(SHRT_OPEN_DRUMS, Qt::CTRL + Qt::Key_D, QT_TRANSLATE_NOOP("shortcuts", "Open drumeditor"), ARRANG_SHRT, "open_drumedit"); + defShrt(SHRT_OPEN_LIST, Qt::CTRL + Qt::Key_L, QT_TRANSLATE_NOOP("shortcuts", "Open listeditor"), ARRANG_SHRT, "open_listedit"); + defShrt(SHRT_OPEN_WAVE, Qt::CTRL + Qt::Key_W, QT_TRANSLATE_NOOP("shortcuts", "Open waveeditor"), ARRANG_SHRT, "open_waveedit"); + defShrt(SHRT_OPEN_GRAPHIC_MASTER, Qt::CTRL + Qt::Key_M, QT_TRANSLATE_NOOP("shortcuts", "Open graphical mastertrack editor"), ARRANG_SHRT, "open_graph_master"); + defShrt(SHRT_OPEN_LIST_MASTER, Qt::CTRL + Qt::SHIFT + Qt::Key_M, QT_TRANSLATE_NOOP("shortcuts", "Open list mastertrack editor"), ARRANG_SHRT, "open_list_master"); + defShrt(SHRT_OPEN_MIDI_TRANSFORM, Qt::CTRL + Qt::Key_T, QT_TRANSLATE_NOOP("shortcuts", "Open midi transformer"), ARRANG_SHRT, "open_midi_transform"); + defShrt(SHRT_ADD_MIDI_TRACK, Qt::CTRL + Qt::Key_J, QT_TRANSLATE_NOOP("shortcuts", "Add midi track"), ARRANG_SHRT, "add_midi_track"); + defShrt(SHRT_ADD_DRUM_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add drum track"), ARRANG_SHRT, "add_drum_track"); + defShrt(SHRT_ADD_NEW_STYLE_DRUM_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add new style drum track"), ARRANG_SHRT, "add_new_style_drum_track"); + defShrt(SHRT_ADD_WAVE_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Add wave track"), ARRANG_SHRT, "add_wave_track"); + defShrt(SHRT_ADD_AUDIO_OUTPUT, 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio output"), ARRANG_SHRT, "add_audio_output"); + defShrt(SHRT_ADD_AUDIO_GROUP, 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio group"), ARRANG_SHRT, "add_audio_group"); + defShrt(SHRT_ADD_AUDIO_INPUT, 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio input"), ARRANG_SHRT, "add_audio_input"); + defShrt(SHRT_ADD_AUDIO_AUX , 0, QT_TRANSLATE_NOOP("shortcuts", "Add audio aux"), ARRANG_SHRT, "add_audio_aux"); + defShrt(SHRT_GLOBAL_CUT, 0, QT_TRANSLATE_NOOP("shortcuts", "Structure: Global cut"), ARRANG_SHRT, "global_cut"); + defShrt(SHRT_GLOBAL_INSERT, 0, QT_TRANSLATE_NOOP("shortcuts", "Structure: Global insert"), ARRANG_SHRT, "global_insert"); + defShrt(SHRT_GLOBAL_SPLIT, 0, QT_TRANSLATE_NOOP("shortcuts", "Structure: Global split"), ARRANG_SHRT, "global_split"); + defShrt(SHRT_CUT_EVENTS, 0, QT_TRANSLATE_NOOP("shortcuts", "Structure: Cut events"), ARRANG_SHRT, "cut_events"); + //defShrt(SHRT_OPEN_MIXER, Qt::Key_F10, QT_TRANSLATE_NOOP("shortcuts", "View: Open mixer window"), ARRANG_SHRT, "toggle_mixer"); + defShrt(SHRT_OPEN_MIXER, Qt::Key_F10, QT_TRANSLATE_NOOP("shortcuts", "View: Open mixer #1 window"), ARRANG_SHRT, "toggle_mixer"); + defShrt(SHRT_OPEN_MIXER2, Qt::CTRL + Qt::Key_F10, QT_TRANSLATE_NOOP("shortcuts", "View: Open mixer #2 window"), ARRANG_SHRT, "toggle_mixer2"); + defShrt(SHRT_OPEN_TRANSPORT, Qt::Key_F11, QT_TRANSLATE_NOOP("shortcuts", "View: Toggle transport window"), ARRANG_SHRT, "toggle_transport"); + defShrt(SHRT_OPEN_BIGTIME, Qt::Key_F12, QT_TRANSLATE_NOOP("shortcuts", "View: Toggle bigtime window"), ARRANG_SHRT, "toggle_bigtime"); + defShrt(SHRT_OPEN_MARKER, Qt::Key_F9, QT_TRANSLATE_NOOP("shortcuts", "View: Open marker window"), ARRANG_SHRT, "marker_window"); + + defShrt(SHRT_FOLLOW_JUMP, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Follow song by page"), ARRANG_SHRT, "follow_jump"); + defShrt(SHRT_FOLLOW_NO, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Follow song off"), ARRANG_SHRT, "follow_no"); + defShrt(SHRT_FOLLOW_CONTINUOUS, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Follow song continuous"), ARRANG_SHRT, "follow_continuous"); + + defShrt(SHRT_GLOBAL_CONFIG, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Global configuration"), ARRANG_SHRT, "configure_global"); + defShrt(SHRT_CONFIG_SHORTCUTS, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Configure shortcuts"), ARRANG_SHRT, "configure_shortcuts"); + defShrt(SHRT_CONFIG_METRONOME, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Configure metronome"), ARRANG_SHRT, "configure_metronome"); + defShrt(SHRT_CONFIG_MIDISYNC, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Midi sync configuration"), ARRANG_SHRT, "configure_midi_sync"); + defShrt(SHRT_MIDI_FILE_CONFIG, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Midi file import/export configuration"), ARRANG_SHRT, "configure_midi_file"); + defShrt(SHRT_APPEARANCE_SETTINGS, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Appearance settings"), ARRANG_SHRT, "configure_appearance_settings"); + defShrt(SHRT_CONFIG_MIDI_PORTS, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Midi ports / Soft Synth"), ARRANG_SHRT, "configure_midi_ports"); + defShrt(SHRT_CONFIG_AUDIO_PORTS, 0, QT_TRANSLATE_NOOP("shortcuts", "Settings: Audio subsystem configuration"), ARRANG_SHRT, "configure_audio_ports"); + //defShrt(SHRT_SAVE_GLOBAL_CONFIG, 0, QT_TRANSLATE_NOOP("shortcuts", "Save global configuration"), ARRANG_SHRT, "configure_save_global"); + + defShrt(SHRT_MIDI_EDIT_INSTRUMENTS, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Edit midi instruments"), ARRANG_SHRT, "midi_edit_instruments"); + defShrt(SHRT_MIDI_INPUT_TRANSFORM, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Open midi input transform"), ARRANG_SHRT, "midi_open_input_transform"); + defShrt(SHRT_MIDI_INPUT_FILTER, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Open midi input filter"), ARRANG_SHRT, "midi_open_input_filter"); + defShrt(SHRT_MIDI_INPUT_TRANSPOSE, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Midi input transpose"), ARRANG_SHRT, "midi_open_input_transpose"); + defShrt(SHRT_MIDI_REMOTE_CONTROL, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Midi remote control"), ARRANG_SHRT, "midi_remote_control"); #ifdef BUILD_EXPERIMENTAL - defShrt(SHRT_RANDOM_RHYTHM_GENERATOR,0,"Midi: Random rhythm generator", ARRANG_SHRT, "midi_random_rhythm_generator"); + defShrt(SHRT_RANDOM_RHYTHM_GENERATOR,0,QT_TRANSLATE_NOOP("shortcuts", "Midi: Random rhythm generator"), ARRANG_SHRT, "midi_random_rhythm_generator"); #endif - defShrt(SHRT_MIDI_RESET, 0, "Midi: Reset midi", ARRANG_SHRT, "midi_reset"); - defShrt(SHRT_MIDI_INIT, 0, "Midi: Init midi", ARRANG_SHRT, "midi_init"); - defShrt(SHRT_MIDI_LOCAL_OFF, 0, "Midi: Midi local off", ARRANG_SHRT, "midi_local_off"); + defShrt(SHRT_MIDI_RESET, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Reset midi"), ARRANG_SHRT, "midi_reset"); + defShrt(SHRT_MIDI_INIT, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Init midi"), ARRANG_SHRT, "midi_init"); + defShrt(SHRT_MIDI_LOCAL_OFF, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Midi local off"), ARRANG_SHRT, "midi_local_off"); - defShrt(SHRT_AUDIO_BOUNCE_TO_TRACK, 0, "Audio: Bounce audio to track", ARRANG_SHRT, "audio_bounce_to_track"); - defShrt(SHRT_AUDIO_BOUNCE_TO_FILE, 0, "Audio: Bounce audio to file", ARRANG_SHRT, "audio_bounce_to_file"); - defShrt(SHRT_AUDIO_RESTART, 0, "Audio: Restart audio", ARRANG_SHRT, "audio_restart"); + defShrt(SHRT_AUDIO_BOUNCE_TO_TRACK, 0, QT_TRANSLATE_NOOP("shortcuts", "Audio: Bounce audio to track"), ARRANG_SHRT, "audio_bounce_to_track"); + defShrt(SHRT_AUDIO_BOUNCE_TO_FILE, 0, QT_TRANSLATE_NOOP("shortcuts", "Audio: Bounce audio to file"), ARRANG_SHRT, "audio_bounce_to_file"); + defShrt(SHRT_AUDIO_RESTART, 0, QT_TRANSLATE_NOOP("shortcuts", "Audio: Restart audio"), ARRANG_SHRT, "audio_restart"); - defShrt(SHRT_MIXER_AUTOMATION, 0, "Automation: Mixer automation", ARRANG_SHRT, "mixer_automation"); - defShrt(SHRT_MIXER_SNAPSHOT, 0, "Automation: Take mixer snapshot", ARRANG_SHRT, "mixer_snapshot"); - defShrt(SHRT_MIXER_AUTOMATION_CLEAR,0, "Automation: Clear mixer automation", ARRANG_SHRT, "mixer_automation_clear"); + defShrt(SHRT_MIXER_AUTOMATION, 0, QT_TRANSLATE_NOOP("shortcuts", "Automation: Mixer automation"), ARRANG_SHRT, "mixer_automation"); + defShrt(SHRT_MIXER_SNAPSHOT, 0, QT_TRANSLATE_NOOP("shortcuts", "Automation: Take mixer snapshot"), ARRANG_SHRT, "mixer_snapshot"); + defShrt(SHRT_MIXER_AUTOMATION_CLEAR,0, QT_TRANSLATE_NOOP("shortcuts", "Automation: Clear mixer automation"), ARRANG_SHRT, "mixer_automation_clear"); -// defShrt(SHRT_OPEN_CLIPS, 0, "View audio clips", ARRANG_SHRT, "view_audio_clips"); - defShrt(SHRT_OPEN_HELP, Qt::Key_F1, "Help: Open Manual", ARRANG_SHRT, "open_help"); - defShrt(SHRT_START_WHATSTHIS, Qt::SHIFT + Qt::Key_F1, "Help: Toggle whatsthis mode", ARRANG_SHRT, "toggle_whatsthis"); +// defShrt(SHRT_OPEN_CLIPS, 0, QT_TRANSLATE_NOOP("shortcuts", "View audio clips"), ARRANG_SHRT, "view_audio_clips"); + defShrt(SHRT_OPEN_HELP, Qt::Key_F1, QT_TRANSLATE_NOOP("shortcuts", "Help: Open Manual"), ARRANG_SHRT, "open_help"); + defShrt(SHRT_START_WHATSTHIS, Qt::SHIFT + Qt::Key_F1, QT_TRANSLATE_NOOP("shortcuts", "Help: Toggle whatsthis mode"), ARRANG_SHRT, "toggle_whatsthis"); - defShrt(SHRT_EDIT_PART, Qt::Key_Return, "Edit: Edit selected part", ARRANG_SHRT, "edit_selected_part"); - defShrt(SHRT_SEL_ABOVE, Qt::Key_Up, "Edit: Select nearest part on track above", ARRANG_SHRT, "sel_part_above"); - defShrt(SHRT_SEL_ABOVE_ADD, Qt::SHIFT + Qt::Key_Up, "Edit: Add nearest part on track above", ARRANG_SHRT, "sel_part_above_add"); - defShrt(SHRT_SEL_BELOW, Qt::Key_Down, "Edit: Select nearest part on track below", ARRANG_SHRT, "sel_part_below"); - defShrt(SHRT_SEL_BELOW_ADD, Qt::SHIFT + Qt::Key_Down, "Edit: Add nearest part on track below", ARRANG_SHRT, "sel_part_below_add"); + defShrt(SHRT_EDIT_PART, Qt::Key_Return, QT_TRANSLATE_NOOP("shortcuts", "Edit: Edit selected part"), ARRANG_SHRT, "edit_selected_part"); + defShrt(SHRT_SEL_ABOVE, Qt::Key_Up, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select nearest part on track above"), ARRANG_SHRT, "sel_part_above"); + defShrt(SHRT_SEL_ABOVE_ADD, Qt::SHIFT + Qt::Key_Up, QT_TRANSLATE_NOOP("shortcuts", "Edit: Add nearest part on track above"), ARRANG_SHRT, "sel_part_above_add"); + defShrt(SHRT_SEL_BELOW, Qt::Key_Down, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select nearest part on track below"), ARRANG_SHRT, "sel_part_below"); + defShrt(SHRT_SEL_BELOW_ADD, Qt::SHIFT + Qt::Key_Down, QT_TRANSLATE_NOOP("shortcuts", "Edit: Add nearest part on track below"), ARRANG_SHRT, "sel_part_below_add"); - defShrt(SHRT_INSERTMEAS, Qt::CTRL+Qt::SHIFT+ Qt::Key_O, "Edit: Insert empty measure", ARRANG_SHRT, "insert_measure"); + defShrt(SHRT_INSERTMEAS, Qt::CTRL+Qt::SHIFT+ Qt::Key_O, QT_TRANSLATE_NOOP("shortcuts", "Edit: Insert empty measure"), ARRANG_SHRT, "insert_measure"); - defShrt(SHRT_PASTE_CLONE, Qt::CTRL+Qt::Key_B, "Edit: Paste as clones", ARRANG_SHRT, "paste_as_clone"); // i changed "paste_clone" to "paste_as_clone" intendedly. otherwise muse would keep its old, conflicting definition (ctrl+shift+v instead of ctrl+b) (flo) - defShrt(SHRT_PASTE_CLONE_DIALOG, Qt::CTRL+Qt::SHIFT+Qt::Key_B, "Edit: Paste as clones (with dialog)", ARRANG_SHRT, "paste_as_clone_dialog"); + defShrt(SHRT_PASTE_CLONE, Qt::CTRL+Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste as clones"), ARRANG_SHRT, "paste_as_clone"); // i changed "paste_clone" to "paste_as_clone" intendedly. otherwise muse would keep its old, conflicting definition (ctrl+shift+v instead of ctrl+b) (flo) + defShrt(SHRT_PASTE_CLONE_DIALOG, Qt::CTRL+Qt::SHIFT+Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste as clones (with dialog)"), ARRANG_SHRT, "paste_as_clone_dialog"); - defShrt(SHRT_SEL_TRACK_ABOVE, Qt::CTRL + Qt::Key_Up, "Select track above", ARRANG_SHRT, "sel_track_above"); - defShrt(SHRT_SEL_TRACK_BELOW, Qt::CTRL + Qt::Key_Down, "Select track below", ARRANG_SHRT, "sel_track_below"); + defShrt(SHRT_SEL_TRACK_ABOVE, Qt::CTRL + Qt::Key_Up, QT_TRANSLATE_NOOP("shortcuts", "Select track above"), ARRANG_SHRT, "sel_track_above"); + defShrt(SHRT_SEL_TRACK_BELOW, Qt::CTRL + Qt::Key_Down, QT_TRANSLATE_NOOP("shortcuts", "Select track below"), ARRANG_SHRT, "sel_track_below"); //----------------------------------------------------------- - defShrt(SHRT_TRANSPOSE, 0, "Midi: Transpose", ARRANG_SHRT + PROLL_SHRT, "midi_transpose"); + defShrt(SHRT_TRANSPOSE, 0, QT_TRANSLATE_NOOP("shortcuts", "Midi: Transpose"), ARRANG_SHRT + PROLL_SHRT, "midi_transpose"); //----------------------------------------------------------- - defShrt(SHRT_SELECT_ALL, Qt::CTRL + Qt::Key_A, "Edit: Select all", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_all"); - defShrt(SHRT_SELECT_NONE, Qt::CTRL + Qt::SHIFT + Qt::Key_A, "Edit: Select none", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_none"); - defShrt(SHRT_SELECT_INVERT, Qt::CTRL + Qt::Key_I, "Edit: Invert Selection", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_inv"); - defShrt(SHRT_SELECT_ILOOP, 0, "Edit: Select events/parts inside locators", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_ins_loc"); - defShrt(SHRT_SELECT_OLOOP, 0, "Edit: Select events/parts outside locators", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_out_loc"); - defShrt(SHRT_SELECT_PREV_PART, Qt::ALT + Qt::Key_Left, "Edit: Select previous part", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_prv_prt"); - defShrt(SHRT_SELECT_NEXT_PART, Qt::ALT + Qt::Key_Right, "Edit: Select next part", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_nxt_prt"); - defShrt(SHRT_SEL_LEFT, Qt::Key_Left, "Edit: Select nearest part/event to the left or move cursor", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_left"); - defShrt(SHRT_SEL_LEFT_ADD, Qt::Key_Left + Qt::SHIFT, "Edit: Add nearest part/event to the left to selection", PROLL_SHRT + DEDIT_SHRT, "sel_left_add"); - defShrt(SHRT_SEL_RIGHT, Qt::Key_Right, "Edit: Select nearest part/event to the right or move cursor", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT,"sel_right"); - defShrt(SHRT_SEL_RIGHT_ADD, Qt::Key_Right + Qt::SHIFT, "Edit: Add nearest part/event to the right to selection", PROLL_SHRT + DEDIT_SHRT,"sel_right_add"); - defShrt(SHRT_LOCATORS_TO_SELECTION, Qt::ALT + Qt::Key_P, "Edit: Set locators to selection", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "loc_to_sel"); - defShrt(SHRT_INC_PITCH, Qt::CTRL + Qt::Key_Up, "Edit: Increase pitch", PROLL_SHRT + DEDIT_SHRT, "sel_inc_pitch"); - defShrt(SHRT_DEC_PITCH, Qt::CTRL + Qt::Key_Down, "Edit: Decrease pitch", PROLL_SHRT + DEDIT_SHRT, "sel_dec_pitch"); - defShrt(SHRT_INC_POS, Qt::CTRL + Qt::Key_Right, "Edit: Increase event position", PROLL_SHRT + DEDIT_SHRT, "sel_inc_pos"); - defShrt(SHRT_DEC_POS, Qt::CTRL + Qt::Key_Left, "Edit: Decrease event position", PROLL_SHRT + DEDIT_SHRT, "sel_dec_pos"); - defShrt(SHRT_ZOOM_IN, Qt::CTRL + Qt::Key_PageUp, "View: Zoom in", PROLL_SHRT + DEDIT_SHRT + ARRANG_SHRT, "zoom_in"); - defShrt(SHRT_ZOOM_OUT, Qt::CTRL + Qt::Key_PageDown, "View: Zoom out", PROLL_SHRT + DEDIT_SHRT + ARRANG_SHRT, "zoom_out"); - defShrt(SHRT_GOTO_CPOS, Qt::Key_C, "View: Goto Current Position", PROLL_SHRT + DEDIT_SHRT, "goto_cpos"); - defShrt(SHRT_SCROLL_LEFT, Qt::Key_H, "View: Scroll left", PROLL_SHRT + DEDIT_SHRT, "scroll_left"); - defShrt(SHRT_SCROLL_RIGHT, Qt::Key_L, "View: Scroll left", PROLL_SHRT + DEDIT_SHRT, "scroll_right"); + defShrt(SHRT_SELECT_ALL, Qt::CTRL + Qt::Key_A, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select all"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_all"); + defShrt(SHRT_SELECT_NONE, Qt::CTRL + Qt::SHIFT + Qt::Key_A, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select none"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_none"); + defShrt(SHRT_SELECT_INVERT, Qt::CTRL + Qt::Key_I, QT_TRANSLATE_NOOP("shortcuts", "Edit: Invert Selection"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_inv"); + defShrt(SHRT_SELECT_ILOOP, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select events/parts inside locators"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_ins_loc"); + defShrt(SHRT_SELECT_OLOOP, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select events/parts outside locators"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_out_loc"); + defShrt(SHRT_SELECT_PREV_PART, Qt::ALT + Qt::Key_Left, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select previous part"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_prv_prt"); + defShrt(SHRT_SELECT_NEXT_PART, Qt::ALT + Qt::Key_Right, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select next part"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_nxt_prt"); + defShrt(SHRT_SEL_LEFT, Qt::Key_Left, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select nearest part/event to the left or move cursor"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "sel_left"); + defShrt(SHRT_SEL_LEFT_ADD, Qt::Key_Left + Qt::SHIFT, QT_TRANSLATE_NOOP("shortcuts", "Edit: Add nearest part/event to the left to selection"), PROLL_SHRT + DEDIT_SHRT, "sel_left_add"); + defShrt(SHRT_SEL_RIGHT, Qt::Key_Right, QT_TRANSLATE_NOOP("shortcuts", "Edit: Select nearest part/event to the right or move cursor"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT,"sel_right"); + defShrt(SHRT_SEL_RIGHT_ADD, Qt::Key_Right + Qt::SHIFT, QT_TRANSLATE_NOOP("shortcuts", "Edit: Add nearest part/event to the right to selection"), PROLL_SHRT + DEDIT_SHRT,"sel_right_add"); + defShrt(SHRT_LOCATORS_TO_SELECTION, Qt::ALT + Qt::Key_P, QT_TRANSLATE_NOOP("shortcuts", "Edit: Set locators to selection"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "loc_to_sel"); + defShrt(SHRT_INC_PITCH, Qt::CTRL + Qt::Key_Up, QT_TRANSLATE_NOOP("shortcuts", "Edit: Increase pitch"), PROLL_SHRT + DEDIT_SHRT, "sel_inc_pitch"); + defShrt(SHRT_DEC_PITCH, Qt::CTRL + Qt::Key_Down, QT_TRANSLATE_NOOP("shortcuts", "Edit: Decrease pitch"), PROLL_SHRT + DEDIT_SHRT, "sel_dec_pitch"); + defShrt(SHRT_INC_POS, Qt::CTRL + Qt::Key_Right, QT_TRANSLATE_NOOP("shortcuts", "Edit: Increase event position"), PROLL_SHRT + DEDIT_SHRT, "sel_inc_pos"); + defShrt(SHRT_DEC_POS, Qt::CTRL + Qt::Key_Left, QT_TRANSLATE_NOOP("shortcuts", "Edit: Decrease event position"), PROLL_SHRT + DEDIT_SHRT, "sel_dec_pos"); + defShrt(SHRT_ZOOM_IN, Qt::CTRL + Qt::Key_PageUp, QT_TRANSLATE_NOOP("shortcuts", "View: Zoom in"), PROLL_SHRT + DEDIT_SHRT + ARRANG_SHRT, "zoom_in"); + defShrt(SHRT_ZOOM_OUT, Qt::CTRL + Qt::Key_PageDown, QT_TRANSLATE_NOOP("shortcuts", "View: Zoom out"), PROLL_SHRT + DEDIT_SHRT + ARRANG_SHRT, "zoom_out"); + defShrt(SHRT_GOTO_CPOS, Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "View: Goto Current Position"), PROLL_SHRT + DEDIT_SHRT, "goto_cpos"); + defShrt(SHRT_SCROLL_LEFT, Qt::Key_H, QT_TRANSLATE_NOOP("shortcuts", "View: Scroll left"), PROLL_SHRT + DEDIT_SHRT, "scroll_left"); + defShrt(SHRT_SCROLL_RIGHT, Qt::Key_L, QT_TRANSLATE_NOOP("shortcuts", "View: Scroll left"), PROLL_SHRT + DEDIT_SHRT, "scroll_right"); //----------------------------------------------------------- //Drum: //----------------------------------------------------------- - defShrt(SHRT_FIXED_LEN, Qt::ALT + Qt::Key_L, "Edit: Set Fixed Length on Midi Events", PROLL_SHRT + DEDIT_SHRT, "midi_fixed_len"); + defShrt(SHRT_FIXED_LEN, Qt::ALT + Qt::Key_L, QT_TRANSLATE_NOOP("shortcuts", "Edit: Set Fixed Length on Midi Events"), PROLL_SHRT + DEDIT_SHRT, "midi_fixed_len"); //----------------------------------------------------------- //Pianoroll: //----------------------------------------------------------- - defShrt(SHRT_QUANTIZE, 0, "Quantize", PROLL_SHRT, "midi_quant"); - defShrt(SHRT_MODIFY_GATE_TIME, 0, "Modify Note Length", PROLL_SHRT, "midi_mod_gate_time"); - defShrt(SHRT_MODIFY_VELOCITY, 0, "Modify Velocity", PROLL_SHRT, "midi_mod_velo"); - defShrt(SHRT_CRESCENDO, 0, "Edit: Crescendo", PROLL_SHRT, "midi_crescendo"); - defShrt(SHRT_THIN_OUT, 0, "Edit: Thin Out", PROLL_SHRT, "midi_thin_out"); - defShrt(SHRT_ERASE_EVENT, 0, "Edit: Erase Event", PROLL_SHRT, "midi_erase_event"); - defShrt(SHRT_DELETE_OVERLAPS, 0, "Edit: Delete Overlaps", PROLL_SHRT, "midi_delete_overlaps"); - defShrt(SHRT_NOTE_SHIFT, 0, "Edit: Note Shift", PROLL_SHRT, "midi_note_shift"); - defShrt(SHRT_MOVE_CLOCK, 0, "Edit: Move Clock", PROLL_SHRT, "midi_move_clock"); - defShrt(SHRT_COPY_MEASURE, 0, "Edit: Copy Measure", PROLL_SHRT, "midi_copy_measure"); - defShrt(SHRT_ERASE_MEASURE, 0, "Edit: Erase Measure", PROLL_SHRT,"midi_erase_measure"); - defShrt(SHRT_DELETE_MEASURE, 0, "Edit: Delete Measure", PROLL_SHRT, "midi_delete_measure"); - defShrt(SHRT_CREATE_MEASURE, 0, "Edit: Create Measure", PROLL_SHRT, "midi_create_measure"); - defShrt(SHRT_EVENT_COLOR, Qt::Key_E, "Edit: Change Event Color", PROLL_SHRT, "change_event_color"); + defShrt(SHRT_QUANTIZE, 0, QT_TRANSLATE_NOOP("shortcuts", "Quantize"), PROLL_SHRT, "midi_quant"); + defShrt(SHRT_MODIFY_GATE_TIME, 0, QT_TRANSLATE_NOOP("shortcuts", "Modify Note Length"), PROLL_SHRT, "midi_mod_gate_time"); + defShrt(SHRT_MODIFY_VELOCITY, 0, QT_TRANSLATE_NOOP("shortcuts", "Modify Velocity"), PROLL_SHRT, "midi_mod_velo"); + defShrt(SHRT_CRESCENDO, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Crescendo"), PROLL_SHRT, "midi_crescendo"); + defShrt(SHRT_THIN_OUT, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Thin Out"), PROLL_SHRT, "midi_thin_out"); + defShrt(SHRT_ERASE_EVENT, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Erase Event"), PROLL_SHRT, "midi_erase_event"); + defShrt(SHRT_DELETE_OVERLAPS, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Delete Overlaps"), PROLL_SHRT, "midi_delete_overlaps"); + defShrt(SHRT_NOTE_SHIFT, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Note Shift"), PROLL_SHRT, "midi_note_shift"); + defShrt(SHRT_MOVE_CLOCK, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Move Clock"), PROLL_SHRT, "midi_move_clock"); + defShrt(SHRT_COPY_MEASURE, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Copy Measure"), PROLL_SHRT, "midi_copy_measure"); + defShrt(SHRT_ERASE_MEASURE, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Erase Measure"), PROLL_SHRT,"midi_erase_measure"); + defShrt(SHRT_DELETE_MEASURE, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Delete Measure"), PROLL_SHRT, "midi_delete_measure"); + defShrt(SHRT_CREATE_MEASURE, 0, QT_TRANSLATE_NOOP("shortcuts", "Edit: Create Measure"), PROLL_SHRT, "midi_create_measure"); + defShrt(SHRT_EVENT_COLOR, Qt::Key_E, QT_TRANSLATE_NOOP("shortcuts", "Edit: Change Event Color"), PROLL_SHRT, "change_event_color"); // Shortcuts for tools // global - defShrt(SHRT_TOOL_POINTER, Qt::Key_A, "Tool: Pointer", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "pointer_tool"); - defShrt(SHRT_TOOL_PENCIL, Qt::Key_D, "Tool: Pencil", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "pencil_tool"); - defShrt(SHRT_TOOL_RUBBER, Qt::Key_R, "Tool: Eraser", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "eraser_tool"); + defShrt(SHRT_TOOL_POINTER, Qt::Key_A, QT_TRANSLATE_NOOP("shortcuts", "Tool: Pointer"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "pointer_tool"); + defShrt(SHRT_TOOL_PENCIL, Qt::Key_D, QT_TRANSLATE_NOOP("shortcuts", "Tool: Pencil"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "pencil_tool"); + defShrt(SHRT_TOOL_RUBBER, Qt::Key_R, QT_TRANSLATE_NOOP("shortcuts", "Tool: Eraser"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "eraser_tool"); // piano roll & drum editor - defShrt(SHRT_TOOL_LINEDRAW, Qt::Key_F, "Tool: Line Draw", ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "line_draw_tool"); + defShrt(SHRT_TOOL_LINEDRAW, Qt::Key_F, QT_TRANSLATE_NOOP("shortcuts", "Tool: Line Draw"), ARRANG_SHRT + PROLL_SHRT + DEDIT_SHRT, "line_draw_tool"); // drum editor - defShrt(SHRT_TOOL_CURSOR, Qt::Key_U, "Tool: Cursor", DEDIT_SHRT, "cursor_tool"); - defShrt(SHRT_ADDNOTE_1, Qt::Key_V, "Add note velocity 1", DEDIT_SHRT, "add_note_velocity_1"); - defShrt(SHRT_ADDNOTE_2, Qt::Key_B, "Add note velocity 2", DEDIT_SHRT, "add_note_velocity_2"); - defShrt(SHRT_ADDNOTE_3, Qt::Key_N, "Add note velocity 3", DEDIT_SHRT, "add_note_velocity_3"); - defShrt(SHRT_ADDNOTE_4, Qt::Key_M, "Add note velocity 4", DEDIT_SHRT, "add_note_velocity_4"); + defShrt(SHRT_TOOL_CURSOR, Qt::Key_U, QT_TRANSLATE_NOOP("shortcuts", "Tool: Cursor"), DEDIT_SHRT, "cursor_tool"); + defShrt(SHRT_ADDNOTE_1, Qt::Key_V, QT_TRANSLATE_NOOP("shortcuts", "Add note velocity 1"), DEDIT_SHRT, "add_note_velocity_1"); + defShrt(SHRT_ADDNOTE_2, Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Add note velocity 2"), DEDIT_SHRT, "add_note_velocity_2"); + defShrt(SHRT_ADDNOTE_3, Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Add note velocity 3"), DEDIT_SHRT, "add_note_velocity_3"); + defShrt(SHRT_ADDNOTE_4, Qt::Key_M, QT_TRANSLATE_NOOP("shortcuts", "Add note velocity 4"), DEDIT_SHRT, "add_note_velocity_4"); - defShrt(SHRT_CURSOR_STEP_UP, Qt::Key_0, "Cursor step size: larger", DEDIT_SHRT, "cursor_step_up"); - defShrt(SHRT_CURSOR_STEP_DOWN, Qt::Key_9, "Cursor step size: smaller", DEDIT_SHRT, "cursor_step_down"); - defShrt(SHRT_INSTRUMENT_STEP_UP, Qt::Key_Up, "Instrument/Cursor up", DEDIT_SHRT, "instrument_up"); - defShrt(SHRT_INSTRUMENT_STEP_DOWN, Qt::Key_Down, "Instrument/Cursor down", DEDIT_SHRT, "instrument_down"); + defShrt(SHRT_CURSOR_STEP_UP, Qt::Key_0, QT_TRANSLATE_NOOP("shortcuts", "Cursor step size: larger"), DEDIT_SHRT, "cursor_step_up"); + defShrt(SHRT_CURSOR_STEP_DOWN, Qt::Key_9, QT_TRANSLATE_NOOP("shortcuts", "Cursor step size: smaller"), DEDIT_SHRT, "cursor_step_down"); + defShrt(SHRT_INSTRUMENT_STEP_UP, Qt::Key_Up, QT_TRANSLATE_NOOP("shortcuts", "Instrument/Cursor up"), DEDIT_SHRT, "instrument_up"); + defShrt(SHRT_INSTRUMENT_STEP_DOWN, Qt::Key_Down, QT_TRANSLATE_NOOP("shortcuts", "Instrument/Cursor down"), DEDIT_SHRT, "instrument_down"); // arranger - defShrt(SHRT_TOOL_SCISSORS, Qt::Key_S, "Tool: Scissor", ARRANG_SHRT, "scissor_tool"); - defShrt(SHRT_TOOL_GLUE, Qt::Key_G, "Tool: Glue", ARRANG_SHRT, "glue_tool"); - defShrt(SHRT_TOOL_MUTE, 0, "Tool: Mute", ARRANG_SHRT, "mute_tool"); + defShrt(SHRT_TOOL_SCISSORS, Qt::Key_S, QT_TRANSLATE_NOOP("shortcuts", "Tool: Scissor"), ARRANG_SHRT, "scissor_tool"); + defShrt(SHRT_TOOL_GLUE, Qt::Key_G, QT_TRANSLATE_NOOP("shortcuts", "Tool: Glue"), ARRANG_SHRT, "glue_tool"); + defShrt(SHRT_TOOL_MUTE, 0, QT_TRANSLATE_NOOP("shortcuts", "Tool: Mute"), ARRANG_SHRT, "mute_tool"); //Increase/decrease current position, is going to be in arranger & drumeditor as well // p4.0.10 Editors and arranger handle these by themselves, otherwise global handler will now use them, too. - defShrt(SHRT_POS_INC, Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase"); - defShrt(SHRT_POS_DEC, Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease"); + defShrt(SHRT_POS_INC, Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase"); + defShrt(SHRT_POS_DEC, Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease"); - defShrt(SHRT_POS_INC_NOSNAP, Qt::SHIFT + Qt::Key_Plus, "Transport: Increase current position, no snap", GLOBAL_SHRT, "curpos_increase_nosnap"); - defShrt(SHRT_POS_DEC_NOSNAP, Qt::SHIFT + Qt::Key_Minus, "Transport: Decrease current position, no snap", GLOBAL_SHRT, "curpos_decrease_nosnap"); + defShrt(SHRT_POS_INC_NOSNAP, Qt::SHIFT + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position, no snap"), GLOBAL_SHRT, "curpos_increase_nosnap"); + defShrt(SHRT_POS_DEC_NOSNAP, Qt::SHIFT + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position, no snap"), GLOBAL_SHRT, "curpos_decrease_nosnap"); /* - defShrt(SHRT_POS_INC_BAR, Qt::CTRL + Qt::ALT + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_bar"); - defShrt(SHRT_POS_DEC_BAR, Qt::CTRL + Qt::ALT + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_bar"); - defShrt(SHRT_POS_INC_BAR_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::ALT + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_bar_nosnap"); - defShrt(SHRT_POS_DEC_BAR_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::ALT + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_bar_nosnap"); + defShrt(SHRT_POS_INC_BAR, Qt::CTRL + Qt::ALT + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_bar"); + defShrt(SHRT_POS_DEC_BAR, Qt::CTRL + Qt::ALT + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_bar"); + defShrt(SHRT_POS_INC_BAR_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::ALT + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_bar_nosnap"); + defShrt(SHRT_POS_DEC_BAR_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::ALT + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_bar_nosnap"); - defShrt(SHRT_POS_INC_BEAT, Qt::ALT + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_beat"); - defShrt(SHRT_POS_DEC_BEAT, Qt::ALT + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_beat"); - defShrt(SHRT_POS_INC_BEAT_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_beat_nosnap"); - defShrt(SHRT_POS_DEC_BEAT_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_beat_nosnap"); + defShrt(SHRT_POS_INC_BEAT, Qt::ALT + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_beat"); + defShrt(SHRT_POS_DEC_BEAT, Qt::ALT + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_beat"); + defShrt(SHRT_POS_INC_BEAT_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_beat_nosnap"); + defShrt(SHRT_POS_DEC_BEAT_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_beat_nosnap"); - defShrt(SHRT_POS_INC_TICK, Qt::CTRL + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_tick"); - defShrt(SHRT_POS_DEC_TICK, Qt::CTRL + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_tick"); - defShrt(SHRT_POS_INC_TICK_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_Plus, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_tick"); - defShrt(SHRT_POS_DEC_TICK_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_Minus, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_tick"); + defShrt(SHRT_POS_INC_TICK, Qt::CTRL + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_tick"); + defShrt(SHRT_POS_DEC_TICK, Qt::CTRL + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_tick"); + defShrt(SHRT_POS_INC_TICK_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_Plus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_tick"); + defShrt(SHRT_POS_DEC_TICK_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_Minus, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_tick"); - defShrt(SHRT_POS_INC_FRAME, Qt::Key_N, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_frame"); - defShrt(SHRT_POS_DEC_FRAME, Qt::Key_B, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_frame"); + defShrt(SHRT_POS_INC_FRAME, Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_frame"); + defShrt(SHRT_POS_DEC_FRAME, Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_frame"); - defShrt(SHRT_POS_INC_SECOND, Qt::CTRL + Qt::Key_N, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_second"); - defShrt(SHRT_POS_DEC_SECOND, Qt::CTRL + Qt::Key_B, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_second"); - defShrt(SHRT_POS_INC_SECOND_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_N, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_second_nosnap"); - defShrt(SHRT_POS_DEC_SECOND_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_B, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_second_nosnap"); + defShrt(SHRT_POS_INC_SECOND, Qt::CTRL + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_second"); + defShrt(SHRT_POS_DEC_SECOND, Qt::CTRL + Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_second"); + defShrt(SHRT_POS_INC_SECOND_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_second_nosnap"); + defShrt(SHRT_POS_DEC_SECOND_NOSNAP, Qt::SHIFT + Qt::CTRL + Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_second_nosnap"); - defShrt(SHRT_POS_INC_MINUTE, Qt::ALT + Qt::Key_N, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_minute"); - defShrt(SHRT_POS_DEC_MINUTE, Qt::ALT + Qt::Key_B, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_minute"); - defShrt(SHRT_POS_INC_MINUTE_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_N, "Transport: Increase current position", GLOBAL_SHRT, "curpos_increase_minute_nosnap"); - defShrt(SHRT_POS_DEC_MINUTE_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_B, "Transport: Decrease current position", GLOBAL_SHRT, "curpos_decrease_minute_nosnap"); + defShrt(SHRT_POS_INC_MINUTE, Qt::ALT + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_minute"); + defShrt(SHRT_POS_DEC_MINUTE, Qt::ALT + Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_minute"); + defShrt(SHRT_POS_INC_MINUTE_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Transport: Increase current position"), GLOBAL_SHRT, "curpos_increase_minute_nosnap"); + defShrt(SHRT_POS_DEC_MINUTE_NOSNAP, Qt::SHIFT + Qt::ALT + Qt::Key_B, QT_TRANSLATE_NOOP("shortcuts", "Transport: Decrease current position"), GLOBAL_SHRT, "curpos_decrease_minute_nosnap"); */ - defShrt(SHRT_SET_QUANT_1, Qt::Key_1, "Quantize: Set quantize to 1/1 note", PROLL_SHRT, "midi_quant_1"); - defShrt(SHRT_SET_QUANT_2, Qt::Key_2, "Quantize: Set quantize to 1/2 note", PROLL_SHRT, "midi_quant_2"); - defShrt(SHRT_SET_QUANT_3, Qt::Key_3, "Quantize: Set quantize to 1/4 note", PROLL_SHRT, "midi_quant_3"); - defShrt(SHRT_SET_QUANT_4, Qt::Key_4, "Quantize: Set quantize to 1/8 note", PROLL_SHRT, "midi_quant_4"); - defShrt(SHRT_SET_QUANT_5, Qt::Key_5, "Quantize: Set quantize to 1/16 note", PROLL_SHRT, "midi_quant_5"); - defShrt(SHRT_SET_QUANT_6, Qt::Key_6, "Quantize: Set quantize to 1/32 note", PROLL_SHRT, "midi_quant_6"); - defShrt(SHRT_SET_QUANT_7, Qt::Key_7, "Quantize: Set quantize to 1/64 note", PROLL_SHRT, "midi_quant_7"); - - defShrt(SHRT_TOGGLE_TRIOL, Qt::Key_T, "Quantize: Toggle triol quantization", PROLL_SHRT, "midi_quant_triol"); - defShrt(SHRT_TOGGLE_PUNCT, Qt::Key_Period, "Quantize: Toggle punctuation quantization", PROLL_SHRT, "midi_quant_punct"); - defShrt(SHRT_TOGGLE_PUNCT2, Qt::Key_Comma, "Quantize: Toggle punctuation quantization (2)", PROLL_SHRT, "midi_quant_punct2"); - defShrt(SHRT_INSERT_AT_LOCATION, Qt::SHIFT + Qt::Key_Right, "Edit: Insert at location", PROLL_SHRT, "midi_insert_at_loc"); - - defShrt(SHRT_INCREASE_LEN, Qt::CTRL + Qt::SHIFT + Qt::Key_Right, "Edit: Increase length", PROLL_SHRT, "increase_len"); - defShrt(SHRT_DECREASE_LEN, Qt::CTRL + Qt::SHIFT + Qt::Key_Left, "Edit: Decrease length", PROLL_SHRT, "decrease_len"); + defShrt(SHRT_SET_QUANT_1, Qt::Key_1, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/1 note"), PROLL_SHRT, "midi_quant_1"); + defShrt(SHRT_SET_QUANT_2, Qt::Key_2, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/2 note"), PROLL_SHRT, "midi_quant_2"); + defShrt(SHRT_SET_QUANT_3, Qt::Key_3, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/4 note"), PROLL_SHRT, "midi_quant_3"); + defShrt(SHRT_SET_QUANT_4, Qt::Key_4, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/8 note"), PROLL_SHRT, "midi_quant_4"); + defShrt(SHRT_SET_QUANT_5, Qt::Key_5, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/16 note"), PROLL_SHRT, "midi_quant_5"); + defShrt(SHRT_SET_QUANT_6, Qt::Key_6, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/32 note"), PROLL_SHRT, "midi_quant_6"); + defShrt(SHRT_SET_QUANT_7, Qt::Key_7, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Set quantize to 1/64 note"), PROLL_SHRT, "midi_quant_7"); + + defShrt(SHRT_TOGGLE_TRIOL, Qt::Key_T, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Toggle triol quantization"), PROLL_SHRT, "midi_quant_triol"); + defShrt(SHRT_TOGGLE_PUNCT, Qt::Key_Period, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Toggle punctuation quantization"), PROLL_SHRT, "midi_quant_punct"); + defShrt(SHRT_TOGGLE_PUNCT2, Qt::Key_Comma, QT_TRANSLATE_NOOP("shortcuts", "Quantize: Toggle punctuation quantization (2)"), PROLL_SHRT, "midi_quant_punct2"); + defShrt(SHRT_INSERT_AT_LOCATION, Qt::SHIFT + Qt::Key_Right, QT_TRANSLATE_NOOP("shortcuts", "Edit: Insert at location"), PROLL_SHRT, "midi_insert_at_loc"); + + defShrt(SHRT_INCREASE_LEN, Qt::CTRL + Qt::SHIFT + Qt::Key_Right, QT_TRANSLATE_NOOP("shortcuts", "Edit: Increase length"), PROLL_SHRT, "increase_len"); + defShrt(SHRT_DECREASE_LEN, Qt::CTRL + Qt::SHIFT + Qt::Key_Left, QT_TRANSLATE_NOOP("shortcuts", "Edit: Decrease length"), PROLL_SHRT, "decrease_len"); //----------------------------------------------------------- // List edit: //----------------------------------------------------------- - defShrt(SHRT_LE_INS_NOTES, Qt::CTRL + Qt::Key_N, "Insert Note", LEDIT_SHRT, "le_ins_note"); - defShrt(SHRT_LE_INS_SYSEX, Qt::CTRL + Qt::Key_S, "Insert SysEx", LEDIT_SHRT, "le_ins_sysex"); - defShrt(SHRT_LE_INS_CTRL, Qt::CTRL + Qt::Key_T, "Insert Ctrl", LEDIT_SHRT, "le_ins_ctrl"); - defShrt(SHRT_LE_INS_META, 0, "Insert Meta", LEDIT_SHRT, "le_ins_meta"); - defShrt(SHRT_LE_INS_CHAN_AFTERTOUCH, Qt::CTRL + Qt::Key_A, "Insert Channel Aftertouch", LEDIT_SHRT, "le_ins_afttouch"); - defShrt(SHRT_LE_INS_POLY_AFTERTOUCH, Qt::CTRL + Qt::Key_P, "Insert Key Aftertouch", LEDIT_SHRT, "le_ins_poly"); + defShrt(SHRT_LE_INS_NOTES, Qt::CTRL + Qt::Key_N, QT_TRANSLATE_NOOP("shortcuts", "Insert Note"), LEDIT_SHRT, "le_ins_note"); + defShrt(SHRT_LE_INS_SYSEX, Qt::CTRL + Qt::Key_S, QT_TRANSLATE_NOOP("shortcuts", "Insert SysEx"), LEDIT_SHRT, "le_ins_sysex"); + defShrt(SHRT_LE_INS_CTRL, Qt::CTRL + Qt::Key_T, QT_TRANSLATE_NOOP("shortcuts", "Insert Ctrl"), LEDIT_SHRT, "le_ins_ctrl"); + defShrt(SHRT_LE_INS_META, 0, QT_TRANSLATE_NOOP("shortcuts", "Insert Meta"), LEDIT_SHRT, "le_ins_meta"); + defShrt(SHRT_LE_INS_CHAN_AFTERTOUCH, Qt::CTRL + Qt::Key_A, QT_TRANSLATE_NOOP("shortcuts", "Insert Channel Aftertouch"), LEDIT_SHRT, "le_ins_afttouch"); + defShrt(SHRT_LE_INS_POLY_AFTERTOUCH, Qt::CTRL + Qt::Key_P, QT_TRANSLATE_NOOP("shortcuts", "Insert Key Aftertouch"), LEDIT_SHRT, "le_ins_poly"); //----------------------------------------------------------- // List masteredit: //----------------------------------------------------------- - defShrt(SHRT_LM_INS_TEMPO, Qt::CTRL + Qt::Key_T, "Insert Tempo", LMEDIT_SHRT, "lm_ins_tempo"); - defShrt(SHRT_LM_INS_SIG , Qt::CTRL + Qt::Key_R, "Insert Signature", LMEDIT_SHRT, "lm_ins_sig"); - defShrt(SHRT_LM_EDIT_BEAT, Qt::CTRL + Qt::SHIFT+ Qt::Key_E, "Change Event Position", LMEDIT_SHRT, "lm_edit_beat"); - defShrt(SHRT_LM_EDIT_VALUE, Qt::CTRL + Qt::Key_E, "Edit Event Value", LMEDIT_SHRT, "lm_edit_val"); - defShrt(SHRT_LM_INS_KEY, Qt::CTRL + Qt::Key_K, "Insert Key", LMEDIT_SHRT, "lm_ins_key"); - - defShrt(SHRT_NEXT_MARKER, Qt::Key_F6, "Goto Next Marker", ARRANG_SHRT, "me_sel_next"); - defShrt(SHRT_PREV_MARKER, Qt::Key_F5, "Goto Prev Marker", ARRANG_SHRT, "me_sel_prev"); + defShrt(SHRT_LM_INS_TEMPO, Qt::CTRL + Qt::Key_T, QT_TRANSLATE_NOOP("shortcuts", "Insert Tempo"), LMEDIT_SHRT, "lm_ins_tempo"); + defShrt(SHRT_LM_INS_SIG , Qt::CTRL + Qt::Key_R, QT_TRANSLATE_NOOP("shortcuts", "Insert Signature"), LMEDIT_SHRT, "lm_ins_sig"); + defShrt(SHRT_LM_EDIT_BEAT, Qt::CTRL + Qt::SHIFT+ Qt::Key_E, QT_TRANSLATE_NOOP("shortcuts", "Change Event Position"), LMEDIT_SHRT, "lm_edit_beat"); + defShrt(SHRT_LM_EDIT_VALUE, Qt::CTRL + Qt::Key_E, QT_TRANSLATE_NOOP("shortcuts", "Edit Event Value"), LMEDIT_SHRT, "lm_edit_val"); + defShrt(SHRT_LM_INS_KEY, Qt::CTRL + Qt::Key_K, QT_TRANSLATE_NOOP("shortcuts", "Insert Key"), LMEDIT_SHRT, "lm_ins_key"); + + defShrt(SHRT_NEXT_MARKER, Qt::Key_F6, QT_TRANSLATE_NOOP("shortcuts", "Goto Next Marker"), ARRANG_SHRT, "me_sel_next"); + defShrt(SHRT_PREV_MARKER, Qt::Key_F5, QT_TRANSLATE_NOOP("shortcuts", "Goto Prev Marker"), ARRANG_SHRT, "me_sel_prev"); } diff --git a/muse2/muse/sig.cpp b/muse2/muse/sig.cpp index 0b62848c..b11aa622 100644 --- a/muse2/muse/sig.cpp +++ b/muse2/muse/sig.cpp @@ -22,7 +22,6 @@ //========================================================= #include <stdio.h> -#include <assert.h> #include "sig.h" #include "gconfig.h" #include "xml.h" @@ -51,14 +50,18 @@ SigList::SigList() void SigList::add(unsigned tick, int z, int n) { if (z == 0 || n == 0) { - printf("SigList::add illegal signature %d/%d\n", z, n); + printf("THIS SHOULD NEVER HAPPEN: SigList::add() illegal signature %d/%d\n", z, n); // Added p3.3.43 return; } tick = raster1(tick, 0); iSigEvent e = upper_bound(tick); - assert(e != end()); + if (e == end()) + { + printf("THIS SHOULD NEVER HAPPEN: could not find upper_bound(%i) in SigList::add()!\n", tick); + return; + } if (tick == e->second->tick) { e->second->z = z; @@ -185,7 +188,11 @@ int SigList::ticksMeasure(unsigned tick) const int SigList::ticksBeat(unsigned tick) const { ciSigEvent i = upper_bound(tick); - assert(i != end()); + if (i == end()) + { + printf("THIS SHOULD NEVER HAPPEN: couldn't find sig event for tick=%i in SigList::ticksBeat()!\n",tick); + return 0; + } return ticks_beat(i->second->n); } @@ -202,7 +209,7 @@ int SigList::ticks_beat(int n) const case 32: m >>= 3; break; // 48 case 64: m >>= 4; break; // 24 case 128: m >>= 5; break; // 12 - default: assert(false); break; + default: printf("THIS SHOULD NEVER HAPPEN: invalid function call in SigList::ticks_beat(): n=%i\n",n); break; } return m; } @@ -308,7 +315,11 @@ unsigned SigList::raster1(unsigned t, int raster) const if (raster == 1) return t; ciSigEvent e = upper_bound(t); - assert(e != end()); + if (e == end()) + { + printf("THIS SHOULD NEVER HAPPEN: couldn't find sig event for tick=%i in SigList::raster1()!\n", t); + return 0; + } int delta = t - e->second->tick; int ticksM = ticks_beat(e->second->n) * e->second->z; @@ -329,7 +340,11 @@ unsigned SigList::raster2(unsigned t, int raster) const if (raster == 1) return t; ciSigEvent e = upper_bound(t); - assert(e != end()); + if (e == end()) + { + printf("THIS SHOULD NEVER HAPPEN: couldn't find sig event for tick=%i in SigList::raster2()!\n", t); + return 0; + } int delta = t - e->second->tick; int ticksM = ticks_beat(e->second->n) * e->second->z; @@ -348,7 +363,11 @@ int SigList::rasterStep(unsigned t, int raster) const { if (raster == 0) { ciSigEvent e = upper_bound(t); - assert(e != end()); + if (e == end()) + { + printf("THIS SHOULD NEVER HAPPEN: couldn't find sig event for tick=%i in SigList::rasterStep()!\n", t); + return 0; + } return ticks_beat(e->second->n) * e->second->z; } return raster; diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index b48f134b..484e2d42 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -72,26 +72,6 @@ namespace MusECore { extern void clearMidiTransforms(); extern void clearMidiInputTransforms(); -/* -//--------------------------------------------------------- -// RoutingMenuItem -//--------------------------------------------------------- - -class RoutingMenuItem : public QCustomMenuItem -{ - Route route; - //virtual QSize sizeHint() { return QSize(80, h); } - virtual void paint(QPainter* p, const QColorGroup&, bool, bool, int x, int y, int w, int h) - { - p->fillRect(x, y, w, h, QBrush(lightGray)); - p->drawText(x, y, w, h, AlignCenter, route.name()); - } - - public: - RoutingMenuItem(const Route& r) : route(r) { } -}; -*/ - //--------------------------------------------------------- // Song //--------------------------------------------------------- @@ -108,6 +88,8 @@ Song::Song(const char* name) redoList = new UndoList; _markerList = new MarkerList; _globalPitchShift = 0; + bounceTrack = NULL; + bounceOutput = NULL; showSongInfo=true; clear(false); } @@ -174,6 +156,7 @@ void Song::setSig(const AL::TimeSignature& sig) Track* Song::addNewTrack(QAction* action, Track* insertAt) { +printf("Song::addNewTrack\n"); int n = action->data().toInt(); // Ignore negative numbers since this slot could be called by a menu or list etc. passing -1. if(n < 0) @@ -183,13 +166,20 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt) if(n >= MENU_ADD_SYNTH_ID_BASE) { n -= MENU_ADD_SYNTH_ID_BASE; + int ntype = n / MENU_ADD_SYNTH_ID_BASE; + if(ntype >= Synth::SYNTH_TYPE_END) + return 0; + + n %= MENU_ADD_SYNTH_ID_BASE; if(n >= (int)MusEGlobal::synthis.size()) return 0; - SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->name(), insertAt); + //printf("Song::addNewTrack synth: type:%d idx:%d class:%s label:%s\n", ntype, n, MusEGlobal::synthis[n]->baseName().toLatin1().constData(), MusEGlobal::synthis[n]->name().toLatin1().constData()); + SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->name(), (Synth::Type)ntype, insertAt); if(!si) return 0; - + if (MusEGlobal::config.unhideTracks) SynthI::setVisible(true); + // Add instance last in midi device list. for (int i = 0; i < MIDI_PORTS; ++i) { @@ -199,15 +189,19 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt) { MusEGlobal::midiSeq->msgSetMidiDevice(port, si); MusEGlobal::muse->changeConfig(true); // save configuration file - deselectTracks(); - si->setSelected(true); - update(); + if (SynthI::visible()) { + deselectTracks(); + si->setSelected(true); + update(); + } return si; } } - deselectTracks(); - si->setSelected(true); - update(SC_SELECTION); + if (SynthI::visible()) { + deselectTracks(); + si->setSelected(true); + update(SC_SELECTION); + } return si; } // Normal track. @@ -218,10 +212,14 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt) if((Track::TrackType)n >= Track::AUDIO_SOFTSYNTH) return 0; - Track* t = addTrack((Track::TrackType)n, insertAt); - deselectTracks(); - t->setSelected(true); - update(SC_SELECTION); + Undo operations; + Track* t = addTrack(operations, (Track::TrackType)n, insertAt); + applyOperationGroup(operations); + if (t->isVisible()) { + deselectTracks(); + t->setSelected(true); + update(SC_SELECTION); + } return t; } } @@ -234,14 +232,16 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt) // If insertAt is valid, inserts before insertAt. Else at the end after all tracks. //--------------------------------------------------------- -Track* Song::addTrack(Track::TrackType type, Track* insertAt) +Track* Song::addTrack(Undo& operations, Track::TrackType type, Track* insertAt) { + printf("Song::addTrack\n"); Track* track = 0; int lastAuxIdx = _auxs.size(); switch(type) { case Track::MIDI: track = new MidiTrack(); track->setType(Track::MIDI); + if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true); break; case Track::NEW_DRUM: track = new MidiTrack(); @@ -252,40 +252,48 @@ Track* Song::addTrack(Track::TrackType type, Track* insertAt) track = new MidiTrack(); track->setType(Track::DRUM); ((MidiTrack*)track)->setOutChannel(9); + if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true); break; case Track::WAVE: track = new MusECore::WaveTrack(); ((AudioTrack*)track)->addAuxSend(lastAuxIdx); + if (MusEGlobal::config.unhideTracks) WaveTrack::setVisible(true); break; case Track::AUDIO_OUTPUT: track = new AudioOutput(); + if (MusEGlobal::config.unhideTracks) AudioOutput::setVisible(true); break; case Track::AUDIO_GROUP: track = new AudioGroup(); ((AudioTrack*)track)->addAuxSend(lastAuxIdx); + if (MusEGlobal::config.unhideTracks) AudioGroup::setVisible(true); break; case Track::AUDIO_AUX: track = new AudioAux(); + if (MusEGlobal::config.unhideTracks) AudioAux::setVisible(true); break; case Track::AUDIO_INPUT: track = new AudioInput(); ((AudioTrack*)track)->addAuxSend(lastAuxIdx); + if (MusEGlobal::config.unhideTracks) AudioInput::setVisible(true); break; case Track::AUDIO_SOFTSYNTH: printf("not implemented: Song::addTrack(SOFTSYNTH)\n"); // ((AudioTrack*)track)->addAuxSend(lastAuxIdx); break; default: - printf("Song::addTrack() illegal type %d\n", type); - abort(); + printf("THIS SHOULD NEVER HAPPEN: Song::addTrack() illegal type %d. returning NULL.\n" + "save your work if you can and expect soon crashes!\n", type); + return NULL; } track->setDefaultName(); int idx = insertAt ? _tracks.index(insertAt) : -1; - insertTrack1(track, idx); - msgInsertTrack(track, idx, true); - insertTrack3(track, idx); + // insertTrack1(track, idx); // this and the below are replaced + // msgInsertTrack(track, idx, true); // by the UndoOp-operation + // insertTrack3(track, idx); // does nothing + operations.push_back(UndoOp(UndoOp::AddTrack, idx, track)); // Add default track <-> midiport routes. if(track->isMidiTrack()) @@ -436,45 +444,6 @@ void Song::changeTrack(Track* oldTrack, Track* newTrack) bool Song::addEvent(Event& event, Part* part) { - /* - if (event.type() == Controller) { - MidiTrack* track = (MidiTrack*)part->track(); - int ch = track->outChannel(); - int tick = event.tick() + part->tick(); - int cntrl = event.dataA(); - int val = event.dataB(); - MidiPort* mp = &MusEGlobal::midiPorts[track->outPort()]; - - // Is it a drum controller event, according to the track port's instrument? - if(track->type() == Track::DRUM) - { - MidiController* mc = mp->drumController(cntrl); - if(mc) - { - int note = cntrl & 0x7f; - cntrl &= ~0xff; - ch = MusEGlobal::drumMap[note].channel; - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; - cntrl |= MusEGlobal::drumMap[note].anote; - } - } - - // Changed by T356. - //if (!mp->setCtrl(ch, tick, cntrl, val)) { - // mp->addManagedController(ch, cntrl); - // if (!mp->setCtrl(ch, tick, cntrl, val)) - // return false; - // } - // Changed again. Don't depend on return value of this - search for the event, below. - //if(!mp->setControllerVal(ch, tick, cntrl, val, part)) - // return false; - if(mp->setControllerVal(ch, tick, cntrl, val, part)) - updateFlags |= SC_MIDI_CONTROLLER; - } - */ - - //addPortCtrlEvents(event, part); - // Return false if the event is already found. // (But allow a port controller value, above, in case it is not already stored.) if(part->events()->find(event) != part->events()->end()) @@ -501,7 +470,6 @@ void Song::changeEvent(Event& oldEvent, Event& newEvent, Part* part) // This can be normal for some (redundant) operations. if(MusEGlobal::debugMsg) printf("Song::changeEvent event not found in part:%s size:%zd\n", part->name().toLatin1().constData(), part->events()->size()); - // abort(); // Removed by T356. Allow it to add the new event. // (And remove the old one from the midi port controller!) //return; @@ -510,59 +478,6 @@ void Song::changeEvent(Event& oldEvent, Event& newEvent, Part* part) part->events()->erase(i); part->events()->add(newEvent); - - /* - if (oldEvent.type() == Controller) { - MidiTrack* track = (MidiTrack*)part->track(); - int ch = track->outChannel(); - int tick = oldEvent.tick() + part->tick(); - int cntrl = oldEvent.dataA(); - MidiPort* mp = &MusEGlobal::midiPorts[track->outPort()]; - // Is it a drum controller event, according to the track port's instrument? - if(track->type() == Track::DRUM) - { - MidiController* mc = mp->drumController(cntrl); - if(mc) - { - int note = cntrl & 0x7f; - cntrl &= ~0xff; - ch = MusEGlobal::drumMap[note].channel; - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; - cntrl |= MusEGlobal::drumMap[note].anote; - } - } - - mp->deleteController(ch, tick, cntrl, part); - } - */ - //removePortCtrlEvents(oldEvent, part); - - /* - if (newEvent.type() == Controller) { - MidiTrack* track = (MidiTrack*)part->track(); - int ch = track->outChannel(); - int tick = newEvent.tick() + part->tick(); - int cntrl = newEvent.dataA(); - int val = newEvent.dataB(); - MidiPort* mp = &MusEGlobal::midiPorts[track->outPort()]; - // Is it a drum controller event, according to the track port's instrument? - if(track->type() == Track::DRUM) - { - MidiController* mc = mp->drumController(cntrl); - if(mc) - { - int note = cntrl & 0x7f; - cntrl &= ~0xff; - ch = MusEGlobal::drumMap[note].channel; - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; - cntrl |= MusEGlobal::drumMap[note].anote; - } - } - - mp->setControllerVal(ch, tick, cntrl, val, part); - } - */ - //addPortCtrlEvents(newEvent, part); } //--------------------------------------------------------- @@ -571,33 +486,6 @@ void Song::changeEvent(Event& oldEvent, Event& newEvent, Part* part) void Song::deleteEvent(Event& event, Part* part) { - /* - if (event.type() == Controller) { - MidiTrack* track = (MidiTrack*)part->track(); - int ch = track->outChannel(); - int tick = event.tick() + part->tick(); - int cntrl = event.dataA(); - - MidiPort* mp = &MusEGlobal::midiPorts[track->outPort()]; - // Is it a drum controller event, according to the track port's instrument? - if(track->type() == Track::DRUM) - { - MidiController* mc = mp->drumController(cntrl); - if(mc) - { - int note = cntrl & 0x7f; - cntrl &= ~0xff; - ch = MusEGlobal::drumMap[note].channel; - mp = &MusEGlobal::midiPorts[MusEGlobal::drumMap[note].port]; - cntrl |= MusEGlobal::drumMap[note].anote; - } - } - - mp->deleteController(ch, tick, cntrl, part); - } - */ - //removePortCtrlEvents(event, part); - iEvent ev = part->events()->find(event); if (ev == part->events()->end()) { // This can be normal for some (redundant) operations. @@ -944,88 +832,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start // Add the event to the new part's port controller values, and do all clone parts. addPortCtrlEvents(event, newPart, true); } - - - /* - if (_recMode == REC_REPLACE) - { - iEvent si = part->events()->lower_bound(startTick - part->tick()); - iEvent ei = part->events()->lower_bound(part->endTick() - part->tick()); - - for (iEvent i = si; i != ei; ++i) - { - Event event = i->second; - // Create an undo op. Indicate do port controller values and clone parts. - //addUndo(UndoOp(UndoOp::DeleteEvent, event, part)); - addUndo(UndoOp(UndoOp::DeleteEvent, event, part, true, true)); - - //if (event.type() == Controller) { - // MidiTrack* track = (MidiTrack*)part->track(); - // int ch = track->outChannel(); - // int tick = event.tick() + part->tick(); - // int cntrl = event.dataA(); - // MusEGlobal::midiPorts[track->outPort()].deleteController(ch, tick, cntrl, part); - // } - - // Remove the event from the part's port controller values, and do all clone parts. - //removePortCtrlEvents(event, part, true); - } - part->events()->erase(si, ei); - } - - // Remove all of the part's port controller values, and do all clone parts. - removePortCtrlEvents(part, true); - - // Clone the part. This doesn't increment aref count, and doesn't chain clones. - // It also gives the new part a new serial number, but it is - // overwritten with the old one by Song::changePart(), below. - Part* newPart = part->clone(); - - endTick = 0; - for (iEvent i = s; i != e; ++i) { - Event event = i->second; - unsigned tick = event.tick() - partTick; - event.setTick(tick); - Event e; - // Create an undo op. Indicate do port controller values and clone parts. - //addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart)); - addUndo(UndoOp(UndoOp::AddEvent, e, event, newPart, true, true)); - - // addEvent also adds port controller values. So does msgChangePart, below. Let msgChangePart handle them. - //addEvent(event, (MidiPart*)newPart); - if(newPart->events()->find(event) == newPart->events()->end()) - newPart->events()->add(event); - - if (endTick < event.tick() + event.lenTick()) - endTick = event.tick() + event.lenTick(); - } - newPart->setLenTick(endTick); // endTick - part->tick() - - //printf("Song::cmdAddRecordedEvents before changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount()); - - // Change the part. - changePart(part, newPart); - // Manually adjust reference counts. - part->events()->incARef(-1); - newPart->events()->incARef(1); - // Replace the part in the clone chain with the new part. - replaceClone(part, newPart); - // Now add all of the new part's port controller values, and do all clone parts. - addPortCtrlEvents(newPart, true); - - //printf("Song::cmdAddRecordedEvents after changePart part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount()); - - //addUndo(UndoOp(UndoOp::ModifyPart, part, newPart)); - // Create an undo op. Indicate do not do port controller values and clone parts. - addUndo(UndoOp(UndoOp::ModifyPart, part, newPart, false, false)); - - // Removed by T356. - //part->events()->incARef(-1); - - updateFlags |= SC_PART_MODIFIED; - //printf("Song::cmdAddRecordedEvents final part:%p events:%p refs:%d Arefs:%d newPart:%p events:%p refs:%d Arefs:%d\n", part, part->events(), part->events()->refCount(), part->events()->arefCount(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount()); - */ - } else { if (_recMode == REC_REPLACE) { @@ -1037,15 +843,6 @@ void Song::cmdAddRecordedEvents(MidiTrack* mt, EventList* events, unsigned start // Create an undo op. Indicate that controller values and clone parts were handled. //addUndo(UndoOp(UndoOp::DeleteEvent, event, part)); addUndo(UndoOp(UndoOp::DeleteEvent, event, part, true, true)); - /* - if (event.type() == Controller) { - MidiTrack* track = (MidiTrack*)part->track(); - int ch = track->outChannel(); - int tick = event.tick() + part->tick(); - int cntrl = event.dataA(); - MusEGlobal::midiPorts[track->outPort()].deleteController(ch, tick, cntrl, part); - } - */ // Remove the event from the part's port controller values, and do all clone parts. removePortCtrlEvents(event, part, true); } @@ -1719,6 +1516,7 @@ void Song::setMType(MType t) void Song::beat() { #if 0 + // Just a rate test... static double _heartbeatRateTimer = 0.0; double t = MusEUtil::curTime(); if(t - _heartbeatRateTimer > 0.0) @@ -2040,14 +1838,12 @@ void Song::processMsg(AudioMsg* msg) break; case SEQM_ADD_TEMPO: - //printf("processMsg (SEQM_ADD_TEMPO) UndoOp::AddTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b)); MusEGlobal::tempomap.addTempo(msg->a, msg->b); updateFlags = SC_TEMPO; break; case SEQM_SET_TEMPO: - //printf("processMsg (SEQM_SET_TEMPO) UndoOp::AddTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b)); MusEGlobal::tempomap.setTempo(msg->a, msg->b); updateFlags = SC_TEMPO; @@ -2058,7 +1854,6 @@ void Song::processMsg(AudioMsg* msg) break; case SEQM_REMOVE_TEMPO: - //printf("processMsg (SEQM_REMOVE_TEMPO) UndoOp::DeleteTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b); addUndo(UndoOp(UndoOp::DeleteTempo, msg->a, msg->b)); MusEGlobal::tempomap.delTempo(msg->a); updateFlags = SC_TEMPO; @@ -2123,7 +1918,6 @@ void Song::cmdRemovePart(Part* part) // cmdChangePart //--------------------------------------------------------- -//void Song::cmdChangePart(Part* oldPart, Part* newPart) void Song::cmdChangePart(Part* oldPart, Part* newPart, bool doCtrls, bool doClones) { //printf("Song::cmdChangePart before changePart oldPart:%p events:%p refs:%d Arefs:%d sn:%d newPart:%p events:%p refs:%d Arefs:%d sn:%d\n", oldPart, oldPart->events(), oldPart->events()->refCount(), oldPart->events()->arefCount(), oldPart->sn(), newPart, newPart->events(), newPart->events()->refCount(), newPart->events()->arefCount(), newPart->sn()); @@ -2172,13 +1966,13 @@ void Song::panic() // If clear_all is false, it will not touch things like midi ports. //--------------------------------------------------------- -void Song::clear(bool signal, bool /*clear_all*/) +void Song::clear(bool signal, bool clear_all) { if(MusEGlobal::debugMsg) printf("Song::clear\n"); bounceTrack = 0; - + _tracks.clear(); _midis.clearDelete(); _waves.clearDelete(); @@ -2197,7 +1991,7 @@ void Song::clear(bool signal, bool /*clear_all*/) // p3.3.50 Reset this. MusEGlobal::midiPorts[i].setFoundInSongFile(false); - //if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems... + if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems... // This will also close the device. MusEGlobal::midiPorts[i].setMidiDevice(0); } @@ -2216,7 +2010,7 @@ void Song::clear(bool signal, bool /*clear_all*/) //if((*imd)->deviceType() == MidiDevice::JACK_MIDI) if(dynamic_cast< MidiJackDevice* >(*imd)) { - //if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems... + if(clear_all) // Allow not touching devices. p4.0.17 TESTING: Maybe some problems... { // Remove the device from the list. MusEGlobal::midiDevices.erase(imd); @@ -2475,7 +2269,6 @@ void Song::seqSignal(int fd) if(MusEGlobal::debugMsg) printf("Song: seqSignal: case f: setFreewheel start\n"); - // Enabled by Tim. p3.3.6 if(MusEGlobal::config.freewheelMode) MusEGlobal::audioDevice->setFreewheel(true); @@ -2485,7 +2278,6 @@ void Song::seqSignal(int fd) if(MusEGlobal::debugMsg) printf("Song: seqSignal: case F: setFreewheel stop\n"); - // Enabled by Tim. p3.3.6 if(MusEGlobal::config.freewheelMode) MusEGlobal::audioDevice->setFreewheel(false); @@ -2502,7 +2294,6 @@ void Song::seqSignal(int fd) MusEGlobal::audioDevice->graphChanged(); break; - // p3.3.37 case 'R': // Registration changed if (MusEGlobal::audioDevice) MusEGlobal::audioDevice->registrationChanged(); @@ -2593,8 +2384,7 @@ void Song::recordEvent(MidiTrack* mt, Event& event) int Song::execAutomationCtlPopup(AudioTrack* track, const QPoint& menupos, int acid) { - //enum { HEADER, SEP1, PREV_EVENT, NEXT_EVENT, SEP2, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS }; - enum { HEADER, PREV_EVENT, NEXT_EVENT, SEP2, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS }; + enum { PREV_EVENT, NEXT_EVENT, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS }; QMenu* menu = new QMenu; int count = 0; @@ -2639,14 +2429,8 @@ int Song::execAutomationCtlPopup(AudioTrack* track, const QPoint& menupos, int a } } - //menu->insertItem(tr("Automation:"), HEADER, HEADER); - //menu->setItemEnabled(HEADER, false); - //MenuTitleItem* title = new MenuTitleItem(tr("Automation:")); ddskrjo - //menu->insertItem(title, HEADER, HEADER); ddskrjo menu->addAction(new MusEGui::MenuTitleItem(tr("Automation:"), menu)); - //menu->insertSeparator(SEP1); - QAction* prevEvent = menu->addAction(tr("previous event")); prevEvent->setData(PREV_EVENT); prevEvent->setEnabled(canSeekPrev); @@ -2655,7 +2439,6 @@ int Song::execAutomationCtlPopup(AudioTrack* track, const QPoint& menupos, int a nextEvent->setData(NEXT_EVENT); nextEvent->setEnabled(canSeekNext); - //menu->insertSeparator(SEP2); menu->addSeparator(); QAction* addEvent = new QAction(menu); @@ -2738,8 +2521,8 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo if(!track && !part) return -1; - //enum { HEADER, SEP1, PREV_EVENT, NEXT_EVENT, SEP2, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS }; - enum { HEADER, ADD_EVENT, CLEAR_EVENT }; + //enum { PREV_EVENT, NEXT_EVENT, ADD_EVENT, CLEAR_EVENT, CLEAR_RANGE, CLEAR_ALL_EVENTS }; + enum { ADD_EVENT, CLEAR_EVENT }; QMenu* menu = new QMenu; //int count = 0; @@ -2825,22 +2608,8 @@ int Song::execMidiAutomationCtlPopup(MidiTrack* track, MidiPart* part, const QPo } } - - //menu->insertItem(tr("Automation:"), HEADER, HEADER); - //menu->setItemEnabled(HEADER, false); - //MenuTitleItem* title = new MenuTitleItem(tr("Automation:")); ddskrjo - ///menu->insertItem(title, HEADER, HEADER); ddskrjo - - //menu->insertSeparator(SEP1); + menu->addAction(new MusEGui::MenuTitleItem(tr("Automation:"), menu)); -// menu->insertItem(tr("previous event"), PREV_EVENT, PREV_EVENT); -// menu->setItemEnabled(PREV_EVENT, canSeekPrev); - -// menu->insertItem(tr("next event"), NEXT_EVENT, NEXT_EVENT); -// menu->setItemEnabled(NEXT_EVENT, canSeekNext); - -// menu->insertSeparator(SEP2); - QAction* addEvent = new QAction(menu); menu->addAction(addEvent); if(isEvent) @@ -3101,220 +2870,6 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect) } } -/* -//--------------------------------------------------------- -// chooseMidiRoutes -//--------------------------------------------------------- - -void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst) -{ - if(!track) - return; - - //if(!track->isMidiTrack()) - // return; - - QPoint ppt = QCursor::pos(); - //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); - pup->setCheckable(true); - - int gid = 0; - int n; - - // FIXME: - // 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(); - gid = 0; - - //MidiInPortList* tl = MusEGlobal::song->midiInPorts(); - //for(iMidiInPort i = tl->begin();i != tl->end(); ++i) - for(int i = 0; i < MIDI_PORTS; ++i) - { - //MidiInPort* track = *i; - // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick wth ports. - MidiPort* mp = &MusEGlobal::midiPorts[i]; - MidiDevice* md = mp->device(); - if(!md) - continue; - - if(!(md->rwFlags() & (dst ? 1 : 2))) - continue; - - //printf("MidiStrip::iRoutePressed adding submenu portnum:%d\n", i); - - //QMenu* m = menu->addMenu(track->name()); - QPopupMenu* subp = new QPopupMenu(parent); - - for(int ch = 0; ch < MIDI_CHANNELS; ++ch) - { - //QAction* a = m->addAction(QString("Channel %1").arg(ch+1)); - //subp->insertItem(QT_TRANSLATE_NOOP("@default", QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch); - gid = i * MIDI_CHANNELS + ch; - - //printf("MidiStrip::iRoutePressed inserting gid:%d\n", gid); - - subp->insertItem(QString("Channel %1").arg(ch+1), gid); - //a->setCheckable(true); - //Route src(track, ch, RouteNode::TRACK); - //Route src(md, ch); - //Route r = Route(src, dst); - //a->setData(QVariant::fromValue(r)); - //a->setChecked(rl->indexOf(r) != -1); - Route srcRoute(md, ch); - for(iRoute ir = rl->begin(); ir != rl->end(); ++ir) - { - //if(*ir == dst) - if(*ir == srcRoute) - { - subp->setItemChecked(gid, true); - break; - } - } - } - pup->insertItem(QT_TRANSLATE_NOOP("@default", md->name()), subp); - } - -// QPopupMenu* pup = new QPopupMenu(iR); -// pup->setCheckable(true); - //MidiTrack* t = (MidiTrack*)track; -// RouteList* irl = track->inRoutes(); - -// MidiTrack* t = (MidiTrack*)track; -// int gid = 0; -// for (int i = 0; i < channel; ++i) -// { -// char buffer[128]; -// snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); -// MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); -// pup->insertItem(titel); - -// if (!MusEGlobal::checkAudioDevice()) return; -// std::list<QString> ol = MusEGlobal::audioDevice->outputPorts(); -// for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) { -// int id = pup->insertItem(*ip, (gid * 16) + i); -// Route dst(*ip, true, i); -// ++gid; -// for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) { -// if (*ir == dst) { -// pup->setItemChecked(id, true); -// break; -// } -// } -// } -// if (i+1 != channel) -// pup->insertSeparator(); -// } - - if(pup->count() == 0) - { - delete pup; - return; - } - - //n = pup->exec(QCursor::pos()); - n = pup->exec(ppt); - ///delete pup; - if (n != -1) - { - int mdidx = n / MIDI_CHANNELS; - int ch = n % MIDI_CHANNELS; - - //if(MusEGlobal::debugMsg) - //printf("Song::chooseMidiRoutes mdidx:%d ch:%d\n", mdidx, ch); - - MidiPort* mp = &MusEGlobal::midiPorts[mdidx]; - MidiDevice* md = mp->device(); - if(!md) - { - delete pup; - return; - } - - //if(!(md->rwFlags() & 2)) - if(!(md->rwFlags() & (dst ? 1 : 2))) - { - delete pup; - return; - } - - //QString s(pup->text(n)); - //QT_TRANSLATE_NOOP("@default", md->name()) - - //Route srcRoute(s, false, -1); - Route aRoute(md, ch); - //Route srcRoute(md, -1); - //Route dstRoute(track, -1); - Route bRoute(track, ch); - - //if (track->type() == Track::AUDIO_INPUT) - // srcRoute.channel = dstRoute.channel = n & 0xf; - iRoute iir = rl->begin(); - for (; iir != rl->end(); ++iir) - { - //if(*iir == (dst ? bRoute : aRoute)) - if(*iir == aRoute) - break; - } - if (iir != rl->end()) - { - // disconnect - if(dst) - { - //printf("Song::chooseMidiRoutes removing route src track name: %s dst device name: %s\n", track->name().toLatin1().constData(), md->name().toLatin1().constData()); - MusEGlobal::audio->msgRemoveRoute(bRoute, aRoute); - } - else - { - //printf("Song::chooseMidiRoutes removing route src device name: %s dst track name: %s\n", md->name().toLatin1().constData(), track->name().toLatin1().constData()); - MusEGlobal::audio->msgRemoveRoute(aRoute, bRoute); - } - } - else - { - // connect - if(dst) - { - //printf("Song::chooseMidiRoutes adding route src track name: %s dst device name: %s\n", track->name().toLatin1().constData(), md->name().toLatin1().constData()); - MusEGlobal::audio->msgAddRoute(bRoute, aRoute); - } - else - { - //printf("Song::chooseMidiRoutes adding route src device name: %s dst track name: %s\n", md->name().toLatin1().constData(), track->name().toLatin1().constData()); - MusEGlobal::audio->msgAddRoute(aRoute, bRoute); - } - } - - //printf("Song::chooseMidiRoutes calling msgUpdateSoloStates\n"); - MusEGlobal::audio->msgUpdateSoloStates(); - //printf("Song::chooseMidiRoutes calling MusEGlobal::song->update\n"); - MusEGlobal::song->update(SC_ROUTE); - - // p3.3.46 - ///goto _redisplay; - } - delete pup; - parent->setDown(false); // pup->exec() catches mouse release event - //printf("Song::chooseMidiRoutes end\n"); - - //} -} -*/ - //--------------------------------------------------------- // insertTrack0 //--------------------------------------------------------- @@ -3403,7 +2958,6 @@ void Song::insertTrack2(Track* track, int idx) break; default: fprintf(stderr, "unknown track type %d\n", track->type()); - // abort(); return; } @@ -3420,43 +2974,12 @@ void Song::insertTrack2(Track* track, int idx) for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { if ((*i)->isMidiTrack()) continue; - MusECore::WaveTrack* wt = (MusECore::WaveTrack*)*i; + MusECore::AudioTrack* wt = (MusECore::AudioTrack*)*i; if (wt->hasAuxSend()) { wt->addAuxSend(n); } } - /* - // - // add routes - // - - if (track->isMidiTrack()) - return; - AudioTrack* at = (AudioTrack*)track; - Route src(at, -1); - if (at->type() == Track::AUDIO_OUTPUT) { - const RouteList* rl = at->inRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->outRoutes()->push_back(src); - } - else if (at->type() == Track::AUDIO_INPUT) { - const RouteList* rl = at->outRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->inRoutes()->push_back(src); - } - else { - const RouteList* rl = at->inRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->outRoutes()->push_back(src); - rl = at->outRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->inRoutes()->push_back(src); - } - */ - - // p3.3.38 - // // add routes // @@ -3472,6 +2995,13 @@ void Song::insertTrack2(Track* track, int idx) Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->outRoutes()->push_back(src); + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update the Audio Output track's aux ref count. p4.0.37 + if(r->track->auxRefCount()) + track->updateAuxRoute( r->track->auxRefCount(), NULL ); + else + if(r->track->type() == Track::AUDIO_AUX) + track->updateAuxRoute( 1, NULL ); } } else if (track->type() == Track::AUDIO_INPUT) @@ -3485,6 +3015,13 @@ void Song::insertTrack2(Track* track, int idx) Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->inRoutes()->push_back(src); + // Is this track an Aux Track or else does it have Aux Tracks routed to it? + // Update the other track's aux ref count and all tracks it is connected to. p4.0.37 + if(track->auxRefCount()) + r->track->updateAuxRoute( track->auxRefCount(), NULL ); + else + if(track->type() == Track::AUDIO_AUX) + r->track->updateAuxRoute( 1, NULL ); } } else if (track->isMidiTrack()) // p3.3.50 @@ -3492,14 +3029,14 @@ void Song::insertTrack2(Track* track, int idx) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - //printf("Song::insertTrack2 %s in route port:%d\n", track->name().toLatin1().constData(), r->midiPort); // p3.3.50 + //printf("Song::insertTrack2 %s in route port:%d\n", track->name().toLatin1().constData(), r->midiPort); Route src(track, r->channel); MusEGlobal::midiPorts[r->midiPort].outRoutes()->push_back(src); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - //printf("Song::insertTrack2 %s out route port:%d\n", track->name().toLatin1().constData(), r->midiPort); // p3.3.50 + //printf("Song::insertTrack2 %s out route port:%d\n", track->name().toLatin1().constData(), r->midiPort); Route src(track, r->channel); MusEGlobal::midiPorts[r->midiPort].inRoutes()->push_back(src); } @@ -3515,6 +3052,13 @@ void Song::insertTrack2(Track* track, int idx) Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->outRoutes()->push_back(src); + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update this track's aux ref count. p4.0.37 + if(r->track->auxRefCount()) + track->updateAuxRoute( r->track->auxRefCount(), NULL ); + else + if(r->track->type() == Track::AUDIO_AUX) + track->updateAuxRoute( 1, NULL ); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) @@ -3525,6 +3069,13 @@ void Song::insertTrack2(Track* track, int idx) Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->inRoutes()->push_back(src); + // Is this track an Aux Track or else does it have Aux Tracks routed to it? + // Update the other track's aux ref count and all tracks it is connected to. p4.0.37 + if(track->auxRefCount()) + r->track->updateAuxRoute( track->auxRefCount(), NULL ); + else + if(track->type() == Track::AUDIO_AUX) + r->track->updateAuxRoute( 1, NULL ); } } @@ -3537,18 +3088,9 @@ void Song::insertTrack2(Track* track, int idx) // non realtime part of insertTrack //--------------------------------------------------------- +// empty. gets executed after the realtime part void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning: unused parameter { - //printf("Song::insertTrack3\n"); - - /* - switch(track->type()) { - case Track::AUDIO_SOFTSYNTH: - break; - default: - break; - } - */ } //--------------------------------------------------------- @@ -3596,7 +3138,7 @@ void Song::removeTrack1(Track* track) SynthI* si = (SynthI*)track; if(si->hasGui()) si->showGui(false); - if(si->hasNativeGui()) // p4.0.20 + if(si->hasNativeGui()) si->showNativeGui(false); } break; @@ -3612,7 +3154,7 @@ void Song::removeTrack1(Track* track) void Song::removeTrack2(Track* track) { - //printf("Song::removeTrack2 track:%s\n", track->name().toLatin1().constData()); // p3.3.50 + //printf("Song::removeTrack2 track:%s\n", track->name().toLatin1().constData()); switch(track->type()) { case Track::MIDI: @@ -3653,38 +3195,6 @@ void Song::removeTrack2(Track* track) } _tracks.erase(track); - - /* - if (track->isMidiTrack()) - return; - // - // remove routes - // - - AudioTrack* at = (AudioTrack*)track; - Route src(at, -1); - if (at->type() == Track::AUDIO_OUTPUT) { - const RouteList* rl = at->inRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->outRoutes()->removeRoute(src); - } - else if (at->type() == Track::AUDIO_INPUT) { - const RouteList* rl = at->outRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->inRoutes()->removeRoute(src); - } - else { - const RouteList* rl = at->inRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->outRoutes()->removeRoute(src); - rl = at->outRoutes(); - for (ciRoute r = rl->begin(); r != rl->end(); ++r) - r->track->inRoutes()->removeRoute(src); - } - */ - - // p3.3.38 - // // remove routes // @@ -3696,11 +3206,18 @@ void Song::removeTrack2(Track* track) { //if(r->track == track) // r->track->outRoutes()->removeRoute(*r); - //printf("Song::removeTrack2 %s audio out track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 + //printf("Song::removeTrack2 %s audio out track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->outRoutes()->removeRoute(src); + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update the Audio Output track's aux ref count. p4.0.37 + if(r->track->auxRefCount()) + track->updateAuxRoute( -r->track->auxRefCount(), NULL ); + else + if(r->track->type() == Track::AUDIO_AUX) + track->updateAuxRoute( -1, NULL ); } } else if (track->type() == Track::AUDIO_INPUT) @@ -3710,11 +3227,18 @@ void Song::removeTrack2(Track* track) { //if(r->track == track) // r->track->inRoutes()->removeRoute(*r); - //printf("Song::removeTrack2 %s audio in track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 + //printf("Song::removeTrack2 %s audio in track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->inRoutes()->removeRoute(src); + // Is this track an Aux Track or else does it have Aux Tracks routed to it? + // Update the other track's aux ref count and all tracks it is connected to. p4.0.37 + if(track->auxRefCount()) + r->track->updateAuxRoute( -track->auxRefCount(), NULL ); + else + if(track->type() == Track::AUDIO_AUX) + r->track->updateAuxRoute( -1, NULL ); } } else if (track->isMidiTrack()) // p3.3.50 @@ -3722,14 +3246,14 @@ void Song::removeTrack2(Track* track) const RouteList* rl = track->inRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - //printf("Song::removeTrack2 %s in route port:%d\n", track->name().toLatin1().constData(), r->midiPort); // p3.3.50 + //printf("Song::removeTrack2 %s in route port:%d\n", track->name().toLatin1().constData(), r->midiPort); Route src(track, r->channel); MusEGlobal::midiPorts[r->midiPort].outRoutes()->removeRoute(src); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { - //printf("Song::removeTrack2 %s out route port:%d\n", track->name().toLatin1().constData(), r->midiPort); // p3.3.50 + //printf("Song::removeTrack2 %s out route port:%d\n", track->name().toLatin1().constData(), r->midiPort); Route src(track, r->channel); MusEGlobal::midiPorts[r->midiPort].inRoutes()->removeRoute(src); } @@ -3741,22 +3265,36 @@ void Song::removeTrack2(Track* track) { //if(r->track == track) // r->track->outRoutes()->removeRoute(*r); - //printf("Song::removeTrack2 %s in route track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 + //printf("Song::removeTrack2 %s in route track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->outRoutes()->removeRoute(src); + // Is the source an Aux Track or else does it have Aux Tracks routed to it? + // Update this track's aux ref count. p4.0.37 + if(r->track->auxRefCount()) + track->updateAuxRoute( -r->track->auxRefCount(), NULL ); + else + if(r->track->type() == Track::AUDIO_AUX) + track->updateAuxRoute( -1, NULL ); } rl = track->outRoutes(); for (ciRoute r = rl->begin(); r != rl->end(); ++r) { //if(r->track == track) // r->track->inRoutes()->removeRoute(*r); - //printf("Song::removeTrack2 %s out route track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 + //printf("Song::removeTrack2 %s out route track:%s\n", track->name().toLatin1().constData(), r->track->name().toLatin1().constData()); // p3.3.50 Route src(track, r->channel, r->channels); src.remoteChannel = r->remoteChannel; r->track->inRoutes()->removeRoute(src); + // Is this track an Aux Track or else does it have Aux Tracks routed to it? + // Update the other track's aux ref count and all tracks it is connected to. p4.0.37 + if(track->auxRefCount()) + r->track->updateAuxRoute( -track->auxRefCount(), NULL ); + else + if(track->type() == Track::AUDIO_AUX) + r->track->updateAuxRoute( -1, NULL ); } } @@ -3767,21 +3305,10 @@ void Song::removeTrack2(Track* track) // non realtime part of removeTrack //--------------------------------------------------------- +//empty. gets executed after the realtime part void Song::removeTrack3(Track* /*track*/)//prevent of compiler warning: unused parameter - { - /* - switch(track->type()) { - case Track::AUDIO_SOFTSYNTH: - { - SynthI* s = (SynthI*) track; - s->deactivate3(); - } - break; - default: - break; - } - */ - } +{ +} //--------------------------------------------------------- // executeScript diff --git a/muse2/muse/song.h b/muse2/muse/song.h index d6d3628c..047dbac3 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -37,6 +37,7 @@ #include "al/sig.h" #include "undo.h" #include "track.h" +#include "synth.h" class QAction; class QFont; @@ -362,7 +363,7 @@ class Song : public QObject { // Configuration //----------------------------------------- - SynthI* createSynthI(const QString& sclass, const QString& label = QString(), Track* insertAt = 0); + SynthI* createSynthI(const QString& sclass, const QString& label = QString(), Synth::Type type = Synth::SYNTH_TYPE_END, Track* insertAt = 0); void rescanAlsaPorts(); @@ -412,7 +413,7 @@ class Song : public QObject { void setQuantize(bool val); void panic(); void seqSignal(int fd); - Track* addTrack(Track::TrackType type, Track* insertAt = 0); + Track* addTrack(Undo& operations, Track::TrackType type, Track* insertAt = 0); Track* addNewTrack(QAction* action, Track* insertAt = 0); QString getScriptPath(int id, bool delivered); void populateScriptMenu(QMenu* menuPlugins, QObject* receiver); diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp index b5c3382d..5726345e 100644 --- a/muse2/muse/songfile.cpp +++ b/muse2/muse/songfile.cpp @@ -21,7 +21,6 @@ // //========================================================= -#include <assert.h> #include <uuid/uuid.h> #include <QProgressDialog> #include <QMessageBox> @@ -29,6 +28,7 @@ #include "app.h" #include "song.h" #include "arranger.h" +#include "arrangerview.h" //#include "arranger/arranger.h" // p4.0.2 #include "cobject.h" #include "drumedit.h" @@ -1302,10 +1302,10 @@ void MusE::readToplevels(MusECore::Xml& xml) } else if (tag == "scoreedit") { MusEGui::ScoreEdit* score = new MusEGui::ScoreEdit(this, 0, _arranger->cursorValue()); - score->show(); toplevels.push_back(score); - connect(score, SIGNAL(deleted(MusEGui::TopWin*)), SLOT(toplevelDeleted(MusEGui::TopWin*))); - connect(score, SIGNAL(name_changed()), SLOT(scoreNamingChanged())); + connect(score, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*))); + connect(score, SIGNAL(name_changed()), arrangerView, SLOT(scoreNamingChanged())); + score->show(); score->readStatus(xml); } else if (tag == "drumedit") { @@ -1334,13 +1334,19 @@ void MusE::readToplevels(MusECore::Xml& xml) } else if (tag == "marker") { showMarker(true); - if (toplevels.back()->type()==MusEGui::TopWin::MARKER) - toplevels.back()->readStatus(xml); + TopWin* tw = toplevels.findType(TopWin::MARKER); + if(!tw) + xml.skip("marker"); + else + tw->readStatus(xml); } else if (tag == "arrangerview") { showArranger(true); - if (toplevels.back()->type()==MusEGui::TopWin::ARRANGER) - toplevels.back()->readStatus(xml); + TopWin* tw = toplevels.findType(TopWin::ARRANGER); + if(!tw) + xml.skip("arrangerview"); + else + tw->readStatus(xml); } else if (tag == "waveedit") { if(!pl->empty()) @@ -1352,8 +1358,11 @@ void MusE::readToplevels(MusECore::Xml& xml) } else if (tag == "cliplist") { startClipList(true); - if (toplevels.back()->type()==MusEGui::TopWin::CLIPLIST) - toplevels.back()->readStatus(xml); + TopWin* tw = toplevels.findType(TopWin::CLIPLIST); + if(!tw) + xml.skip("cliplist"); + else + tw->readStatus(xml); } else xml.unknown("MusE"); @@ -1515,9 +1524,34 @@ void MusE::read(MusECore::Xml& xml, bool skipConfig, bool isTemplate) else if (tag == "configuration") if (skipConfig) //xml.skip(tag); - readConfiguration(xml,true /* only read sequencer settings */, false /* do NOT read global settings */); + readConfiguration(xml,true /* only read sequencer settings */, false /* do NOT read global settings, see below */); + // see even more below! else - readConfiguration(xml, false, false /* do NOT read global settings */); + readConfiguration(xml, false, false /* do NOT read global settings, see below */); + /* Explanation for why "do NOT read global settings": + * if you would use true here, then muse would overwrite certain global config stuff + * by the settings stored in the song. but you don't want this. imagine that you + * send a friend a .med file. your friend opens it and baaam, his configuration is + * garbled. why? well, because these readConfigurations here would have overwritten + * parts (but not all) of his global config (like MDI/SDI, toolbar states etc.) + * with the data stored in the song. (it IS stored there. dunny why, i find it pretty + * senseless.) + * + * If you've a problem which seems to be solved by replacing "false" with "true", i've + * a better solution for you: go into conf.cpp, in void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig) + * (around line 525), look for a comment like this: + * "Global and/or per-song config stuff ends here" (alternatively just search for + * "----"). Your problem is probably that some non-global setting should be loaded but + * is not. Fix it by either placing the else if (foo)... clause responsible for that + * setting to be loaded into the first part, that is, before "else if (!doReadGlobalConfig)" + * or (if the settings actually IS global and not per-song), ensure that the routine + * which writes the global (and not the song-)configuration really writes that setting. + * (it might happen that it formerly worked because it was written to the song instead + * of the global config by mistake, and now isn't loaded anymore. write it to the + * correct location.) + * + * -- flo93 + */ else if (tag == "song") { MusEGlobal::song->read(xml, isTemplate); diff --git a/muse2/muse/structure.cpp b/muse2/muse/structure.cpp index 90d02908..70b19540 100644 --- a/muse2/muse/structure.cpp +++ b/muse2/muse/structure.cpp @@ -137,7 +137,7 @@ void adjustGlobalLists(Undo& operations, int startPos, int diff) // - cut master track //--------------------------------------------------------- -void globalCut() +void globalCut(bool onlySelectedTracks) { int lpos = MusEGlobal::song->lpos(); int rpos = MusEGlobal::song->rpos(); @@ -146,17 +146,11 @@ void globalCut() Undo operations; TrackList* tracks = MusEGlobal::song->tracks(); - bool at_least_one_selected=false; - - for (iTrack it = tracks->begin(); it != tracks->end(); ++it) - if ( (*it)->selected() ) { - at_least_one_selected=true; - break; - } for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { - MidiTrack* track = dynamic_cast<MidiTrack*>(*it); - if (track == 0 || (at_least_one_selected && !track->selected())) + //MidiTrack* track = dynamic_cast<MidiTrack*>(*it); + Track* track = *it; + if (track == 0 || (onlySelectedTracks && !track->selected())) continue; PartList* pl = track->parts(); for (iPart p = pl->begin(); p != pl->end(); ++p) { @@ -169,63 +163,61 @@ void globalCut() operations.push_back(UndoOp(UndoOp::DeletePart,part)); } else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) { - // remove part tail - int len = lpos - t; - MidiPart* nPart = new MidiPart(*(MidiPart*)part); - nPart->setLenTick(len); - // - // cut Events in nPart - EventList* el = nPart->events(); - for (iEvent ie = el->lower_bound(len); ie != el->end(); ++ie) - operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, nPart, false, false)); - - operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); - } + // remove part tail + int len = lpos - t; + Part *nPart; + if (track->isMidiTrack()) + nPart = new MidiPart(*(MidiPart*)part); + else + nPart = new WavePart(*(WavePart*)part); + + nPart->setLenTick(len); + // + // cut Events in nPart + EventList* el = nPart->events(); + for (iEvent ie = el->lower_bound(len); ie != el->end(); ++ie) + operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, nPart, false, false)); + + operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); + } else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) { //---------------------- // remove part middle //---------------------- + Part* p1; + Part* p2; + Part* p3; + track->splitPart(part, lpos, p1, p2); + delete p2; + track->splitPart(part, rpos, p2, p3); + delete p2; + p3->setTick(lpos); + p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ + p3->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ - MidiPart* nPart = new MidiPart(*(MidiPart*)part); - EventList* el = nPart->events(); - iEvent is = el->lower_bound(lpos-t); - iEvent ie = el->lower_bound(rpos-t); //lower bound, because we do NOT want to erase the events at rpos-t - for (iEvent i = is; i != ie; ++i) - operations.push_back(UndoOp(UndoOp::DeleteEvent,i->second, nPart, false, false)); - - for (iEvent i = el->lower_bound(rpos-t); i != el->end(); ++i) { - Event event = i->second; - Event nEvent = event.clone(); - nEvent.setTick(nEvent.tick() - (rpos-lpos)); - // Indicate no undo, and do not do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::ModifyEvent,nEvent, event, nPart, false, false)); - } - nPart->setLenTick(l - (rpos-lpos)); // Indicate no undo, and do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); + operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, true)); + operations.push_back(UndoOp(UndoOp::AddPart,p3)); } else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) { // remove part head - MidiPart* nPart = new MidiPart(*(MidiPart*)part); - EventList* el = nPart->events(); - iEvent i_end = el->lower_bound(rpos-t); //lower bound, because we do NOT want to erase the events at rpos-t - for (iEvent it = el->begin(); it!=i_end; it++) - operations.push_back(UndoOp(UndoOp::DeleteEvent,it->second, nPart, false, false)); - - for (iEvent it = el->lower_bound(rpos-t); it!=el->end(); it++) { - Event event = it->second; - Event nEvent = event.clone(); - nEvent.setTick(nEvent.tick() - (rpos-t)); - // Indicate no undo, and do not do port controller values and clone parts. - operations.push_back(UndoOp(UndoOp::ModifyEvent,nEvent, event, nPart, false, false)); - } - - nPart->setLenTick(l - (rpos-t)); - operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); + Part* p1; + Part* p2; + track->splitPart(part, rpos, p1, p2); + delete p1; + p2->setTick(lpos); + p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ + operations.push_back(UndoOp(UndoOp::ModifyPart,part, p2, true, true)); } else if (t >= rpos) { - MidiPart* nPart = new MidiPart(*(MidiPart*)part); + // move part to the left + Part *nPart; + if (track->isMidiTrack()) + nPart = new MidiPart(*(MidiPart*)part); + else + nPart = new WavePart(*(WavePart*)part); + //MidiPart* nPart = new MidiPart(*(MidiPart*)part); int nt = part->tick(); nPart->setTick(nt - (rpos -lpos)); // Indicate no undo, and do port controller values but not clone parts. @@ -246,33 +238,24 @@ void globalCut() // - insert in master track //--------------------------------------------------------- -void globalInsert() - { - Undo operations=movePartsTotheRight(MusEGlobal::song->lpos(), MusEGlobal::song->rpos()-MusEGlobal::song->lpos(), true); +void globalInsert(bool onlySelectedTracks) +{ + Undo operations=movePartsTotheRight(MusEGlobal::song->lpos(), MusEGlobal::song->rpos()-MusEGlobal::song->lpos(), onlySelectedTracks); MusEGlobal::song->applyOperationGroup(operations); - } - +} Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selected, set<Track*>* tracklist) - { +{ if (moveTicks<=0) return Undo(); Undo operations; TrackList* tracks = MusEGlobal::song->tracks(); - bool at_least_one_selected=false; - - for (iTrack it = tracks->begin(); it != tracks->end(); ++it) - if ( (*it)->selected() ) { - at_least_one_selected=true; - break; - } - for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { - MidiTrack* track = dynamic_cast<MidiTrack*>(*it); + Track* track = *it; if ( (track == 0) || - (only_selected && at_least_one_selected && !track->selected()) || + (only_selected && !track->selected()) || (tracklist && tracklist->find(track)==tracklist->end()) ) continue; PartList* pl = track->parts(); @@ -283,23 +266,23 @@ Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selec if (t + l <= startTicks) continue; if (startTicks > t && startTicks < (t+l)) { - MidiPart* nPart = new MidiPart(*(MidiPart*)part); - nPart->setLenTick(l + moveTicks); - EventList* el = nPart->events(); - - for (riEvent i = el->rbegin(); i!=el->rend(); ++i) - { - if (i->first < startTicks-t) - break; - Event event = i->second; - Event nEvent = i->second.clone(); - nEvent.setTick(nEvent.tick() + moveTicks); - operations.push_back(UndoOp(UndoOp::ModifyEvent, nEvent, event, nPart, false, false)); - } - operations.push_back(UndoOp(UndoOp::ModifyPart, part, nPart, true, true)); + // split part to insert new space + Part* p1; + Part* p2; + track->splitPart(part, startTicks, p1, p2); + p2->setTick(startTicks+moveTicks); + p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ + p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ + + operations.push_back(UndoOp(UndoOp::ModifyPart, part, p1, true, true)); + operations.push_back(UndoOp(UndoOp::AddPart, p2)); } else if (t >= startTicks) { - MidiPart* nPart = new MidiPart(*(MidiPart*)part); + Part *nPart; + if (track->isMidiTrack()) + nPart = new MidiPart(*(MidiPart*)part); + else + nPart = new WavePart(*(WavePart*)part); nPart->setTick(t + moveTicks); operations.push_back(UndoOp(UndoOp::ModifyPart, part, nPart, true, false)); } @@ -317,47 +300,50 @@ Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selec // - split all parts at the song position pointer //--------------------------------------------------------- -void globalSplit() - { - int pos = MusEGlobal::song->cpos(); - Undo operations; - TrackList* tracks = MusEGlobal::song->tracks(); - bool at_least_one_selected=false; - - for (iTrack it = tracks->begin(); it != tracks->end(); ++it) - if ( (*it)->selected() ) { - at_least_one_selected=true; - break; - } - - - for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { - Track* track = *it; - if (track == 0 || (at_least_one_selected && !track->selected())) - continue; - - PartList* pl = track->parts(); - for (iPart p = pl->begin(); p != pl->end(); ++p) { - Part* part = p->second; - int p1 = part->tick(); - int l0 = part->lenTick(); - if (pos > p1 && pos < (p1+l0)) { - Part* p1; - Part* p2; - track->splitPart(part, pos, p1, p2); +void globalSplit(bool onlySelectedTracks) +{ + Undo operations=partSplitter(MusEGlobal::song->cpos(), onlySelectedTracks); + MusEGlobal::song->applyOperationGroup(operations); +} - p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it - p2->events()->incARef(-1); // so we must decrement it first :/ +Undo partSplitter(unsigned int pos, bool onlySelectedTracks) +{ + Undo operations; + TrackList* tracks = MusEGlobal::song->tracks(); + + for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { + Track* track = *it; + if (track == 0 || (onlySelectedTracks && !track->selected())) + continue; + + PartList* pl = track->parts(); + for (iPart p = pl->begin(); p != pl->end(); ++p) { + Part* part = p->second; + unsigned int p1 = part->tick(); + unsigned int l0 = part->lenTick(); + if (pos > p1 && pos < (p1+l0)) { + Part* p1; + Part* p2; + track->splitPart(part, pos, p1, p2); + + p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it + p2->events()->incARef(-1); // so we must decrement it first :/ + + //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ModifyPart + MusEGlobal::song->informAboutNewParts(part, p2); + operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, false)); + operations.push_back(UndoOp(UndoOp::AddPart,p2)); + if (MusEGlobal::debugMsg) + { + printf("in partSplitter: part1 %d\n",p1->events()->refCount()); + printf("in partSplitter: part2 %d\n",p2->events()->refCount()); + } + break; + } + } + } + return operations; +} - //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ModifyPart - MusEGlobal::song->informAboutNewParts(part, p2); - operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, false)); - operations.push_back(UndoOp(UndoOp::AddPart,p2)); - break; - } - } - } - MusEGlobal::song->applyOperationGroup(operations); - } } // namespace MusECore diff --git a/muse2/muse/structure.h b/muse2/muse/structure.h index b92c4e14..3a359dc0 100644 --- a/muse2/muse/structure.h +++ b/muse2/muse/structure.h @@ -28,10 +28,11 @@ namespace MusECore { Undo movePartsTotheRight(unsigned int startTick, int moveTick, bool only_selected=false, std::set<Track*>* tracklist=NULL); +Undo partSplitter(unsigned int tick, bool onlySelectedTracks=false); void adjustGlobalLists(Undo& operations, int startPos, int diff); -void globalCut(); -void globalInsert(); -void globalSplit(); +void globalCut(bool onlySelectedTracks=false); +void globalInsert(bool onlySelectedTracks=false); +void globalSplit(bool onlySelectedTracks=false); } #endif diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index fd526931..7ab18bda 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -32,6 +32,7 @@ #include <dlfcn.h> #include <QDir> +#include <QString> //#include <QMenu> #include "app.h" @@ -60,7 +61,20 @@ std::vector<MusECore::Synth*> synthis; // array of available MusEGlobal::synthi namespace MusECore { extern void connectNodes(AudioTrack*, AudioTrack*); -bool SynthI::_isVisible=true; +bool SynthI::_isVisible=false; + +const char* synthTypes[] = { "METRONOME", "MESS", "DSSI", "VST", "UNKNOWN" }; +QString synthType2String(Synth::Type type) { return QString(synthTypes[type]); } + +Synth::Type string2SynthType(const QString& type) +{ + for(int i = 0; i < Synth::SYNTH_TYPE_END; ++i) + { + if(synthType2String((Synth::Type)i) == type) + return (Synth::Type)i; + } + return Synth::SYNTH_TYPE_END; +} /* //--------------------------------------------------------- @@ -145,19 +159,17 @@ void MessSynthIF::setNativeGeometry(int x, int y, int w, int h) // search for synthesizer base class //--------------------------------------------------------- -//static Synth* findSynth(const QString& sclass) -static Synth* findSynth(const QString& sclass, const QString& label) +static Synth* findSynth(const QString& sclass, const QString& label, Synth::Type type = Synth::SYNTH_TYPE_END) { for (std::vector<Synth*>::iterator i = MusEGlobal::synthis.begin(); i != MusEGlobal::synthis.end(); ++i) { - //if ((*i)->baseName() == sclass) - //if ((*i)->name() == sclass) - if ( ((*i)->baseName() == sclass) && (label.isEmpty() || ((*i)->name() == label)) ) - - return *i; + if( ((*i)->baseName() == sclass) && + (label.isEmpty() || ((*i)->name() == label)) && + (type == Synth::SYNTH_TYPE_END || type == (*i)->synthType()) ) + return *i; } - printf("synthi class:%s label:%s not found\n", sclass.toLatin1().constData(), label.toLatin1().constData()); + printf("synthi type:%d class:%s label:%s not found\n", type, sclass.toLatin1().constData(), label.toLatin1().constData()); return 0; } @@ -166,10 +178,9 @@ static Synth* findSynth(const QString& sclass, const QString& label) // create a synthesizer instance of class "label" //--------------------------------------------------------- -static SynthI* createSynthInstance(const QString& sclass, const QString& label) +static SynthI* createSynthInstance(const QString& sclass, const QString& label, Synth::Type type = Synth::SYNTH_TYPE_END) { - //Synth* s = findSynth(sclass); - Synth* s = findSynth(sclass, label); + Synth* s = findSynth(sclass, label, type); SynthI* si = 0; if (s) { si = new SynthI(); @@ -652,13 +663,11 @@ void initMidiSynth() // If insertAt is valid, inserts before insertAt. Else at the end after all tracks. //--------------------------------------------------------- -SynthI* Song::createSynthI(const QString& sclass, const QString& label, Track* insertAt) +SynthI* Song::createSynthI(const QString& sclass, const QString& label, Synth::Type type, Track* insertAt) { //printf("Song::createSynthI calling ::createSynthI class:%s\n", sclass.toLatin1().constData()); - //SynthI* si = ::createSynthI(sclass); - //SynthI* si = ::createSynthI(sclass, label); - SynthI* si = createSynthInstance(sclass, label); + SynthI* si = createSynthInstance(sclass, label, type); if(!si) return 0; //printf("Song::createSynthI created SynthI. Before insertTrack1...\n"); @@ -705,6 +714,9 @@ void SynthI::write(int level, Xml& xml) const { xml.tag(level++, "SynthI"); AudioTrack::writeProperties(level, xml); + //xml.intTag(level, "synthType", synth()->synthType()); + xml.strTag(level, "synthType", synthType2String(synth()->synthType())); + xml.strTag(level, "class", synth()->baseName()); // To support plugins like dssi-vst where all the baseNames are the same 'dssi-vst' and the label is the name of the dll file. @@ -823,7 +835,8 @@ void SynthI::read(Xml& xml) { QString sclass; QString label; - + Synth::Type type = Synth::SYNTH_TYPE_END; + int port = -1; bool startgui = false; bool startngui = false; @@ -837,7 +850,10 @@ void SynthI::read(Xml& xml) case Xml::End: return; case Xml::TagStart: - if (tag == "class") + if (tag == "synthType") + //type = xml.parseInt(); + type = string2SynthType(xml.parse1()); + else if (tag == "class") sclass = xml.parse1(); else if (tag == "label") label = xml.parse1(); @@ -866,8 +882,15 @@ void SynthI::read(Xml& xml) break; case Xml::TagEnd: if (tag == "SynthI") { - //Synth* s = findSynth(sclass); - Synth* s = findSynth(sclass, label); + + // NOTICE: This is a hack to quietly change songs to use the new 'fluid_synth' name instead of 'fluidsynth'. + // Recent linker changes required the name change in fluidsynth's cmakelists. Nov 8, 2011 By Tim. + if(sclass == QString("fluidsynth") && + (type == Synth::SYNTH_TYPE_END || type == Synth::MESS_SYNTH) && + (label.isEmpty() || label == QString("FluidSynth")) ) + sclass = QString("fluid_synth"); + + Synth* s = findSynth(sclass, label, type); if (s == 0) return; if (initInstance(s, name())) diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h index c5b63424..497395c0 100644 --- a/muse2/muse/synth.h +++ b/muse2/muse/synth.h @@ -72,6 +72,8 @@ class Synth { QString _version; public: + enum Type { METRO_SYNTH=0, MESS_SYNTH, DSSI_SYNTH, VST_SYNTH, SYNTH_TYPE_END }; + //Synth(const QFileInfo& fi); //Synth(const QFileInfo& fi, QString label); Synth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver); @@ -80,6 +82,7 @@ class Synth { //virtual const char* description() const { return ""; } //virtual const char* version() const { return ""; } + virtual Type synthType() const = 0; int instances() const { return _instances; } virtual void incInstances(int val) { _instances += val; } QString completeBaseName() /*const*/ { return info.completeBaseName(); } // ddskrjo @@ -117,6 +120,8 @@ class MessSynth : public Synth { //virtual const char* description() const; //virtual const char* version() const; + virtual Type synthType() const { return MESS_SYNTH; } + //virtual void* instantiate(); virtual void* instantiate(const QString&); @@ -363,6 +368,9 @@ class MessSynthIF : public SynthIF { virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval); }; +extern QString synthType2String(Synth::Type); +extern Synth::Type string2SynthType(const QString&); + } // namespace MusECore namespace MusEGlobal { diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp index 1edc0b12..6d3721ea 100644 --- a/muse2/muse/ticksynth.cpp +++ b/muse2/muse/ticksynth.cpp @@ -49,6 +49,7 @@ class MetronomeSynth : public Synth { //MetronomeSynth(const QFileInfo& fi) : Synth(fi, QString("Metronome")) {} MetronomeSynth(const QFileInfo& fi) : Synth(fi, QString("Metronome"), QString("Metronome"), QString(), QString()) {} virtual ~MetronomeSynth() {} + virtual Type synthType() const { return METRO_SYNTH; } virtual void incInstances(int) {} virtual void* instantiate(); diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index 4140732d..07a2dff0 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -4,6 +4,7 @@ // $Id: track.cpp,v 1.34.2.11 2009/11/30 05:05:49 terminator356 Exp $ // // (C) Copyright 2000-2004 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -37,10 +38,12 @@ namespace MusECore { //bool Track::_isVisible=true; -unsigned int Track::_soloRefCnt = 0; +unsigned int Track::_soloRefCnt = 0; Track* Track::_tmpSoloChainTrack = 0; bool Track::_tmpSoloChainDoIns = false; bool Track::_tmpSoloChainNoDec = false; +//bool Track::_tmpIsAuxProcessing = false; +//int Track::_tmpIsAuxProcRefCount = 0; const char* Track::_cname[] = { "Midi", "Drum", "NewStyleDrum", "Wave", @@ -145,6 +148,34 @@ void removePortCtrlEvents(MidiTrack* t) } } +//--------------------------------------------------------- +// isVisible +//--------------------------------------------------------- +bool Track::isVisible() +{ + switch (type()) + { + case Track::AUDIO_AUX: + return AudioAux::visible(); + break; + case Track::AUDIO_GROUP: + return AudioGroup::visible(); + case Track::AUDIO_INPUT: + return AudioInput::visible(); + case Track::AUDIO_OUTPUT: + return AudioOutput::visible(); + case Track::WAVE: + return WaveTrack::visible(); + case Track::MIDI: + return MidiTrack::visible(); + case Track::AUDIO_SOFTSYNTH: + return AudioAux::visible(); + default: + break; + } + + return false; +} //--------------------------------------------------------- @@ -172,6 +203,8 @@ int Track::y() const void Track::init() { + _auxRouteCount = 0; + _nodeTraversed = false; _activity = 0; _lastActivity = 0; _recordFlag = false; @@ -206,6 +239,8 @@ Track::Track(Track::TrackType t) //Track::Track(const Track& t) Track::Track(const Track& t, bool cloneParts) { + _auxRouteCount = t._auxRouteCount; + _nodeTraversed = t._nodeTraversed; _activity = t._activity; _lastActivity = t._lastActivity; _recordFlag = t._recordFlag; @@ -271,6 +306,8 @@ Track::~Track() Track& Track::operator=(const Track& t) { + _auxRouteCount = t._auxRouteCount; + _nodeTraversed = t._nodeTraversed; _activity = t._activity; _lastActivity = t._lastActivity; _recordFlag = t._recordFlag; @@ -388,6 +425,107 @@ void Track::dump() const _name.toLatin1().constData(), _type, _parts.size(), _selected); } +//--------------------------------------------------------- +// updateAuxRoute +// Internal use. Update all the Aux ref counts of tracks dst is connected to. +// If dst is valid, start traversal from there, not from this track. +//--------------------------------------------------------- + +void Track::updateAuxRoute(int refInc, Track* dst) +{ + //if(isMidiTrack() || _type == AUDIO_AUX) + if(isMidiTrack()) + return; + + //printf("Track::updateAuxRoute %s _auxRouteCount:%d refInc:%d\n", name().toLatin1().constData(), _auxRouteCount, refInc); + + if(dst) + { + _nodeTraversed = true; + dst->updateAuxRoute(refInc, NULL); + _nodeTraversed = false; + return; + } + + if(_type == AUDIO_AUX) + return; + + if(_nodeTraversed) + { + fprintf(stderr, "Track::updateAuxRoute %s _auxRouteCount:%d refInc:%d :\n", name().toLatin1().constData(), _auxRouteCount, refInc); + if(refInc >= 0) + fprintf(stderr, " MusE Warning: Please check your routes: Circular path found!\n"); + else + fprintf(stderr, " MusE: Circular path removed.\n"); + return; + } + + _nodeTraversed = true; + + _auxRouteCount += refInc; + if(_auxRouteCount < 0) + { + fprintf(stderr, "Track::updateAuxRoute Ref underflow! %s _auxRouteCount:%d refInc:%d\n", name().toLatin1().constData(), _auxRouteCount, refInc); + //_auxRouteCount = 0; + } + + for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i) + { + if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) + continue; + Track* t = (*i).track; + //if(t->isMidiTrack()) + // continue; + t->updateAuxRoute(refInc, NULL); + } + + _nodeTraversed = false; +} + +//--------------------------------------------------------- +// isCircularRoute +// If dst is valid, start traversal from there, not from this track. +// Returns true if circular. +//--------------------------------------------------------- + +bool Track::isCircularRoute(Track* dst) +{ + //if(isMidiTrack() || _type == AUDIO_AUX) + //if(isMidiTrack()) + // return; + + bool rv = false; + + if(dst) + { + _nodeTraversed = true; + rv = dst->isCircularRoute(NULL); + _nodeTraversed = false; + //if(rv) + // fprintf(stderr, " Circular route %s -> %s\n", name().toLatin1().constData(), dst->name().toLatin1().constData()); + return rv; + } + + if(_nodeTraversed) + return true; + + _nodeTraversed = true; + + for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i) + { + if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) + continue; + Track* t = (*i).track; + //if(t->isMidiTrack()) + // continue; + rv = t->isCircularRoute(NULL); + if(rv) + break; + } + + _nodeTraversed = false; + return rv; +} //--------------------------------------------------------- // MidiTrack @@ -468,7 +606,6 @@ void MidiTrack::init() { _outPort = 0; _outChannel = (type()==NEW_DRUM) ? 9 : 0; - // Changed by Tim. p3.3.8 //_inPortMask = 0xffff; ///_inPortMask = 0xffffffff; @@ -569,7 +706,7 @@ void MidiTrack::setOutPortAndChannelAndUpdate(int port, int ch) //--------------------------------------------------------- // setInPortAndChannelMask // For old song files with port mask (max 32 ports) and channel mask (16 channels), -// before midi routing was added (the iR button). p3.3.48 +// before midi routing was added (the iR button). //--------------------------------------------------------- void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask) @@ -582,7 +719,7 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask) for(int port = 0; port < 32; ++port) // 32 is the old maximum number of ports. { - // p3.3.50 If the port was not used in the song file to begin with, just ignore it. + // If the port was not used in the song file to begin with, just ignore it. // This saves from having all of the first 32 ports' channels connected. if(!MusEGlobal::midiPorts[port].foundInSongFile()) continue; @@ -590,34 +727,18 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask) //if(!(portmask & (1 << port))) // continue; - // p3.3.50 Removed. Allow to connect to port with no device so user can change device later. + // Removed. Allow to connect to port with no device so user can change device later. //MidiPort* mp = &MusEGlobal::midiPorts[port]; //MidiDevice* md = mp->device(); //if(!md) // continue; - //for(int ch = 0; ch < MIDI_CHANNELS; ++ch) // p3.3.50 Removed. - //{ - //if(!(chanmask & (1 << ch))) - // continue; - - //Route aRoute(md, ch); - //Route bRoute(this, ch); - Route aRoute(port, chanmask); // p3.3.50 + Route aRoute(port, chanmask); Route bRoute(this, chanmask); - // p3.3.50 Removed. - //iRoute iir = rl->begin(); - //for(; iir != rl->end(); ++iir) - //{ - //if(*iir == aRoute) - // if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == port) // p3.3.50 - // break; - //} - // Route wanted? //if((portmask & (1 << port)) && (chanmask & (1 << ch))) - if(portmask & (1 << port)) // p3.3.50 + if(portmask & (1 << port)) { // Route already exists? //if(iir != rl->end()) @@ -923,11 +1044,11 @@ void MidiTrack::read(Xml& xml) //setInPortMask(xml.parseInt()); ///setInPortMask(xml.parseUInt()); //xml.skip(tag); // Obsolete. - portmask = xml.parseUInt(); // p3.3.48: Support old files. + portmask = xml.parseUInt(); // Support old files. else if (tag == "inchannelMap") ///setInChannelMask(xml.parseInt()); //xml.skip(tag); // Obsolete. - chanmask = xml.parseInt(); // p3.3.48: Support old files. + chanmask = xml.parseInt(); // Support old files. else if (tag == "locked") _locked = xml.parseInt(); else if (tag == "echo") @@ -950,7 +1071,7 @@ void MidiTrack::read(Xml& xml) case Xml::TagEnd: if (tag == "miditrack" || tag == "drumtrack" || tag == "newdrumtrack") { - setInPortAndChannelMask(portmask, chanmask); // p3.3.48: Support old files. + setInPortAndChannelMask(portmask, chanmask); // Support old files. return; } default: @@ -1184,15 +1305,15 @@ void Track::writeRouting(int level, Xml& xml) const // Support Midi Port to Audio Input track routes. p4.0.14 Tim. if(r->type == Route::MIDI_PORT_ROUTE) { - s = QT_TRANSLATE_NOOP("@default", "Route"); + s = "Route"; if(r->channel != -1 && r->channel != 0) - s += QString(QT_TRANSLATE_NOOP("@default", " channelMask=\"%1\"")).arg(r->channel); // Use new channel mask. + s += QString(" channelMask=\"%1\"").arg(r->channel); // Use new channel mask. xml.tag(level++, s.toLatin1().constData()); xml.tag(level, "source mport=\"%d\"/", r->midiPort); - s = QT_TRANSLATE_NOOP("@default", "dest"); - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(name())); + s = "dest"; + s += QString(" name=\"%1\"/").arg(Xml::xmlString(name())); xml.tag(level, s.toLatin1().constData()); xml.etag(level--, "Route"); @@ -1200,17 +1321,17 @@ void Track::writeRouting(int level, Xml& xml) const else if(!r->name().isEmpty()) { - s = QT_TRANSLATE_NOOP("@default", "Route"); + s = "Route"; if(r->channel != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); + s += QString(" channel=\"%1\"").arg(r->channel); xml.tag(level++, s.toAscii().constData()); - // p3.3.38 New routing scheme. - s = QT_TRANSLATE_NOOP("@default", "source"); + // New routing scheme. + s = "source"; if(r->type != Route::TRACK_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); + s += QString(" type=\"%1\"").arg(r->type); + s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); xml.tag(level, s.toAscii().constData()); xml.tag(level, "dest name=\"%s\"/", Xml::xmlString(name()).toLatin1().constData()); @@ -1228,42 +1349,42 @@ void Track::writeRouting(int level, Xml& xml) const if(r->type == Route::TRACK_ROUTE && r->track && r->track->type() == Track::AUDIO_INPUT) continue; - if(r->midiPort != -1 || !r->name().isEmpty()) // p3.3.49 + if(r->midiPort != -1 || !r->name().isEmpty()) { - s = QT_TRANSLATE_NOOP("@default", "Route"); - if(r->type == Route::MIDI_PORT_ROUTE) // p3.3.50 + s = "Route"; + if(r->type == Route::MIDI_PORT_ROUTE) { if(r->channel != -1 && r->channel != 0) - s += QString(QT_TRANSLATE_NOOP("@default", " channelMask=\"%1\"")).arg(r->channel); // Use new channel mask. + s += QString(" channelMask=\"%1\"").arg(r->channel); // Use new channel mask. } else { if(r->channel != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); + s += QString(" channel=\"%1\"").arg(r->channel); } if(r->channels != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " channels=\"%1\"")).arg(r->channels); + s += QString(" channels=\"%1\"").arg(r->channels); if(r->remoteChannel != -1) - s += QString(QT_TRANSLATE_NOOP("@default", " remch=\"%1\"")).arg(r->remoteChannel); + s += QString(" remch=\"%1\"").arg(r->remoteChannel); xml.tag(level++, s.toAscii().constData()); // Allow for a regular mono or stereo track to feed a multi-channel synti. xml.tag(level, "source name=\"%s\"/", Xml::xmlString(name()).toLatin1().constData()); - s = QT_TRANSLATE_NOOP("@default", "dest"); + s = "dest"; - //if(r->type == Route::MIDI_DEVICE_ROUTE) // p3.3.49 Obsolete since 1.1-RC2 + //if(r->type == Route::MIDI_DEVICE_ROUTE) // Obsolete since 1.1-RC2 // s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType()); // //if(r->type != Route::TRACK_ROUTE) // if(r->type != Route::TRACK_ROUTE && r->type != Route::MIDI_PORT_ROUTE) - s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); + s += QString(" type=\"%1\"").arg(r->type); //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name()); - if(r->type == Route::MIDI_PORT_ROUTE) // p3.3.49 - s += QString(QT_TRANSLATE_NOOP("@default", " mport=\"%1\"/")).arg(r->midiPort); + if(r->type == Route::MIDI_PORT_ROUTE) + s += QString(" mport=\"%1\"/").arg(r->midiPort); else - s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); + s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); xml.tag(level, s.toAscii().constData()); diff --git a/muse2/muse/track.h b/muse2/muse/track.h index bbda67e4..f2e12e3a 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -4,6 +4,7 @@ // $Id: track.h,v 1.39.2.17 2009/12/20 05:00:35 terminator356 Exp $ // // (C) Copyright 1999-2004 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -71,9 +72,10 @@ class Track { static bool _tmpSoloChainDoIns; static bool _tmpSoloChainNoDec; - // p3.3.38 RouteList _inRoutes; RouteList _outRoutes; + bool _nodeTraversed; // Internal anti circular route traversal flag. + int _auxRouteCount; // Number of aux paths feeding this track. QString _name; bool _recordFlag; @@ -90,8 +92,6 @@ class Track { int _activity; int _lastActivity; - //int _meter[MAX_CHANNELS]; - //int _peak[MAX_CHANNELS]; double _meter[MAX_CHANNELS]; double _peak[MAX_CHANNELS]; @@ -148,7 +148,10 @@ class Track { bool noInRoute() const { return _inRoutes.empty(); } bool noOutRoute() const { return _outRoutes.empty(); } void writeRouting(int, Xml&) const; - + bool isCircularRoute(Track* dst); + int auxRefCount() const { return _auxRouteCount; } // Number of Aux Tracks with routing paths to this track. + void updateAuxRoute(int refInc, Track* dst); // Internal use. + PartList* parts() { return &_parts; } const PartList* cparts() const { return &_parts; } Part* findPart(unsigned tick); @@ -169,20 +172,21 @@ class Track { virtual void setMute(bool val); virtual void setOff(bool val); - virtual void updateSoloStates(bool noDec) = 0; - virtual void updateInternalSoloStates(); - void updateSoloState(); void setInternalSolo(unsigned int val); - static void clearSoloRefCounts(); virtual void setSolo(bool val) = 0; virtual bool isMute() const = 0; - unsigned int internalSolo() const { return _internalSolo; } bool soloMode() const { return _soloRefCnt; } bool solo() const { return _solo; } bool mute() const { return _mute; } bool off() const { return _off; } bool recordFlag() const { return _recordFlag; } + // + // Internal use... + static void clearSoloRefCounts(); + void updateSoloState(); + virtual void updateSoloStates(bool noDec) = 0; + virtual void updateInternalSoloStates(); int activity() { return _activity; } void setActivity(int v) { _activity = v; } @@ -191,8 +195,6 @@ class Track { void addActivity(int v) { _activity += v; } void resetPeaks(); static void resetAllMeter(); - //int meter(int ch) const { return _meter[ch]; } - //int peak(int ch) const { return _peak[ch]; } double meter(int ch) const { return _meter[ch]; } double peak(int ch) const { return _peak[ch]; } void resetMeter(); @@ -207,6 +209,7 @@ class Track { virtual AutomationType automationType() const = 0; virtual void setAutomationType(AutomationType t) = 0; static void setVisible(bool) { } + bool isVisible(); }; @@ -221,9 +224,9 @@ class MidiTrack : public Track { int _outPort; int _outChannel; //int _inPortMask; - ///unsigned int _inPortMask; // bitmask of accepted record ports - ///int _inChannelMask; // bitmask of accepted record channels - bool _recEcho; // For midi (and audio). Whether to echo incoming record events to output device. + //unsigned int _inPortMask; // bitmask of accepted record ports + //int _inChannelMask; // bitmask of accepted record channels + bool _recEcho; // For midi (and audio). Whether to echo incoming record events to output device. EventList* _events; // tmp Events during midi import MPEventList* _mpevents; // tmp Events druring recording @@ -284,17 +287,17 @@ class MidiTrack : public Track { void setOutPortAndChannelAndUpdate(int /*port*/, int /*chan*/); //void setInPortMask(int i) { _inPortMask = i; } - ///void setInPortMask(unsigned int i) { _inPortMask = i; } // Obsolete - ///void setInChannelMask(int i) { _inChannelMask = i; } // + //void setInPortMask(unsigned int i) { _inPortMask = i; } // Obsolete + //void setInChannelMask(int i) { _inChannelMask = i; } // // Backward compatibility: For reading old songs. void setInPortAndChannelMask(unsigned int /*portmask*/, int /*chanmask*/); void setRecEcho(bool b) { _recEcho = b; } int outPort() const { return _outPort; } //int inPortMask() const { return _inPortMask; } - ///unsigned int inPortMask() const { return _inPortMask; } + //unsigned int inPortMask() const { return _inPortMask; } int outChannel() const { return _outChannel; } - ///int inChannelMask() const { return _inChannelMask; } + //int inChannelMask() const { return _inChannelMask; } bool recEcho() const { return _recEcho; } virtual bool isMute() const; @@ -324,14 +327,10 @@ class MidiTrack : public Track { void readOurDrumMap(Xml& xml, bool dont_init=false); }; -} // namespace MusECore - -namespace MusECore { - //--------------------------------------------------------- // AudioTrack // this track can hold audio automation data and can -// hold tracktypes AUDIO, AUDIO_MASTER, AUDIO_GROUP, +// hold tracktypes WAVE, AUDIO_GROUP, AUDIO_OUTPUT, // AUDIO_INPUT, AUDIO_SOFTSYNTH, AUDIO_AUX //--------------------------------------------------------- @@ -339,25 +338,19 @@ class AudioTrack : public Track { //friend class MidiTrack; //static unsigned int _soloRefCnt; - bool _haveData; + bool _haveData; // Whether we have data from a previous process call during current cycle. CtrlListList _controller; CtrlRecList _recEvents; // recorded automation events bool _prefader; // prefader metering std::vector<double> _auxSend; - Pipeline* _efxPipe; - - AutomationType _automationType; - - //RouteList _inRoutes; - //RouteList _outRoutes; - - bool _sendMetronome; - //void readRecfile(Xml& xml); void readAuxSend(Xml& xml); - + + bool _sendMetronome; + AutomationType _automationType; + Pipeline* _efxPipe; protected: float** outBuffers; @@ -370,7 +363,7 @@ class AudioTrack : public Track { SndFile* _recFile; Fifo fifo; // fifo -> _recFile bool _processed; - + public: AudioTrack(TrackType t); //AudioTrack(TrackType t, int num_out_bufs = MAX_CHANNELS); @@ -450,12 +443,6 @@ class AudioTrack : public Track { void readVolume(Xml& xml); //void writeRouting(int, Xml&) const; - // routing - //RouteList* inRoutes() { return &_inRoutes; } - //RouteList* outRoutes() { return &_outRoutes; } - //bool noInRoute() const { return _inRoutes.empty(); } - //bool noOutRoute() const { return _outRoutes.empty(); } - virtual void preProcessAlways() { _processed = false; } virtual void addData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/); virtual void copyData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/); diff --git a/muse2/muse/transport.cpp b/muse2/muse/transport.cpp index 60494bc4..e978cb2e 100644 --- a/muse2/muse/transport.cpp +++ b/muse2/muse/transport.cpp @@ -45,13 +45,6 @@ namespace MusEGui { -static const char* recordTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to enable recording"); -static const char* stopTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to stop playback"); -static const char* playTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to start playback"); -static const char* startTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to rewind to start position"); -static const char* frewindTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to rewind"); -static const char* fforwardTransportText = QT_TRANSLATE_NOOP("@default", "Click this button to forward current play position"); - //--------------------------------------------------------- // toolButton //--------------------------------------------------------- @@ -401,25 +394,25 @@ Transport::Transport(QWidget* parent, const char* name) tb->setSpacing(0); buttons[0] = newButton(startIcon, tr("rewind to start")); - buttons[0]->setWhatsThis(tr(startTransportText)); + buttons[0]->setWhatsThis(tr("Click this button to rewind to start position")); buttons[1] = newButton(frewindIcon, tr("rewind")); buttons[1]->setAutoRepeat(true); - buttons[1]->setWhatsThis(tr(frewindTransportText)); + buttons[1]->setWhatsThis(tr("Click this button to rewind")); buttons[2] = newButton(fforwardIcon, tr("forward")); buttons[2]->setAutoRepeat(true); - buttons[2]->setWhatsThis(tr(fforwardTransportText)); + buttons[2]->setWhatsThis(tr("Click this button to forward current play position")); buttons[3] = newButton(stopIcon, tr("stop"), true); buttons[3]->setChecked(true); // set STOP - buttons[3]->setWhatsThis(tr(stopTransportText)); + buttons[3]->setWhatsThis(tr("Click this button to stop playback")); buttons[4] = newButton(playIcon, tr("play"), true); - buttons[4]->setWhatsThis(tr(playTransportText)); + buttons[4]->setWhatsThis(tr("Click this button to start playback")); buttons[5] = newButton(record_on_Icon, tr("record"), true); - buttons[5]->setWhatsThis(tr(recordTransportText)); + buttons[5]->setWhatsThis(tr("Click this button to enable recording")); for (int i = 0; i < 6; ++i) { diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index 5bbcfcd8..06c190a2 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -50,8 +50,11 @@ const char* UndoOp::typeName() "AddTrack", "DeleteTrack", "ModifyTrack", "AddPart", "DeletePart", "ModifyPart", "AddEvent", "DeleteEvent", "ModifyEvent", - "AddTempo", "DeleteTempo", "AddSig", "DeleteSig", - "SwapTrack", "ModifyClip" + "AddTempo", "DeleteTempo", + "AddSig", "DeleteSig", + "AddKey", "DeleteKey", + "SwapTrack", "ModifyClip", "ModifyMarker", + "ModifySongLen", "DoNothing" }; return name[type]; } @@ -95,6 +98,7 @@ void UndoOp::dump() case ModifyMarker: case AddKey: case DeleteKey: + case ModifySongLen: case DoNothing: break; } @@ -530,6 +534,10 @@ void Song::doUndo2() MusEGlobal::keymap.addKey(i->a, (key_enum)i->b); updateFlags |= SC_KEY; break; + case UndoOp::ModifySongLen: + _len=i->b; + updateFlags = -1; // set all flags + break; case UndoOp::ModifyClip: case UndoOp::ModifyMarker: case UndoOp::DoNothing: @@ -767,6 +775,10 @@ void Song::doRedo2() MusEGlobal::keymap.delKey(i->a); updateFlags |= SC_KEY; break; + case UndoOp::ModifySongLen: + _len=i->a; + updateFlags = -1; // set all flags + break; case UndoOp::ModifyClip: case UndoOp::ModifyMarker: case UndoOp::DoNothing: diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 42a80763..dffa1f55 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -54,6 +54,7 @@ struct UndoOp { SwapTrack, ModifyClip, ModifyMarker, + ModifySongLen, // a = new len, b = old len DoNothing }; UndoType type; diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h index b57b598d..b41e7137 100644 --- a/muse2/muse/vst.h +++ b/muse2/muse/vst.h @@ -50,6 +50,7 @@ class VstSynth : public Synth { } virtual ~VstSynth() {} + virtual Type synthType() const { return VST_SYNTH; } virtual void incInstances(int val); virtual void* instantiate(); //virtual SynthIF* createSIF() const; diff --git a/muse2/muse/wave.cpp b/muse2/muse/wave.cpp index 06759441..f22f6f97 100644 --- a/muse2/muse/wave.cpp +++ b/muse2/muse/wave.cpp @@ -105,7 +105,7 @@ SndFile::~SndFile() bool SndFile::openRead() { if (openFlag) { - printf("SndFile:: alread open\n"); + printf("SndFile:: already open\n"); return false; } QString p = path(); @@ -468,7 +468,7 @@ size_t SndFile::readWithHeap(int srcChannels, float** dst, size_t n, bool overwr { float *buffer = new float[n * sfinfo.channels]; int rn = readInternal(srcChannels,dst,n,overwrite, buffer); - delete buffer; + delete[] buffer; return rn; } @@ -588,11 +588,11 @@ size_t SndFile::write(int srcChannels, float** src, size_t n) else { printf("SndFile:write channel mismatch %d -> %d\n", srcChannels, dstChannels); - delete buffer; + delete[] buffer; return 0; } int nbr = sf_writef_float(sf, buffer, n) ; - delete buffer; + delete[] buffer; return nbr; } @@ -1120,6 +1120,22 @@ SndFileR::~SndFileR() } } +void SndFileList::clearDelete() +{ + // ~SndFile searches itself on the list (and will find for + // sure) and deletes the entry on its own. + while (!empty()) + delete *begin(); + + /* this is wrong, because ~SndFile deletes itself from the + * list, causing the iterator to be invalidated -> fail. + for (SndFileList::iterator i = begin(); i != end(); ++i) + delete *i; + clear(); + */ +} + + } // namespace MusECore namespace MusEGui { diff --git a/muse2/muse/wave.h b/muse2/muse/wave.h index 58e0ab87..535df939 100644 --- a/muse2/muse/wave.h +++ b/muse2/muse/wave.h @@ -182,11 +182,7 @@ class SndFileR { class SndFileList : public std::list<SndFile*> { public: SndFile* search(const QString& name); - void clearDelete() { - for (SndFileList::iterator i = begin(); i != end(); ++i) - delete *i; - clear(); - } + void clearDelete(); }; typedef SndFileList::iterator iSndFile; diff --git a/muse2/muse/waveedit/waveedit.cpp b/muse2/muse/waveedit/waveedit.cpp index 424f0688..1c1115b1 100644 --- a/muse2/muse/waveedit/waveedit.cpp +++ b/muse2/muse/waveedit/waveedit.cpp @@ -64,10 +64,12 @@ namespace MusEGui { void WaveEdit::closeEvent(QCloseEvent* e) { + _isDeleting = true; // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. + QSettings settings("MusE", "MusE-qt"); //settings.setValue("Waveedit/geometry", saveGeometry()); settings.setValue("Waveedit/windowState", saveState()); - emit deleted(static_cast<TopWin*>(this)); + emit isDeleting(static_cast<TopWin*>(this)); e->accept(); } @@ -92,23 +94,23 @@ WaveEdit::WaveEdit(MusECore::PartList* pl) menuGain = menuFunctions->addMenu(tr("&Gain")); - act = menuGain->addAction(tr("200%")); + act = menuGain->addAction("200%"); mapper->setMapping(act, CMD_GAIN_200); connect(act, SIGNAL(triggered()), mapper, SLOT(map())); - act = menuGain->addAction(tr("150%")); + act = menuGain->addAction("150%"); mapper->setMapping(act, CMD_GAIN_150); connect(act, SIGNAL(triggered()), mapper, SLOT(map())); - act = menuGain->addAction(tr("75%")); + act = menuGain->addAction("75%"); mapper->setMapping(act, CMD_GAIN_75); connect(act, SIGNAL(triggered()), mapper, SLOT(map())); - act = menuGain->addAction(tr("50%")); + act = menuGain->addAction("50%"); mapper->setMapping(act, CMD_GAIN_50); connect(act, SIGNAL(triggered()), mapper, SLOT(map())); - act = menuGain->addAction(tr("25%")); + act = menuGain->addAction("25%"); mapper->setMapping(act, CMD_GAIN_25); connect(act, SIGNAL(triggered()), mapper, SLOT(map())); @@ -287,6 +289,7 @@ WaveEdit::WaveEdit(MusECore::PartList* pl) } initTopwinState(); + MusEGlobal::muse->topwinMenuInited(this); } void WaveEdit::initShortcuts() @@ -458,7 +461,9 @@ void WaveEdit::readStatus(MusECore::Xml& xml) void WaveEdit::songChanged1(int bits) { - + if(_isDeleting) // Ignore while while deleting to prevent crash. + return; + if (bits & SC_SOLO) { MusECore::WavePart* part = (MusECore::WavePart*)(parts()->begin()->second); diff --git a/muse2/muse/waveedit/waveedit.h b/muse2/muse/waveedit/waveedit.h index b40aa93a..85e71a60 100644 --- a/muse2/muse/waveedit/waveedit.h +++ b/muse2/muse/waveedit/waveedit.h @@ -94,7 +94,7 @@ class WaveEdit : public MidiEditor { signals: - void deleted(MusEGui::TopWin*); + void isDeleting(MusEGui::TopWin*); public: WaveEdit(MusECore::PartList*); diff --git a/muse2/muse/wavetrack.cpp b/muse2/muse/wavetrack.cpp index 9edeffb6..0d699cbe 100644 --- a/muse2/muse/wavetrack.cpp +++ b/muse2/muse/wavetrack.cpp @@ -229,8 +229,8 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float* ciRoute i = irl->begin(); if(i->track->isMidiTrack()) { - if(MusEGlobal::debugMsg) - printf("WaveTrack::getData: Error: First route is a midi track route!\n"); + //if(MusEGlobal::debugMsg) + // printf("WaveTrack::getData: Error: First route is a midi track route!\n"); return false; } // p3.3.38 @@ -246,8 +246,8 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float* { if(i->track->isMidiTrack()) { - if(MusEGlobal::debugMsg) - printf("WaveTrack::getData: Error: Route is a midi track route!\n"); + //if(MusEGlobal::debugMsg) + // printf("WaveTrack::getData: Error: Route is a midi track route!\n"); //return false; continue; } diff --git a/muse2/muse/widgets/citem.h b/muse2/muse/widgets/citem.h index 1777eb23..199d18b0 100644 --- a/muse2/muse/widgets/citem.h +++ b/muse2/muse/widgets/citem.h @@ -90,7 +90,7 @@ class CItem { }; typedef std::multimap<int, CItem*, std::less<int> >::iterator iCItem; -//typedef std::multimap<int, CItem*, std::less<int> >::const_iterator ciCItem; +typedef std::multimap<int, CItem*, std::less<int> >::const_iterator ciCItem; typedef std::multimap<int, CItem*, std::less<int> >::const_reverse_iterator rciCItem; //--------------------------------------------------------- diff --git a/muse2/muse/widgets/comboQuant.cpp b/muse2/muse/widgets/comboQuant.cpp index aee7ad5c..6d8dc30c 100644 --- a/muse2/muse/widgets/comboQuant.cpp +++ b/muse2/muse/widgets/comboQuant.cpp @@ -37,9 +37,9 @@ static int quantTable[] = { }; static const char* quantStrings[] = { - QT_TRANSLATE_NOOP("@default", "Off"), "64T", "32T", "16T", "8T", "4T", "2T", "1T", - QT_TRANSLATE_NOOP("@default", "Off"), "64", "32", "16", "8", "4", "2", "1", - QT_TRANSLATE_NOOP("@default", "Off"), "64.", "32.", "16.", "8.", "4.", "2.", "1." + QT_TRANSLATE_NOOP("MusEGui::ComboQuant", "Off"), "64T", "32T", "16T", "8T", "4T", "2T", "1T", + QT_TRANSLATE_NOOP("MusEGui::ComboQuant", "Off"), "64", "32", "16", "8", "4", "2", "1", + QT_TRANSLATE_NOOP("MusEGui::ComboQuant", "Off"), "64.", "32.", "16.", "8.", "4.", "2.", "1." }; //--------------------------------------------------------- diff --git a/muse2/muse/widgets/configmidifilebase.ui b/muse2/muse/widgets/configmidifilebase.ui index c050450c..3eb7063e 100644 --- a/muse2/muse/widgets/configmidifilebase.ui +++ b/muse2/muse/widgets/configmidifilebase.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>548</width> - <height>346</height> + <width>546</width> + <height>367</height> </rect> </property> <property name="windowTitle"> @@ -28,8 +28,8 @@ <property name="title"> <string>Import:</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> + <layout class="QGridLayout"> + <item row="0" column="0"> <widget class="QCheckBox" name="splitPartsCheckBox"> <property name="toolTip"> <string>Split tracks into parts, or one single part</string> @@ -42,7 +42,7 @@ </property> </widget> </item> - <item> + <item row="1" column="0"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QRadioButton" name="newDrumsCheckbox"> @@ -78,10 +78,10 @@ <string>Export:</string> </property> <layout class="QGridLayout"> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QLineEdit" name="copyrightEdit"/> </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QComboBox" name="divisionCombo"> <item> <property name="text"> @@ -100,7 +100,7 @@ </item> </widget> </item> - <item row="3" column="0" colspan="2"> + <item row="4" column="0" colspan="2"> <widget class="QCheckBox" name="extendedFormat"> <property name="enabled"> <bool>true</bool> @@ -110,7 +110,7 @@ </property> </widget> </item> - <item row="4" column="0" colspan="2"> + <item row="5" column="0" colspan="2"> <widget class="QCheckBox" name="twoByteTimeSigs"> <property name="text"> <string>Use &2-byte time signatures instead of standard 4</string> @@ -120,7 +120,7 @@ </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <widget class="QLabel" name="textLabel2"> <property name="text"> <string>Copyright:</string> @@ -140,7 +140,23 @@ </property> </widget> </item> - <item row="1" column="0"> + <item row="1" column="0" colspan="2"> + <widget class="QLabel" name="textLabel4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Note: Format 0 uses the FIRST midi track's name/comment in the arranger</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="2" column="0"> <widget class="QLabel" name="textLabel1"> <property name="text"> <string>Division:</string> @@ -150,7 +166,7 @@ </property> </widget> </item> - <item row="5" column="0" colspan="2"> + <item row="6" column="0" colspan="2"> <widget class="QCheckBox" name="optNoteOffs"> <property name="text"> <string>Save space by replacing note-offs with &zero velocity note-ons</string> diff --git a/muse2/muse/widgets/filedialog.cpp b/muse2/muse/widgets/filedialog.cpp index df391b45..7f2c1681 100644 --- a/muse2/muse/widgets/filedialog.cpp +++ b/muse2/muse/widgets/filedialog.cpp @@ -33,6 +33,7 @@ #include "filedialog.h" #include "../globals.h" #include "gconfig.h" +#include "helper.h" namespace MusEGui { @@ -122,11 +123,13 @@ void MFileDialog::userToggled(bool flag) if (lastUserDir.isEmpty()) { - lastUserDir = MusEGlobal::museUser + QString("/") + baseDir; // Initialize if first time + //lastUserDir = MusEGlobal::museUser + QString("/") + baseDir; // Initialize if first time + lastUserDir = MusEGlobal::configPath + QString("/") + baseDir; // Initialize if first time // p4.0.39 } if (testDirCreate(this, lastUserDir)) - setDirectory(MusEGlobal::museUser); + //setDirectory(MusEGlobal::museUser); + setDirectory(MusEGlobal::configPath); // p4.0.39 else setDirectory(lastUserDir); @@ -269,40 +272,14 @@ void MFileDialog::directoryChanged(const QString&) } } - -//--------------------------------------------------------- -// getFilterExtension -//--------------------------------------------------------- - -QString getFilterExtension(const QString &filter) -{ - // - // Return the first extension found. Must contain at least one * character. - // - - int pos = filter.indexOf('*'); - if(pos == -1) - return QString(); - - QString filt; - int len = filter.length(); - ++pos; - for( ; pos < len; ++pos) - { - QChar c = filter[pos]; - if((c == ')') || (c == ';') || (c == ',') || (c == ' ')) - break; - filt += filter[pos]; - } - return filt; -} - //--------------------------------------------------------- // getOpenFileName //--------------------------------------------------------- -QString getOpenFileName(const QString &startWith, - const QStringList& filters, QWidget* parent, const QString& name, bool* all, MFileDialog::ViewType viewType) +QString getOpenFileName(const QString &startWith, const char** filters_chararray, + QWidget* parent, const QString& name, bool* all, MFileDialog::ViewType viewType) { + QStringList filters = localizedStringListFromCharArray(filters_chararray, "file_patterns"); + QString initialSelection; // FIXME Tim. MFileDialog *dlg = new MFileDialog(startWith, QString::null, parent, false); dlg->setNameFilters(filters); @@ -339,9 +316,10 @@ QString getOpenFileName(const QString &startWith, //--------------------------------------------------------- QString getSaveFileName(const QString &startWith, - //const char** filters, QWidget* parent, const QString& name) - const QStringList& filters, QWidget* parent, const QString& name) + const char** filters_chararray, QWidget* parent, const QString& name) { + QStringList filters = localizedStringListFromCharArray(filters_chararray, "file_patterns"); + MFileDialog *dlg = new MFileDialog(startWith, QString::null, parent, true); dlg->setNameFilters(filters); dlg->setWindowTitle(name); @@ -404,9 +382,9 @@ QString getSaveFileName(const QString &startWith, //--------------------------------------------------------- QString getImageFileName(const QString& startWith, - //const char** filters, QWidget* parent, const QString& name) - const QStringList& filters, QWidget* parent, const QString& name) + const char** filters_chararray, QWidget* parent, const QString& name) { + QStringList filters = localizedStringListFromCharArray(filters_chararray, "file_patterns"); QString initialSelection; QString* workingDirectory = new QString(QDir::currentPath()); if (!startWith.isEmpty() ) { @@ -505,10 +483,12 @@ FILE* fileOpen(QWidget* parent, QString name, const QString& ext, FILE* fp = 0; if (popenFlag) { if (strcmp(mode, "r") == 0) - zip += QString(" -d < "); + //zip += QString(" -d < "); + zip += QString(" -d < \""); // p4.0.40 else - zip += QString(" > "); - zip += name; + zip += QString(" > \""); + //zip += name; + zip = zip + name + QString("\""); // p4.0.40 fp = popen(zip.toAscii().data(), mode); } else { @@ -547,15 +527,14 @@ MFile::~MFile() // open //--------------------------------------------------------- -//FILE* MFile::open(const char* mode, const char** pattern, -FILE* MFile::open(const char* mode, const QStringList& pattern, +FILE* MFile::open(const char* mode, const char** patterns_chararray, QWidget* parent, bool noError, bool warnIfOverwrite, const QString& caption) { QString name; if (strcmp(mode, "r") == 0) - name = getOpenFileName(path, pattern, parent, caption, 0); + name = getOpenFileName(path, patterns_chararray, parent, caption, 0); else - name = getSaveFileName(path, pattern, parent, caption); + name = getSaveFileName(path, patterns_chararray, parent, caption); if (name.isEmpty()) return 0; f = fileOpen(parent, name, ext, mode, isPopen, noError, diff --git a/muse2/muse/widgets/filedialog.h b/muse2/muse/widgets/filedialog.h index e5687494..b4e21e2c 100644 --- a/muse2/muse/widgets/filedialog.h +++ b/muse2/muse/widgets/filedialog.h @@ -3,6 +3,7 @@ // Linux Music Editor // $Id: filedialog.h,v 1.2.2.2 2008/01/19 13:33:46 wschweer Exp $ // (C) Copyright 2000 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -24,8 +25,6 @@ #include "ui_fdialogbuttons.h" -class QStringList; - namespace MusEGui { //--------------------------------------------------------- @@ -91,14 +90,11 @@ class ContentsPreview : public QWidget, public Q3FilePreview { }; */ -//QString getSaveFileName(const QString& startWidth, const char** filter, -QString getSaveFileName(const QString& startWidth, const QStringList& filters, +QString getSaveFileName(const QString& startWidth, const char** filters, QWidget* parent, const QString& name); -//QString getOpenFileName(const QString& startWidth, const char** filter, -QString getOpenFileName(const QString& startWidth, const QStringList& filters, +QString getOpenFileName(const QString& startWidth, const char** filters, QWidget* parent, const QString& name, bool* openAll, MFileDialog::ViewType viewType = MFileDialog::PROJECT_VIEW); -//QString getImageFileName(const QString& startWith, const char** filters, -QString getImageFileName(const QString& startWith, const QStringList& filters, +QString getImageFileName(const QString& startWith, const char** filters, QWidget* parent, const QString& name); FILE* fileOpen(QWidget*, QString, const QString&, @@ -119,8 +115,7 @@ class MFile { public: MFile(const QString& path, const QString& ext); ~MFile(); - //FILE* open(const char* mode, const char** pattern, - FILE* open(const char* mode, const QStringList& pattern, + FILE* open(const char* mode, const char** patterns, QWidget* parent, bool noError, bool warnIfOverwrite, const QString& caption); }; diff --git a/muse2/muse/widgets/function_dialogs/quantbase.ui b/muse2/muse/widgets/function_dialogs/quantbase.ui index 973be7b8..31173e46 100644 --- a/muse2/muse/widgets/function_dialogs/quantbase.ui +++ b/muse2/muse/widgets/function_dialogs/quantbase.ui @@ -157,7 +157,7 @@ <bool>false</bool> </property> <property name="currentIndex"> - <number>3</number> + <number>0</number> </property> <property name="frame"> <bool>true</bool> @@ -174,7 +174,12 @@ </item> <item> <property name="text"> - <string>Quarter</string> + <string>4th</string> + </property> + </item> + <item> + <property name="text"> + <string>4th Triplet</string> </property> </item> <item> @@ -184,14 +189,29 @@ </item> <item> <property name="text"> + <string>8th Triplet</string> + </property> + </item> + <item> + <property name="text"> <string>16th</string> </property> </item> <item> <property name="text"> + <string>16th Triplet</string> + </property> + </item> + <item> + <property name="text"> <string>32th</string> </property> </item> + <item> + <property name="text"> + <string>32th Triplet</string> + </property> + </item> </widget> </item> <item row="3" column="0"> diff --git a/muse2/muse/widgets/function_dialogs/quantize.cpp b/muse2/muse/widgets/function_dialogs/quantize.cpp index df7c0298..7233c2b8 100644 --- a/muse2/muse/widgets/function_dialogs/quantize.cpp +++ b/muse2/muse/widgets/function_dialogs/quantize.cpp @@ -26,6 +26,20 @@ namespace MusEGui { +int rasterVals[] = { + 1, // Whole note divisor + 2, // Half note divisor + 4, // 4th note divisor + 6, // 4thT divisor + 8, // 8th divisor + 12,//8thT divisor + 16,// ... + 24, + 32, + 48, + 64 +}; + Quantize::Quantize(QWidget* parent) : QDialog(parent) { @@ -44,7 +58,7 @@ void Quantize::pull_values() range = range_group->checkedId(); strength = strength_spinbox->value(); threshold = threshold_spinbox->value(); - raster_power2 = raster_combobox->currentIndex(); + raster_index = raster_combobox->currentIndex(); quant_len = len_checkbox->isChecked(); swing = swing_spinbox->value(); } @@ -62,7 +76,7 @@ int Quantize::exec() range_group->button(range)->setChecked(true); strength_spinbox->setValue(strength); threshold_spinbox->setValue(threshold); - raster_combobox->setCurrentIndex(raster_power2); + raster_combobox->setCurrentIndex(raster_index); len_checkbox->setChecked(quant_len); swing_spinbox->setValue(swing); @@ -88,7 +102,7 @@ void Quantize::read_configuration(MusECore::Xml& xml) else if (tag == "threshold") threshold=xml.parseInt(); else if (tag == "raster") - raster_power2=xml.parseInt(); + raster_index=xml.parseInt(); else if (tag == "swing") swing=xml.parseInt(); else if (tag == "quant_len") @@ -113,7 +127,7 @@ void Quantize::write_configuration(int level, MusECore::Xml& xml) xml.intTag(level, "range", range); xml.intTag(level, "strength", strength); xml.intTag(level, "threshold", threshold); - xml.intTag(level, "raster", raster_power2); + xml.intTag(level, "raster", raster_index); xml.intTag(level, "swing", swing); xml.intTag(level, "quant_len", quant_len); xml.tag(level, "/quantize"); diff --git a/muse2/muse/widgets/function_dialogs/quantize.h b/muse2/muse/widgets/function_dialogs/quantize.h index 6ce74215..b5229f9e 100644 --- a/muse2/muse/widgets/function_dialogs/quantize.h +++ b/muse2/muse/widgets/function_dialogs/quantize.h @@ -33,6 +33,7 @@ class Xml; namespace MusEGui { + class Quantize : public QDialog, public Ui::QuantBase { Q_OBJECT @@ -50,18 +51,18 @@ class Quantize : public QDialog, public Ui::QuantBase int range; int strength; int threshold; - int raster_power2; + int raster_index; int swing; bool quant_len; void read_configuration(MusECore::Xml& xml); void write_configuration(int level, MusECore::Xml& xml); - public slots: int exec(); }; +extern int rasterVals[]; } // namespace MusEGui #endif diff --git a/muse2/muse/widgets/genset.cpp b/muse2/muse/widgets/genset.cpp index dd91e9ec..df7dea78 100644 --- a/muse2/muse/widgets/genset.cpp +++ b/muse2/muse/widgets/genset.cpp @@ -4,6 +4,7 @@ // $Id: genset.cpp,v 1.7.2.8 2009/12/01 03:52:40 terminator356 Exp $ // // (C) Copyright 2001-2004 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -24,8 +25,10 @@ #include <stdio.h> #include <QFileDialog> +#include <QFileInfo> #include <QRect> #include <QShowEvent> +#include <QString> #include "genset.h" #include "app.h" @@ -33,6 +36,7 @@ #include "midiseq.h" #include "globals.h" #include "icons.h" +#include "helper.h" namespace MusEGui { @@ -100,12 +104,6 @@ GlobalSettingsConfig::GlobalSettingsConfig(QWidget* parent) } } - userInstrumentsPath->setText(MusEGlobal::config.userInstrumentsDir); - selectInstrumentsDirButton->setIcon(*openIcon); - defaultInstrumentsDirButton->setIcon(*undoIcon); - connect(selectInstrumentsDirButton, SIGNAL(clicked()), SLOT(selectInstrumentsPath())); - connect(defaultInstrumentsDirButton, SIGNAL(clicked()), SLOT(defaultInstrumentsPath())); - guiRefreshSelect->setValue(MusEGlobal::config.guiRefresh); minSliderSelect->setValue(int(MusEGlobal::config.minSlider)); minMeterSelect->setValue(MusEGlobal::config.minMeter); @@ -126,6 +124,9 @@ GlobalSettingsConfig::GlobalSettingsConfig(QWidget* parent) Period affects midi playback resolution. Shorter periods are desirable.</string> </property> */ + + projDirEntry->setText(MusEGlobal::config.projectBaseFolder); + projDirOpenToolButton->setIcon(*openIcon); startSongEntry->setText(MusEGlobal::config.startSong); startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); @@ -180,9 +181,14 @@ Shorter periods are desirable.</string> popsDefStayOpenCheckBox->setChecked(MusEGlobal::config.popupsDefaultStayOpen); lmbDecreasesCheckBox->setChecked(MusEGlobal::config.leftMouseButtonCanDecrease); rangeMarkerWithoutMMBCheckBox->setChecked(MusEGlobal::config.rangeMarkerWithoutMMB); - + + addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); + unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); + //updateSettings(); // TESTING + connect(projDirOpenToolButton, SIGNAL(clicked()), SLOT(browseProjDir())); + connect(applyButton, SIGNAL(clicked()), SLOT(apply())); connect(okButton, SIGNAL(clicked()), SLOT(ok())); connect(cancelButton, SIGNAL(clicked()), SLOT(cancel())); @@ -267,6 +273,8 @@ void GlobalSettingsConfig::updateSettings() //dummyAudioRealRate->setText(dad ? QString().setNum(sampleRate) : "---"); //dummyAudioRealRate->setText(QString().setNum(sampleRate)); // Not used any more. p4.0.20 + projDirEntry->setText(MusEGlobal::config.projectBaseFolder); + startSongEntry->setText(MusEGlobal::config.startSong); startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); @@ -321,6 +329,9 @@ void GlobalSettingsConfig::updateSettings() lmbDecreasesCheckBox->setChecked(MusEGlobal::config.leftMouseButtonCanDecrease); rangeMarkerWithoutMMBCheckBox->setChecked(MusEGlobal::config.rangeMarkerWithoutMMB); + addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); + unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); + updateMdiSettings(); } @@ -361,7 +372,9 @@ void GlobalSettingsConfig::apply() MusEGlobal::config.useOutputLimiter = outputLimiterCheckBox->isChecked(); MusEGlobal::config.vstInPlace = vstInPlaceCheckBox->isChecked(); MusEGlobal::config.rtcTicks = rtcResolutions[rtcticks]; - MusEGlobal::config.userInstrumentsDir = userInstrumentsPath->text(); + + MusEGlobal::config.projectBaseFolder = projDirEntry->text(); + MusEGlobal::config.startSong = startSongEntry->text(); MusEGlobal::config.startMode = startSongGroup->checkedId(); MusEGlobal::config.newDrumRecordCondition = MusECore::newDrumRecordCondition_t(recDrumGroup->checkedId()); @@ -421,6 +434,9 @@ void GlobalSettingsConfig::apply() MusEGlobal::config.leftMouseButtonCanDecrease = lmbDecreasesCheckBox->isChecked(); MusEGlobal::config.rangeMarkerWithoutMMB = rangeMarkerWithoutMMBCheckBox->isChecked(); + MusEGlobal::config.addHiddenTracks = addHiddenCheckBox->isChecked(); + MusEGlobal::config.unhideTracks = unhideTracksCheckBox->isChecked(); + //MusEGlobal::muse->showMixer(MusEGlobal::config.mixerVisible); MusEGlobal::muse->showMixer1(MusEGlobal::config.mixer1Visible); MusEGlobal::muse->showMixer2(MusEGlobal::config.mixer2Visible); @@ -455,8 +471,6 @@ void GlobalSettingsConfig::apply() MusEGlobal::muse->resize(MusEGlobal::config.geometryMain.size()); MusEGlobal::muse->move(MusEGlobal::config.geometryMain.topLeft()); - MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; - MusEGlobal::muse->setHeartBeat(); // set guiRefresh MusEGlobal::midiSeq->msgSetRtc(); // set midi tick rate @@ -559,21 +573,6 @@ void GlobalSettingsConfig::transportCurrent() transportY->setValue(r.y()); } -void GlobalSettingsConfig::selectInstrumentsPath() - { - QString dir = QFileDialog::getExistingDirectory(this, - tr("Selects instruments directory"), - MusEGlobal::config.userInstrumentsDir); - userInstrumentsPath->setText(dir); - } - -void GlobalSettingsConfig::defaultInstrumentsPath() - { - QString dir = MusEGlobal::configPath + "/instruments"; - userInstrumentsPath->setText(dir); - } - - void GlobalSettingsConfig::traditionalPreset() { for (std::list<MdiSettings*>::iterator it = mdisettings.begin(); it!=mdisettings.end(); it++) @@ -611,5 +610,12 @@ void GlobalSettingsConfig::borlandPreset() updateMdiSettings(); } +void GlobalSettingsConfig::browseProjDir() +{ + QString dir = MusEGui::browseProjectFolder(this); + if(!dir.isEmpty()) + projDirEntry->setText(dir); +} + } // namespace MusEGui diff --git a/muse2/muse/widgets/genset.h b/muse2/muse/widgets/genset.h index 92da61e3..53f5c2c1 100644 --- a/muse2/muse/widgets/genset.h +++ b/muse2/muse/widgets/genset.h @@ -4,6 +4,7 @@ // $Id: genset.h,v 1.3 2004/01/25 09:55:17 wschweer Exp $ // // (C) Copyright 2001 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -53,8 +54,7 @@ class GlobalSettingsConfig : public QDialog, public Ui::GlobalSettingsDialogBase void bigtimeCurrent(); void mainCurrent(); void transportCurrent(); - void selectInstrumentsPath(); - void defaultInstrumentsPath(); + void browseProjDir(); void traditionalPreset(); void mdiPreset(); void borlandPreset(); diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui index 39dcd4c3..1abc3cd1 100644 --- a/muse2/muse/widgets/gensetbase.ui +++ b/muse2/muse/widgets/gensetbase.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>556</width> - <height>527</height> + <height>552</height> </rect> </property> <property name="windowTitle"> @@ -23,14 +23,43 @@ </sizepolicy> </property> <property name="currentIndex"> - <number>2</number> + <number>0</number> </property> <widget class="QWidget" name="TabPage"> <attribute name="title"> <string>Application</string> </attribute> <layout class="QGridLayout"> - <item row="1" column="0"> + <item row="0" column="0"> + <widget class="QGroupBox" name="projDirGroupBox"> + <property name="title"> + <string>Project directory</string> + </property> + <layout class="QHBoxLayout" name="qhboxProjDir"> + <item> + <widget class="QLabel" name="textLabel_ProjDir"> + <property name="text"> + <string>Projects:</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="projDirEntry"/> + </item> + <item> + <widget class="QToolButton" name="projDirOpenToolButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="0"> <widget class="QGroupBox" name="groupBox4"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> @@ -413,14 +442,14 @@ </layout> </widget> </item> - <item row="0" column="0"> + <item row="1" column="0"> <widget class="QGroupBox" name="groupBox3"> <property name="title"> <string>Start Muse</string> </property> <layout class="QGridLayout"> <item row="0" column="0"> - <layout class="QGridLayout"> + <layout class="QGridLayout" name="gridLayout11"> <item row="1" column="0"> <spacer name="spacer7_2"> <property name="orientation"> @@ -438,7 +467,7 @@ </spacer> </item> <item row="2" column="0" colspan="2"> - <layout class="QHBoxLayout"> + <layout class="QHBoxLayout" name="qhboxStartSong"> <item> <widget class="QLabel" name="textLabel1_2"> <property name="text"> @@ -811,9 +840,9 @@ Adjusts responsiveness of audio controls and <number>2</number> </property> <item row="0" column="0"> - <layout class="QGridLayout"> + <layout class="QGridLayout" name="gridLayoutwaveEditor"> <item row="0" column="0"> - <layout class="QHBoxLayout"> + <layout class="QHBoxLayout" name="qhboxLayoutWaveEditor"> <item> <widget class="QLabel" name="textLabel2_2"> <property name="sizePolicy"> @@ -995,13 +1024,7 @@ Adjusts responsiveness of audio controls and <attribute name="title"> <string>Midi</string> </attribute> - <layout class="QVBoxLayout"> - <property name="spacing"> - <number>6</number> - </property> - <property name="margin"> - <number>11</number> - </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> <item> <widget class="QGroupBox" name="GroupBox2"> <property name="title"> @@ -1179,30 +1202,6 @@ Adjusts responsiveness of audio controls and </item> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="TextLabel3_4"> - <property name="text"> - <string>Instruments Directory</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLineEdit" name="userInstrumentsPath"/> - </item> - <item row="3" column="2"> - <widget class="QPushButton" name="selectInstrumentsDirButton"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="3" column="3"> - <widget class="QPushButton" name="defaultInstrumentsDirButton"> - <property name="text"> - <string/> - </property> - </widget> - </item> </layout> </widget> </item> @@ -1244,14 +1243,14 @@ Adjusts responsiveness of audio controls and </widget> </item> <item> - <spacer name="verticalSpacer_2"> + <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>20</width> - <height>40</height> + <width>191</width> + <height>166</height> </size> </property> </spacer> @@ -1260,7 +1259,7 @@ Adjusts responsiveness of audio controls and </widget> <widget class="QWidget" name="tab3"> <attribute name="title"> - <string>GUI</string> + <string>GUI Behaviour</string> </attribute> <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="spacing"> @@ -1443,10 +1442,58 @@ left button behave like the middle button in such areas.</string> </property> </widget> </item> + <item row="9" column="0"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="7" column="1"> + <widget class="QCheckBox" name="addHiddenCheckBox"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Allow adding hidden tracks in track list menu</string> + </property> + </widget> + </item> + <item row="8" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Unhide tracks when adding hidden tracks</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <widget class="QCheckBox" name="unhideTracksCheckBox"> + <property name="text"> + <string/> + </property> + </widget> + </item> </layout> </widget> </item> - <item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>GUI Style</string> + </attribute> + <layout class="QGridLayout" name="gridLayoutTab2"> + <item row="0" column="0"> <widget class="QGroupBox" name="groupBox_2"> <property name="title"> <string>MDI-subwindowness and sharing menus</string> @@ -1497,8 +1544,8 @@ left button behave like the middle button in such areas.</string> <rect> <x>0</x> <y>0</y> - <width>482</width> - <height>143</height> + <width>96</width> + <height>26</height> </rect> </property> <layout class="QHBoxLayout" name="horizontalLayout_3"> diff --git a/muse2/muse/widgets/header.cpp b/muse2/muse/widgets/header.cpp index 2c1057c3..968e7f73 100644 --- a/muse2/muse/widgets/header.cpp +++ b/muse2/muse/widgets/header.cpp @@ -51,7 +51,7 @@ void Header::readStatus(MusECore::Xml& xml) 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); + int section = visualIndex(logialIdx - (isHidden? 1:0)); moveSection(section, index); if (isHidden) hideSection(logialIdx-1); @@ -65,7 +65,7 @@ void Header::readStatus(MusECore::Xml& xml) bool foundIt=false; for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) { int id=((*it).toInt()); - if ( id == i || i ==1-id ) + if ( id == i || i == -1 - id ) foundIt=true; } if (foundIt == false) { @@ -97,7 +97,7 @@ void Header::writeStatus(int level, MusECore::Xml& xml) const //xml.nput(level, "<%s> ", name()); xml.nput(level, "<%s> ", MusECore::Xml::xmlString(objectName()).toLatin1().constData()); int n = count(); - for (int i = n; i >= 0; --i) { + for (int i = n-1; i >= 0; --i) { if (isSectionHidden(logicalIndex(i))) xml.nput("%d ", -logicalIndex(i)-1); // hidden is stored as negative value starting from -1 else diff --git a/muse2/muse/widgets/knob.cpp b/muse2/muse/widgets/knob.cpp index 920d2028..269f65cf 100644 --- a/muse2/muse/widgets/knob.cpp +++ b/muse2/muse/widgets/knob.cpp @@ -323,6 +323,30 @@ void Knob::rangeChange() repaint(); } +void Knob::mousePressEvent(QMouseEvent *e) +{ + if (e->button() == Qt::MidButton || e->modifiers() & Qt::ControlModifier) { + int xpos = e->x() - width() /2; + double v = float(e->y()) / height() * 1.2; + + double halfRange = (maxValue() - minValue())/2; + double midValue = minValue() + halfRange; + // apply to range + if (xpos < 0) { // left values + v = -v; + } + setValue(v * halfRange + midValue); + SliderBase::valueChange(); + + // fake a left-click to make the knob still "stick" to + // the mouse. + QMouseEvent temp(e->type(), e->pos(), Qt::LeftButton, e->buttons(), e->modifiers()); + SliderBase::mousePressEvent(&temp); + return; + } + SliderBase::mousePressEvent(e); +} + //--------------------------------------------------------- // resizeEvent //--------------------------------------------------------- diff --git a/muse2/muse/widgets/knob.h b/muse2/muse/widgets/knob.h index 483fafa6..bd8621a1 100644 --- a/muse2/muse/widgets/knob.h +++ b/muse2/muse/widgets/knob.h @@ -80,6 +80,7 @@ class Knob : public SliderBase, public ScaleIf virtual void paintEvent(QPaintEvent *); virtual void resizeEvent(QResizeEvent *e); + virtual void mousePressEvent(QMouseEvent *e); double getValue(const QPoint &p); void getScrollMode( QPoint &p, const Qt::MouseButton &button, int &scrollMode, int &direction ); void scaleChange() { repaint(); } diff --git a/muse2/muse/widgets/meter.cpp b/muse2/muse/widgets/meter.cpp index 5c79ffb2..d9ca8e20 100644 --- a/muse2/muse/widgets/meter.cpp +++ b/muse2/muse/widgets/meter.cpp @@ -229,6 +229,8 @@ void Meter::setRange(double min, double max) void Meter::paintEvent(QPaintEvent* ev) { + // For some reason upon resizing we get double calls here and in resizeEvent. + QPainter p(this); p.setRenderHint(QPainter::Antialiasing); @@ -534,8 +536,11 @@ void Meter::drawVU(QPainter& p, const QRect& rect, const QPainterPath& drawPath, void Meter::resizeEvent(QResizeEvent* ev) { - QFrame::resizeEvent(ev); + // For some reason upon resizing we get double calls here and in paintEvent. + //printf("Meter::resizeEvent w:%d h:%d\n", ev->size().width(), ev->size().height()); cur_yv = -1; // Force re-initialization. + QFrame::resizeEvent(ev); + update(); } //--------------------------------------------------------- diff --git a/muse2/muse/widgets/metronome.cpp b/muse2/muse/widgets/metronome.cpp index e6b7bd91..416e9e47 100644 --- a/muse2/muse/widgets/metronome.cpp +++ b/muse2/muse/widgets/metronome.cpp @@ -85,7 +85,7 @@ void MetronomeConfig::audioBeepRoutesClicked() int nn = 0; for(MusECore::iAudioOutput iao = ol->begin(); iao != ol->end(); ++iao) { - QAction* action = pup->addAction(QT_TRANSLATE_NOOP("@default", (*iao)->name())); + QAction* action = pup->addAction((*iao)->name()); action->setCheckable(true); action->setData(nn); if((*iao)->sendMetronome()) diff --git a/muse2/muse/widgets/midisync.ui b/muse2/muse/widgets/midisync.ui index 8fc6248a..81d7451e 100644 --- a/muse2/muse/widgets/midisync.ui +++ b/muse2/muse/widgets/midisync.ui @@ -388,6 +388,19 @@ Enabled inputs in the list will </column> </widget> </item> + <item row="5" column="0"> + <widget class="QLabel" name="toBeDoneLabel"> + <property name="text"> + <string>Note: Sync delay and MTC sync currently not fully implemeted</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index d0c0e070..7952308e 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -579,7 +579,8 @@ void MidiTrackInfo::setLabelText() //gradient.setColorAt(0, c.darker()); //gradient.setColorAt(0, c); //gradient.setColorAt(1, c.darker()); - gradient.setColorAt(0, c.lighter()); + gradient.setColorAt(0, c); + gradient.setColorAt(0.5, c.lighter()); gradient.setColorAt(1, c); //palette.setBrush(QPalette::Button, gradient); //palette.setBrush(QPalette::Window, gradient); @@ -640,14 +641,17 @@ void MidiTrackInfo::iOutputPortChanged(int index) { if(!selected) return; + int port_num = iOutput->itemData(index).toInt(); + if(port_num < 0 || port_num >= MIDI_PORTS) + return; MusECore::MidiTrack* track = (MusECore::MidiTrack*)selected; - if (index == track->outPort()) + if (port_num == track->outPort()) return; // Changed by T356. - //track->setOutPort(index); + //track->setOutPort(port_num); MusEGlobal::audio->msgIdle(true); - //audio->msgSetTrackOutPort(track, index); - track->setOutPortAndUpdate(index); + //audio->msgSetTrackOutPort(track, port_num); + track->setOutPortAndUpdate(port_num); MusEGlobal::audio->msgIdle(false); //MusEGlobal::song->update(SC_MIDI_TRACK_PROP); @@ -1086,11 +1090,9 @@ void MidiTrackInfo::instrPopup() //QMenu* pup = new QMenu; PopupMenu* pup = new PopupMenu(true); - //instr->populatePatchPopup(pop, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); - populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); + //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack()); - //if(pop->actions().count() == 0) - // return; if(pup->actions().count() == 0) { delete pup; @@ -1100,7 +1102,6 @@ void MidiTrackInfo::instrPopup() connect(pup, SIGNAL(triggered(QAction*)), SLOT(instrPopupActivated(QAction*))); //connect(pup, SIGNAL(hovered(QAction*)), SLOT(instrPopupActivated(QAction*))); - //QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5))); QAction *act = pup->exec(iPatch->mapToGlobal(QPoint(10,5))); if(act) { @@ -1351,12 +1352,20 @@ void MidiTrackInfo::updateTrackInfo(int flags) //iInput->clear(); iOutput->clear(); + int item_idx = 0; for (int i = 0; i < MIDI_PORTS; ++i) { + MusECore::MidiDevice* md = MusEGlobal::midiPorts[i].device(); + if(!md) // In the case of this combo box, don't bother listing empty ports. p4.0.41 + continue; + //if(!(md->rwFlags() & 1 || md->isSynti()) && (i != outPort)) + if(!(md->rwFlags() & 1) && (i != outPort)) // Only writeable ports, or current one. p4.0.41 + continue; QString name; name.sprintf("%d:%s", i+1, MusEGlobal::midiPorts[i].portname().toLatin1().constData()); - iOutput->insertItem(i, name); + iOutput->insertItem(item_idx, name, i); if (i == outPort) - iOutput->setCurrentIndex(i); + iOutput->setCurrentIndex(item_idx); + item_idx++; } iOutput->blockSignals(false); diff --git a/muse2/muse/widgets/mtscale_flo.cpp b/muse2/muse/widgets/mtscale_flo.cpp index df077102..c54ef1ad 100644 --- a/muse2/muse/widgets/mtscale_flo.cpp +++ b/muse2/muse/widgets/mtscale_flo.cpp @@ -45,6 +45,9 @@ MTScaleFlo::MTScaleFlo(ScoreCanvas* parent_editor, QWidget* parent_widget) pos[0] = MusEGlobal::song->cpos(); pos[1] = MusEGlobal::song->lpos(); pos[2] = MusEGlobal::song->rpos(); + xpos=0; + xoffset=0; + button = Qt::NoButton; setMouseTracking(true); connect(MusEGlobal::song, SIGNAL(posChanged(int, unsigned, bool)), SLOT(setPos(int, unsigned, bool))); diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp index 27e6d523..32a886fa 100644 --- a/muse2/muse/widgets/musewidgetsplug.cpp +++ b/muse2/muse/widgets/musewidgetsplug.cpp @@ -159,7 +159,8 @@ MusEGlobal::GlobalConfigValues config = { -60.0, // double minSlider; false, // use Jack freewheel 20, // int guiRefresh; - QString(""), // helpBrowser + QString(""), // userInstrumentsDir // Obsolete. Must keep for compatibility. + //QString(""), // helpBrowser // Obsolete true, // extendedMidi 384, // division for smf export QString(""), // copyright string for smf export diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index af546ec3..af870975 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -341,21 +341,38 @@ void PopupMenu::popHovered(QAction* action) void PopupMenu::mouseReleaseEvent(QMouseEvent *e) { - #ifdef POPUP_MENU_DISABLE_STAY_OPEN + QAction* action = actionAt(e->pos()); + if (!(action && action == activeAction() && !action->isSeparator() && action->isEnabled())) + action=NULL; + + #ifdef POPUP_MENU_DISABLE_STAY_OPEN + if (action && action->menu() != NULL && action->isCheckable()) + action->activate(QAction::Trigger); + QMenu::mouseReleaseEvent(e); + + if (action && action->menu() != NULL && action->isCheckable()) + close(); + return; #else // Check for Ctrl to stay open. if(!_stayOpen || (!MusEGlobal::config.popupsDefaultStayOpen && (e->modifiers() & Qt::ControlModifier) == 0)) { + if (action && action->menu() != NULL && action->isCheckable()) + action->activate(QAction::Trigger); + QMenu::mouseReleaseEvent(e); + + if (action && action->menu() != NULL && action->isCheckable()) + close(); + return; } //printf("PopupMenu::mouseReleaseEvent\n"); - QAction *action = actionAt(e->pos()); - if (action && action == activeAction() && !action->isSeparator() && action->isEnabled()) + if (action) action->activate(QAction::Trigger); else QMenu::mouseReleaseEvent(e); diff --git a/muse2/muse/widgets/poslabel.cpp b/muse2/muse/widgets/poslabel.cpp index 6cdcb27e..b893c58d 100644 --- a/muse2/muse/widgets/poslabel.cpp +++ b/muse2/muse/widgets/poslabel.cpp @@ -138,7 +138,11 @@ void PosLabel::setTickValue(unsigned val) if (val == _tickValue) return; if (val >= MAX_TICK) - abort(); + { + printf("THIS SHOULD NEVER HAPPEN: val=%u > MAX_TICK=%u in PosLabel::setTickValue()!\n",val, MAX_TICK); + val=MAX_TICK-1; + } + _tickValue = val; updateValue(); } diff --git a/muse2/muse/widgets/projectcreate.ui b/muse2/muse/widgets/projectcreate.ui index 406c83d6..d03f093c 100644 --- a/muse2/muse/widgets/projectcreate.ui +++ b/muse2/muse/widgets/projectcreate.ui @@ -17,28 +17,94 @@ <item> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Project Name:</string> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Projects folder:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="projDirLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="projDirToolButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> </widget> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Project Name:</string> + </property> + </widget> + </item> + <item> <widget class="QLineEdit" name="projectNameEdit"/> </item> <item> + <widget class="QCheckBox" name="templateCheckBox"> + <property name="text"> + <string>Project is a Template</string> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>60</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Project song file type:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="projectFileTypeCB"/> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>75</width> + <width>40</width> <height>20</height> </size> </property> @@ -87,9 +153,16 @@ </widget> </item> <item> - <widget class="QPushButton" name="browseDirButton"> + <widget class="QToolButton" name="browseDirButton"> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="restorePathButton"> <property name="text"> - <string>Browse</string> + <string>...</string> </property> </widget> </item> @@ -123,6 +196,18 @@ </item> </layout> </widget> + <tabstops> + <tabstop>projectNameEdit</tabstop> + <tabstop>templateCheckBox</tabstop> + <tabstop>projectFileTypeCB</tabstop> + <tabstop>createFolderCheckbox</tabstop> + <tabstop>storageDirEdit</tabstop> + <tabstop>browseDirButton</tabstop> + <tabstop>commentEdit</tabstop> + <tabstop>buttonBox</tabstop> + <tabstop>projDirLineEdit</tabstop> + <tabstop>projDirToolButton</tabstop> + </tabstops> <resources/> <connections> <connection> diff --git a/muse2/muse/widgets/projectcreateimpl.cpp b/muse2/muse/widgets/projectcreateimpl.cpp index 31973101..665d725e 100644 --- a/muse2/muse/widgets/projectcreateimpl.cpp +++ b/muse2/muse/widgets/projectcreateimpl.cpp @@ -4,6 +4,7 @@ // $Id: ./muse/widgets/projectcreateimpl.cpp $ // // Copyright (C) 1999-2011 by Werner Schweer and others +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -21,12 +22,16 @@ // //========================================================= #include <stdio.h> -#include <qfiledialog.h> -#include <qdir.h> +#include <QFileDialog> +#include <QDir> +#include <QStringList> + #include "projectcreateimpl.h" #include "gconfig.h" #include "globals.h" #include "app.h" +#include "helper.h" +#include "icons.h" namespace MusEGui { @@ -35,10 +40,51 @@ ProjectCreateImpl::ProjectCreateImpl(QWidget *parent) : { setupUi(this); - createFolderCheckbox->setChecked(MusEGlobal::config.projectStoreInFolder); + //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath); + directoryPath = MusEGlobal::config.projectBaseFolder; + + QStringList filters = localizedStringListFromCharArray(MusEGlobal::project_create_file_save_pattern, "file_patterns"); + projectFileTypeCB->addItems(filters); + + QString proj_title = MusEGlobal::muse->projectTitle(); + QString proj_path = MusEGlobal::muse->projectPath(); + QString proj_ext = MusEGlobal::muse->projectExtension(); + + projectNameEdit->setText(proj_title); + + bool is_template = proj_path.startsWith(MusEGlobal::configPath + "/templates"); + + templateCheckBox->setChecked(is_template); + + projDirPath = proj_path; + + int type_idx = 0; + if(!proj_ext.isEmpty()) + { + // FIXME Imperfect. Trying to avoid adding yet another series of character strings. p4.0.40 + type_idx = projectFileTypeCB->findText(proj_ext, Qt::MatchContains | Qt::MatchCaseSensitive); + if(type_idx == -1) + type_idx = 0; + } + projectFileTypeCB->setCurrentIndex(type_idx); + + projDirToolButton->setIcon(*openIcon); + browseDirButton->setIcon(*openIcon); + restorePathButton->setIcon(*undoIcon); + + restorePathButton->setEnabled(false); // Disabled at first. + + //createFolderCheckbox->setChecked(MusEGlobal::config.projectStoreInFolder && is_new); // Suggest no folder if not new. + + connect(templateCheckBox,SIGNAL(clicked()), this, SLOT(templateButtonChanged())); + //connect(templateCheckBox,SIGNAL(clicked()), this, SLOT(updateDirectoryPath())); + connect(projDirToolButton,SIGNAL(clicked()), this, SLOT(browseProjDir())); + connect(restorePathButton,SIGNAL(clicked()), this, SLOT(restorePath())); connect(browseDirButton,SIGNAL(clicked()), this, SLOT(selectDirectory())); - connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateDirectoryPath())); - connect(createFolderCheckbox,SIGNAL(clicked()), this, SLOT(updateDirectoryPath())); + //connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateDirectoryPath())); + connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateProjectName())); + connect(createFolderCheckbox,SIGNAL(clicked()), this, SLOT(createProjFolderChanged())); + connect(projectFileTypeCB,SIGNAL(currentIndexChanged(int)), this, SLOT(updateDirectoryPath())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(ok())); #if QT_VERSION >= 0x040700 projectNameEdit->setPlaceholderText("<Project Name>"); @@ -46,52 +92,155 @@ ProjectCreateImpl::ProjectCreateImpl(QWidget *parent) : // as of Qt-4.7.1 //commentEdit->setPlaceholderText("<Add information about project here>"); #endif - directoryPath = MusEGlobal::config.projectBaseFolder; updateDirectoryPath(); show(); } void ProjectCreateImpl::selectDirectory() { - QFileDialog qfd; - qfd.selectFile(directoryPath); - qfd.setFileMode(QFileDialog::DirectoryOnly); - if (qfd.exec() == QDialog::Rejected) { - return; - } - directoryPath=qfd.selectedFiles().first(); + QString dpath = templateCheckBox->isChecked() ? + (overrideTemplDirPath.isEmpty() ? (MusEGlobal::configPath + QString("/templates")) : overrideTemplDirPath) : + (overrideDirPath.isEmpty() ? directoryPath : overrideDirPath); + + QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), dpath); + if(dir.isEmpty()) + return; + + (templateCheckBox->isChecked() ? overrideTemplDirPath : overrideDirPath) = dir; + restorePathButton->setEnabled(true); updateDirectoryPath(); } -void ProjectCreateImpl::updateDirectoryPath() +void ProjectCreateImpl::updateProjectName() { + QString curExt = projectFileTypeCB->currentText(); + if(curExt.isEmpty()) + curExt = ".med"; + else + { + curExt = MusEGui::getFilterExtension(curExt); + // Do we have a valid extension? + if(curExt.isEmpty()) + curExt = ".med"; + } + QString name = ""; if (createFolderCheckbox->isChecked()) { if (!projectNameEdit->text().isEmpty()) - name = projectNameEdit->text() + "/" + projectNameEdit->text() + ".med"; + //name = projectNameEdit->text() + "/" + projectNameEdit->text() + ".med"; + name = projectNameEdit->text() + "/" + projectNameEdit->text() + curExt; //storageDirEdit->setText(directoryPath + name ); } else { if (!projectNameEdit->text().isEmpty()) - name = projectNameEdit->text() + ".med"; + //name = projectNameEdit->text() + ".med"; + name = projectNameEdit->text() + curExt; //storageDirEdit->setText(directoryPath +"/" + name); } - storageDirEdit->setText(directoryPath +"/" + name ); // Tim + + bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath); + + QString dpath = templateCheckBox->isChecked() ? + (overrideTemplDirPath.isEmpty() ? (MusEGlobal::configPath + QString("/templates")) : overrideTemplDirPath) : + (overrideDirPath.isEmpty() ? (is_new ? directoryPath : projDirPath) : overrideDirPath); + + QDir proj_dir(dpath); + //if(is_project && MusEGlobal::config.projectStoreInFolder) + bool is_project = dpath.startsWith(MusEGlobal::config.projectBaseFolder); + //bool is_template = dpath.startsWith(MusEGlobal::configPath + "/templates") && templateCheckBox->isChecked(); + //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath) && MusEGlobal::config.projectStoreInFolder; + //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath) && + MusEGlobal::config.projectStoreInFolder && + (templateCheckBox->isChecked() ? overrideTemplDirPath.isEmpty() : overrideDirPath.isEmpty()); + //bool is_template = is_new && dpath.startsWith(MusEGlobal::configPath + "/templates") && templateCheckBox->isChecked(); + if(!is_new && createFolderCheckbox->isChecked() && !templateCheckBox->isChecked() && + (templateCheckBox->isChecked() ? overrideTemplDirPath.isEmpty() : overrideDirPath.isEmpty())) + proj_dir.cdUp(); + dpath = proj_dir.absolutePath(); + + //if(!initProjPath.isEmpty()) + //{ + // initProjPath.clear(); + //} + + storageDirEdit->blockSignals(true); + storageDirEdit->setText(dpath + "/" + name ); + storageDirEdit->blockSignals(false); + + projDirLineEdit->setEnabled(!templateCheckBox->isChecked() && is_project); +} + +void ProjectCreateImpl::updateDirectoryPath() +{ + updateProjectName(); + + projDirLineEdit->blockSignals(true); + projDirLineEdit->setText(MusEGlobal::config.projectBaseFolder); + projDirLineEdit->blockSignals(false); } -QString ProjectCreateImpl::getProjectPath() +QString ProjectCreateImpl::getProjectPath() const { return storageDirEdit->text(); } -QString ProjectCreateImpl::getSongInfo() + +QString ProjectCreateImpl::getSongInfo() const { return commentEdit->toPlainText(); } + void ProjectCreateImpl::ok() { MusEGlobal::config.projectStoreInFolder = createFolderCheckbox->isChecked(); - MusEGlobal::config.projectBaseFolder = directoryPath; - MusEGlobal::muse->changeConfig(true); + //MusEGlobal::config.projectBaseFolder = directoryPath; + //MusEGlobal::muse->changeConfig(true); emit accept(); } +void ProjectCreateImpl::createProjFolderChanged() +{ + //MusEGlobal::config.projectStoreInFolder = createFolderCheckbox->isChecked(); + //MusEGlobal::muse->changeConfig(true); // Save to config file. + updateDirectoryPath(); +} + +void ProjectCreateImpl::browseProjDir() +{ + QString dir = MusEGui::browseProjectFolder(this); + if(!dir.isEmpty()) + { + directoryPath = dir; + MusEGlobal::config.projectBaseFolder = dir; + MusEGlobal::muse->changeConfig(true); // Save to config file. + updateDirectoryPath(); + } +} + +void ProjectCreateImpl::templateButtonChanged() +{ + restorePathButton->setEnabled(templateCheckBox->isChecked() ? !overrideTemplDirPath.isEmpty() : !overrideDirPath.isEmpty()); + updateDirectoryPath(); +} + +void ProjectCreateImpl::restorePath() +{ + if(templateCheckBox->isChecked()) + overrideTemplDirPath.clear(); + else + overrideDirPath.clear(); + restorePathButton->setEnabled(templateCheckBox->isChecked() ? !overrideTemplDirPath.isEmpty() : !overrideDirPath.isEmpty()); + updateDirectoryPath(); +} + +/* +bool ProjectCreateImpl::getProjectIsTemplate() const +{ + return templateCheckBox->isChecked(); +} + +QString ProjectCreateImpl::getTemplatePath() const +{ + return templDirPath; +} +*/ + } //namespace MusEGui diff --git a/muse2/muse/widgets/projectcreateimpl.h b/muse2/muse/widgets/projectcreateimpl.h index 258b0921..f08cb1bc 100644 --- a/muse2/muse/widgets/projectcreateimpl.h +++ b/muse2/muse/widgets/projectcreateimpl.h @@ -4,6 +4,7 @@ // $Id: ./muse/widgets/projectcreateimpl.h $ // // Copyright (C) 1999-2011 by Werner Schweer and others +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -33,18 +34,28 @@ class ProjectCreateImpl : public QDialog, Ui::ProjectCreate Q_OBJECT QString directoryPath; + QString overrideDirPath; + QString overrideTemplDirPath; + QString projDirPath; + public: explicit ProjectCreateImpl(QWidget *parent = 0); - QString getProjectPath(); - QString getSongInfo(); + QString getProjectPath() const; + QString getSongInfo() const; + //bool getProjectIsTemplate() const; + //QString getTemplatePath() const; signals: -public slots: +protected slots: + void updateProjectName(); void updateDirectoryPath(); void selectDirectory(); void ok(); - + void createProjFolderChanged(); + void browseProjDir(); + void templateButtonChanged(); + void restorePath(); }; } // namespace MusEGui diff --git a/muse2/muse/widgets/routepopup.cpp b/muse2/muse/widgets/routepopup.cpp index 73d29c25..0f1f8264 100644 --- a/muse2/muse/widgets/routepopup.cpp +++ b/muse2/muse/widgets/routepopup.cpp @@ -43,10 +43,10 @@ namespace MusEGui { int RoutePopupMenu::addMenuItem(MusECore::AudioTrack* track, MusECore::Track* route_track, PopupMenu* lb, int id, int channel, int channels, bool isOutput) { // totalInChannels is only used by syntis. - int toch = ((MusECore::AudioTrack*)track)->totalOutChannels(); + //int toch = ((MusECore::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; + //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)) @@ -95,6 +95,13 @@ int RoutePopupMenu::addMenuItem(MusECore::AudioTrack* track, MusECore::Track* ro } } } + + if(!act->isChecked()) // If circular route exists, allow user to break it, otherwise forbidden. + { + if( (isOutput ? track : route_track)->isCircularRoute(isOutput ? route_track : track) ) + act->setEnabled(false); + } + return ++id; } @@ -220,9 +227,9 @@ int RoutePopupMenu::addSyntiPorts(MusECore::AudioTrack* t, PopupMenu* lb, int id { char buffer[128]; if(tchans == 2) - snprintf(buffer, 128, "%s %d,%d", chpup->tr("Channel").toLatin1().constData(), ch+1, ch+2); + snprintf(buffer, 128, "%s %d,%d", tr("Channel").toLatin1().constData(), ch+1, ch+2); else - snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); + snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), ch+1); act = chpup->addAction(QString(buffer)); act->setCheckable(true); @@ -259,6 +266,13 @@ int RoutePopupMenu::addSyntiPorts(MusECore::AudioTrack* t, PopupMenu* lb, int id } } } + + if(!act->isChecked()) // If circular route exists, allow user to break it, otherwise forbidden. + { + if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) ) + act->setEnabled(false); + } + ++id; } @@ -347,7 +361,7 @@ int RoutePopupMenu::addMultiChannelPorts(MusECore::AudioTrack* t, PopupMenu* pup if(chans > 1) { char buffer[128]; - snprintf(buffer, 128, "%s %d", pup->tr("Channel").toLatin1().constData(), ch+1); + snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), ch+1); chpup->setTitle(QString(buffer)); pup->addMenu(chpup); } @@ -425,7 +439,7 @@ int RoutePopupMenu::addMultiChannelPorts(MusECore::AudioTrack* t, PopupMenu* pup if(chans > 2) { char buffer[128]; - snprintf(buffer, 128, "%s %d,%d", pup->tr("Channel").toLatin1().constData(), ch+1, ch+2); + snprintf(buffer, 128, "%s %d,%d", tr("Channel").toLatin1().constData(), ch+1, ch+2); chpup->setTitle(QString(buffer)); pup->addMenu(chpup); } @@ -482,7 +496,7 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l for(int ch = 0; ch < chans; ++ch) { char buffer[128]; - snprintf(buffer, 128, "%s %d", chpup->tr("Channel").toLatin1().constData(), ch+1); + snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), ch+1); act = chpup->addAction(QString(buffer)); act->setCheckable(true); @@ -520,6 +534,13 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l } } } + + if(!act->isChecked()) // If circular route exists, allow user to break it, otherwise forbidden. + { + if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) ) + act->setEnabled(false); + } + ++id; } @@ -535,7 +556,7 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l 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); + snprintf(buffer, 128, "%s %d,%d", tr("Channel").toLatin1().constData(), ch+1, ch+2); act = chpup->addAction(QString(buffer)); act->setCheckable(true); @@ -573,6 +594,13 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l } } } + + if(!act->isChecked()) // If circular route exists, allow user to break it, otherwise forbidden. + { + if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) ) + act->setEnabled(false); + } + ++id; } } @@ -1062,9 +1090,8 @@ void RoutePopupMenu::prepare() for( ; pi < MIDI_PORTS; ++pi) { MusECore::MidiDevice* md = MusEGlobal::midiPorts[pi].device(); - //if(md && !md->isSynti() && (md->rwFlags() & 2)) - //if(md && (md->rwFlags() & 2)) // p4.0.27 - if(md && (md->rwFlags() & 2 || md->isSynti()) ) // p4.0.27 + if(md && !md->isSynti() && (md->rwFlags() & 2)) + //if(md && (md->rwFlags() & 2 || md->isSynti()) ) // p4.0.27 Reverted p4.0.35 break; } if(pi == MIDI_PORTS) @@ -1091,12 +1118,9 @@ void RoutePopupMenu::prepare() // continue; // Do not list synth devices! - ///if(md && md->isSynti()) - /// continue; - ///if(md && !(md->rwFlags() & 2)) - /// continue; - // p4.0.27 Go ahead. Synths esp MESS send out stuff. - if( md && !(md->rwFlags() & 2) && !md->isSynti() ) + if( md && (!(md->rwFlags() & 2) || md->isSynti()) ) + // p4.0.27 Go ahead. Synths esp MESS send out stuff. Reverted p4.0.35 + //if( md && !(md->rwFlags() & 2) && !md->isSynti() ) continue; //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i); diff --git a/muse2/muse/widgets/shortcutcapturedialog.cpp b/muse2/muse/widgets/shortcutcapturedialog.cpp index 46a3e75d..ad78a2ad 100644 --- a/muse2/muse/widgets/shortcutcapturedialog.cpp +++ b/muse2/muse/widgets/shortcutcapturedialog.cpp @@ -30,7 +30,6 @@ // // Description: // Dialog window for capturing keyboard shortcuts -// #include "shortcutcapturedialog.h" #include "shortcuts.h" @@ -39,6 +38,7 @@ #include <QKeySequence> #include <QInputEvent> #include <QChar> +#include <QApplication> namespace MusEGui { @@ -105,7 +105,7 @@ void ShortcutCaptureDialog::keyPressEvent(QKeyEvent* e) (( shortcuts[i].type & (shortcuts[shortcutindex].type | INVIS_SHRT)) || shortcuts[i].type & GLOBAL_SHRT || shortcuts[shortcutindex].type & GLOBAL_SHRT)) { // affect the same scope - msgString = tr("Shortcut conflicts with %1").arg(shortcuts[i].descr); + msgString = tr("Shortcut conflicts with %1").arg(qApp->translate("shortcuts",shortcuts[i].descr)); conflict = true; break; } diff --git a/muse2/muse/widgets/shortcutconfig.cpp b/muse2/muse/widgets/shortcutconfig.cpp index fc08e7ce..609564cc 100644 --- a/muse2/muse/widgets/shortcutconfig.cpp +++ b/muse2/muse/widgets/shortcutconfig.cpp @@ -30,12 +30,12 @@ // // Description: // Dialog for configuring keyboard shortcuts -// #include <QCloseEvent> #include <QKeySequence> #include <QString> #include <QSettings> +#include <QApplication> #include "shortcutconfig.h" #include "shortcutcapturedialog.h" @@ -86,12 +86,12 @@ void ShortcutConfig::updateSCListView(int category) for (int i=0; i < SHRT_NUM_OF_ELEMENTS; i++) { if (shortcuts[i].type & category) { newItem = new SCListViewItem(scListView, i); - newItem->setText(SHRT_DESCR_COL, tr(shortcuts[i].descr)); + newItem->setText(SHRT_DESCR_COL, qApp->translate("shortcuts", shortcuts[i].descr)); //if(category == ALL_SHRT) // catpre = QString(shortcut_category[shortcuts[i].type].name) + QString(": "); //else // catpre.clear(); - //newItem->setText(SHRT_DESCR_COL, catpre + tr(shortcuts[i].descr)); // Tim + //newItem->setText(SHRT_DESCR_COL, catpre + tr(qApp->translate("shortcuts", shortcuts[i].descr)); // Tim QKeySequence key = QKeySequence(shortcuts[i].key); newItem->setText(SHRT_SHRTCUT_COL, key); } diff --git a/muse2/muse/widgets/shortcutconfigbase.ui b/muse2/muse/widgets/shortcutconfigbase.ui index 119a7007..6dd5d5b7 100644 --- a/muse2/muse/widgets/shortcutconfigbase.ui +++ b/muse2/muse/widgets/shortcutconfigbase.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>466</width> - <height>403</height> + <width>512</width> + <height>452</height> </rect> </property> <property name="windowTitle"> @@ -16,67 +16,64 @@ <property name="sizeGripEnabled"> <bool>true</bool> </property> - <layout class="QVBoxLayout"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="groupBox3"> - <property name="title"> - <string/> + <widget class="QSplitter" name="splitter"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <layout class="QHBoxLayout"> - <property name="spacing"> - <number>3</number> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="childrenCollapsible"> + <bool>false</bool> + </property> + <widget class="QTreeWidget" name="cgListView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>105</width> + <height>200</height> + </size> + </property> + <column> + <property name="text"> + <string>Shortcut Category</string> + </property> + </column> + </widget> + <widget class="QTreeWidget" name="scListView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>2</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <property name="margin"> - <number>0</number> + <property name="minimumSize"> + <size> + <width>170</width> + <height>230</height> + </size> </property> - <item> - <widget class="QTreeWidget" name="cgListView"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> - <horstretch>1</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>105</width> - <height>200</height> - </size> - </property> - <column> - <property name="text"> - <string>Shortcut Category</string> - </property> - </column> - </widget> - </item> - <item> - <widget class="QTreeWidget" name="scListView"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> - <horstretch>2</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>170</width> - <height>230</height> - </size> - </property> - <column> - <property name="text"> - <string>Shortcut</string> - </property> - </column> - <column> - <property name="text"> - <string>Description</string> - </property> - </column> - </widget> - </item> - </layout> + <column> + <property name="text"> + <string>Shortcut</string> + </property> + </column> + <column> + <property name="text"> + <string>Description</string> + </property> + </column> + </widget> </widget> </item> <item> diff --git a/muse2/muse/widgets/spinbox.cpp b/muse2/muse/widgets/spinbox.cpp index f7afcf2a..a763eea1 100644 --- a/muse2/muse/widgets/spinbox.cpp +++ b/muse2/muse/widgets/spinbox.cpp @@ -99,4 +99,19 @@ void SpinBox::stepDown() _clearFocus = true; } +void SpinBox::keyPressEvent(QKeyEvent* ev) +{ + switch (ev->key()) { + case Qt::Key_Return: + clearFocus(); + //emit returnPressed(); + // return; + break; + default: + break; + } + QSpinBox::keyPressEvent(ev); +} + } // namespace MusEGui + diff --git a/muse2/muse/widgets/spinbox.h b/muse2/muse/widgets/spinbox.h index cee112d4..cd37fb32 100644 --- a/muse2/muse/widgets/spinbox.h +++ b/muse2/muse/widgets/spinbox.h @@ -43,7 +43,8 @@ class SpinBox : public QSpinBox { protected: bool eventFilter(QObject* obj, QEvent* ev); - + virtual void keyPressEvent(QKeyEvent*); + public slots: virtual void stepUp(); virtual void stepDown(); diff --git a/muse2/muse/widgets/synthconfigbase.ui b/muse2/muse/widgets/synthconfigbase.ui index 97f0beaa..500241a8 100644 --- a/muse2/muse/widgets/synthconfigbase.ui +++ b/muse2/muse/widgets/synthconfigbase.ui @@ -6,12 +6,12 @@ <rect> <x>0</x> <y>0</y> - <width>630</width> + <width>810</width> <height>492</height> </rect> </property> <property name="windowTitle"> - <string>MusE: Synth Configuration</string> + <string>Midi Port and Soft Synth Configuration</string> </property> <layout class="QGridLayout"> <item row="1" column="1"> @@ -32,6 +32,11 @@ </column> <column> <property name="text"> + <string>Type</string> + </property> + </column> + <column> + <property name="text"> <string>Midi Port</string> </property> </column> @@ -137,6 +142,11 @@ </column> <column> <property name="text"> + <string>Type</string> + </property> + </column> + <column> + <property name="text"> <string>Inst</string> </property> </column> diff --git a/muse2/muse/widgets/tb1.cpp b/muse2/muse/widgets/tb1.cpp index 3174260f..589726a9 100644 --- a/muse2/muse/widgets/tb1.cpp +++ b/muse2/muse/widgets/tb1.cpp @@ -20,7 +20,6 @@ // //========================================================= -//#include <assert.h> #include <stdio.h> #include <values.h> @@ -45,9 +44,9 @@ static int rasterTable[] = { }; static const char* rasterStrings[] = { - QT_TRANSLATE_NOOP("@default", "Off"), "2pp", "5pp", "64T", "32T", "16T", "8T", "4T", "2T", "1T", - QT_TRANSLATE_NOOP("@default", "Off"), "3pp", "6pp", "64", "32", "16", "8", "4", "2", "1", - QT_TRANSLATE_NOOP("@default", "Off"), "4pp", "7pp", "64.", "32.", "16.", "8.", "4.", "2.", "1." + QT_TRANSLATE_NOOP("MusEGui::Toolbar1", "Off"), "2pp", "5pp", "64T", "32T", "16T", "8T", "4T", "2T", "1T", + QT_TRANSLATE_NOOP("MusEGui::Toolbar1", "Off"), "3pp", "6pp", "64", "32", "16", "8", "4", "2", "1", + QT_TRANSLATE_NOOP("MusEGui::Toolbar1", "Off"), "4pp", "7pp", "64.", "32.", "16.", "8.", "4.", "2.", "1." }; diff --git a/muse2/muse/widgets/tools.cpp b/muse2/muse/widgets/tools.cpp index 162d2b97..d46126a9 100644 --- a/muse2/muse/widgets/tools.cpp +++ b/muse2/muse/widgets/tools.cpp @@ -30,42 +30,42 @@ namespace MusEGui { -const char* infoPointer = QT_TRANSLATE_NOOP("@default", "select Pointer Tool:\n" +const char* infoPointer = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Pointer Tool:\n" "with the pointer tool you can:\n" " select parts\n" " move parts\n" " copy parts"); -const char* infoPencil = QT_TRANSLATE_NOOP("@default", "select Pencil Tool:\n" +const char* infoPencil = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Pencil Tool:\n" "with the pencil tool you can:\n" " create new parts\n" " modify length of parts"); -const char* infoDel = QT_TRANSLATE_NOOP("@default", "select Delete Tool:\n" +const char* infoDel = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Delete Tool:\n" "with the delete tool you can delete parts"); -const char* infoCut = QT_TRANSLATE_NOOP("@default", "select Cut Tool:\n" +const char* infoCut = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Cut Tool:\n" "with the cut tool you can split a part"); -const char* infoGlue = QT_TRANSLATE_NOOP("@default", "select Glue Tool:\n" +const char* infoGlue = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Glue Tool:\n" "with the glue tool you can glue two parts"); -const char* infoScore = QT_TRANSLATE_NOOP("@default", "select Score Tool:\n"); -const char* infoQuant = QT_TRANSLATE_NOOP("@default", "select Quantize Tool:\n" +const char* infoScore = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Score Tool:\n"); +const char* infoQuant = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Quantize Tool:\n" "insert display quantize event"); -const char* infoDraw = QT_TRANSLATE_NOOP("@default", "select Drawing Tool"); -const char* infoMute = QT_TRANSLATE_NOOP("@default", "select Muting Tool:\n" +const char* infoDraw = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Drawing Tool"); +const char* infoMute = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "select Muting Tool:\n" "click on part to mute/unmute"); -const char* infoAutomation = QT_TRANSLATE_NOOP("@default", "Manipulate automation"); -const char* infoCursor = QT_TRANSLATE_NOOP("@default", "Cursor tool"); +const char* infoAutomation = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "Manipulate automation"); +const char* infoCursor = QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "Cursor tool"); ToolB toolList[] = { - {&pointerIcon, QT_TRANSLATE_NOOP("@default", "pointer"), infoPointer }, - {&pencilIcon, QT_TRANSLATE_NOOP("@default", "pencil"), infoPencil }, - {&deleteIcon, QT_TRANSLATE_NOOP("@default", "eraser"), infoDel }, - {&cutIcon, QT_TRANSLATE_NOOP("@default", "cutter"), infoCut }, - {¬e1Icon, QT_TRANSLATE_NOOP("@default", "score"), infoScore }, - {&glueIcon, QT_TRANSLATE_NOOP("@default", "glue"), infoGlue }, - {&quantIcon, QT_TRANSLATE_NOOP("@default", "quantize"), infoQuant }, - {&drawIcon, QT_TRANSLATE_NOOP("@default", "draw"), infoDraw }, - {&editmuteIcon, QT_TRANSLATE_NOOP("@default", "mute parts"), infoMute }, - {&drawIcon, QT_TRANSLATE_NOOP("@default", "edit automation"),infoAutomation}, - {&cursorIcon, QT_TRANSLATE_NOOP("@default", "cursor"), infoCursor}, + {&pointerIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "pointer"), infoPointer }, + {&pencilIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "pencil"), infoPencil }, + {&deleteIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "eraser"), infoDel }, + {&cutIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "cutter"), infoCut }, + {¬e1Icon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "score"), infoScore }, + {&glueIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "glue"), infoGlue }, + {&quantIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "quantize"), infoQuant }, + {&drawIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "draw"), infoDraw }, + {&editmuteIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "mute parts"), infoMute }, + {&drawIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "edit automation"),infoAutomation}, + {&cursorIcon, QT_TRANSLATE_NOOP("MusEGui::EditToolBar", "cursor"), infoCursor}, }; //--------------------------------------------------------- @@ -94,7 +94,7 @@ EditToolBar::EditToolBar(QWidget* parent, int tools, const char*) continue; ToolB* t = &toolList[i]; - Action* a = new Action(action, 1<<i, t->tip, true); + Action* a = new Action(action, 1<<i, tr(t->tip).toAscii().data(), true); actions[n] = a; //a->setIconSet(QIcon(**(t->icon))); a->setIcon(QIcon(**(t->icon))); diff --git a/muse2/muse/widgets/utils.cpp b/muse2/muse/widgets/utils.cpp index 708bef07..1641b267 100644 --- a/muse2/muse/widgets/utils.cpp +++ b/muse2/muse/widgets/utils.cpp @@ -528,7 +528,8 @@ int get_paste_len() if (p->endTick() > end_tick) end_tick=p->endTick(); - + + unchainClone(p); delete p; } } diff --git a/muse2/muse/widgets/visibletracks.cpp b/muse2/muse/widgets/visibletracks.cpp index 84e7dd42..4976ecf9 100644 --- a/muse2/muse/widgets/visibletracks.cpp +++ b/muse2/muse/widgets/visibletracks.cpp @@ -29,25 +29,26 @@ #include "action.h" #include "track.h" #include "synth.h" +#include "app.h" namespace MusEGui { -const char* waveTrack = QT_TRANSLATE_NOOP("@default", "Show wave tracks"); -const char* groupTrack = QT_TRANSLATE_NOOP("@default", "Show group tracks"); -const char* auxTrack = QT_TRANSLATE_NOOP("@default", "Show aux tracks"); -const char* inputTrack = QT_TRANSLATE_NOOP("@default", "Show input tracks"); -const char* outputTrack = QT_TRANSLATE_NOOP("@default", "Show output tracks"); -const char* midiTrack = QT_TRANSLATE_NOOP("@default", "Show midi tracks"); -const char* synthTrack = QT_TRANSLATE_NOOP("@default", "Show synth tracks"); +const char* waveTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show wave tracks"); +const char* groupTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show group tracks"); +const char* auxTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show aux tracks"); +const char* inputTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show input tracks"); +const char* outputTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show output tracks"); +const char* midiTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show midi tracks"); +const char* synthTrack = QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show synth tracks"); VisibleToolB visTrackList[] = { - {&addtrack_wavetrackIcon, QT_TRANSLATE_NOOP("@default", "Show wave tracks"), waveTrack }, - {&addtrack_audiogroupIcon, QT_TRANSLATE_NOOP("@default", "Show group tracks"), groupTrack }, - {&addtrack_auxsendIcon, QT_TRANSLATE_NOOP("@default", "Show aux tracks"), auxTrack }, - {&addtrack_audioinputIcon, QT_TRANSLATE_NOOP("@default", "Show input tracks"), inputTrack }, - {&addtrack_audiooutputIcon, QT_TRANSLATE_NOOP("@default", "Show output tracks"), outputTrack }, - {&addtrack_addmiditrackIcon,QT_TRANSLATE_NOOP("@default", "Show midi tracks"), midiTrack }, - {&synthIcon, QT_TRANSLATE_NOOP("@default", "Show synth tracks"), midiTrack }, + {&addtrack_wavetrackIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show wave tracks"), waveTrack }, + {&addtrack_audiogroupIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show group tracks"), groupTrack }, + {&addtrack_auxsendIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show aux tracks"), auxTrack }, + {&addtrack_audioinputIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show input tracks"), inputTrack }, + {&addtrack_audiooutputIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show output tracks"), outputTrack }, + {&addtrack_addmiditrackIcon,QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show midi tracks"), midiTrack }, + {&synthIcon, QT_TRANSLATE_NOOP("MusEGui::VisibleTracks", "Show synth tracks"), midiTrack }, }; //--------------------------------------------------------- @@ -67,7 +68,7 @@ VisibleTracks::VisibleTracks(QWidget* parent, const char*) for (unsigned i = 0; i < sizeof(visTrackList)/sizeof(*visTrackList); ++i) { VisibleToolB* t = &visTrackList[i]; - Action* a = new Action(action, i, t->tip, true); + Action* a = new Action(action, i, tr(t->tip).toAscii().data(), true); actions[n] = a; //a->setIconSet(QIcon(**(t->icon))); a->setIcon(QIcon(**(t->icon))); @@ -130,6 +131,7 @@ void VisibleTracks::visibilityChanged(QAction* action) default: break; } + MusEGlobal::muse->changeConfig(true); // save settings emit visibilityChanged(); } diff --git a/muse2/muse/widgets/visibletracks.h b/muse2/muse/widgets/visibletracks.h index d56c9ce7..bf49c068 100644 --- a/muse2/muse/widgets/visibletracks.h +++ b/muse2/muse/widgets/visibletracks.h @@ -52,13 +52,14 @@ class VisibleTracks : public QToolBar { private slots: void visibilityChanged(QAction* action); + public slots: + void updateVisibleTracksButtons(); signals: void visibilityChanged(); public: VisibleTracks(QWidget* /*parent*/, const char* name = 0); // Needs a parent ! - void updateVisibleTracksButtons(); ~VisibleTracks(); }; diff --git a/muse2/muse/xml.cpp b/muse2/muse/xml.cpp index 139437c1..45bed368 100644 --- a/muse2/muse/xml.cpp +++ b/muse2/muse/xml.cpp @@ -4,6 +4,7 @@ // $Id: xml.cpp,v 1.17.2.6 2009/12/07 20:48:45 spamatica Exp $ // // (C) Copyright 2000 Werner Schweer (ws@seh.de) +// (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -24,6 +25,7 @@ #include <stdio.h> #include <stdarg.h> +#include <QByteArray> #include <QString> #include <QColor> #include <QWidget> @@ -112,9 +114,12 @@ void Xml::nextc() void Xml::token(int cc) { - char buffer[512]; + //char buffer[512]; + QByteArray buffer; + int i = 0; - for (; i < 511;) { + //for (; i < 511;) { + for (; i < 9999999;) { // Stop at a reasonably large amount 10 million. if (c == ' ' || c == '\t' || c == cc || c == '\n' || c == EOF) break; buffer[i++] = c; @@ -131,12 +136,16 @@ void Xml::token(int cc) void Xml::stoken() { - char buffer[1024*4]; + //char buffer[1024*4]; + QByteArray buffer; + int i = 0; buffer[i] = c; ++i; next(); - for (;i < 1024*4-1;) { + + //for (;i < 1024*4-1;) { + for (;i < 10000000*4-1;) { // Stop at a reasonably large amount 10 million. if (c == '"') { buffer[i++] = c; next(); @@ -207,8 +216,10 @@ QString Xml::strip(const QString& s) Xml::Token Xml::parse() { - char buffer[1024*1024]; // increase buffer -rj - char* p; + //char buffer[1024*1024]; // increase buffer -rj + //char* p; + QByteArray buffer; + int idx = 0; again: bool endFlag = false; @@ -262,15 +273,23 @@ Xml::Token Xml::parse() } if (c == '?') { next(); - p = buffer; + //p = buffer; + //p = buffer.data(); + idx = 0; for (;;) { if (c == '?' || c == EOF || c == '>') break; - *p++ = c; + + //*p++ = c; + buffer[idx++] = c; + // TODO: check overflow next(); } - *p = 0; + + //*p = 0; + buffer[idx] = 0; + _s1 = QString(buffer); if (c == EOF) { fprintf(stderr, "XML: unexpected EOF\n"); @@ -298,15 +317,23 @@ Xml::Token Xml::parse() } goto again; } - p = buffer; + //p = buffer; + //p = buffer.data(); + idx = 0; for (;;) { if (c == '/' || c == ' ' || c == '\t' || c == '>' || c == '\n' || c == EOF) break; // TODO: check overflow - *p++ = c; + + //*p++ = c; + buffer[idx++] = c; + next(); } - *p = 0; + + //*p = 0; + buffer[idx] = 0; + _s1 = QString(buffer); // skip white space: while (c == ' ' || c == '\t' || c == '\n') @@ -355,26 +382,43 @@ Xml::Token Xml::parse() fprintf(stderr, "XML: level = 0\n"); goto error; } - p = buffer; + //p = buffer; + //p = buffer.data(); + idx = 0; for (;;) { if (c == EOF || c == '<') break; if (c == '&') { next(); if (c == '<') { // be tolerant with old muse files - *p++ = '&'; + + //*p++ = '&'; + buffer[idx++] = '&'; + continue; } - char name[32]; - char* dp = name; - *dp++ = c; - for (; dp-name < 31;) { + + //char name[32]; + //char* dp = name; + QByteArray name; + int name_idx = 0; + + //*dp++ = c; + name[name_idx++] = c; + + //for (; dp-name < 31;) { + for (; name_idx < 9999999;) { // Stop at a reasonably large amount 10 million. next(); if (c == ';') break; - *dp++ = c; + + //*dp++ = c; + name[name_idx++] = c; } - *dp = 0; + + //*dp = 0; + name[name_idx] = 0; + if (strcmp(name, "lt") == 0) c = '<'; else if (strcmp(name, "gt") == 0) @@ -388,10 +432,16 @@ Xml::Token Xml::parse() else c = '?'; } - *p++ = c; + + //*p++ = c; + buffer[idx++] = c; + next(); } - *p = 0; + + //*p = 0; + buffer[idx] = 0; + _s1 = QString(buffer); if (c == '<') |