summaryrefslogtreecommitdiff
path: root/attic/muse_qt4_evolution/muse/muse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'attic/muse_qt4_evolution/muse/muse.cpp')
-rw-r--r--attic/muse_qt4_evolution/muse/muse.cpp3029
1 files changed, 3029 insertions, 0 deletions
diff --git a/attic/muse_qt4_evolution/muse/muse.cpp b/attic/muse_qt4_evolution/muse/muse.cpp
new file mode 100644
index 00000000..01f0d1c4
--- /dev/null
+++ b/attic/muse_qt4_evolution/muse/muse.cpp
@@ -0,0 +1,3029 @@
+//=============================================================================
+// MusE
+// Linux Music Editor
+// $Id:$
+//
+// Copyright (C) 2002-2006 by Werner Schweer and others
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//=============================================================================
+
+#include "config.h"
+#include <sys/mman.h>
+#include "muse.h"
+#include "transport.h"
+#include "widgets/bigtime.h"
+#include "arranger.h"
+#include "midiedit/pianoroll.h"
+#include "al/al.h"
+#include "al/xml.h"
+#include "al/dsp.h"
+#include "al/tempo.h"
+#include "conf.h"
+#include "liste/listedit.h"
+#include "master/masteredit.h"
+#include "midiedit/drumedit.h"
+#include "mixer.h"
+#include "audiodev.h"
+#include "waveedit/waveedit.h"
+#include "icons.h"
+#include "widgets/mixdowndialog.h"
+#include "midictrl.h"
+#include "widgets/filedialog.h"
+#include "plugin.h"
+#include "marker/markerview.h"
+#include "transpose.h"
+#include "preferences.h"
+#include "audio.h"
+#include "audioprefetch.h"
+#include "audiowriteback.h"
+#include "widgets/shortcutconfig.h"
+#include "gconfig.h"
+#include "ticksynth.h"
+#include "song.h"
+#include "awl/poslabel.h"
+#include "shortcuts.h"
+#include "midiplugin.h"
+#include "midiedit/drummap.h"
+#include "widgets/utils.h"
+#include "instruments/editinstrument.h"
+#include "part.h"
+#include "projectdialog.h"
+#include "templatedialog.h"
+#include "midiedit/miditracker.h"
+#include "projectpropsdialog.h"
+#include "liste/listedit.h"
+#include "strip.h"
+
+extern void initMidiInstruments();
+
+#define PROJECT_LIST_LEN 6
+static QString* projectList[PROJECT_LIST_LEN];
+
+extern void initIcons();
+extern void initMidiSynth();
+extern bool initDummyAudio();
+extern void initVST();
+extern void initDSSI();
+extern bool initJackAudio();
+extern void exitJackAudio();
+
+QStyle* smallStyle;
+
+pthread_t splashThread;
+MusE* muse;
+
+//
+// Arranger Snap values
+//
+
+struct RasterVal {
+ int val;
+ QString label;
+ };
+
+static RasterVal rasterTable[] = {
+ { 1, QT_TR_NOOP("Off") },
+ { 0, QT_TR_NOOP("Bar") },
+ { 2 * config.division, "1/2" },
+ { config.division, "1/4" },
+ { config.division/2, "1/8" },
+ { config.division/4, "1/16" }
+ };
+
+//---------------------------------------------------------
+// seqStart
+//---------------------------------------------------------
+
+bool MusE::seqStart()
+ {
+ if (audioState != AUDIO_STOP) {
+ printf("seqStart(): already running\n");
+ return true;
+ }
+ audioState = AUDIO_START1;
+ if (!audio->start()) {
+ QMessageBox::critical( muse, tr("Failed to start audio!"),
+ tr("Was not able to start audio, check if jack is running.\n"));
+ return false;
+ }
+ //
+ // wait for jack callback
+ //
+ for (int i = 0; i < 60; ++i) {
+ if (audioState == AUDIO_START2)
+ break;
+ sleep(1);
+ }
+ if (audioState != AUDIO_START2) {
+ QMessageBox::critical( muse, tr("Failed to start audio!"),
+ tr("Was not able to start audio, check if jack is running.\n"));
+ }
+ //
+ // now its safe to ask the driver for realtime
+ // priority
+
+ realTimePriority = audioDriver->realtimePriority();
+ audioState = AUDIO_RUNNING;
+ if (realTimePriority) {
+ audioPrefetch->start(realTimePriority - 5);
+ audioWriteback->start(realTimePriority - 5);
+ }
+ else {
+ audioPrefetch->start(0);
+ audioWriteback->start(0);
+ }
+ //
+ // do connections
+ //
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i)
+ (*i)->activate2();
+ return true;
+ }
+
+//---------------------------------------------------------
+// stop
+//---------------------------------------------------------
+
+void MusE::seqStop()
+ {
+ song->setStop(true);
+ song->setStopPlay(false);
+ audio->stop();
+ audioWriteback->stop(true);
+ audioPrefetch->stop(true);
+ audioState = AUDIO_STOP;
+ }
+
+//---------------------------------------------------------
+// seqRestart
+//---------------------------------------------------------
+
+bool MusE::seqRestart()
+ {
+ bool restartSequencer = audioState == AUDIO_RUNNING;
+ if (restartSequencer) {
+ if (audio->isPlaying()) {
+ audio->msgPlay(false);
+ while (audio->isPlaying())
+ qApp->processEvents();
+ }
+ seqStop();
+ }
+
+ if (!seqStart())
+ return false;
+
+ audioDriver->graphChanged();
+ return true;
+ }
+
+//---------------------------------------------------------
+// addProject
+//---------------------------------------------------------
+
+void addProject(const QString& name)
+ {
+ for (int i = 0; i < PROJECT_LIST_LEN; ++i) {
+ if (projectList[i] == 0)
+ break;
+ if (name == *projectList[i]) {
+ int dst = i;
+ int src = i+1;
+ int n = PROJECT_LIST_LEN - i - 1;
+ delete projectList[i];
+ for (int k = 0; k < n; ++k)
+ projectList[dst++] = projectList[src++];
+ projectList[dst] = 0;
+ break;
+ }
+ }
+ QString** s = &projectList[PROJECT_LIST_LEN - 2];
+ QString** d = &projectList[PROJECT_LIST_LEN - 1];
+ if (*d)
+ delete *d;
+ for (int i = 0; i < PROJECT_LIST_LEN-1; ++i)
+ *d-- = *s--;
+ projectList[0] = new QString(name);
+ }
+
+//---------------------------------------------------------
+// populateAddTrack
+// this is also used in "mixer"
+//---------------------------------------------------------
+
+void populateAddTrack(QMenu* m)
+ {
+ m->setSeparatorsCollapsible(false);
+ m->clear();
+ QAction* a;
+
+ a = m->addSeparator();
+ a->setText(QT_TR_NOOP("Midi"));
+ QFont f(a->font());
+ f.setBold(true);
+ f.setPointSize(8);
+ a->setFont(f);
+
+ a = m->addAction(QIcon(*addtrack_addmiditrackIcon), QT_TR_NOOP("Add Midi Track"));
+ a->setData(Track::MIDI);
+
+ a = m->addAction(QIcon(*addtrack_addmiditrackIcon), QT_TR_NOOP("Add Midi Output"));
+ a->setData(Track::MIDI_OUT);
+
+ a = m->addAction(QIcon(*addtrack_addmiditrackIcon), QT_TR_NOOP("Add Midi Input"));
+ a->setData(Track::MIDI_IN);
+
+ QMenu* ps = m->addMenu(QMenu::tr("Add Midi Generator..."));
+
+ int idx = 5000;
+ for (iMidiPlugin i = midiPlugins.begin(); i != midiPlugins.end(); ++i) {
+ if ((*i)->type() != MEMPI_GENERATOR)
+ continue;
+ a = ps->addAction((*i)->name());
+ a->setData(idx);
+ }
+
+ if (!midiOnly) {
+ a = m->addSeparator();
+ a->setText(QT_TR_NOOP("Audio"));
+ a->setFont(f);
+
+ a = m->addAction(QIcon(*addtrack_wavetrackIcon), QT_TR_NOOP("Add Wave Track"));
+ a->setData(Track::WAVE);
+ a = m->addAction(QIcon(*addtrack_audiooutputIcon), QT_TR_NOOP("Add Audio Output"));
+ a->setData(Track::AUDIO_OUTPUT);
+ a = m->addAction(QIcon(*addtrack_audiogroupIcon), QT_TR_NOOP("Add Audio Group"));
+ a->setData(Track::AUDIO_GROUP);
+ a = m->addAction(QIcon(*addtrack_audioinputIcon), QT_TR_NOOP("Add Audio Input"));
+ a->setData(Track::AUDIO_INPUT);
+
+ ps = m->addMenu(QMenu::tr("Add Soft Synth..."));
+
+ int idx = 1000;
+ for (std::vector<Synth*>::iterator is = synthis.begin(); is != synthis.end(); ++is, ++idx) {
+ a = ps->addAction((*is)->name());
+ a->setData(idx);
+ }
+ }
+ m->connect(m, SIGNAL(triggered(QAction*)), song, SLOT(addTrack(QAction*)));
+ }
+
+//---------------------------------------------------------
+// setupTransportToolbar
+//---------------------------------------------------------
+
+void MusE::setupTransportToolbar(QToolBar* tb) const
+ {
+ tb->addAction(loopAction);
+ tb->addAction(punchinAction);
+ tb->addAction(punchoutAction);
+ tb->addAction(startAction);
+
+ // hack to implement auto repeat:
+ // the action auto repeat does only work for
+ // shortcuts but not for mouse press:
+
+ QToolButton* rewindTb = new QToolButton;
+ rewindTb->setDefaultAction(rewindAction);
+ rewindTb->setAutoRepeat(true);
+ tb->addWidget(rewindTb);
+ connect(rewindTb, SIGNAL(clicked()), song, SLOT(rewind()));
+
+ QToolButton* forwardTb = new QToolButton;
+ forwardTb->setDefaultAction(forwardAction);
+ forwardTb->setAutoRepeat(true);
+ tb->addWidget(forwardTb);
+ connect(forwardTb, SIGNAL(clicked()), song, SLOT(forward()));
+
+ tb->addAction(stopAction);
+ tb->addAction(playAction);
+ tb->addAction(recordAction);
+ }
+
+//---------------------------------------------------------
+// MusE
+//---------------------------------------------------------
+
+MusE::MusE()
+ : QMainWindow()
+ {
+ setWindowIcon(*museIcon);
+ setIconSize(ICON_SIZE);
+ setFocusPolicy(Qt::WheelFocus);
+
+ muse = this; // hack
+ midiSyncConfig = 0;
+ midiRemoteConfig = 0;
+ midiPortConfig = 0;
+ metronomeConfig = 0;
+ audioConfig = 0;
+ midiFileConfig = 0;
+ midiFilterConfig = 0;
+ midiInputTransform = 0;
+ midiRhythmGenerator = 0;
+ preferencesDialog = 0;
+ softSynthesizerConfig = 0;
+ midiTransformerDialog = 0;
+ shortcutConfig = 0;
+ editInstrument = 0;
+ appName = QString("MusE");
+ _raster = 0;
+ audioState = AUDIO_STOP;
+ bigtime = 0;
+ mixer1 = 0;
+ mixer2 = 0;
+ markerView = 0;
+ exportMidiDialog = 0;
+ projectPropsDialog = 0;
+ listEditor = 0;
+
+ //---------------------------------------------------
+ // Transport
+ //---------------------------------------------------
+
+ loopAction = getAction("toggle_loop", this);
+ loopAction->setCheckable(true);
+ connect(loopAction, SIGNAL(triggered(bool)), song, SLOT(setLoop(bool)));
+
+ punchinAction = getAction("punchin", this);
+ punchinAction->setCheckable(true);
+ connect(punchinAction, SIGNAL(toggled(bool)), song, SLOT(setPunchin(bool)));
+
+ punchoutAction = getAction("punchout", this);
+ punchoutAction->setCheckable(true);
+ connect(punchoutAction, SIGNAL(toggled(bool)), song, SLOT(setPunchout(bool)));
+
+ recordAction = getAction("toggle_rec", this);
+ recordAction->setCheckable(true);
+ connect(recordAction, SIGNAL(triggered(bool)), song, SLOT(setRecord(bool)));
+
+ panicAction = getAction("panic", this);
+ connect(panicAction, SIGNAL(triggered()), song, SLOT(panic()));
+
+ startAction = getAction("start", this);
+ connect(startAction, SIGNAL(triggered()), song, SLOT(rewindStart()));
+
+ playAction = getAction("play", this);
+ playAction->setCheckable(true);
+ connect(playAction, SIGNAL(triggered(bool)), song, SLOT(setPlay(bool)));
+
+ QAction* a = getAction("play_toggle", this);
+ connect(a, SIGNAL(triggered()), SLOT(playToggle()));
+ addAction(a);
+
+ a = getAction("toggle_metro", this);
+ connect(a, SIGNAL(triggered()), song, SLOT(toggleClick()));
+ addAction(a);
+
+ a = getAction("goto_left", this);
+ connect(a, SIGNAL(triggered()), song, SLOT(gotoLeftMarker()));
+ addAction(a);
+
+ a = getAction("goto_right", this);
+ connect(a, SIGNAL(triggered()), song, SLOT(gotoRightMarker()));
+ addAction(a);
+
+ rewindAction = getAction("rewind", this);
+ rewindAction->setAutoRepeat(true);
+
+ forwardAction = getAction("forward", this);
+ forwardAction->setAutoRepeat(true);
+
+ stopAction = getAction("stop", this);
+ stopAction->setCheckable(true);
+ connect(stopAction, SIGNAL(triggered(bool)), song, SLOT(setStop(bool)));
+
+ song->blockSignals(true);
+ heartBeatTimer = new QTimer(this);
+ connect(heartBeatTimer, SIGNAL(timeout()), SLOT(beat()));
+
+ //---------------------------------------------------
+ // undo/redo
+ //---------------------------------------------------
+
+ undoAction = getAction("undo", this);
+ undoAction->setEnabled(false);
+ connect(undoAction, SIGNAL(triggered()), song, SLOT(undo()));
+
+ redoAction = getAction("redo", this);
+ redoAction->setEnabled(false);
+ connect(redoAction, SIGNAL(triggered()), song, SLOT(redo()));
+
+ fileOpenAction = getAction("open_project", this);
+ connect(fileOpenAction, SIGNAL(triggered()), SLOT(loadProject()));
+
+ fileSaveAction = getAction("save_project", this);
+ connect(fileSaveAction, SIGNAL(triggered()), SLOT(save()));
+
+ fileSaveAsAction = getAction("save_project_as", this);
+ connect(fileSaveAsAction, SIGNAL(triggered()), SLOT(saveAs()));
+
+ pianoAction = getAction("open_pianoroll", this);
+ connect(pianoAction, SIGNAL(triggered()), SLOT(startPianoroll()));
+
+ waveAction = getAction("open_waveedit", this);
+ connect(waveAction, SIGNAL(triggered()), SLOT(startWaveEditor()));
+
+ trackerAction = getAction("open_miditracker", this);
+ connect(trackerAction, SIGNAL(triggered()), SLOT(startMidiTrackerEditor()));
+
+ //--------------------------------------------------
+ // Toolbar
+ //--------------------------------------------------
+
+ tools = new QToolBar(tr("Project Buttons"));
+ addToolBar(tools);
+
+ tools->addAction(fileOpenAction);
+ tools->addAction(fileSaveAction);
+ tools->addAction(QWhatsThis::createAction(this));
+
+ tools->addSeparator();
+ tools->addAction(undoAction);
+ tools->addAction(redoAction);
+
+ tools1 = new EditToolBar(this, arrangerTools);
+ addToolBar(tools1);
+
+ QToolBar* transportToolbar = addToolBar(tr("Transport"));
+ setupTransportToolbar(transportToolbar);
+
+ QToolBar* panicToolbar = new QToolBar(tr("Panic"), this);
+ addToolBar(panicToolbar);
+ panicToolbar->addAction(panicAction);
+
+ addToolBarBreak();
+
+ audio = new Audio();
+ audioPrefetch = new AudioPrefetch("Prefetch");
+ audioWriteback = new AudioWriteback("Writeback");
+
+ //---------------------------------------------------
+ // MenuBar
+ //---------------------------------------------------
+
+ QMenuBar* mb = menuBar();
+
+ //-------------------------------------------------------------
+ // File
+ //-------------------------------------------------------------
+
+ menu_file = mb->addMenu(tr("&Project"));
+
+ menu_file->addAction(fileOpenAction);
+
+ openRecent = new QMenu(tr("Open &Recent"), this);
+ connect(openRecent, SIGNAL(aboutToShow()), this, SLOT(openRecentMenu()));
+ connect(openRecent, SIGNAL(triggered(QAction*)), this, SLOT(selectProject(QAction*)));
+
+ menu_file->addMenu(openRecent);
+ menu_file->addSeparator();
+ menu_file->addAction(fileSaveAction);
+ menu_file->addAction(fileSaveAsAction);
+ a = getAction("save_as_template", this);
+ connect(a, SIGNAL(triggered()), SLOT(saveAsTemplate()));
+ menu_file->addAction(a);
+
+ menu_file->addSeparator();
+ a = menu_file->addAction(*openIcon, tr("Import Midifile"));
+ connect(a, SIGNAL(triggered()), this, SLOT(importMidi()));
+ a = menu_file->addAction(*saveIcon, tr("Export Midifile"));
+ connect(a, SIGNAL(triggered()), this, SLOT(exportMidi()));
+ menu_file->addSeparator();
+
+ a = menu_file->addAction(*openIcon, tr("Import Wave File"));
+ connect(a, SIGNAL(triggered()), this, SLOT(importWave()));
+ a->setEnabled(!midiOnly);
+
+ menu_file->addSeparator();
+ a = getAction("quit", this);
+ menu_file->addAction(a);
+ connect(a, SIGNAL(triggered()), this, SLOT(quitDoc()));
+ menu_file->addSeparator();
+
+ //-------------------------------------------------------------
+ // Edit
+ //-------------------------------------------------------------
+
+ menuEdit = mb->addMenu(tr("&Edit"));
+
+ menuEdit->addAction(undoAction);
+ menuEdit->addAction(redoAction);
+ menuEdit->addSeparator();
+
+ cutAction = getAction("cut", this);
+ menuEdit->addAction(cutAction);
+ copyAction = getAction("copy", this);
+ menuEdit->addAction(copyAction);
+ pasteAction = getAction("paste", this);
+ menuEdit->addAction(pasteAction);
+
+ menuEdit->addSeparator();
+ a = menuEdit->addAction(QIcon(*edit_track_delIcon), tr("Delete Selected Tracks"));
+ a->setData("delete_track");
+
+ addTrack = menuEdit->addMenu(*edit_track_addIcon, tr("Add Track"));
+ // delay creation of menu (at this moment the list of software
+ // synthesizer is empty):
+ connect(addTrack, SIGNAL(aboutToShow()), SLOT(aboutToShowAddTrack()));
+
+ menuEdit->addSeparator();
+ select = menuEdit->addMenu(QIcon(*selectIcon), tr("Select"));
+ select->addAction(getAction("sel_all", this));
+ select->addAction(getAction("sel_none", this));
+ select->addAction(getAction("sel_inv", this));
+ select->addAction(getAction("sel_ins_loc", this));
+ select->addAction(getAction("sel_out_loc", this));
+ select->addAction(getAction("select_parts_on_track", this));
+
+ menuEdit->addSeparator();
+ menuEdit->addAction(pianoAction);
+ menuEdit->addAction(waveAction);
+ menuEdit->addAction(trackerAction);
+
+ a = getAction("open_drumedit", this);
+ menuEdit->addAction(a);
+ connect(a, SIGNAL(triggered()), SLOT(startDrumEditor()));
+
+ a = getAction("open_master", this);
+ menuEdit->addAction(a);
+ connect(a, SIGNAL(triggered()), SLOT(startMasterEditor()));
+
+ a = menuEdit->addAction(*saveIcon, tr("Project Properties"));
+ connect(a, SIGNAL(triggered()), SLOT(showProjectPropsDialog()));
+
+ menuEdit->addSeparator();
+ connect(menuEdit, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*)));
+ connect(select, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*)));
+
+ midiEdit = menuEdit->addMenu(QIcon(*edit_midiIcon), tr("Midi"));
+
+#if 0 // TODO
+ midiEdit->insertItem(tr("Modify Gate Time"), this, SLOT(modifyGateTime()));
+ midiEdit->insertItem(tr("Modify Velocity"), this, SLOT(modifyVelocity()));
+ midiEdit->insertItem(tr("Crescendo"), this, SLOT(crescendo()));
+ midiEdit->insertItem(tr("Transpose"), this, SLOT(transpose()));
+ midiEdit->insertItem(tr("Thin Out"), this, SLOT(thinOut()));
+ midiEdit->insertItem(tr("Erase Event"), this, SLOT(eraseEvent()));
+ midiEdit->insertItem(tr("Note Shift"), this, SLOT(noteShift()));
+ midiEdit->insertItem(tr("Move Clock"), this, SLOT(moveClock()));
+ midiEdit->insertItem(tr("Copy Measure"), this, SLOT(copyMeasure()));
+ midiEdit->insertItem(tr("Erase Measure"), this, SLOT(eraseMeasure()));
+ midiEdit->insertItem(tr("Delete Measure"), this, SLOT(deleteMeasure()));
+ midiEdit->insertItem(tr("Create Measure"), this, SLOT(createMeasure()));
+ midiEdit->insertItem(tr("Mix Track"), this, SLOT(mixTrack()));
+#endif
+ a = midiEdit->addAction(QIcon(*midi_transposeIcon), tr("Transpose"));
+ connect(a, SIGNAL(triggered()), this, SLOT(transpose()));
+
+ //-------------------------------------------------------------
+ // View
+ //-------------------------------------------------------------
+
+ menuView = mb->addMenu(tr("&View"));
+
+ tr_id = getAction("toggle_transport", this);
+ tr_id->setCheckable(true);
+ menuView->addAction(tr_id);
+ connect(tr_id, SIGNAL(triggered(bool)), this, SLOT(showTransport(bool)));
+
+ bt_id = getAction("toggle_bigtime", this);
+ bt_id->setCheckable(true);
+ menuView->addAction(bt_id);
+ connect(bt_id, SIGNAL(triggered(bool)), this, SLOT(showBigtime(bool)));
+
+ aid1a = getAction("toggle_mixer1", this);
+ aid1a->setCheckable(true);
+ menuView->addAction(aid1a);
+ connect(aid1a, SIGNAL(triggered(bool)), this, SLOT(showMixer1(bool)));
+
+ aid1b = getAction("toggle_mixer2", this);
+ aid1b->setCheckable(true);
+ menuView->addAction(aid1b);
+ connect(aid1b, SIGNAL(triggered(bool)), this, SLOT(showMixer2(bool)));
+
+ mk_id = getAction("marker_window", this);
+ mk_id->setCheckable(true);
+ menuView->addAction(mk_id);
+ connect(mk_id , SIGNAL(triggered(bool)), this, SLOT(showMarker(bool)));
+
+ //-------------------------------------------------------------
+ // Structure
+ //-------------------------------------------------------------
+
+ menuStructure = mb->addMenu(tr("&Structure"));
+
+ a = menuStructure->addAction(tr("Global Cut"));
+ connect(a, SIGNAL(triggered()), this, SLOT(globalCut()));
+
+ a = menuStructure->addAction(tr("Global Insert"));
+ connect(a, SIGNAL(triggered()), this, SLOT(globalInsert()));
+
+ a = menuStructure->addAction(tr("Global Split"));
+ connect(a, SIGNAL(triggered()), this, SLOT(globalSplit()));
+
+ a = menuStructure->addAction(tr("Copy Range"));
+ connect(a, SIGNAL(triggered()), this, SLOT(copyRange()));
+ a->setEnabled(false);
+
+ menuStructure->addSeparator();
+
+ a = menuStructure->addAction(tr("Cut Events"));
+ connect(a, SIGNAL(triggered()), this, SLOT(cutEvents()));
+ a->setEnabled(false);
+
+ //-------------------------------------------------------------
+ // Midi
+ //-------------------------------------------------------------
+
+ menu_functions = mb->addMenu(tr("&Midi"));
+
+ a = menu_functions->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit Instrument"));
+ connect(a, SIGNAL(triggered()), this, SLOT(startEditInstrument()));
+
+ menu_functions->addSeparator();
+ a = menu_functions->addAction(QIcon(*midi_reset_instrIcon), tr("Reset Instr."));
+ connect(a, SIGNAL(triggered()), this, SLOT(resetMidiDevices()));
+ a = menu_functions->addAction(QIcon(*midi_init_instrIcon), tr("Init Instr."));
+ connect(a, SIGNAL(triggered()), this, SLOT(initMidiDevices()));
+ a = menu_functions->addAction(QIcon(*midi_local_offIcon), tr("local off"));
+ connect(a, SIGNAL(triggered()), this, SLOT(localOff()));
+
+ //-------------------------------------------------------------
+ // Audio
+ //-------------------------------------------------------------
+
+ menu_audio = mb->addMenu(tr("&Audio"));
+
+ a = menu_audio->addAction(QIcon(*audio_bounce_to_trackIcon), tr("Bounce to Track"));
+ connect(a, SIGNAL(triggered()), this, SLOT(bounceToTrack()));
+
+ a = menu_audio->addAction(QIcon(*audio_bounce_to_fileIcon), tr("Bounce to File"));
+ connect(a, SIGNAL(triggered()), this, SLOT(bounceToFile()));
+ menu_audio->setEnabled(!midiOnly);
+ a = menu_audio->addAction(QIcon(*audio_restartaudioIcon), tr("Restart Audio"));
+ connect(a, SIGNAL(triggered()), this, SLOT(seqRestart()));
+
+ //-------------------------------------------------------------
+ // Settings
+ //-------------------------------------------------------------
+
+ menuSettings = mb->addMenu(tr("Setti&ngs"));
+ a = menuSettings->addAction(QIcon(*settings_configureshortcutsIcon), tr("Configure shortcuts"));
+ connect(a, SIGNAL(triggered()), this, SLOT(configShortCuts()));
+
+ follow = menuSettings->addMenu(QIcon(*settings_follow_songIcon), tr("follow song"));
+ //follow->menuAction()->setShortcut(Qt::Key_F);
+ fid0 = follow->addAction(tr("dont follow Song"));
+ fid0->setData("follow_no");
+ fid0->setCheckable(true);
+ fid1 = follow->addAction(tr("follow page"));
+ fid1->setData("follow_jump");
+ fid1->setCheckable(true);
+ fid2 = follow->addAction(tr("follow continuous"));
+ fid2->setData("follow_continuous");
+ fid2->setCheckable(true);
+ fid0->setChecked(TimeCanvas::followMode == FOLLOW_NO);
+ fid1->setChecked(TimeCanvas::followMode == FOLLOW_JUMP);
+ fid2->setChecked(TimeCanvas::followMode == FOLLOW_CONTINUOUS);
+ connect(follow, SIGNAL(triggered(QAction*)), SLOT(cmd(QAction*)));
+
+ menuSettings->addSeparator();
+ a = menuSettings->addAction(QIcon(*settings_midisyncIcon), tr("Midi Sync"));
+ connect(a, SIGNAL(triggered()), this, SLOT(configMidiSync()));
+ a = menuSettings->addAction(QIcon(*settings_midifileexportIcon), tr("Midi File Export"));
+ connect(a, SIGNAL(triggered()), this, SLOT(configMidiFile()));
+ menuSettings->addSeparator();
+ QAction* action = menuSettings->addAction(QIcon(*settings_globalsettingsIcon), tr("Preferences"));
+ connect(action, SIGNAL(triggered()), this, SLOT(preferences()));
+
+ //---------------------------------------------------
+ // Help
+ //---------------------------------------------------
+
+ mb->addSeparator();
+ menu_help = mb->addMenu(tr("&Help"));
+
+ a = menu_help->addAction(tr("&Manual"));
+ connect(a, SIGNAL(triggered()), this, SLOT(startHelpBrowser()));
+ a = menu_help->addAction(tr("&MusE homepage"));
+ connect(a, SIGNAL(triggered()), this, SLOT(startHomepageBrowser()));
+ menu_help->addSeparator();
+ a = menu_help->addAction(tr("&Report Bug..."));
+ connect(a, SIGNAL(triggered()), this, SLOT(startBugBrowser()));
+ menu_help->addSeparator();
+ a = menu_help->addAction(tr("&About MusE"));
+ a->setIcon(QIcon(*museIcon));
+ connect(a, SIGNAL(triggered()), this, SLOT(about()));
+ a = menu_help->addAction(tr("About&Qt"));
+ connect(a, SIGNAL(triggered()), this, SLOT(aboutQt()));
+ menu_help->addSeparator();
+ a = QWhatsThis::createAction(this);
+ a->setText(tr("What's &This?"));
+ menu_help->addAction(a);
+
+ //---------------------------------------------------
+ // ToolBar
+ //---------------------------------------------------
+
+ QToolBar* aToolBar = addToolBar(tr("Arranger"));
+
+ QLabel* label = new QLabel(tr("Cursor"));
+ label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ label->setIndent(3);
+ aToolBar->addWidget(label);
+
+ Awl::PosLabel* cursorPos = new Awl::PosLabel;
+ aToolBar->addWidget(cursorPos);
+ cursorPos->setFixedHeight(25);
+
+ label = new QLabel(tr("Snap"));
+ label->setIndent(5);
+ aToolBar->addWidget(label);
+
+ rasterCombo = new QComboBox;
+ rasterCombo->setFixedHeight(24);
+ aToolBar->addWidget(rasterCombo);
+ for (unsigned i = 0; i < sizeof(rasterTable)/sizeof(*rasterTable); i++)
+ rasterCombo->addItem(rasterTable[i].label, i);
+ rasterCombo->setCurrentIndex(1);
+ connect(rasterCombo, SIGNAL(activated(int)), SLOT(setRaster(int)));
+
+ // Song len
+ label = new QLabel(tr("Len"));
+ label->setIndent(5);
+ aToolBar->addWidget(label);
+
+ // song length is limited to 10000 bars; the real song len is limited
+ // by overflows in tick computations
+ //
+ QSpinBox* lenEntry = new QSpinBox;
+ lenEntry->setFixedHeight(24);
+ lenEntry->setRange(1, 10000);
+ aToolBar->addWidget(lenEntry);
+ lenEntry->setValue(song->len());
+ connect(lenEntry, SIGNAL(valueChanged(int)), song, SLOT(setMeasureLen(int)));
+ connect(song, SIGNAL(measureLenChanged(int)), lenEntry, SLOT(setValue(int)));
+
+ label = new QLabel(tr("Pitch"));
+ label->setIndent(5);
+ aToolBar->addWidget(label);
+
+ QSpinBox* globalPitchSpinBox = new QSpinBox;
+ globalPitchSpinBox->setFixedHeight(24);
+ globalPitchSpinBox->setRange(-127, 127);
+ aToolBar->addWidget(globalPitchSpinBox);
+ globalPitchSpinBox->setValue(song->globalPitchShift());
+ globalPitchSpinBox->setToolTip(tr("midi pitch"));
+ globalPitchSpinBox->setWhatsThis(tr("global midi pitch shift"));
+ connect(globalPitchSpinBox, SIGNAL(valueChanged(int)), SLOT(globalPitchChanged(int)));
+
+ label = new QLabel(tr("Tempo"));
+ label->setIndent(5);
+ aToolBar->addWidget(label);
+
+ globalTempoSpinBox = new QSpinBox;
+ globalTempoSpinBox->setFixedHeight(24);
+ globalTempoSpinBox->setRange(50, 200);
+ aToolBar->addWidget(globalTempoSpinBox);
+ globalTempoSpinBox->setSuffix(QString("%"));
+ globalTempoSpinBox->setValue(AL::tempomap.globalTempo());
+ globalTempoSpinBox->setToolTip(tr("midi tempo"));
+ globalTempoSpinBox->setWhatsThis(tr("midi tempo"));
+ connect(globalTempoSpinBox, SIGNAL(valueChanged(int)), SLOT(globalTempoChanged(int)));
+
+ QToolButton* tempo50 = new QToolButton;
+ tempo50->setFixedHeight(24);
+ aToolBar->addWidget(tempo50);
+ tempo50->setText(QString("50%"));
+ connect(tempo50, SIGNAL(clicked()), SLOT(setTempo50()));
+
+ QToolButton* tempo100 = new QToolButton;
+ tempo100->setFixedHeight(24);
+ aToolBar->addWidget(tempo100);
+ tempo100->setText(tr("N"));
+ connect(tempo100, SIGNAL(clicked()), SLOT(setTempo100()));
+
+ QToolButton* tempo200 = new QToolButton;
+ tempo200->setFixedHeight(24);
+ aToolBar->addWidget(tempo200);
+ tempo200->setText(QString("200%"));
+ connect(tempo200, SIGNAL(clicked()), SLOT(setTempo200()));
+
+ //---------------------------------------------------
+ // Central Widget
+ //---------------------------------------------------
+
+ arranger = new Arranger(this);
+ setCentralWidget(arranger);
+
+ connect(tools1, SIGNAL(toolChanged(int)), SLOT(setTool(int)));
+ connect(arranger, SIGNAL(toolChanged(int)), SLOT(setTool(int)));
+ connect(arranger, SIGNAL(editPart(Part*)), SLOT(startEditor(Part*)));
+//TODO1 connect(arranger, SIGNAL(dropSongFile(const QString&)), SLOT(loadProject(const QString&)));
+//TODO1 connect(arranger, SIGNAL(dropMidiFile(const QString&)), SLOT(importMidi(const QString&)));
+ connect(arranger, SIGNAL(cursorPos(const AL::Pos&,bool)), cursorPos, SLOT(setValue(const AL::Pos&,bool)));
+
+ //---------------------------------------------------
+ // read list of "Recent Projects"
+ //---------------------------------------------------
+
+ QString prjPath(getenv("HOME"));
+ prjPath += QString("/.musePrj");
+ FILE* f = fopen(prjPath.toLatin1().data(), "r");
+ if (f == 0) {
+ if (debugMsg) {
+ fprintf(stderr, "open projectfile <%s> failed: %s",
+ prjPath.toLatin1().data(), strerror(errno));
+ }
+ for (int i = 0; i < PROJECT_LIST_LEN; ++i)
+ projectList[i] = 0;
+ }
+ else {
+ for (int i = 0; i < PROJECT_LIST_LEN; ++i) {
+ char buffer[256];
+ if (fgets(buffer, 256, f)) {
+ int n = strlen(buffer);
+ if (n && buffer[n-1] == '\n')
+ buffer[n-1] = 0;
+ projectList[i] = *buffer ? new QString(buffer) : 0;
+ }
+ else
+ break;
+ }
+ fclose(f);
+ }
+
+ initMidiSynth();
+
+ transport = new Transport;
+ transport->hide();
+ connect(transport, SIGNAL(closed()), SLOT(transportClosed()));
+
+ QClipboard* cb = QApplication::clipboard();
+ connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));
+ connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged()));
+ song->blockSignals(false);
+ }
+
+//---------------------------------------------------------
+// aboutToShowAddTrack
+//---------------------------------------------------------
+
+void MusE::aboutToShowAddTrack()
+ {
+ populateAddTrack(addTrack);
+ }
+
+//---------------------------------------------------------
+// setRaster
+//---------------------------------------------------------
+
+void MusE::setRaster(int val)
+ {
+ _raster = rasterTable[val].val;
+ emit rasterChanged(_raster);
+ }
+
+//---------------------------------------------------------
+// initRaster
+//---------------------------------------------------------
+
+void MusE::initRaster(int val)
+ {
+ for (unsigned i = 0; i < sizeof(rasterTable)/sizeof(*rasterTable); ++i) {
+ if (rasterTable[i].val == val) {
+ _raster = val;
+ rasterCombo->setCurrentIndex(i);
+ return;
+ }
+ }
+ _raster = rasterTable[1].val;
+ rasterCombo->setCurrentIndex(1);
+ }
+
+//---------------------------------------------------------
+// setHeartBeat
+//---------------------------------------------------------
+
+void MusE::setHeartBeat()
+ {
+ heartBeatTimer->start(1000/config.guiRefresh);
+ }
+
+//---------------------------------------------------------
+// resetDevices
+//---------------------------------------------------------
+
+void MusE::resetMidiDevices()
+ {
+ audio->msgResetMidiDevices();
+ }
+
+//---------------------------------------------------------
+// initMidiDevices
+//---------------------------------------------------------
+
+void MusE::initMidiDevices()
+ {
+ audio->msgInitMidiDevices();
+ }
+
+//---------------------------------------------------------
+// localOff
+//---------------------------------------------------------
+
+void MusE::localOff()
+ {
+ audio->msgLocalOff();
+ }
+
+//---------------------------------------------------------
+// loadProject
+//---------------------------------------------------------
+
+void MusE::loadProject(const QString& path)
+ {
+ //
+ // stop audio threads if running
+ //
+ bool restartSequencer = audioState == AUDIO_RUNNING;
+ if (restartSequencer) {
+ if (audio->isPlaying()) {
+ audio->msgPlay(false);
+ while (audio->isPlaying())
+ qApp->processEvents();
+ }
+ seqStop();
+ }
+ loadProject1(path);
+ if (restartSequencer)
+ seqStart();
+ audio->msgSeek(song->cPos());
+ }
+
+//---------------------------------------------------------
+// loadProject1
+//---------------------------------------------------------
+
+void MusE::loadProject1(const QString& path)
+ {
+ QFileInfo file(path);
+ QString header = tr("MusE: new project");
+
+ if (leaveProject())
+ return;
+
+ if (mixer1)
+ mixer1->clear();
+ if (mixer2)
+ mixer2->clear();
+
+ QString name(file.fileName());
+ QDir pd(QDir::homePath() + "/" + config.projectPath + "/" + path);
+
+ addProject(path); // add to history
+
+ bool newProject = false;
+ if (!pd.exists()) {
+ newProject = true;
+ if (!pd.mkdir(pd.path())) {
+ QString s(tr("Cannot create project folder <%1>"));
+ QMessageBox::critical(this, header, s.arg(pd.path()));
+ return;
+ }
+ }
+ //
+ // close all toplevel windows
+ //
+ foreach(QWidget* w, QApplication::topLevelWidgets()) {
+ if (!w->isVisible())
+ continue;
+ static const char* const top[] = {
+ "DrumEdit", "PianoRoll", "MasterEdit", "WaveEdit",
+ "ListEdit", "PluginGui"
+ };
+ for (unsigned i = 0; i < sizeof(top)/sizeof(*top); ++i) {
+ if (strcmp(top[i], w->metaObject()->className()) == 0) {
+ w->close();
+ break;
+ }
+ }
+ }
+ emit startLoadSong();
+
+ song->setProjectPath(path);
+ song->clear(false);
+ song->setCreated(newProject);
+
+ QString s = pd.absoluteFilePath(name + ".med");
+
+ QFile f(s);
+
+ song->blockSignals(true);
+
+ bool rv = true;
+ if (f.open(QIODevice::ReadOnly)) {
+ rv = song->read(&f);
+ f.close();
+ }
+ else {
+ TemplateDialog templateDialog;
+ if (templateDialog.exec() == 1) {
+ s = templateDialog.templatePath();
+ if (!s.isEmpty()) {
+ QFile f(s);
+ if (f.open(QIODevice::ReadOnly)) {
+ rv = song->read(&f);
+ f.close();
+ }
+ else {
+ QString msg(tr("Cannot open template file\n%1"));
+ QMessageBox::critical(this, header, msg.arg(s));
+ }
+ }
+ }
+ }
+ if (!rv) {
+ QString msg(tr("File <%1> read error"));
+ QMessageBox::critical(this, header, msg.arg(s));
+ }
+ tr_id->setChecked(config.transportVisible);
+ bt_id->setChecked(config.bigTimeVisible);
+
+ showBigtime(config.bigTimeVisible);
+ showMixer1(config.mixer1Visible);
+ showMixer2(config.mixer2Visible);
+ if (mixer1 && config.mixer1Visible)
+ mixer1->setUpdateMixer();
+ if (mixer2 && config.mixer2Visible)
+ mixer2->setUpdateMixer();
+// resize(config.geometryMain.size());
+// move(config.geometryMain.topLeft());
+ if (config.transportVisible)
+ transport->show();
+ transport->move(config.geometryTransport.topLeft());
+ showTransport(config.transportVisible);
+ song->blockSignals(false);
+ transport->setMasterFlag(song->masterFlag());
+ punchinAction->setChecked(song->punchin());
+ punchoutAction->setChecked(song->punchout());
+ loopAction->setChecked(song->loop());
+ clipboardChanged(); // enable/disable "Paste"
+ song->setLen(song->len()); // emit song->lenChanged() signal
+
+ selectionChanged(); // enable/disable "Copy" & "Paste"
+ arranger->endLoadSong();
+ song->updatePos();
+ song->updateCurrentMarker();
+ //
+ // send "cur" controller values to devices
+ //
+
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i) {
+ Track* track = *i;
+// track->blockSignals(true);
+ CtrlList* cl = track->controller();
+ for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) {
+ Ctrl* ctrl = ic->second;
+ if (ctrl->type() & Ctrl::INT) {
+ CVal val;
+ val = ctrl->curVal();
+ if (track->isMidiTrack() && val.i == CTRL_VAL_UNKNOWN)
+ continue;
+ ctrl->setCurVal(CTRL_VAL_UNKNOWN);
+ song->setControllerVal(track, ctrl, val);
+ }
+ }
+// track->blockSignals(false);
+ }
+ setWindowTitle(QString("MusE: Song: ") + name);
+ }
+
+//---------------------------------------------------------
+// MusE::loadProject
+//---------------------------------------------------------
+
+void MusE::loadProject()
+ {
+ ProjectDialog projectDialog;
+ int rv = projectDialog.exec();
+ if (rv == 0)
+ return;
+ QString path = projectDialog.projectPath();
+ if (path.isEmpty())
+ return;
+ loadProject(path);
+ }
+
+//---------------------------------------------------------
+// save
+//---------------------------------------------------------
+
+bool MusE::save()
+ {
+ QString backupCommand;
+
+ QString name(song->projectName() + ".med");
+ QFileInfo fi(song->absoluteProjectPath() + "/" + name);
+
+ QTemporaryFile tmp(fi.path() + "/MusEXXXXXX");
+ tmp.setAutoRemove(false);
+
+ if (!tmp.open()) {
+ QString s("Creating temp file failed: ");
+ s += strerror(errno);
+ QMessageBox::critical(this,
+ tr("MusE: Create tmp file failed"), s);
+ return false;
+ }
+ Xml xml(&tmp);
+ write(xml);
+ if (tmp.error()) {
+ QString s = QString("Write File\n") + tmp.fileName() + QString("\nfailed: ")
+ + tmp.errorString();
+ QMessageBox::critical(this, tr("MusE: Write File failed"), s);
+ return false;
+ }
+ if (!song->backupWritten()) {
+ //
+ // remove old backup file
+ //
+ QDir dir(fi.path());
+ QString backupName = QString(".") + fi.fileName() + QString(",");
+ dir.remove(backupName);
+
+ //
+ // rename old file to backup
+ //
+ QString n(fi.filePath());
+ dir.rename(n, backupName);
+ }
+ //
+ // rename temp name to file name
+ //
+ tmp.rename(fi.filePath());
+
+ song->dirty = false;
+ SndFile::updateRecFiles();
+ return true;
+ }
+
+//---------------------------------------------------------
+// saveAs
+//---------------------------------------------------------
+
+bool MusE::saveAs()
+ {
+ printf("SAVEAS\n");
+ ProjectDialog projectDialog;
+ int rv = projectDialog.exec();
+ if (rv == 0)
+ return false;
+ QString path = projectDialog.projectPath();
+ if (path.isEmpty())
+ return false;
+
+ QDir pd(QDir::homePath() + "/" + config.projectPath + "/" + path);
+ QString header = tr("MusE: new project");
+ if (!pd.exists()) {
+ if (!pd.mkdir(pd.path())) {
+ QString s(tr("Cannot create project folder <%1>"));
+ QMessageBox::critical(this, header, s.arg(pd.path()));
+ return false;
+ }
+ }
+ addProject(path);
+ song->setProjectPath(path);
+ QString name = song->projectName();
+ setWindowTitle(QString("MusE: Song: ") + name);
+ return save();
+ }
+
+
+//---------------------------------------------------------
+// saveAsTemplate
+//---------------------------------------------------------
+
+void MusE::saveAsTemplate()
+ {
+ printf("Not implemented: save as template\n");
+ }
+
+//---------------------------------------------------------
+// quitDoc
+//---------------------------------------------------------
+
+void MusE::quitDoc()
+ {
+ close();
+ }
+
+//---------------------------------------------------------
+// leaveProject
+// return false if user aborts operation
+//---------------------------------------------------------
+
+bool MusE::leaveProject()
+ {
+ if (song->dirty) {
+ int n = 0;
+ n = QMessageBox::warning(this, appName,
+ tr("The current Project contains unsaved data\n"
+ "Save Current Project?"),
+ tr("&Save"), tr("&Nosave"), tr("&Abort"), 0, 2);
+ if (n == 0)
+ return !save();
+ else if (n == 2)
+ return true;
+ //
+ // delete all wave files created in this session and not
+ // referenced any more
+ // delete all if we drop the song
+ //
+ SndFile::cleanupRecFiles(n == 1);
+ }
+ else
+ SndFile::cleanupRecFiles(true);
+ //
+ // if this is a new created project,
+ // delete project directory
+ //
+ if (song->created()) {
+ // delete project directory
+ QDir pp;
+ if (!pp.rmdir(song->absoluteProjectPath()))
+ printf("cannot remove dir <%s>\n", song->absoluteProjectPath().toLatin1().data());
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// closeEvent
+//---------------------------------------------------------
+
+void MusE::closeEvent(QCloseEvent* event)
+ {
+ song->setStop(true);
+ //
+ // wait for sequencer
+ //
+ while (audio->isPlaying()) {
+ qApp->processEvents();
+ }
+
+ if (leaveProject()) {
+ event->ignore();
+ return;
+ }
+
+ seqStop();
+
+ // save "Open Recent" list
+ QString prjPath(getenv("HOME"));
+ prjPath += "/.musePrj";
+ FILE* f = fopen(prjPath.toLatin1().data(), "w");
+ if (f) {
+ for (int i = 0; i < PROJECT_LIST_LEN; ++i) {
+ fprintf(f, "%s\n", projectList[i] ? projectList[i]->toLatin1().data() : "");
+ }
+ fclose(f);
+ }
+ exitJackAudio();
+ SynthIList* sl = song->syntis();
+ for (iSynthI i = sl->begin(); i != sl->end(); ++i)
+ delete *i;
+
+ // Cleanup temporary wavefiles + peakfiles used for undo
+ for (std::list<QString>::iterator i = temporaryWavFiles.begin(); i != temporaryWavFiles.end(); i++) {
+ QString filename = *i;
+ QFileInfo f(filename);
+ QDir d = f.dir();
+ d.remove(filename);
+ d.remove(f.baseName() + ".wca");
+ }
+ writeSettings();
+ qApp->quit();
+ }
+
+//---------------------------------------------------------
+// showTransport
+//---------------------------------------------------------
+
+void MusE::showTransport(bool flag)
+ {
+ transport->setShown(flag);
+ tr_id->setChecked(flag);
+ if (flag)
+ transport->setValues();
+ }
+
+//---------------------------------------------------------
+// printVersion
+//---------------------------------------------------------
+
+static void printVersion(const char* prog)
+ {
+ fprintf(stderr, "%s: Linux Music Editor; Version %s\n", prog, VERSION);
+ }
+
+//---------------------------------------------------------
+// startEditor
+//---------------------------------------------------------
+
+void MusE::startEditor(PartList* pl, int type)
+ {
+ switch (type) {
+ case 0: startPianoroll(pl); break;
+ case 1: startListEditor(pl); break;
+ case 2: startMidiTrackerEditor(pl); break;
+ case 3: startDrumEditor(pl); break;
+ case 4: startWaveEditor(pl); break;
+ }
+ }
+
+//---------------------------------------------------------
+// startEditor
+//---------------------------------------------------------
+
+void MusE::startEditor(Part* part, int type)
+ {
+ PartList* pl = new PartList();
+ pl->add(part);
+ startEditor(pl, type);
+ }
+
+//---------------------------------------------------------
+// startEditor
+//---------------------------------------------------------
+
+void MusE::startEditor(Part* part)
+ {
+ PartList* pl = new PartList();
+ pl->add(part);
+ Track* track = part->track();
+ switch (track->type()) {
+ case Track::MIDI:
+ {
+ MidiTrack* t = (MidiTrack*)track;
+ if (t->useDrumMap())
+ startDrumEditor(pl);
+ else
+ startPianoroll(pl);
+ }
+ break;
+ case Track::WAVE:
+ startWaveEditor(pl);
+ break;
+ default:
+ break;
+ }
+ }
+
+//---------------------------------------------------------
+// getMidiPartsToEdit
+//---------------------------------------------------------
+
+PartList* MusE::getMidiPartsToEdit()
+ {
+ PartList* pl = song->getSelectedMidiParts();
+ if (pl->empty()) {
+ QMessageBox::critical(this, QString("MusE"), tr("Nothing to edit"));
+ delete pl;
+ return 0;
+ }
+ return pl;
+ }
+
+//---------------------------------------------------------
+// startPianoroll
+//---------------------------------------------------------
+
+void MusE::startPianoroll()
+ {
+ PartList* pl = getMidiPartsToEdit();
+ if (pl == 0)
+ return;
+ startPianoroll(pl);
+ }
+
+void MusE::startPianoroll(PartList* pl)
+ {
+ PianoRoll* pianoroll = new PianoRoll(pl, false);
+ pianoroll->show();
+// connect(muse, SIGNAL(configChanged()), pianoroll, SLOT(configChanged()));
+ }
+
+//---------------------------------------------------------
+// startListEditor
+//---------------------------------------------------------
+
+void MusE::startListEditor()
+ {
+// PartList* pl = getMidiPartsToEdit();
+// if (pl == 0)
+// return;
+// startListEditor(pl);
+ startListEditor(0);
+ }
+
+void MusE::startListEditor(PartList* pl)
+ {
+ Part* part = 0;
+ if (pl && !pl->empty()) {
+ part = pl->begin()->second;
+ showListEditor(Pos(), part->track(), part, 0);
+ }
+ else
+ showListEditor(Pos(), 0, 0, 0);
+ }
+
+void MusE::showListEditor(const Pos& pos, Track* track, Part* part, Ctrl* ctrl)
+ {
+ if (listEditor == 0)
+ listEditor = new ListEdit(this);
+ listEditor->selectItem(pos, track, part, ctrl);
+ listEditor->show();
+ }
+
+//---------------------------------------------------------
+// startMidiTrackerEditor
+//---------------------------------------------------------
+
+void MusE::startMidiTrackerEditor()
+ {
+ PartList* pl = getMidiPartsToEdit();
+ if (pl == 0)
+ return;
+ startMidiTrackerEditor(pl);
+ }
+
+void MusE::startMidiTrackerEditor(PartList* pl)
+ {
+ MidiTrackerEditor* miditracker = new MidiTrackerEditor(pl, false);
+ miditracker->show();
+ connect(muse, SIGNAL(configChanged()), miditracker, SLOT(configChanged()));
+ }
+
+//---------------------------------------------------------
+// startMasterEditor
+//---------------------------------------------------------
+
+void MusE::startMasterEditor()
+ {
+ MasterEdit* masterEditor = new MasterEdit();
+ masterEditor->show();
+ }
+
+//---------------------------------------------------------
+// showProjectPropsDialog
+//---------------------------------------------------------
+
+void MusE::showProjectPropsDialog()
+ {
+ if (projectPropsDialog == 0)
+ projectPropsDialog = new ProjectPropsDialog(this);
+ projectPropsDialog->show();
+ }
+
+//---------------------------------------------------------
+// startDrumEditor
+//---------------------------------------------------------
+
+void MusE::startDrumEditor()
+ {
+ PartList* pl = getMidiPartsToEdit();
+ if (pl == 0)
+ return;
+ startDrumEditor(pl);
+ }
+
+void MusE::startDrumEditor(PartList* pl)
+ {
+ DrumEdit* drumEditor = new DrumEdit(pl, false);
+ drumEditor->show();
+// connect(muse, SIGNAL(configChanged()), drumEditor, SLOT(configChanged()));
+ }
+
+//---------------------------------------------------------
+// startWaveEditor
+//---------------------------------------------------------
+
+void MusE::startWaveEditor()
+ {
+ PartList* pl = song->getSelectedWaveParts();
+ if (pl->empty()) {
+ QMessageBox::critical(this, QString("MusE"), tr("Nothing to edit"));
+ delete pl;
+ return;
+ }
+ startWaveEditor(pl);
+ }
+
+void MusE::startWaveEditor(PartList* pl)
+ {
+ WaveEdit* waveEditor = new WaveEdit(pl, false);
+ waveEditor->show();
+ connect(muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged()));
+ }
+
+//---------------------------------------------------------
+// fileMenu
+//---------------------------------------------------------
+
+void MusE::openRecentMenu()
+ {
+ openRecent->clear();
+ for (int i = 0; i < PROJECT_LIST_LEN; ++i) {
+ if (projectList[i] == 0)
+ break;
+ const char* path = projectList[i]->toLatin1().data();
+ const char* p = strrchr(path, '/');
+ if (p == 0)
+ p = path;
+ else
+ ++p;
+ QAction* a = openRecent->addAction(QString(p));
+ a->setData(i);
+ }
+ }
+
+//---------------------------------------------------------
+// selectProject
+//---------------------------------------------------------
+
+void MusE::selectProject(QAction* a)
+ {
+ if (a == 0)
+ return;
+ int id = a->data().toInt();
+ if (id < 0)
+ return;
+ assert(id < PROJECT_LIST_LEN);
+ QString* name = projectList[id];
+ if (name == 0)
+ return;
+ loadProject(*name);
+ }
+
+//---------------------------------------------------------
+// playToggle
+//---------------------------------------------------------
+
+void MusE::playToggle()
+ {
+ if (audio->isPlaying())
+ song->setStop(true);
+ else
+ song->setPlay(true);
+// else if (song->cpos() != song->lpos())
+// song->setPos(0, song->lPos());
+// else {
+// Pos p(0, AL::TICKS);
+// song->setPos(0, p);
+// }
+ }
+
+//---------------------------------------------------------
+// MuseApplication
+//---------------------------------------------------------
+
+MuseApplication::MuseApplication(int& argc, char** argv)
+ : QApplication(argc, argv)
+ {
+ muse = 0;
+ for (unsigned i = 0;; ++i) {
+ if (sc[i].xml == 0)
+ break;
+ shortcuts[sc[i].xml] = &sc[i];
+ }
+ }
+
+//---------------------------------------------------------
+// usage
+//---------------------------------------------------------
+
+static void usage(const char* prog, const char* txt)
+ {
+ fprintf(stderr, "%s: %s\nusage: %s flags midifile\n Flags:",
+ prog, txt, prog);
+ fprintf(stderr, " -v print version\n");
+ fprintf(stderr, " -m MIDI only mode\n");
+ fprintf(stderr, " -d debug mode: no threads, no RT\n");
+ fprintf(stderr, " -D debug mode: enable some debug messages\n");
+ fprintf(stderr, " -i debug mode: trace midi Input\n");
+ fprintf(stderr, " -o debug mode: trace midi Output\n");
+ fprintf(stderr, " -s debug mode: trace sync\n");
+ fprintf(stderr, " -p don't load LADSPA plugins\n");
+#ifdef VST_SUPPORT
+ fprintf(stderr, " -V don't load VST plugins\n");
+#endif
+#ifdef DSSI_SUPPORT
+ fprintf(stderr, " -I don't load DSSI plugins\n");
+#endif
+ }
+
+//---------------------------------------------------------
+// catchSignal
+// only for debugging
+//---------------------------------------------------------
+
+#if 0
+static void catchSignal(int sig)
+ {
+ if (debugMsg)
+ fprintf(stderr, "MusE: signal %d catched\n", sig);
+ if (sig == SIGSEGV) {
+ fprintf(stderr, "MusE: segmentation fault\n");
+ abort();
+ }
+ if (sig == SIGCHLD) {
+ M_DEBUG("caught SIGCHLD - child died\n");
+ int status;
+ int n = waitpid (-1, &status, WNOHANG);
+ if (n > 0) {
+ fprintf(stderr, "SIGCHLD for unknown process %d received\n", n);
+ }
+ }
+ }
+#endif
+
+//---------------------------------------------------------
+// setFollow
+//---------------------------------------------------------
+
+void MusE::setFollow(FollowMode fm)
+ {
+ TimeCanvas::followMode = fm;
+ fid0->setChecked(fm == FOLLOW_NO);
+ fid1->setChecked(fm == FOLLOW_JUMP);
+ fid2->setChecked(fm == FOLLOW_CONTINUOUS);
+ changeConfig(true); // save settings
+ }
+
+//---------------------------------------------------------
+// copyParts
+// copy all selected Parts of type MIDI or WAVE to
+// clipboard whatever first found
+//---------------------------------------------------------
+
+void MusE::copyParts(bool cutFlag)
+ {
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
+ AL::Xml xml(&buffer);
+
+ if (cutFlag)
+ song->startUndo();
+ int midiType = -1;
+ TrackList* tl = song->tracks();
+ for (iTrack i = tl->begin(); i != tl->end(); ++i) {
+ Track* track = *i;
+ if (midiType == 1 && !track->isMidiTrack())
+ continue;
+ PartList* pl = track->parts();
+ for (iPart ip = pl->begin(); ip != pl->end(); ++ip) {
+ Part* part = ip->second;
+ if (part->selected()) {
+ if (midiType == -1)
+ midiType = track->isMidiTrack();
+ part->write(xml);
+ if (cutFlag)
+ song->removePart(part);
+ }
+ }
+ }
+ buffer.close();
+ QMimeData* mimeData = new QMimeData;
+ const char* t = midiType ? "application/muse/part/midi" : "application/muse/part/audio";
+ mimeData->setData(t, buffer.buffer());
+ QApplication::clipboard()->setMimeData(mimeData);
+ if (cutFlag)
+ song->endUndo(0);
+ }
+
+//---------------------------------------------------------
+// cmd
+// some cmd's from pulldown menu
+//---------------------------------------------------------
+
+void MusE::cmd(QAction* a)
+ {
+ QString cmd = a->data().toString();
+ TrackList* tracks = song->tracks();
+ int l = song->lpos();
+ int r = song->rpos();
+
+ if (cmd == "cut")
+ copyParts(true);
+ else if (cmd == "copy")
+ copyParts(false);
+ else if (cmd == "paste") {
+ const QMimeData* s = QApplication::clipboard()->mimeData();
+ int isMidi = -1;
+ QByteArray data;
+ if (s->hasFormat("application/muse/part/midi")) {
+ isMidi = 1;
+ data = s->data("application/muse/part/midi");
+ }
+ else if (s->hasFormat("application/muse/part/audio")) {
+ isMidi = 0;
+ data = s->data("application/muse/part/audio");
+ }
+ // exit if unknown format
+ if (isMidi == -1) {
+ printf("paste: unknown format\n");
+ return;
+ }
+
+ // search target track
+ TrackList* tl = song->tracks();
+ Track* track = 0;
+ for (iTrack i = tl->begin(); i != tl->end(); ++i) {
+ Track* t = *i;
+ if ((isMidi == 1 && t->type() == Track::MIDI)
+ || (isMidi == 0 && t->type() == Track::WAVE)) {
+ track = t;
+ break;
+ }
+ }
+ if (track == 0) {
+ printf("no destination track selected\n");
+ return;
+ }
+
+ QDomDocument doc;
+ int line, column;
+ QString err;
+ PartList pl;
+ if (!doc.setContent(data, false, &err, &line, &column)) {
+ QString col, ln, error;
+ col.setNum(column);
+ ln.setNum(line);
+ error = err + "\n at line: " + ln + " col: " + col;
+ printf("error parsing part: %s\n", error.toLatin1().data());
+ return;
+ }
+ int tick = -1;
+ for (QDomNode node = doc.documentElement(); !node.isNull(); node = node.nextSibling()) {
+ QDomElement e = node.toElement();
+ if (e.isNull())
+ continue;
+ if (e.tagName() == "part") {
+ Part* p = new Part(0);
+ p->ref();
+ p->read(node, true);
+ pl.add(p);
+ if (tick == -1 || p->tick() < unsigned(tick))
+ tick = int(p->tick());
+ }
+ else
+ printf("MusE: %s not supported\n", e.tagName().toLatin1().data());
+ }
+
+ unsigned cpos = song->cpos();
+ song->startUndo();
+ for (iPart ip = pl.begin(); ip != pl.end(); ++ip) {
+ Part* part = ip->second;
+ part->setTick(part->tick() - tick + cpos);
+ part->setTrack(track);
+ song->addPart(part);
+ cpos += part->lenTick();
+ }
+ song->endUndo(0);
+ track->partListChanged();
+ }
+
+ else if (cmd == "delete") {
+ TrackList* tl = song->tracks();
+ bool partsMarked = false;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it) {
+ PartList* pl2 = (*it)->parts();
+ for (iPart ip = pl2->begin(); ip != pl2->end(); ++ip) {
+ if (ip->second->selected()) {
+ partsMarked = true;
+ break;
+ }
+ }
+ }
+ if (partsMarked)
+ song->cmdRemoveParts();
+ else
+ audio->msgRemoveTracks();
+ }
+ else if (cmd == "delete_track")
+ audio->msgRemoveTracks();
+ else if (cmd == "sel_all" || cmd == "sel_none" || cmd == "sel_inv"
+ || cmd == "sel_ins_loc" || cmd == "sel_out_loc") {
+ for (iTrack i = tracks->begin(); i != tracks->end(); ++i) {
+ PartList* parts = (*i)->parts();
+ for (iPart p = parts->begin(); p != parts->end(); ++p) {
+ bool f = false;
+ int t1 = p->second->tick();
+ int t2 = t1 + p->second->lenTick();
+ bool inside =
+ ((t1 >= l) && (t1 < r))
+ || ((t2 > l) && (t2 < r))
+ || ((t1 <= l) && (t2 > r));
+ if (cmd == "sel_inv")
+ f = !p->second->selected();
+ else if (cmd == "sel_none")
+ f = false;
+ else if (cmd == "sel_all")
+ f = true;
+ else if (cmd == "sel_ins_loc")
+ f = inside;
+ else if (cmd == "sel_out_loc")
+ f = !inside;
+ p->second->setSelected(f);
+ }
+ (*i)->partListChanged(); // repaints canvaswidget
+ }
+ song->update();
+ }
+ else if (cmd == "select_parts_on_track") {
+ for (iTrack i = tracks->begin(); i != tracks->end(); ++i) {
+ if (!(*i)->selected())
+ continue;
+ PartList* parts = (*i)->parts();
+ for (iPart p = parts->begin(); p != parts->end(); ++p)
+ p->second->setSelected(true);
+ }
+ song->update();
+ }
+
+ else if (cmd == "follow_no")
+ setFollow(FOLLOW_NO);
+ else if (cmd == "follow_jump")
+ setFollow(FOLLOW_JUMP);
+ else if (cmd == "follow_continuous")
+ setFollow(FOLLOW_CONTINUOUS);
+ }
+
+//---------------------------------------------------------
+// clipboardChanged
+//---------------------------------------------------------
+
+void MusE::clipboardChanged()
+ {
+// QString subtype("partlist");
+ const QMimeData* ms = QApplication::clipboard()->mimeData();
+ if (ms == 0)
+ return;
+ bool flag = ms->hasFormat("application/muse/part/midi")
+ || ms->hasFormat("application/muse/part/audio");
+ pasteAction->setEnabled(flag);
+ }
+
+//---------------------------------------------------------
+// selectionChanged
+//---------------------------------------------------------
+
+void MusE::selectionChanged()
+ {
+ int k = 0;
+ TrackList* tl = song->tracks();
+ for (iTrack t = tl->begin(); t != tl->end(); ++t)
+ k += (*t)->selected();
+ cutAction->setEnabled(k == 1);
+ copyAction->setEnabled(k == 1);
+ song->updateSelectedTrack();
+ }
+
+//---------------------------------------------------------
+// transpose
+//---------------------------------------------------------
+
+void MusE::transpose()
+ {
+ Transpose *w = new Transpose();
+ w->show();
+ }
+
+//---------------------------------------------------------
+// modifyGateTime
+//---------------------------------------------------------
+
+void MusE::modifyGateTime()
+ {
+//TODO GateTime* w = new GateTime(this);
+// w->show();
+ }
+
+//---------------------------------------------------------
+// modifyVelocity
+//---------------------------------------------------------
+
+void MusE::modifyVelocity()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// crescendo
+//---------------------------------------------------------
+
+void MusE::crescendo()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// thinOut
+//---------------------------------------------------------
+
+void MusE::thinOut()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// eraseEvent
+//---------------------------------------------------------
+
+void MusE::eraseEvent()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// noteShift
+//---------------------------------------------------------
+
+void MusE::noteShift()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// moveClock
+//---------------------------------------------------------
+
+void MusE::moveClock()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// copyMeasure
+//---------------------------------------------------------
+
+void MusE::copyMeasure()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// eraseMeasure
+//---------------------------------------------------------
+
+void MusE::eraseMeasure()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// deleteMeasure
+//---------------------------------------------------------
+
+void MusE::deleteMeasure()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// createMeasure
+//---------------------------------------------------------
+
+void MusE::createMeasure()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// mixTrack
+//---------------------------------------------------------
+
+void MusE::mixTrack()
+ {
+ printf("not implemented\n");
+ }
+
+//---------------------------------------------------------
+// configAppearance
+//---------------------------------------------------------
+//
+//void MusE::configAppearance()
+// {
+// if (!appearance)
+// appearance = new Appearance(arranger);
+// appearance->resetValues();
+// appearance->show();
+// }
+
+//---------------------------------------------------------
+// preferences
+//---------------------------------------------------------
+
+void MusE::preferences()
+ {
+ if (!preferencesDialog)
+ preferencesDialog = new PreferencesDialog(arranger);
+ preferencesDialog->resetValues();
+ preferencesDialog->show();
+ }
+
+//---------------------------------------------------------
+// configChanged
+// - called whenever configuration has changed
+// - when configuration has changed by user, call with
+// writeFlag=true to save configuration in ~/.MusE
+//---------------------------------------------------------
+
+void MusE::changeConfig(bool writeFlag)
+ {
+ if (writeFlag)
+ writeGlobalConfiguration();
+ updateConfiguration();
+ emit configChanged();
+ }
+
+//---------------------------------------------------------
+// configShortCuts
+//---------------------------------------------------------
+
+void MusE::configShortCuts()
+ {
+ if (!shortcutConfig)
+ shortcutConfig = new ShortcutConfig(this);
+ shortcutConfig->_config_changed = false;
+ if (shortcutConfig->exec())
+ changeConfig(true);
+ }
+
+//---------------------------------------------------------
+// globalCut
+// - remove area between left and right locator
+// - do not touch muted track
+// - cut master track
+//---------------------------------------------------------
+
+void MusE::globalCut()
+ {
+ int lpos = song->lpos();
+ int rpos = song->rpos();
+ if ((lpos - rpos) >= 0)
+ return;
+
+ song->startUndo();
+ MidiTrackList* tracks = song->midis();
+ for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it) {
+ MidiTrack* track = *it;
+ if (track->mute())
+ continue;
+ PartList* pl = track->parts();
+ for (iPart p = pl->begin(); p != pl->end(); ++p) {
+ Part* part = p->second;
+ int t = part->tick();
+ int l = part->lenTick();
+ if (t + l <= lpos)
+ continue;
+ if ((t >= lpos) && ((t+l) <= rpos)) {
+ song->removePart(part);
+ }
+ else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) {
+ // remove part tail
+ int len = lpos - t;
+ Part* nPart = new Part(*part);
+ nPart->setLenTick(len);
+ //
+ // cut Events in nPart
+ EventList* el = nPart->events();
+ iEvent ie = el->lower_bound(t + len);
+ for (; ie != el->end();) {
+ iEvent i = ie;
+ ++ie;
+ audio->msgDeleteEvent(i->second, nPart, false);
+ }
+ song->changePart(part, nPart);
+ }
+ else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) {
+ //----------------------
+ // remove part middle
+ //----------------------
+
+ Part* nPart = new Part(*part);
+ EventList* el = nPart->events();
+ iEvent is = el->lower_bound(lpos);
+ iEvent ie = el->upper_bound(rpos);
+ for (iEvent i = is; i != ie;) {
+ iEvent ii = i;
+ ++i;
+ audio->msgDeleteEvent(ii->second, nPart, false);
+ }
+
+ ie = el->lower_bound(rpos);
+ for (; ie != el->end();) {
+ iEvent i = ie;
+ ++ie;
+ Event event = i->second;
+ Event nEvent = event.clone();
+ nEvent.setTick(nEvent.tick() - (rpos-lpos));
+ audio->msgChangeEvent(event, nEvent, nPart, false);
+ }
+ nPart->setLenTick(l - (rpos-lpos));
+ song->changePart(part, nPart);
+ }
+ else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) {
+ // TODO: remove part head
+ }
+ else if (t >= rpos) {
+ Part* nPart = new Part(*part);
+ int nt = part->tick();
+ nPart->setTick(nt - (rpos -lpos));
+ song->changePart(part, nPart);
+ }
+ }
+ }
+ // TODO: cut tempo track
+ // TODO: process marker
+ song->endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_REMOVED);
+ }
+
+//---------------------------------------------------------
+// globalInsert
+// - insert empty space at left locator position upto
+// right locator
+// - do not touch muted track
+// - insert in master track
+//---------------------------------------------------------
+
+void MusE::globalInsert()
+ {
+ unsigned lpos = song->lpos();
+ unsigned rpos = song->rpos();
+ if (lpos >= rpos)
+ return;
+
+ song->startUndo();
+ MidiTrackList* tracks = song->midis();
+ for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it) {
+ MidiTrack* track = *it;
+ //
+ // process only non muted midi tracks
+ //
+ if (track->mute())
+ continue;
+ PartList* pl = track->parts();
+ for (iPart p = pl->begin(); p != pl->end(); ++p) {
+ Part* part = p->second;
+ unsigned t = part->tick();
+ int l = part->lenTick();
+ if (t + l <= lpos)
+ continue;
+ if (lpos >= t && lpos < (t+l)) {
+ Part* nPart = new Part(*part);
+ nPart->setLenTick(l + (rpos-lpos));
+ EventList* el = nPart->events();
+
+ iEvent i = el->end();
+ while (i != el->begin()) {
+ --i;
+ if (i->first < lpos)
+ break;
+ Event event = i->second;
+ Event nEvent = i->second.clone();
+ nEvent.setTick(nEvent.tick() + (rpos-lpos));
+ audio->msgChangeEvent(event, nEvent, nPart, false);
+ }
+ song->changePart(part, nPart);
+ }
+ else if (t > lpos) {
+ Part* nPart = new Part(*part);
+ nPart->setTick(t + (rpos -lpos));
+ song->changePart(part, nPart);
+ }
+ }
+ }
+ // TODO: process tempo track
+ // TODO: process marker
+ song->endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_REMOVED);
+ }
+
+//---------------------------------------------------------
+// globalSplit
+// - split all parts at the song position pointer
+// - do not touch muted track
+//---------------------------------------------------------
+
+void MusE::globalSplit()
+ {
+ int pos = song->cpos();
+ song->startUndo();
+ TrackList* tracks = song->tracks();
+ for (iTrack it = tracks->begin(); it != tracks->end(); ++it) {
+ Track* track = *it;
+ 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);
+ song->changePart(part, p1);
+ song->addPart(p2);
+ break;
+ }
+ }
+ }
+ song->endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_INSERTED);
+ }
+
+//---------------------------------------------------------
+// copyRange
+// - copy space between left and right locator position
+// to song position pointer
+// - dont process muted tracks
+// - create a new part for every track containing the
+// copied events
+//---------------------------------------------------------
+
+void MusE::copyRange()
+ {
+ QMessageBox::critical(this,
+ tr("MusE: Copy Range"),
+ tr("not implemented")
+ );
+ }
+
+//---------------------------------------------------------
+// cutEvents
+// - make sure that all events in a part end where the
+// part ends
+// - process only marked parts
+//---------------------------------------------------------
+
+void MusE::cutEvents()
+ {
+ QMessageBox::critical(this,
+ tr("MusE: Cut Events"),
+ tr("not implemented")
+ );
+ }
+
+//---------------------------------------------------------
+// checkRegionNotNull
+// return true if (rPos - lPos) <= 0
+//---------------------------------------------------------
+
+bool MusE::checkRegionNotNull()
+ {
+ int start = song->lPos().frame();
+ int end = song->rPos().frame();
+ if (end - start <= 0) {
+ QMessageBox::critical(this,
+ tr("MusE: Bounce"),
+ tr("set left/right marker for bounce range")
+ );
+ return true;
+ }
+ return false;
+ }
+
+//---------------------------------------------------------
+// resetAllRecordFlags
+//---------------------------------------------------------
+
+static void resetAllRecordFlags()
+ {
+ WaveTrackList* wtl = song->waves();
+ for (iWaveTrack i = wtl->begin(); i != wtl->end(); ++i) {
+ if((*i)->recordFlag())
+ song->setRecordFlag(*i, false);
+ }
+ MidiTrackList* mtl = song->midis();
+ for (iMidiTrack i = mtl->begin(); i != mtl->end(); ++i) {
+ if((*i)->recordFlag())
+ song->setRecordFlag(*i, false);
+ }
+ }
+
+//---------------------------------------------------------
+// bounceToTrack
+//---------------------------------------------------------
+
+void MusE::bounceToTrack()
+ {
+ if (checkRegionNotNull())
+ return;
+ // search target track
+ TrackList* tl = song->tracks();
+ WaveTrack* track = 0;
+ for (iTrack it = tl->begin(); it != tl->end(); ++it) {
+ Track* t = *it;
+ if (t->selected()) {
+ if (track) {
+ QMessageBox::critical(this,
+ tr("MusE: Bounce to Track"),
+ tr("more than one target track selected")
+ );
+ return;
+ }
+ if (t->type() != Track::WAVE) {
+ QMessageBox::critical(this,
+ tr("MusE: Bounce to Track"),
+ tr("wrong target track type,\nselect wave track as target")
+ );
+ return;
+ }
+ track = (WaveTrack*)t;
+ }
+ }
+ if (track == 0) {
+ QMessageBox::critical(this,
+ tr("MusE: Bounce to Track"),
+ tr("no target track selected")
+ );
+ return;
+ }
+ song->bounceTrack = track;
+ song->setRecord(true);
+ resetAllRecordFlags();
+ song->setRecordFlag(track, true);
+ audio->msgBounce();
+ }
+
+//---------------------------------------------------------
+// bounceToFile
+//---------------------------------------------------------
+
+void MusE::bounceToFile()
+ {
+ if (checkRegionNotNull())
+ return;
+ SndFile* sf = getSndFile(0, this);
+ if (sf == 0)
+ return;
+ OutputList* ol = song->outputs();
+ AudioOutput* ao = ol->front();
+ if (ao == 0) {
+ QMessageBox::critical(this,
+ tr("MusE: Bounce to File"),
+ tr("no output track found")
+ );
+ return;
+ }
+ ao->setRecFile(sf);
+ song->setRecord(true);
+ resetAllRecordFlags();
+ song->setRecordFlag(ao, true);
+ audio->msgBounce();
+ }
+
+//---------------------------------------------------------
+// startEditInstrument
+//---------------------------------------------------------
+
+void MusE::startEditInstrument()
+ {
+ if (editInstrument == 0)
+ editInstrument = new EditInstrument(this);
+ editInstrument->show();
+ }
+
+//---------------------------------------------------------
+// updateConfiguration
+// called whenever the configuration has changed
+//---------------------------------------------------------
+
+void MusE::updateConfiguration()
+ {
+ }
+
+//---------------------------------------------------------
+// showBigtime
+//---------------------------------------------------------
+
+void MusE::showBigtime(bool on)
+ {
+ if (on && bigtime == 0) {
+ bigtime = new BigTime(0);
+ bigtime->setPos(0, song->cpos(), false);
+ connect(song, SIGNAL(posChanged(int,const AL::Pos&, bool)), bigtime, SLOT(setPos(int,const AL::Pos&, bool)));
+ connect(muse, SIGNAL(configChanged()), bigtime, SLOT(configChanged()));
+ connect(bigtime, SIGNAL(closed()), SLOT(bigtimeClosed()));
+ bigtime->resize(config.geometryBigTime.size());
+ bigtime->move(config.geometryBigTime.topLeft());
+ }
+ if (bigtime)
+ bigtime->setShown(on);
+ bt_id->setChecked(on);
+ }
+
+//---------------------------------------------------------
+// showMarker
+//---------------------------------------------------------
+
+void MusE::showMarker(bool on)
+ {
+ if (on && markerView == 0) {
+ markerView = new MarkerView;
+ connect(markerView, SIGNAL(closed()), SLOT(markerClosed()));
+ }
+ if (markerView)
+ markerView->setShown(on);
+ mk_id->setChecked(on);
+ }
+
+//---------------------------------------------------------
+// markerClosed
+//---------------------------------------------------------
+
+void MusE::markerClosed()
+ {
+ mk_id->setChecked(false);
+ markerView = 0;
+ }
+
+//---------------------------------------------------------
+// bigtimeClosed
+//---------------------------------------------------------
+
+void MusE::bigtimeClosed()
+ {
+ bt_id->setChecked(false);
+ }
+
+//---------------------------------------------------------
+// transportClosed
+//---------------------------------------------------------
+
+void MusE::transportClosed()
+ {
+ tr_id->setChecked(false);
+ }
+
+//---------------------------------------------------------
+// showMixer1
+//---------------------------------------------------------
+
+void MusE::showMixer1(bool on)
+ {
+ if (on && mixer1 == 0) {
+ mixer1 = new Mixer(this, &(config.mixer1));
+ connect(mixer1, SIGNAL(closed()), SLOT(mixer1Closed()));
+ mixer1->resize(config.mixer1.geometry.size());
+ mixer1->move(config.mixer1.geometry.topLeft());
+ }
+ if (mixer1)
+ mixer1->setShown(on);
+ aid1a->setChecked(on);
+ }
+
+//---------------------------------------------------------
+// showMixer2
+//---------------------------------------------------------
+
+void MusE::showMixer2(bool on)
+ {
+ if (on && mixer2 == 0) {
+ mixer2 = new Mixer(this, &(config.mixer2));
+ connect(mixer2, SIGNAL(closed()), SLOT(mixer2Closed()));
+ mixer2->resize(config.mixer2.geometry.size());
+ mixer2->move(config.mixer2.geometry.topLeft());
+ }
+ if (mixer2)
+ mixer2->setShown(on);
+ aid1b->setChecked(on);
+ }
+
+//---------------------------------------------------------
+// mixer1Closed
+//---------------------------------------------------------
+
+void MusE::mixer1Closed()
+ {
+ aid1a->setChecked(false);
+ }
+
+//---------------------------------------------------------
+// mixer2Closed
+//---------------------------------------------------------
+
+void MusE::mixer2Closed()
+ {
+ aid1b->setChecked(false);
+ }
+
+//---------------------------------------------------------
+// transportWindow
+//---------------------------------------------------------
+
+QWidget* MusE::transportWindow()
+ {
+ return transport;
+ }
+
+//---------------------------------------------------------
+// bigtimeWindow
+//---------------------------------------------------------
+
+QWidget* MusE::bigtimeWindow()
+ {
+ return bigtime;
+ }
+
+//---------------------------------------------------------
+// mixer1Window
+//---------------------------------------------------------
+
+QWidget* MusE::mixer1Window()
+ {
+ return mixer1;
+ }
+
+//---------------------------------------------------------
+// mixer2Window
+//---------------------------------------------------------
+
+QWidget* MusE::mixer2Window()
+ {
+ return mixer2;
+ }
+
+//---------------------------------------------------------
+// focusInEvent
+//---------------------------------------------------------
+
+void MusE::focusInEvent(QFocusEvent* ev)
+ {
+ if (mixer1)
+ mixer1->raise();
+ if (mixer2)
+ mixer2->raise();
+ raise();
+ QMainWindow::focusInEvent(ev);
+ }
+
+//---------------------------------------------------------
+// setTool
+//---------------------------------------------------------
+
+void MusE::setTool(int tool)
+ {
+ tools1->set(tool);
+ arranger->setTool(tool);
+ }
+
+void MusE::setTool(const QString& s)
+ {
+ int id = 0;
+ for (int i = 0; i < TOOLS; ++i) {
+ if (toolList[i] == s) {
+ id = i;
+ break;
+ }
+ }
+ id = 1 << id;
+ tools1->set(id);
+ arranger->setTool(id);
+ }
+
+//---------------------------------------------------------
+// globalPitchChanged
+//---------------------------------------------------------
+
+void MusE::globalPitchChanged(int val)
+ {
+ song->setGlobalPitchShift(val);
+ }
+
+//---------------------------------------------------------
+// globalTempoChanged
+//---------------------------------------------------------
+
+void MusE::globalTempoChanged(int val)
+ {
+ audio->msgSetGlobalTempo(val);
+ song->update(SC_TEMPO);
+ }
+
+//---------------------------------------------------------
+// setTempo50
+//---------------------------------------------------------
+
+void MusE::setTempo50()
+ {
+ setGlobalTempo(50);
+ }
+
+//---------------------------------------------------------
+// setTempo100
+//---------------------------------------------------------
+
+void MusE::setTempo100()
+ {
+ setGlobalTempo(100);
+ }
+
+//---------------------------------------------------------
+// setTempo200
+//---------------------------------------------------------
+
+void MusE::setTempo200()
+ {
+ setGlobalTempo(200);
+ }
+
+//---------------------------------------------------------
+// setGlobalTempo
+//---------------------------------------------------------
+
+void MusE::setGlobalTempo(int val)
+ {
+ globalTempoSpinBox->setValue(val);
+ }
+
+//---------------------------------------------------------
+// main
+//---------------------------------------------------------
+
+int main(int argc, char* argv[])
+ {
+ char c;
+ QString opts("mvdDiosP:p");
+
+#ifdef VST_SUPPORT
+ opts += "V";
+#endif
+#ifdef DSSI_SUPPORT
+ opts += "I";
+#endif
+ while ((c = getopt(argc, argv, opts.toLatin1().data())) != EOF) {
+ switch (c) {
+ case 'v': printVersion(argv[0]); return 0;
+ case 'd':
+ debugMode = true;
+ realTimePriority = false;
+ break;
+ case 'm': midiOnly = true; break;
+ case 'D': debugMsg = true; break;
+ case 'i': midiInputTrace = true; break;
+ case 'o': midiOutputTrace = true; break;
+ case 's': debugSync = true; break;
+ case 'p': loadPlugins = false; break;
+ case 'V': loadVST = false; break;
+ case 'I': loadDSSI = false; break;
+ default: usage(argv[0], "bad argument"); return -1;
+ }
+ }
+ AL::debugMsg = debugMsg;
+ if (midiOnly) {
+ loadDSSI = false;
+ loadPlugins = false;
+ loadVST = false;
+ }
+ AL::initDsp();
+
+ museUser = QString(getenv("MUSEHOME"));
+ if (museUser.isEmpty())
+ museUser = QDir::homePath();
+ QString museGlobal;
+ const char* p = getenv("MUSE");
+ museGlobal = p ? p : INSTPREFIX;
+
+ museGlobalLib = museGlobal + "/lib/" INSTALL_NAME;
+ museGlobalShare = museGlobal + "/share/" INSTALL_NAME;
+ configName = museUser + QString("/." INSTALL_NAME);
+ lastMidiPath = museUser + "/" + ::config.importMidiPath;
+ lastWavePath = museUser + "/" + ::config.importWavePath;
+
+ srand(time(0)); // initialize random number generator
+ initMidiController();
+ initMidiInstruments();
+ MuseApplication app(argc, argv);
+ QCoreApplication::setOrganizationName("MusE");
+ QCoreApplication::setOrganizationDomain("muse.org");
+ QCoreApplication::setApplicationName("MusE");
+
+ gmDrumMap.initGm(); // init default drum map
+ readConfiguration();
+
+ // this style is used for scrollbars in mixer plugin racks:
+ smallStyle = new QWindowsStyle();
+
+ // SHOW MUSE SPLASH SCREEN
+ if (config.showSplashScreen) {
+ QPixmap splsh(":/xpm/splash.png");
+
+ if (!splsh.isNull()) {
+ QSplashScreen* muse_splash = new QSplashScreen(splsh,
+ Qt::WindowStaysOnTopHint);
+ muse_splash->show();
+ QTimer* stimer = new QTimer(0);
+ muse_splash->connect(stimer, SIGNAL(timeout()), muse_splash, SLOT(close()));
+ stimer->start(6000);
+ }
+ }
+
+ QFile cf(config.styleSheetFile);
+ if (cf.open(QIODevice::ReadOnly)) {
+ QByteArray ss = cf.readAll();
+ QString sheet(QString::fromUtf8(ss.data()));
+ app.setStyleSheet(sheet);
+ cf.close();
+ }
+ else
+ printf("loading style sheet <%s> failed\n", qPrintable(config.styleSheetFile));
+
+ bool useJACK = !(debugMode || midiOnly);
+ if (useJACK) {
+ if (initJackAudio()) {
+ if (!debugMode)
+ {
+ QMessageBox::critical(NULL, "MusE fatal error",
+ "MusE failed to find a Jack audio server.\n"
+ "Check that Jack was started.\n"
+ "If Jack was started check that it was\n"
+ "started as the same user as MusE.");
+ // fatalError("cannot start JACK");
+ }
+ else
+ {
+ fprintf(stderr, "fatal error: no JACK audio server found\n");
+ fprintf(stderr, "no audio functions available\n");
+ fprintf(stderr, "*** experimental mode -- no play possible ***\n");
+ }
+ useJACK = false;
+ debugMode = true;
+ }
+ }
+ if (!useJACK)
+ initDummyAudio();
+
+ argc -= optind;
+ ++argc;
+
+ if (debugMsg) {
+ printf("global lib: <%s>\n", museGlobalLib.toLatin1().data());
+ printf("global share: <%s>\n", museGlobalShare.toLatin1().data());
+ printf("muse home: <%s>\n", museUser.toLatin1().data());
+ printf("project dir: <%s>\n", config.projectPath.toLatin1().data());
+ printf("config file: <%s>\n", configName.toLatin1().data());
+ }
+
+ static QTranslator translator;
+ QFile f(":/muse.qm");
+ if (f.exists()) {
+ if (debugMsg)
+ printf("locale file found\n");
+ if (translator.load(":/muse.qm")) {
+ if (debugMsg)
+ printf("locale file loaded\n");
+ }
+ qApp->installTranslator(&translator);
+ }
+ else {
+ if (debugMsg) {
+ printf("locale file not found for locale <%s>\n",
+ QLocale::system().name().toLatin1().data());
+ }
+ }
+
+ if (loadPlugins) {
+ initPlugins();
+ initMidiPlugins();
+ }
+ if (loadVST)
+ initVST();
+
+ if (loadDSSI)
+ initDSSI();
+
+ initIcons();
+ if (!midiOnly)
+ initMetronome();
+
+ if (debugMsg) {
+ QStringList list = app.libraryPaths();
+ QStringList::Iterator it = list.begin();
+ printf("QtLibraryPath:\n");
+ while(it != list.end()) {
+ printf(" <%s>\n", (*it).toLatin1().data());
+ ++it;
+ }
+ }
+
+ song = new Song();
+ muse = new MusE();
+ muse->readSettings();
+ app.setMuse(muse);
+
+ //---------------------------------------------------
+ // load project
+ //---------------------------------------------------
+
+ // check for project directory:
+
+ QDir pd(QDir::homePath() + "/" + config.projectPath);
+ if (!pd.exists()) {
+ // ask user to create a new project directory
+ QString title(QT_TR_NOOP("MusE: create project directory"));
+
+ QString s;
+ s = "The MusE project directory\n%1\ndoes not exists";
+ s = s.arg(pd.path());
+
+ int rv = QMessageBox::question(0,
+ title,
+ s,
+ "Create",
+ "Abort",
+ QString(),
+ 0, 1);
+ if (rv == 1)
+ exit(0);
+ if (!pd.mkpath(pd.path())) {
+ // TODO: tell user why this has happened
+ QMessageBox::critical(0,
+ title,
+ "Creating project directory failed");
+ exit(-1);
+ }
+ }
+
+ // check for template directory:
+
+ pd.setPath(QDir::homePath() + "/" + config.templatePath);
+ if (!pd.exists()) {
+ // ask user to create a new template directory
+ QString title(QT_TR_NOOP("MusE: create template directory"));
+
+ QString s;
+ s = "The MusE template directory\n%1\ndoes not exists";
+ s = s.arg(pd.path());
+
+ int rv = QMessageBox::question(0,
+ title,
+ s,
+ "Create",
+ "Abort",
+ QString(),
+ 0, 1);
+ if (rv == 0) {
+ if (!pd.mkpath(pd.path())) {
+ // TODO: tell user why this has happened
+ QMessageBox::critical(0,
+ title,
+ "Creating template directory failed");
+ }
+ }
+ }
+
+ // check for instruments directory:
+
+ pd.setPath(QDir::homePath() + "/" + config.instrumentPath);
+ if (!pd.exists()) {
+ // ask user to create a new instruments directory
+ QString title(QT_TR_NOOP("MusE: create instruments directory"));
+
+ QString s;
+ s = "The MusE instruments directory\n%1\ndoes not exists";
+ s = s.arg(pd.path());
+
+ int rv = QMessageBox::question(0,
+ title,
+ s,
+ "Create",
+ "Abort",
+ QString(),
+ 0, 1);
+ if (rv == 0) {
+ if (!pd.mkpath(pd.path())) {
+ // TODO: tell user why this has happened
+ QMessageBox::critical(0,
+ title,
+ "Creating instruments directory failed");
+ }
+ }
+ }
+
+ QString path; // project path relativ to config.projectPath
+ if (argc >= 2)
+ path = argv[optind]; // start with first name on command line
+ else if (config.startMode == START_LAST_PROJECT) {
+ if (projectList[0])
+ path = *projectList[0];
+ }
+ else if (config.startMode == START_START_PROJECT)
+ path = config.startProject;
+
+ QString name = path.split("/").last();
+ if (!path.isEmpty()) {
+ QFile f(QDir::homePath() +"/"+config.projectPath+"/"+path+"/"+name+".med");
+ if (!f.exists()) {
+ QString s(QT_TR_NOOP("Cannot find project <%1>"));
+ QString header(QT_TR_NOOP("MusE: load Project"));
+ QMessageBox::critical(0, header, s.arg(f.fileName()));
+ path = "";
+ }
+ }
+ if (path.isEmpty()) {
+ //
+ // ask user for a project
+ //
+ for (;;) {
+ ProjectDialog projectDialog;
+ projectDialog.setProjectName(name);
+ int rv = projectDialog.exec();
+ if (rv == 1) {
+ path = projectDialog.projectPath();
+ if (!path.isEmpty())
+ break;
+ }
+ // the user did not select/create a project
+ rv = QMessageBox::question(0,
+ "MusE: create/select project",
+ "before MusE starts, you must select a project\n"
+ "or create a new one",
+ "Go Back",
+ "Abort",
+ QString(),
+ 0, 1);
+ if (rv == 1)
+ exit(0);
+ }
+ }
+
+ muse->loadProject(path);
+ muse->changeConfig(false);
+ if (!debugMode) {
+ if (mlockall(MCL_CURRENT | MCL_FUTURE))
+ perror("WARNING: Cannot lock memory:");
+ }
+ muse->show();
+ muse->seqStart();
+ int n = app.exec();
+ if (n)
+ fprintf(stderr, "app end %d\n", n);
+ return n;
+ }
+
+//---------------------------------------------------------
+// beat
+// heart beat
+//---------------------------------------------------------
+
+void MusE::beat()
+ {
+ song->beat();
+ if (mixer1 && mixer1->isVisible())
+ mixer1->heartBeat();
+ if (mixer2 && mixer2->isVisible())
+ mixer2->heartBeat();
+ if (arranger && arranger->getStrip() && arranger->getStrip()->isVisible())
+ arranger->getStrip()->heartBeat();
+ }
+
+//---------------------------------------------------------
+// writeSettings
+//---------------------------------------------------------
+
+void MusE::writeSettings()
+ {
+ QSettings settings;
+ settings.beginGroup("MainWindow");
+ settings.setValue("size", size());
+ settings.setValue("pos", pos());
+ settings.endGroup();
+ }
+
+//---------------------------------------------------------
+// readSettings
+//---------------------------------------------------------
+
+void MusE::readSettings()
+ {
+ QSettings settings;
+ settings.beginGroup("MainWindow");
+ resize(settings.value("size", QSize(950, 500)).toSize());
+ move(settings.value("pos", QPoint(10, 10)).toPoint());
+ settings.endGroup();
+ }
+
+