//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: app.cpp,v 1.113.2.6 2005/01/04 22:29:40 spamatica Exp $
//
//  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
//=========================================================

#include "config.h"

#include <assert.h>
#include <getopt.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <stdarg.h>

#include <qbuttongroup.h>
#include <qpopupmenu.h>
#include <qmessagebox.h>
#include <qclipboard.h>
#include <qsocketnotifier.h>
#include <qtextcodec.h>
#include <qstylefactory.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qtimer.h>
#include <qstyle.h>
#include <qsplashscreen.h>

#include "app.h"
#include "transport.h"
#include "bigtime.h"
#include "arranger.h"
#include "pianoroll.h"
#include "xml.h"
#include "midi.h"
#include "conf.h"
#include "listedit.h"
#include "master/masteredit.h"
#include "master/lmaster.h"
#include "drumedit.h"
#include "ttoolbar.h"
#include "amixer.h"
#include "cliplist/cliplist.h"
#include "midiport.h"
#include "audiodev.h"
#include "mididev.h"
#include "waveedit.h"
#include "icons.h"
#include "minstrument.h"
#include "mixdowndialog.h"
#include "midictrl.h"
#include "filedialog.h"
#include "plugin.h"
#include "marker/markerview.h"
#include "transpose.h"
#include "appearance.h"
#include "gatetime.h"
#include "metronome.h"
#include "debug.h"
#include "event.h"
#include "audio.h"
#include "midiseq.h"
#include "audioprefetch.h"
#include "wave.h"
#include "shortcutconfig.h"
#include "gconfig.h"
#include "driver/jackaudio.h"
#include "track.h"
#include "ticksynth.h"

#include <alsa/asoundlib.h>

static pthread_t watchdogThread;

static const char* fileOpenText =
      QT_TR_NOOP("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_TR_NOOP("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_TR_NOOP("Create New Song");

static const char* infoLoopButton     = QT_TR_NOOP("loop between left mark and right mark");
static const char* infoPunchinButton  = QT_TR_NOOP("record starts at left mark");
static const char* infoPunchoutButton = QT_TR_NOOP("record stops at right mark");
static const char* infoStartButton    = QT_TR_NOOP("rewind to start position");
static const char* infoRewindButton   = QT_TR_NOOP("rewind current position");
static const char* infoForwardButton  = QT_TR_NOOP("move current position");
static const char* infoStopButton     = QT_TR_NOOP("stop sequencer");
static const char* infoPlayButton     = QT_TR_NOOP("start sequencer play");
static const char* infoRecordButton   = QT_TR_NOOP("to record press record and then play");
static const char* infoPanicButton    = QT_TR_NOOP("send note off to all midi channels");

#define PROJECT_LIST_LEN  6
static QString* projectList[PROJECT_LIST_LEN];

extern void initIcons();
extern void initMidiSynth();
extern bool initDummyAudio();
extern void initVST();

#ifdef HAVE_LADCCA
#include <ladcca/ladcca.h>
cca_client_t * cca_client;
extern snd_seq_t * alsaSeq;
#endif /* HAVE_LADCCA */

int watchAudio, watchAudioPrefetch, watchMidi;
pthread_t splashThread;

//---------------------------------------------------------
//   getCapabilities
//---------------------------------------------------------

static void getCapabilities()
      {
#ifdef RTCAP
#ifdef __linux__
      const char* napp = getenv("GIVERTCAP");
      if (napp == 0)
            napp = "givertcap";
      int pid = fork();
      if (pid == 0) {
            if (execlp(napp, napp, 0) == -1)
                  perror("exec givertcap failed");
            }
      else if (pid == -1) {
            perror("fork givertcap failed");
            }
      else {
            waitpid(pid, 0, 0);
            }
#endif // __linux__
#endif
      }

//---------------------------------------------------------
//   watchdog thread
//---------------------------------------------------------

static void* watchdog(void*)
      {
      doSetuid();
      
      struct sched_param rt_param;
      memset(&rt_param, 0, sizeof(rt_param));
      rt_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
      int rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
      if (rv != 0)
            perror("3set realtime scheduler");

      int policy;
      if (pthread_getschedparam(pthread_self(), &policy, &rt_param)!= 0) {
            printf("Cannot get current client scheduler: %s\n", strerror(errno));
            }
      if (policy != SCHED_FIFO)
            printf("watchdog process %d _NOT_ running SCHED_FIFO\n", getpid());
      else if (debugMsg)
            printf("watchdog set to SCHED_FIFO priority %d\n",
               sched_get_priority_max(SCHED_FIFO));
      
      undoSetuid();
      int fatal = 0;
      for (;;) {
            watchAudio = 0;
            watchMidi = 0;

            sleep(3);

            bool timeout = false;
            if (midiSeqRunning && watchMidi == 0)
            {
                  printf("midiSeqRunning = %i watchMidi %i\n", midiSeqRunning, watchMidi);
                  timeout = true;
            }
            if (watchAudio == 0)
                  timeout = true;
            if (watchAudio > 500000)
                  timeout = true;
            if (timeout)
                  ++fatal;
            else
                  fatal = 0;
            if (fatal >= 3) {
                  printf("WatchDog: fatal error, realtime task timeout\n");
                  printf("   (%d,%d-%d) - stopping all services\n",
                     watchMidi, watchAudio, fatal);
                  break;
                  }
//            printf("wd %d %d %d\n", watchMidi, watchAudio, fatal);
            }
      audio->stop(true);
      audioPrefetch->stop(true);
      printf("watchdog exit\n");
      exit(-1);
      }

//---------------------------------------------------------
//   seqStart
//---------------------------------------------------------

void MusE::seqStart()
      {
      
      if (audio->isRunning()) {
            printf("seqStart(): already running\n");
            return;
            }
      if (realTimeScheduling) {
            //
            //  create watchdog thread with max priority
            //
            doSetuid();
            struct sched_param rt_param;
            memset(&rt_param, 0, sizeof(rt_param));
            rt_param.sched_priority = realTimePriority +1;//sched_get_priority_max(SCHED_FIFO);

            pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
            pthread_attr_init(attributes);

//             if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) {
//                   printf("MusE: cannot set FIFO scheduling class for RT thread\n");
//                   }
//             if (pthread_attr_setschedparam (attributes, &rt_param)) {
//                   // printf("Cannot set scheduling priority for RT thread (%s)\n", strerror(errno));
//                   }
//             if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) {
//                   printf("MusE: Cannot set scheduling scope for RT thread\n");
//                   }
            if (pthread_create(&watchdogThread, attributes, ::watchdog, 0))
                  perror("MusE: creating watchdog thread failed:");
            pthread_attr_destroy(attributes);
            undoSetuid();
            }
      audioPrefetch->start();
      midiSeqRunning = !midiSeq->start();
      audio->start();
      
      }

//---------------------------------------------------------
//   stop
//---------------------------------------------------------

void MusE::seqStop()
      {
      song->setStop(true);
      song->setStopPlay(false);
      midiSeq->stop(true);
      midiSeqRunning = false;
      audio->stop(true);
      audioPrefetch->stop(true);
      if (realTimeScheduling && watchdogThread)
            pthread_cancel(watchdogThread);
      }

extern bool initJackAudio();
extern void exitJackAudio();

//---------------------------------------------------------
//   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(QPopupMenu* addTrack)
      {
      addTrack->insertItem(QIconSet(*addtrack_addmiditrackIcon),
         QT_TR_NOOP("Add Midi Track"), Track::MIDI);
      addTrack->insertItem(QIconSet(*addtrack_drumtrackIcon),
         QT_TR_NOOP("Add Drum Track"), Track::DRUM);
      addTrack->insertItem(QIconSet(*addtrack_wavetrackIcon),
         QT_TR_NOOP("Add Wave Track"), Track::WAVE);
      addTrack->insertItem(QIconSet(*addtrack_audiooutputIcon),
         QT_TR_NOOP("Add Audio Output"), Track::AUDIO_OUTPUT);
      addTrack->insertItem(QIconSet(*addtrack_audiogroupIcon),
         QT_TR_NOOP("Add Audio Group"), Track::AUDIO_GROUP);
      addTrack->insertItem(QIconSet(*addtrack_audioinputIcon),
         QT_TR_NOOP("Add Audio Input"), Track::AUDIO_INPUT);
      addTrack->insertItem(QIconSet(*addtrack_auxsendIcon),
         QT_TR_NOOP("Add Aux Send"), Track::AUDIO_AUX);
      addTrack->connect(addTrack, SIGNAL(activated(int)), song, SLOT(addTrack(int)));
      }

//---------------------------------------------------------
//   MusE
//---------------------------------------------------------

MusE::MusE(int argc, char** argv) : QMainWindow(0, "mainwindow")
      {
      setFocusPolicy(WheelFocus);
      muse                  = this;    // hack
      clipListEdit          = 0;
      midiSyncConfig        = 0;
      midiRemoteConfig      = 0;
      midiPortConfig        = 0;
      metronomeConfig       = 0;
      audioConfig           = 0;
      midiFileConfig        = 0;
      midiFilterConfig      = 0;
      midiInputTransform    = 0;
      midiRhythmGenerator   = 0;
      globalSettingsConfig  = 0;
      markerView            = 0;
      softSynthesizerConfig = 0;
      midiTransformerDialog = 0;
      shortcutConfig        = 0;
      appearance            = 0;
      audioMixer            = 0;
      watchdogThread        = 0;

      appName               = QString("MusE");

      song           = new Song("song");
      song->blockSignals(true);
      heartBeatTimer = new QTimer(this, "timer");
      connect(heartBeatTimer, SIGNAL(timeout()), song, SLOT(beat()));

      //---------------------------------------------------
      //    undo/redo
      //---------------------------------------------------

      undoRedo = new QActionGroup(this, tr("UndoRedo"), false);
      undoAction = new QAction(tr("undo"), QIconSet(*undoIconS, *undoIcon), tr("Und&o"),
        CTRL+Key_Z, undoRedo, "undo");
      redoAction = new QAction(tr("redo"), QIconSet(*redoIconS, *redoIcon), tr("Re&do"),
        CTRL+Key_Y, undoRedo, "redo");
      undoAction->setWhatsThis(tr("undo last change to song"));
      redoAction->setWhatsThis(tr("redo last undo"));
      undoAction->setEnabled(false);
      redoAction->setEnabled(false);
      connect(redoAction, SIGNAL(activated()), song, SLOT(redo()));
      connect(undoAction, SIGNAL(activated()), song, SLOT(undo()));

      //---------------------------------------------------
      //    Transport
      //---------------------------------------------------

      transportAction = new QActionGroup(this, tr("Transport"), false);

      loopAction = new QAction(tr("loop"), QIconSet(*loop1Icon),
         tr("Loop"), 0, transportAction, "loop", true);
      loopAction->setWhatsThis(tr(infoLoopButton));
      connect(loopAction, SIGNAL(toggled(bool)), song, SLOT(setLoop(bool)));

      punchinAction = new QAction(tr("punchin"), QIconSet(*punchin1Icon),
         tr("Punchin"), 0, transportAction, "Punchin", true);
      punchinAction->setWhatsThis(tr(infoPunchinButton));
      connect(punchinAction, SIGNAL(toggled(bool)), song, SLOT(setPunchin(bool)));

      punchoutAction = new QAction(tr("punchout"), QIconSet(*punchout1Icon),
         tr("Punchout"), 0, transportAction, "punchout", true);
      punchoutAction->setWhatsThis(tr(infoPunchoutButton));
      connect(punchoutAction, SIGNAL(toggled(bool)), song, SLOT(setPunchout(bool)));

      transportAction->addSeparator();

      startAction = new QAction(tr("start"), QIconSet(*startIcon),
         tr("Start"), 0, transportAction, "start");
      startAction->setWhatsThis(tr(infoStartButton));
      connect(startAction, SIGNAL(activated()), song, SLOT(rewindStart()));

      rewindAction = new QAction(tr("rewind"), QIconSet(*frewindIcon),
         tr("Rewind"), 0, transportAction, "rewind");
      rewindAction->setWhatsThis(tr(infoRewindButton));
      connect(rewindAction, SIGNAL(activated()), song, SLOT(rewind()));

      forwardAction = new QAction(tr("forward"), QIconSet(*fforwardIcon),
         tr("Forward"), 0, transportAction, "forward");
      forwardAction->setWhatsThis(tr(infoForwardButton));
      connect(forwardAction, SIGNAL(activated()), song, SLOT(forward()));

      stopAction = new QAction(tr("stop"), QIconSet(*stopIcon),
         tr("Stop"), 0, transportAction, "stop", true);
      stopAction->setWhatsThis(tr(infoStopButton));
      stopAction->setOn(true);
      connect(stopAction, SIGNAL(toggled(bool)), song, SLOT(setStop(bool)));

      playAction = new QAction(tr("play"),  QIconSet(*playIcon),
         tr("Play"), 0, transportAction, "play", true);
      playAction->setWhatsThis(tr(infoPlayButton));
      playAction->setOn(false);
      connect(playAction, SIGNAL(toggled(bool)), song, SLOT(setPlay(bool)));

      recordAction = new QAction(tr("record"),  QIconSet(*recordIcon),
         tr("Record"), 0, transportAction, "record", true);
      recordAction->setWhatsThis(tr(infoRecordButton));
      connect(recordAction, SIGNAL(toggled(bool)), song, SLOT(setRecord(bool)));

      panicAction = new QAction(tr("panic"),  QIconSet(*panicIcon),
         tr("Panic"), 0, 0, "panic", false);
      panicAction->setWhatsThis(tr(infoPanicButton));
      connect(panicAction, SIGNAL(activated()), song, SLOT(panic()));

      initMidiInstruments();
      initMidiPorts();
      ::initMidiDevices();

      //----Actions

      fileNewAction = new QAction(tr("new"),
        QIconSet(*filenewIconS, *filenewIcon), tr("&New"), 0, this, "new");
      fileNewAction->setToolTip(tr(fileNewText));
      fileNewAction->setWhatsThis(tr(fileNewText));

      fileOpenAction = new QAction(tr("open"),
        QIconSet(*openIconS, *openIcon), tr("&Open"), 0, this, "open");
      fileOpenAction->setToolTip(tr(fileOpenText));
      fileOpenAction->setWhatsThis(tr(fileOpenText));

      fileSaveAction = new QAction(tr("save"),
        QIconSet(*saveIconS, *saveIcon), tr("&Save"), 0, this, "save");
      fileSaveAction->setToolTip(tr(fileSaveText));
      fileSaveAction->setWhatsThis(tr(fileSaveText));

      pianoAction = new QAction(tr("pianoroll"),
        *pianoIconSet, tr("Pianoroll"), 0, this, "pianoroll");
      connect(pianoAction, SIGNAL(activated()), SLOT(startPianoroll()));

      markerAction = new QAction(tr("marker"), QIconSet(*view_markerIcon), tr("Marker"),
        0, this, "marker");
      connect(markerAction, SIGNAL(activated()), SLOT(startMarkerView()));

      connect(fileNewAction,  SIGNAL(activated()), SLOT(loadTemplate()));
      connect(fileOpenAction, SIGNAL(activated()), SLOT(loadProject()));
      connect(fileSaveAction, SIGNAL(activated()), SLOT(save()));

      //--------------------------------------------------
      //    Toolbar
      //--------------------------------------------------

      tools = new QToolBar(tr("File Buttons"), this);
      fileNewAction->addTo(tools);
      fileOpenAction->addTo(tools);
      fileSaveAction->addTo(tools);

      //
      //    Whats This
      //
      QWhatsThis::whatsThisButton(tools);

      tools->addSeparator();
      undoRedo->addTo(tools);

      tools1 = new EditToolBar(this, arrangerTools);

      QToolBar* transportToolbar = new QToolBar(this);
      transportAction->addTo(transportToolbar);

      QToolBar* panicToolbar = new QToolBar(this);
      panicAction->addTo(panicToolbar);

      if (realTimePriority < sched_get_priority_min(SCHED_FIFO))
            realTimePriority = sched_get_priority_min(SCHED_FIFO);
      else if (realTimePriority > sched_get_priority_max(SCHED_FIFO))
            realTimePriority = sched_get_priority_max(SCHED_FIFO);

      midiSeq       = new MidiSeq(realTimeScheduling ? realTimePriority : 0, "Midi");
      audio         = new Audio();
      audioPrefetch = new AudioPrefetch(0, "Disc");

      //---------------------------------------------------
      //    Popups
      //---------------------------------------------------
      //-------------------------------------------------------------
      //    popup File
      //-------------------------------------------------------------

      menu_file = new QPopupMenu(this);
      menuBar()->insertItem(tr("&File"), menu_file);
      fileNewAction->addTo(menu_file);
      fileOpenAction->addTo(menu_file);
      openRecent = new QPopupMenu(this);
      connect(openRecent, SIGNAL(aboutToShow()), this, SLOT(openRecentMenu()));
      connect(openRecent, SIGNAL(activated(int)), this, SLOT(selectProject(int)));
      menu_ids[CMD_OPEN_RECENT] = menu_file->insertItem(tr("Open &Recent"), openRecent, 0);
      menu_file->insertSeparator();
      fileSaveAction->addTo(menu_file);
      menu_ids[CMD_SAVE_AS] = menu_file->insertItem(tr("Save &As"), this, SLOT(saveAs()), 0, -2);
      menu_file->insertSeparator();
      menu_ids[CMD_IMPORT_MIDI] = menu_file->insertItem(*openIconS, tr("Import Midifile"), this, SLOT(importMidi()), 0, -2);
      menu_ids[CMD_EXPORT_MIDI] = menu_file->insertItem(*saveIconS, tr("Export Midifile"), this, SLOT(exportMidi()), 0, -2);
      menu_file->insertSeparator();
      menu_ids[CMD_IMPORT_AUDIO] = menu_file->insertItem(*openIconS, tr("Import Wave File"), this, SLOT(importWave()), 0, -2);
      menu_file->insertSeparator();
      menu_ids[CMD_QUIT] = menu_file->insertItem(*exitIconS, tr("&Quit"), this, SLOT(quitDoc()), 0, -2);
      menu_file->insertSeparator();

      //-------------------------------------------------------------
      //    popup Edit
      //-------------------------------------------------------------

      menuEdit = new QPopupMenu(this);
      undoRedo->addTo(menuEdit);
      menuEdit->insertSeparator();
      menuBar()->insertItem(tr("&Edit"), menuEdit);

      menuEdit->insertItem(*editcutIconSet, tr("C&ut"),   CMD_CUT);
      menuEdit->setAccel(CTRL+Key_X, CMD_CUT);
      menuEdit->insertItem(*editcopyIconSet, tr("&Copy"),  CMD_COPY);
      menuEdit->setAccel(CTRL+Key_C, CMD_COPY);
      menuEdit->insertItem(*editpasteIconSet, tr("&Paste"), CMD_PASTE);
      menuEdit->setAccel(CTRL+Key_V, CMD_PASTE);

      menuEdit->insertSeparator();
      menuEdit->insertItem(QIconSet(*edit_track_delIcon),
         tr("Delete Selected Tracks"), CMD_DELETE_TRACK);

      addTrack = new QPopupMenu(this);
      populateAddTrack(addTrack);
      menuEdit->insertItem(QIconSet(*edit_track_addIcon),
         tr("Add Track"), addTrack);

      select = new QPopupMenu(this);
      select->insertItem(QIconSet(*select_allIcon),
         tr("Select &All"),  CMD_SELECT_ALL);
      select->insertItem(QIconSet(*select_deselect_allIcon),
         tr("&Deselect All"), CMD_SELECT_NONE);
      menuEdit->insertSeparator();
      select->insertItem(QIconSet(*select_invert_selectionIcon),
         tr("Invert &Selection"), CMD_SELECT_INVERT);
      select->insertItem(QIconSet(*select_inside_loopIcon),
         tr("&Inside Loop"), CMD_SELECT_ILOOP);
      select->insertItem(QIconSet(*select_outside_loopIcon),
         tr("&Outside Loop"), CMD_SELECT_OLOOP);
      select->insertItem(QIconSet(*select_all_parts_on_trackIcon),
         tr("All &Parts on Track"), CMD_SELECT_PARTS);
      menuEdit->insertItem(QIconSet(*selectIcon),
         tr("Select"), select);
      menuEdit->insertSeparator();

      pianoAction->addTo(menuEdit);
      menu_ids[CMD_OPEN_DRUMS] = menuEdit->insertItem(
         QIconSet(*edit_drummsIcon), tr("Drums"), this, SLOT(startDrumEditor()), 0);
      menu_ids[CMD_OPEN_LIST]  = menuEdit->insertItem(
         QIconSet(*edit_listIcon), tr("List"), this, SLOT(startListEditor()), 0);

      master = new QPopupMenu(this);
      master->setCheckable(false);
      menu_ids[CMD_OPEN_GRAPHIC_MASTER] = master->insertItem(
        QIconSet(*mastertrack_graphicIcon),tr("Graphic"), this, SLOT(startMasterEditor()), 0);
      menu_ids[CMD_OPEN_LIST_MASTER] = master->insertItem(
	QIconSet(*mastertrack_listIcon),tr("List"), this, SLOT(startLMasterEditor()), 0);
      menuEdit->insertItem(QIconSet(*edit_mastertrackIcon),
         tr("Mastertrack"), master, Key_F);

      menuEdit->insertSeparator();
      connect(menuEdit, SIGNAL(activated(int)), SLOT(cmd(int)));
      connect(select, SIGNAL(activated(int)), SLOT(cmd(int)));

      midiEdit = new QPopupMenu(this);
      midiEdit->setCheckable(false);
      menu_ids[CMD_OPEN_MIDI_TRANSFORM] = midiEdit->insertItem(
         QIconSet(*midi_transformIcon), tr("Midi &Transform"), this, SLOT(startMidiTransformer()), 0);
#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
      menu_ids[CMD_TRANSPOSE] = midiEdit->insertItem(
         QIconSet(*midi_transposeIcon), tr("Transpose"), this, SLOT(transpose()), 0);
      menuEdit->insertItem(
         QIconSet(*edit_midiIcon), tr("Midi"), midiEdit);

      //-------------------------------------------------------------
      //    popup View
      //-------------------------------------------------------------

      menuView = new QPopupMenu(this);
      menuView->setCheckable(true);
      menuBar()->insertItem(tr("View"), menuView);

      tr_id = menuView->insertItem(
         QIconSet(*view_transport_windowIcon), tr("Transport Panel"), this, SLOT(toggleTransport()), 0);
      bt_id = menuView->insertItem(
         QIconSet(*view_bigtime_windowIcon), tr("Bigtime window"),  this, SLOT(toggleBigTime()), 0);
      aid1  = menuView->insertItem(
         QIconSet(*mixerSIcon), tr("Mixer"), this, SLOT(toggleMixer()), 0);
//      aid2  = menuView->insertItem(
//         QIconSet(*cliplistSIcon), tr("Cliplist"), this, SLOT(startClipList()), 0);
      markerAction->addTo(menuView);

      //-------------------------------------------------------------
      //    popup Structure
      //-------------------------------------------------------------

      menuStructure = new QPopupMenu(this);
      menuStructure->setCheckable(false);
      menuBar()->insertItem(tr("&Structure"), menuStructure);
      menu_ids[CMD_GLOBAL_CUT] = menuStructure->insertItem(tr("Global Cut"),    this, SLOT(globalCut()), 0);
      menu_ids[CMD_GLOBAL_INSERT] = menuStructure->insertItem(tr("Global Insert"), this, SLOT(globalInsert()), 0);
      menu_ids[CMD_GLOBAL_SPLIT] = menuStructure->insertItem(tr("Global Split"),  this, SLOT(globalSplit()), 0);
      menu_ids[CMD_COPY_RANGE] = menuStructure->insertItem(tr("Copy Range"),    this, SLOT(copyRange()), 0);
      menuStructure->setItemEnabled(menu_ids[CMD_COPY_RANGE], false);
      menuStructure->insertSeparator();
      menu_ids[CMD_CUT_EVENTS] = menuStructure->insertItem(tr("Cut Events"),    this, SLOT(cutEvents()), 0);
      menuStructure->setItemEnabled(menu_ids[CMD_CUT_EVENTS], false);

      //-------------------------------------------------------------
      //    popup Midi
      //-------------------------------------------------------------

      midiInputPlugins = new QPopupMenu(this);
      midiInputPlugins->setCheckable(false);
      mpid0 = midiInputPlugins->insertItem(
         QIconSet(*midi_inputplugins_transposeIcon), tr("Transpose"), 0);
      mpid1 = midiInputPlugins->insertItem(
         QIconSet(*midi_inputplugins_midi_input_transformIcon), tr("Midi Input Transform"), 1);
      mpid2 = midiInputPlugins->insertItem(
         QIconSet(*midi_inputplugins_midi_input_filterIcon), tr("Midi Input Filter"), 2);
      mpid3 = midiInputPlugins->insertItem(
         QIconSet(*midi_inputplugins_remote_controlIcon), tr("Midi Remote Control"), 3);
      mpid4 = midiInputPlugins->insertItem(
         QIconSet(*midi_inputplugins_random_rhythm_generatorIcon), tr("Random Rhythm Generator"), 4);
      connect(midiInputPlugins, SIGNAL(activated(int)), SLOT(startMidiInputPlugin(int)));
      midiInputPlugins->setItemEnabled(mpid4, false);

      menu_functions = new QPopupMenu(this);
      menu_functions->setCheckable(true);
      menuBar()->insertItem(tr("&Midi"), menu_functions);
      menu_functions->setCaption(tr("Midi"));
      menu_ids[CMD_MIDI_EDIT_INSTRUMENTS] = menu_functions->insertItem(
         QIconSet(*midi_edit_instrumentIcon), tr("Edit Instrument"), this, SLOT(startEditInstrument()), 0);
      //TODO:
      menu_functions->setItemEnabled(menu_ids[CMD_MIDI_EDIT_INSTRUMENTS], false);
      menu_functions->insertItem(
         QIconSet(*midi_inputpluginsIcon), tr("Input Plugins"), midiInputPlugins, Key_P);
      menu_functions->insertSeparator();
      menu_ids[CMD_MIDI_RESET] = menu_functions->insertItem(
         QIconSet(*midi_reset_instrIcon), tr("Reset Instr."), this, SLOT(resetMidiDevices()), 0);
      menu_ids[CMD_MIDI_INIT] = menu_functions->insertItem(
         QIconSet(*midi_init_instrIcon), tr("Init Instr."),  this, SLOT(initMidiDevices()), 0);
      menu_ids[CMD_MIDI_LOCAL_OFF] = menu_functions->insertItem(
         QIconSet(*midi_local_offIcon), tr("local off"), this, SLOT(localOff()), 0);

      //-------------------------------------------------------------
      //    popup Audio
      //-------------------------------------------------------------

      menu_audio = new QPopupMenu(this);
      menu_audio->setCheckable(true);
      menuBar()->insertItem(tr("&Audio"), menu_audio);
      menu_ids[CMD_AUDIO_BOUNCE_TO_TRACK] = menu_audio->insertItem(
         QIconSet(*audio_bounce_to_trackIcon), tr("Bounce to Track"), this, SLOT(bounceToTrack()), 0);
      menu_ids[CMD_AUDIO_BOUNCE_TO_FILE] = menu_audio->insertItem(
         QIconSet(*audio_bounce_to_fileIcon), tr("Bounce to File"), this, SLOT(bounceToFile()), 0);
      menu_audio->insertSeparator();
      menu_ids[CMD_AUDIO_RESTART] = menu_audio->insertItem(
         QIconSet(*audio_restartaudioIcon), tr("Restart Audio"), this, SLOT(seqStart()), 0);

      //-------------------------------------------------------------
      //    popup Automation
      //-------------------------------------------------------------

      menuAutomation = new QPopupMenu(this);
      menuAutomation->setCheckable(true);
      menuBar()->insertItem(tr("Automation"), menuAutomation);
      autoId = menuAutomation->insertItem(
         QIconSet(*automation_mixerIcon), tr("Mixer Automation"), this, SLOT(switchMixerAutomation()), 0);
      menuAutomation->insertSeparator();
      menu_ids[CMD_MIXER_SNAPSHOT] = menuAutomation->insertItem(
         QIconSet(*automation_take_snapshotIcon), tr("Take Snapshot"), this, SLOT(takeAutomationSnapshot()), 0);
      menu_ids[CMD_MIXER_AUTOMATION_CLEAR] = menuAutomation->insertItem(
         QIconSet(*automation_clear_dataIcon), tr("Clear Automation Data"), this, SLOT(clearAutomation()), 0);
      menuAutomation->setItemEnabled(menu_ids[CMD_MIXER_AUTOMATION_CLEAR], false);

      //-------------------------------------------------------------
      //    popup Settings
      //-------------------------------------------------------------

      follow = new QPopupMenu(this);
      follow->setCheckable(false);
      fid0 = follow->insertItem(tr("dont follow Song"), CMD_FOLLOW_NO);
      fid1 = follow->insertItem(tr("follow page"), CMD_FOLLOW_JUMP);
      fid2 = follow->insertItem(tr("follow continuous"), CMD_FOLLOW_CONTINUOUS);
      follow->setItemChecked(fid1, true);
      connect(follow, SIGNAL(activated(int)), SLOT(cmd(int)));

      menuSettings = new QPopupMenu(this);
      menuSettings->setCheckable(false);
      menuBar()->insertItem(tr("Settings"), menuSettings);
      menu_ids[CMD_GLOBAL_CONFIG] = menuSettings->insertItem(
         QIconSet(*settings_globalsettingsIcon), tr("Global Settings"), this, SLOT(configGlobalSettings()),0);
      menu_ids[CMD_CONFIG_SHORTCUTS] = menuSettings->insertItem(
         QIconSet(*settings_configureshortcutsIcon), tr("Configure shortcuts"), this, SLOT(configShortCuts()), 0);
      menuSettings->insertItem(
         QIconSet(*settings_follow_songIcon), tr("follow song"), follow, Key_F);
      menu_ids[CMD_CONFIG_METRONOME] = menuSettings->insertItem(
         QIconSet(*settings_metronomeIcon), tr("Metronome"), this, SLOT(configMetronome()), 0);
      menuSettings->insertSeparator();
      menu_ids[CMD_CONFIG_MIDISYNC] = menuSettings->insertItem(
         QIconSet(*settings_midisyncIcon), tr("Midi Sync"), this, SLOT(configMidiSync()), 0);
      menu_ids[CMD_MIDI_FILE_CONFIG] = menuSettings->insertItem(
         QIconSet(*settings_midifileexportIcon), tr("Midi File Export"), this, SLOT(configMidiFile()), 0);
      menuSettings->insertSeparator();
      menu_ids[CMD_APPEARANCE_SETTINGS] = menuSettings->insertItem(
         QIconSet(*settings_appearance_settingsIcon), tr("Appearance settings"), this, SLOT(configAppearance()), 0);
      menuSettings->insertSeparator();
      menu_ids[CMD_CONFIG_MIDI_PORTS] = menuSettings->insertItem(
         QIconSet(*settings_midiport_softsynthsIcon), tr("Midi Ports / Soft Synth"), this, SLOT(configMidiPorts()), 0);

      //---------------------------------------------------
      //    popup Help
      //---------------------------------------------------

      menuBar()->insertSeparator();
      menu_help = new QPopupMenu(this);
      menu_help->setCheckable(false);
      menuBar()->insertItem(tr("&Help"), menu_help);

      menu_ids[CMD_OPEN_HELP] = menu_help->insertItem(tr("&Manual"), this, SLOT(startHelpBrowser()), 0);
      menu_ids[CMD_OPEN_HOMEPAGE] = menu_help->insertItem(tr("&MusE homepage"), this, SLOT(startHomepageBrowser()), 0);
      menu_help->insertSeparator();
      menu_ids[CMD_OPEN_BUG] = menu_help->insertItem(tr("&Report Bug..."), this, SLOT(startBugBrowser()), 0);
      menu_help->insertSeparator();
      menu_help->insertItem(tr("&About MusE"), this, SLOT(about()));
      menu_help->insertItem(tr("About&Qt"), this, SLOT(aboutQt()));
      menu_help->insertSeparator();
      menu_ids[CMD_START_WHATSTHIS] = menu_help->insertItem(tr("What's &This?"), this, SLOT(whatsThis()), 0);

      //---------------------------------------------------
      //    Central Widget
      //---------------------------------------------------

      arranger = new Arranger(this, "arranger");
      setCentralWidget(arranger);

      connect(tools1, SIGNAL(toolChanged(int)), arranger, SLOT(setTool(int)));
      connect(arranger, SIGNAL(editPart(Track*)), SLOT(startEditor(Track*)));
      connect(arranger, SIGNAL(dropSongFile(const QString&)), SLOT(loadProjectFile(const QString&)));
      connect(arranger, SIGNAL(dropMidiFile(const QString&)), SLOT(importMidi(const QString&)));
      connect(arranger, SIGNAL(startEditor(PartList*,int)),  SLOT(startEditor(PartList*,int)));
      connect(arranger, SIGNAL(toolChanged(int)), tools1, SLOT(set(int)));
      connect(this, SIGNAL(configChanged()), arranger, SLOT(configChanged()));

      connect(arranger, SIGNAL(setUsedTool(int)), SLOT(setUsedTool(int)));

      //---------------------------------------------------
      //  read list of "Recent Projects"
      //---------------------------------------------------

      QString prjPath(getenv("HOME"));
      prjPath += QString("/.musePrj");
      FILE* f = fopen(prjPath.latin1(), "r");
      if (f == 0) {
            perror("open projectfile");
            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(this, "transport");
      bigtime   = 0;

      QClipboard* cb = QApplication::clipboard();
      connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));
      connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged()));
      connect(arranger, SIGNAL(selectionChanged()), SLOT(selectionChanged()));

      //---------------------------------------------------
      //  load project
      //    if no songname entered on command line:
      //    startMode: 0  - load last song
      //               1  - load default template
      //               2  - load configured start song
      //---------------------------------------------------

      QString name;
      bool useTemplate = false;
      if (argc >= 2)
            name = argv[0];
      else if (config.startMode == 0) {
            if (argc < 2)
                  name = projectList[0] ? *projectList[0] : QString("untitled");
            else
                  name = argv[0];
            }
      else if (config.startMode == 1) {
            printf("starting with default template\n");
            name = museGlobalShare + QString("/templates/default.med");
            useTemplate = true;
            }
      else if (config.startMode == 2)
            name = config.startSong;
      song->blockSignals(false);
      loadProjectFile(name, useTemplate, true);
      changeConfig(false);

      song->update();
      }

//---------------------------------------------------------
//   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();
      }

//---------------------------------------------------------
//   loadProjectFile
//    load *.med, *.mid, *.kar
//
//    template - if true, load file but do not change
//                project name
//---------------------------------------------------------

// for drop:
void MusE::loadProjectFile(const QString& name)
      {
      loadProjectFile(name, false, false);
      }

void MusE::loadProjectFile(const QString& name, bool songTemplate, bool loadAll)
      {
      //
      // stop audio threads if running
      //
      bool restartSequencer = audio->isRunning();
      if (restartSequencer) {
            if (audio->isPlaying()) {
                  audio->msgPlay(false);
                  while (audio->isPlaying())
                        qApp->processEvents();
                  }
            seqStop();
            }
      loadProjectFile1(name, songTemplate, loadAll);
      if (restartSequencer)
            seqStart();
      }

//---------------------------------------------------------
//   loadProjectFile
//    load *.med, *.mid, *.kar
//
//    template - if true, load file but do not change
//                project name
//    loadAll  - load song data + configuration data
//---------------------------------------------------------

void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll)
      {
      if (audioMixer)
            audioMixer->clear();
      arranger->clear();      // clear track info
      if (clearSong())
            return;

      QFileInfo fi(name);
      if (songTemplate) {
            if (!fi.isReadable()) {
                  QMessageBox::critical(this, QString("MusE"),
                     tr("Cannot read template"));
                  return;
                  }
            project.setFile("untitled");
            }
      else {
            museProject = fi.dirPath(true);
            project.setFile(name);
            }
      QString ex = fi.extension(true).lower();
      if (ex.length() == 3)
            ex += ".";
      ex = ex.left(4);
      if (ex.isEmpty() || ex == "med.") {
            //
            //  read *.med file
            //
            bool popenFlag;
            FILE* f = fileOpen(this, fi.filePath(), QString(".med"), "r", popenFlag, true);
            if (f == 0) {
                  if (errno != ENOENT) {
                        QMessageBox::critical(this, QString("MusE"),
                           tr("File open error"));
                        setUntitledProject();
                        }
                  else
                        setConfigDefaults();
                  }
            else {
                  Xml xml(f);
                  read(xml, !loadAll);
                  bool fileError = ferror(f);
                  popenFlag ? pclose(f) : fclose(f);
                  if (fileError) {
                        QMessageBox::critical(this, QString("MusE"),
                           tr("File read error"));
                        setUntitledProject();
                        }
                  }
            }
      else if (ex == "mid." || ex == "kar.") {
            setConfigDefaults();
            if (!importMidi(name, false))
                  setUntitledProject();
            }
      else {
            QMessageBox::critical(this, QString("MusE"),
               tr("Unknown File Format"));
            setUntitledProject();
            }
      if (!songTemplate) {
            addProject(project.absFilePath());
            setCaption(QString("MusE: Song: ") + project.baseName());
            }
      song->dirty = false;

      menuView->setItemChecked(tr_id, config.transportVisible);
      menuView->setItemChecked(bt_id, config.bigTimeVisible);
      menuAutomation->setItemChecked(autoId, automation);

      if (loadAll) {
            showBigtime(config.bigTimeVisible);
            showMixer(config.mixerVisible);
            resize(config.geometryMain.size());
            move(config.geometryMain.topLeft());

            if (config.transportVisible)
                  transport->show();
            transport->move(config.geometryTransport.topLeft());
            showTransport(config.transportVisible);
            }

      transport->setMasterFlag(song->masterFlag());
      punchinAction->setOn(song->punchin());
      punchoutAction->setOn(song->punchout());
      loopAction->setOn(song->loop());
      song->update();
      song->updatePos();
      clipboardChanged(); // enable/disable "Paste"
      selectionChanged(); // enable/disable "Copy" & "Paste"
      }

//---------------------------------------------------------
//   setUntitledProject
//---------------------------------------------------------

void MusE::setUntitledProject()
      {
      setConfigDefaults();
      QString name("untitled");
      museProject = QFileInfo(name).dirPath(true);
      project.setFile(name);
      setCaption(tr("MusE: Song: ") + project.baseName());
      }

//---------------------------------------------------------
//   setConfigDefaults
//---------------------------------------------------------

void MusE::setConfigDefaults()
      {
      readConfiguration();    // used for reading midi files
#if 0
      if (readConfiguration()) {
            //
            // failed to load config file
            // set buildin defaults
            //
            configTransportVisible = false;
            configBigTimeVisible   = false;

            for (int channel = 0; channel < 2; ++channel)
                  song->addTrack(Track::AUDIO_GROUP);
            AudioTrack* out = (AudioTrack*)song->addTrack(Track::AUDIO_OUTPUT);
            AudioTrack* in  = (AudioTrack*)song->addTrack(Track::AUDIO_INPUT);

            // set some default routes
            std::list<QString> il = audioDevice->inputPorts();
            int channel = 0;
            for (std::list<QString>::iterator i = il.begin(); i != il.end(); ++i, ++channel) {
                  if (channel == 2)
                        break;
                  audio->msgAddRoute(Route(out,channel), Route(*i,channel));
                  }
            channel = 0;
            std::list<QString> ol = audioDevice->outputPorts();
            for (std::list<QString>::iterator i = ol.begin(); i != ol.end(); ++i, ++channel) {
                  if (channel == 2)
                        break;
                  audio->msgAddRoute(Route(*i, channel), Route(in,channel));
                  }
            }
#endif
      song->dirty = false;
      }

//---------------------------------------------------------
//   setFollow
//---------------------------------------------------------

void MusE::setFollow()
      {
      Song::FollowMode fm = song->follow();
      follow->setItemChecked(fid0, fm == Song::NO);
      follow->setItemChecked(fid1, fm == Song::JUMP);
      follow->setItemChecked(fid2, fm == Song::CONTINUOUS);
      }

//---------------------------------------------------------
//   MusE::loadProject
//---------------------------------------------------------

void MusE::loadProject()
      {
      bool loadAll;
      QString fn = getOpenFileName(QString(""), med_file_pattern, this,
         tr("MusE: load project"), &loadAll);
      if (!fn.isEmpty()) {
            museProject = QFileInfo(fn).dirPath(true);
            loadProjectFile(fn, false, loadAll);
            }
      }

//---------------------------------------------------------
//   loadTemplate
//---------------------------------------------------------

void MusE::loadTemplate()
      {
      QString fn = getOpenFileName(QString("templates"), med_file_pattern, this,
         tr("MusE: load template"), 0);
      if (!fn.isEmpty()) {
            // museProject = QFileInfo(fn).dirPath(true);
            loadProjectFile(fn, true, true);
            setUntitledProject();
            }
      }

//---------------------------------------------------------
//   save
//---------------------------------------------------------

bool MusE::save()
      {
      if (project.baseName() == "untitled")
            return saveAs();
      else
            return save(project.filePath(), false);
      }

//---------------------------------------------------------
//   save
//---------------------------------------------------------

bool MusE::save(const QString& name, bool overwriteWarn)
      {
      QString backupCommand;

      if (QFile::exists(name)) {
            backupCommand.sprintf("cp \"%s\" \"%s.backup\"", name.latin1(), name.latin1());
            }
      else if (QFile::exists(name + QString(".med"))) {
            backupCommand.sprintf("cp \"%s.med\" \"%s.med.backup\"", name.latin1(), name.latin1());
            }
      if (!backupCommand.isEmpty())
            system(backupCommand.latin1());

      bool popenFlag;
      FILE* f = fileOpen(this, name, QString(".med"), "w", popenFlag, false, overwriteWarn);
      if (f == 0)
            return false;
      Xml xml(f);
      write(xml);
      if (ferror(f)) {
            QString s = "Write File\n" + name + "\nfailed: "
               + strerror(errno);
            QMessageBox::critical(this,
               tr("MusE: Write File failed"), s);
            popenFlag? pclose(f) : fclose(f);
            unlink(name.latin1());
            return false;
            }
      else {
            popenFlag? pclose(f) : fclose(f);
            song->dirty = false;
            return true;
            }
      }

//---------------------------------------------------------
//   quitDoc
//---------------------------------------------------------

void MusE::quitDoc()
      {
      close(true);
      }

//---------------------------------------------------------
//   closeEvent
//---------------------------------------------------------

void MusE::closeEvent(QCloseEvent*)
      {
      song->setStop(true);
      //
      // wait for sequencer
      //
      while (audio->isPlaying()) {
            qApp->processEvents();
            }
      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) {
                  if (!save())      // donīt quit if save failed
                        return;
                  }
            else if (n == 2)
                  return;
            }
      seqStop();

      WaveTrackList* wt = song->waves();
      for (iWaveTrack iwt = wt->begin(); iwt != wt->end(); ++iwt) {
            WaveTrack* t = *iwt;
            if (t->recFile() && t->recFile()->samples() == 0) {
                  t->recFile()->remove();
                  }
            }

      // save "Open Recent" list
      QString prjPath(getenv("HOME"));
      prjPath += "/.musePrj";
      FILE* f = fopen(prjPath.latin1(), "w");
      if (f) {
            for (int i = 0; i < PROJECT_LIST_LEN; ++i) {
                  fprintf(f, "%s\n", projectList[i] ? projectList[i]->latin1() : "");
                  }
            fclose(f);
            }
      exitJackAudio();
      SynthIList* sl = song->syntis();
      for (iSynthI i = sl->begin(); i != sl->end(); ++i)
            delete *i;

      qApp->quit();
      }

//---------------------------------------------------------
//   toggleTransport
//---------------------------------------------------------

void MusE::toggleTransport()
      {
      showTransport(!menuView->isItemChecked(tr_id));
      }

//---------------------------------------------------------
//   showTransport
//---------------------------------------------------------

void MusE::showTransport(bool flag)
      {
      transport->setShown(flag);
      menuView->setItemChecked(tr_id, flag);
      }

//---------------------------------------------------------
//   saveAs
//---------------------------------------------------------

bool MusE::saveAs()
      {
//      QString name = getSaveFileName(museProject, med_file_pattern, this,
      QString name = getSaveFileName(QString(""), med_file_pattern, this,
         tr("MusE: Save As"));
      bool ok = false;
      if (!name.isEmpty()) {
            ok = save(name, true);
            if (ok) {
                  project.setFile(name);
                  setCaption(tr("MusE: Song: ") + project.baseName());
                  addProject(name);
                  museProject = QFileInfo(name).dirPath(true);
                  }
            }

      return ok;
      }

//---------------------------------------------------------
//   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 3: startDrumEditor(pl); break;
            case 4: startWaveEditor(pl); break;
            }
      }

//---------------------------------------------------------
//   startEditor
//---------------------------------------------------------

void MusE::startEditor(Track* t)
      {
      switch (t->type()) {
            case Track::MIDI: startPianoroll(); break;
            case Track::DRUM: startDrumEditor(); break;
            case Track::WAVE: startWaveEditor(); break;
            default:
                  break;
            }
      }

//---------------------------------------------------------
//   getMidiPartsToEdit
//---------------------------------------------------------

PartList* MusE::getMidiPartsToEdit()
      {
      PartList* pl = song->getSelectedMidiParts();
      if (pl->empty()) {
            QMessageBox::critical(this, QString("MusE"), tr("Nothing to edit"));
            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, this);
      pianoroll->show();
      toplevels.push_back(Toplevel(Toplevel::PIANO_ROLL, int(pianoroll), pianoroll));
      connect(pianoroll, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      connect(muse, SIGNAL(configChanged()), pianoroll, SLOT(configChanged()));
      }

//---------------------------------------------------------
//   startListenEditor
//---------------------------------------------------------

void MusE::startListEditor()
      {
      PartList* pl = getMidiPartsToEdit();
      if (pl == 0)
            return;
      startListEditor(pl);
      }

void MusE::startListEditor(PartList* pl)
      {
      ListEdit* listEditor = new ListEdit(pl);
      listEditor->show();
      toplevels.push_back(Toplevel(Toplevel::LISTE, int(listEditor), listEditor));
      connect(listEditor, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      connect(muse,SIGNAL(configChanged()), listEditor, SLOT(configChanged()));
      }

//---------------------------------------------------------
//   startMasterEditor
//---------------------------------------------------------

void MusE::startMasterEditor()
      {
      MasterEdit* masterEditor = new MasterEdit();
      masterEditor->show();
      toplevels.push_back(Toplevel(Toplevel::MASTER, int(masterEditor), masterEditor));
      connect(masterEditor, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      }

//---------------------------------------------------------
//   startLMasterEditor
//---------------------------------------------------------

void MusE::startLMasterEditor()
      {
      LMaster* lmaster = new LMaster();
      lmaster->show();
      toplevels.push_back(Toplevel(Toplevel::LMASTER, int(lmaster), lmaster));
      connect(lmaster, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      connect(muse, SIGNAL(configChanged()), lmaster, SLOT(configChanged()));
      }

//---------------------------------------------------------
//   startDrumEditor
//---------------------------------------------------------

void MusE::startDrumEditor()
      {
      PartList* pl = getMidiPartsToEdit();
      if (pl == 0)
            return;
      startDrumEditor(pl);
      }

void MusE::startDrumEditor(PartList* pl)
      {
      DrumEdit* drumEditor = new DrumEdit(pl, this);
      drumEditor->show();
      toplevels.push_back(Toplevel(Toplevel::DRUM, int(drumEditor), drumEditor));
      connect(drumEditor, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      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"));
            return;
            }
      startWaveEditor(pl);
      }

void MusE::startWaveEditor(PartList* pl)
      {
      WaveEdit* waveEditor = new WaveEdit(pl);
      waveEditor->show();
      connect(muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged()));
      toplevels.push_back(Toplevel(Toplevel::WAVE, int(waveEditor), waveEditor));
      connect(waveEditor, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
      }

//---------------------------------------------------------
//   startDefineController
//---------------------------------------------------------

// void MusE::startDefineController()
//      {
//      configMidiController();
//      }

//---------------------------------------------------------
//   startMarkerView
//---------------------------------------------------------

void MusE::startMarkerView()
      {
      if (markerView == 0) {
            markerView = new MarkerView(this);

            connect(arranger, SIGNAL(addMarker(int)), markerView, SLOT(addMarker(int)));
            toplevels.push_back(Toplevel(Toplevel::MARKER, int(markerView), markerView));
//            connect(markerView, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
            }
      markerView->show();
      }

//---------------------------------------------------------
//   startClipList
//---------------------------------------------------------

void MusE::startClipList()
      {
      if (clipListEdit == 0) {
            clipListEdit = new ClipListEdit();
            toplevels.push_back(Toplevel(Toplevel::CLIPLIST, int(clipListEdit), clipListEdit));
            connect(clipListEdit, SIGNAL(deleted(int)), SLOT(toplevelDeleted(int)));
            }
      clipListEdit->show();
      menu_audio->setItemChecked(aid2, true);
      }

//---------------------------------------------------------
//   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]->latin1();
            const char* p = strrchr(path, '/');
            if (p == 0)
                  p = path;
            else
                  ++p;
            openRecent->insertItem(QString(p), i);
            }
      }

//---------------------------------------------------------
//   selectProject
//---------------------------------------------------------

void MusE::selectProject(int id)
      {
      if (id < 0)
            return;
      assert(id < PROJECT_LIST_LEN);
      QString* name = projectList[id];
      if (name == 0)
            return;
      loadProjectFile(*name, false, true);
      }

//---------------------------------------------------------
//   toplevelDeleted
//---------------------------------------------------------

void MusE::toplevelDeleted(int tl)
      {
      for (iToplevel i = toplevels.begin(); i != toplevels.end(); ++i) {
            if (i->object() == tl) {
                  switch(i->type()) {
                        case Toplevel::MARKER:
                              break;
                        case Toplevel::CLIPLIST:
                              menu_audio->setItemChecked(aid2, false);
                              return;
                        // the followin editors can exist in more than
                        // one instantiation:
                        case Toplevel::PIANO_ROLL:
                        case Toplevel::LISTE:
                        case Toplevel::DRUM:
                        case Toplevel::MASTER:
                        case Toplevel::WAVE:
                        case Toplevel::LMASTER:
                              break;
                        }
                  toplevels.erase(i);
                  return;
                  }
            }
      printf("topLevelDeleted: top leve %x not found\n", tl);
      assert(false);
      }

//---------------------------------------------------------
//   ctrlChanged
//    midi ctrl value changed
//---------------------------------------------------------

#if 0
void MusE::ctrlChanged()
      {
      arranger->updateInspector();
      }
#endif

//---------------------------------------------------------
//   kbAccel
//---------------------------------------------------------

void MusE::kbAccel(int key)
      {
      if (key == shortcuts[SHRT_TOGGLE_METRO].key) {
            song->setClick(!song->click());
            }
      else if (key == shortcuts[SHRT_PLAY_TOGGLE].key) {
            if (audio->isPlaying())
                  //song->setStopPlay(false);
                  song->setStop(true);
            else if (song->cpos() != song->lpos())
                  song->setPos(0, song->lPos());
            else {
                  Pos p(0, true);
                  song->setPos(0, p);
                  }
            }
      else if (key == shortcuts[SHRT_STOP].key) {
            //song->setPlay(false);
            song->setStop(true);
            }
      else if (key == shortcuts[SHRT_PLAY_SONG].key ) {
            song->setPlay(true);
            }
      else if (key == shortcuts[SHRT_GOTO_LEFT].key) {
            if (!song->record())
                  song->setPos(0, song->lPos());
            }
      else if (key == shortcuts[SHRT_GOTO_RIGHT].key) {
            if (!song->record())
                  song->setPos(0, song->rPos());
            }
      else if (key == shortcuts[SHRT_TOGGLE_LOOP].key) {
            song->setLoop(!song->loop());
            }
      else if (key == shortcuts[SHRT_START_REC].key) {
            if (!audio->isPlaying()) {
                  song->setRecord(!song->record());
                  }
            }
      else if (key == shortcuts[SHRT_OPEN_TRANSPORT].key) {
            toggleTransport();
            }
      else if (key == shortcuts[SHRT_OPEN_BIGTIME].key) {
            toggleBigTime();
            }
      else if (key == shortcuts[SHRT_OPEN_MIXER].key) {
            toggleMixer();
            }
      else {
            if (debugMsg)
                  printf("unknown kbAccel 0x%x\n", key);
            }
      }

//---------------------------------------------------------
//   MuseApplication
//---------------------------------------------------------

class MuseApplication : public QApplication {
      MusE* muse;

   public:
      MuseApplication(int& argc, char** argv)
         : QApplication(argc, argv)
            {
            muse = 0;
            }


      void setMuse(MusE* m) {
            muse = m;
#ifdef HAVE_LADCCA
            startTimer (300);
#endif
            }

      bool notify(QObject* receiver, QEvent* event) {
            bool flag = QApplication::notify(receiver, event);
            if (event->type() == QEvent::KeyPress) {
                  QKeyEvent* ke = (QKeyEvent*)event;
                  globalKeyState = ke->stateAfter();
                  bool accepted = ke->isAccepted();
                  if (!accepted) {
                        muse->kbAccel(ke->key());
                        return true;
                        }
                  }
            if (event->type() == QEvent::KeyRelease) {
                  QKeyEvent* ke = (QKeyEvent*)event;
                  globalKeyState = ke->stateAfter();
                  }

            return flag;
            }

#ifdef HAVE_LADCCA
     virtual void timerEvent (QTimerEvent * e) {
            muse->cca_idle_cb ();
            }
#endif /* HAVE_LADCCA */

      };

//---------------------------------------------------------
//   usage
//---------------------------------------------------------

static void usage(const char* prog, const char* txt)
      {
     fprintf(stderr, "%s: %s\nusage: %s flags midifile\n   Flags:\n",
         prog, txt, prog);
      fprintf(stderr, "   -h       this help\n");
      fprintf(stderr, "   -v       print version\n");
      fprintf(stderr, "   -d       debug mode: no threads, no RT\n");
      fprintf(stderr, "   -D       debug mode: enable some debug messages\n");
      fprintf(stderr, "   -m       debug mode: trace midi Input\n");
      fprintf(stderr, "   -M       debug mode: trace midi Output\n");
      fprintf(stderr, "   -s       debug mode: trace sync\n");
      fprintf(stderr, "   -a       no audio\n");
      fprintf(stderr, "   -P  n    set real time priority to n (default: 50)\n");
      fprintf(stderr, "   -p       don't load LADSPA plugins\n");
#ifdef VST_SUPPORT
      fprintf(stderr, "   -V       don't load VST 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

//---------------------------------------------------------
//   main
//---------------------------------------------------------

int main(int argc, char* argv[])
      {
      ruid = getuid();
      euid = geteuid();
      undoSetuid();
      getCapabilities();
      int noAudio = false;

      museUser = getenv("MUSEHOME");
      if (museUser == 0)
            museUser = getenv("HOME");
      QString museGlobal;
      const char* p = getenv("MUSE");
      if (p)
            museGlobal = p;

      if (museGlobal.isEmpty()) {
            QString museGlobal(INSTPREFIX);
            museGlobalLib   =  museGlobal + "/lib/muse";
            museGlobalShare =  museGlobal + "/share/muse";
            }
      else {
            museGlobalLib   = museGlobal + "/lib";
            museGlobalShare = museGlobal + "/share";
            }
      museProject = museProjectInitPath; //getcwd(0, 0);
      configName  = QString(getenv("HOME")) + QString("/.MusE");

#ifdef HAVE_LADCCA
      cca_args_t * cca_args;
      cca_args = cca_extract_args (&argc, &argv);
#endif

      srand(time(0));   // initialize random number generator
//      signal(SIGCHLD, catchSignal);  // interferes with initVST()
      initMidiController();
      QApplication::setColorSpec(QApplication::ManyColor);
      MuseApplication app(argc, argv);

      initShortCuts();
      readConfiguration();

      // SHOW MUSE SPLASH SCREEN
      if (config.showSplashScreen) {
            QPixmap splsh(museGlobalShare + "/splash.png");

            if (!splsh.isNull()) {
                  QSplashScreen* muse_splash = new QSplashScreen(splsh,
                     Qt::WStyle_StaysOnTop | Qt::WDestructiveClose);
                  muse_splash->show();
                  QTimer* stimer = new QTimer(0);
                  muse_splash->connect(stimer, SIGNAL(timeout()), muse_splash, SLOT(close()));
                  stimer->start(6000, true);
                  }
            }
      int i;
#ifdef VST_SUPPORT
      while ((i = getopt(argc, argv, "ahvdDmMsP:pV")) != EOF) {
#else
      while ((i = getopt(argc, argv, "ahvdDmMsP:p")) != EOF) {
#endif
      char c = (char)i;
            switch (c) {
                  case 'v': printVersion(argv[0]); return 0;
                  case 'd':
                        debugMode = true;
                        realTimeScheduling = false;
                        break;
                  case 'a':
                        noAudio = true;
                        break;
                  case 'D': debugMsg = true; break;
                  case 'm': midiInputTrace = true; break;
                  case 'M': midiOutputTrace = true; break;
                  case 's': debugSync = true; break;
                  case 'P': realTimePriority = atoi(optarg); break;
                  case 'p': loadPlugins = false; break;
                  case 'V': loadVST = false; break;
                  case 'h': usage(argv[0], argv[1]); return -1;
                  default:  usage(argv[0], "bad argument"); return -1;
                  }
            }
      if (debugMsg)
            printf("Start euid: %d ruid: %d, Now euid %d\n",
               euid, ruid, geteuid());
      if (debugMode) {
            initDummyAudio();
            realTimeScheduling = false;
            }
      else if (noAudio) {
            initDummyAudio();
            realTimeScheduling = true;
            if (debugMode) {
                      realTimeScheduling = false;
                      }
            }
      else 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.");

                  exit(-1);
                  }
            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");
                  initDummyAudio();
                  }
            realTimeScheduling = true;
            }
      else
            realTimeScheduling = audioDevice->isRealtime();
      argc -= optind;
      ++argc;

      if (debugMsg) {
            printf("global lib:   <%s>\n", museGlobalLib.latin1());
            printf("global share: <%s>\n", museGlobalShare.latin1());
            printf("muse home:    <%s>\n", museUser.latin1());
            printf("project dir:  <%s>\n", museProject.latin1());
            }

      static QTranslator translator(0);
      QString locale(QTextCodec::locale());
      if (locale != "C") {
            QString loc("muse_");
            loc += QString(QTextCodec::locale());
            if (translator.load(loc, QString(".")) == false) {
                  QString lp(museGlobalShare);
                  lp += QString("/locale");
                  if (translator.load(loc, lp) == false) {
                        printf("no locale <%s>/<%s>\n", loc.latin1(), lp.latin1());
                        }
                  }
            app.installTranslator(&translator);
            }

      if (locale == "de") {
            printf("locale de\n");
            hIsB = false;
            }

      if (loadPlugins)
            initPlugins();

      if (loadVST)
            initVST();

      initIcons();
      
      initMetronome();
      QApplication::clipboard()->setSelectionMode(false);

      QApplication::addLibraryPath(museGlobalLib + "/qtplugins");
      if (debugMsg) {
            QStringList list = app.libraryPaths();
            QStringList::Iterator it = list.begin();
            printf("QtLibraryPath:\n");
            while(it != list.end()) {
                  printf("  <%s>\n", (*it).latin1());
                  ++it;
                  }
            }

      muse = new MusE(argc, &argv[optind]);
      app.setMuse(muse);
      muse->setIcon(*museIcon);
      muse->show();
      muse->seqStart();

#ifdef HAVE_LADCCA
      {
        int cca_flags = CCA_Config_File;

        cca_client = cca_init (cca_args, ((JackAudioDevice*)audioDevice)->getJackName(), cca_flags, CCA_PROTOCOL(2,0));

        cca_alsa_client_id (cca_client, snd_seq_client_id (alsaSeq));

        cca_jack_client_name (cca_client, ((JackAudioDevice*)audioDevice)->getJackName());

      }
#endif /* HAVE_LADCCA */

      return app.exec();
      }

#if 0
//---------------------------------------------------------
//   configPart
//---------------------------------------------------------

void MusE::configPart(int id)
      {
      if (id < 3) {
            partConfig->setItemChecked(0, id == 0);
            partConfig->setItemChecked(1, id == 1);
            partConfig->setItemChecked(2, id == 2);
            arranger->setShowPartType(id);
            for (int i = 3; i < 10; ++i) {
                  partConfig->setItemEnabled(i, id == 2);
                  }
            }
      else {
            bool flag = !partConfig->isItemChecked(id);
            partConfig->setItemChecked(id, flag);
            int val = arranger->showPartEvent();
            if (flag) {
                  val |= 1 << (id-3);
                  }
            else {
                  val &= ~(1 << (id-3));
                  }
            arranger->setShowPartEvent(val);
            }
      }
#endif

//---------------------------------------------------------
//   cmd
//    some cmd's from pulldown menu
//---------------------------------------------------------

void MusE::cmd(int cmd)
      {
      TrackList* tracks = song->tracks();
      int l = song->lpos();
      int r = song->rpos();

      switch(cmd) {
            case CMD_CUT:
                  arranger->cmd(Arranger::CMD_CUT_PART);
                  break;
            case CMD_COPY:
                  arranger->cmd(Arranger::CMD_COPY_PART);
                  break;
            case CMD_PASTE:
                  arranger->cmd(Arranger::CMD_PASTE_PART);
                  break;
            case CMD_DELETE:
                  song->startUndo();
                  if (song->msgRemoveParts()) {
                        song->endUndo(SC_PART_REMOVED);
                        break;
                        }
                  else
                        audio->msgRemoveTracks();
                  song->endUndo(SC_TRACK_REMOVED);
                  break;
            case CMD_DELETE_TRACK:
                  song->startUndo();
                  audio->msgRemoveTracks();
                  song->endUndo(SC_TRACK_REMOVED);
                  break;

            case CMD_SELECT_ALL:
            case CMD_SELECT_NONE:
            case CMD_SELECT_INVERT:
            case CMD_SELECT_ILOOP:
            case CMD_SELECT_OLOOP:
                  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));
                              switch(cmd) {
                                    case CMD_SELECT_INVERT:
                                          f = !p->second->selected();
                                          break;
                                    case CMD_SELECT_NONE:
                                          f = false;
                                          break;
                                    case CMD_SELECT_ALL:
                                          f = true;
                                          break;
                                    case CMD_SELECT_ILOOP:
                                          f = inside;
                                          break;
                                    case CMD_SELECT_OLOOP:
                                          f = !inside;
                                          break;
                                    }
                              p->second->setSelected(f);
                              }
                        }
                  song->update();
                  break;

            case CMD_SELECT_PARTS:
                  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();
                  break;
            case CMD_FOLLOW_NO:
                  song->setFollow(Song::NO);
                  setFollow();
                  break;
            case CMD_FOLLOW_JUMP:
                  song->setFollow(Song::JUMP);
                  setFollow();
                  break;
            case CMD_FOLLOW_CONTINUOUS:
                  song->setFollow(Song::CONTINUOUS);
                  setFollow();
                  break;
            }
      }

//---------------------------------------------------------
//   clipboardChanged
//---------------------------------------------------------

void MusE::clipboardChanged()
      {
      QCString subtype("partlist");
      QMimeSource* ms = QApplication::clipboard()->data(QClipboard::Clipboard);
      if (ms == 0)
            return;
      bool flag = false;
      for (int i = 0; ms->format(i); ++i) {
// printf("Format <%s\n", ms->format(i));
            if ((strncmp(ms->format(i), "text/midipartlist", 17) == 0)
               || strncmp(ms->format(i), "text/wavepartlist", 17) == 0) {
                  flag = true;
                  break;
                  }
            }
      menuEdit->setItemEnabled(CMD_PASTE, flag);
      }

//---------------------------------------------------------
//   selectionChanged
//---------------------------------------------------------

void MusE::selectionChanged()
      {
      bool flag = arranger->isSingleSelection();
      menuEdit->setItemEnabled(CMD_CUT, flag);
      menuEdit->setItemEnabled(CMD_COPY, flag);
      }

//---------------------------------------------------------
//   transpose
//---------------------------------------------------------

void MusE::transpose()
      {
      Transpose *w = new Transpose();
      w->show();
      }

//---------------------------------------------------------
//   modifyGateTime
//---------------------------------------------------------

void MusE::modifyGateTime()
      {
      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();
      }

//---------------------------------------------------------
//   loadTheme
//---------------------------------------------------------

void MusE::loadTheme(QString s)
      {
      if (style().name() != s)
            QApplication::setStyle(s);
      }

//---------------------------------------------------------
//   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();
	loadTheme(config.style);
      setFont(config.fonts[0], true);
      emit configChanged();
      updateConfiguration();
      }

//---------------------------------------------------------
//   configMetronome
//---------------------------------------------------------

void MusE::configMetronome()
      {
      if (!metronomeConfig)
            metronomeConfig = new MetronomeConfig(this, "metronome");
      metronomeConfig->show();
      }

//---------------------------------------------------------
//   configShortCuts
//---------------------------------------------------------

void MusE::configShortCuts()
      {
      if (!shortcutConfig)
            shortcutConfig = new ShortcutConfig(this, "shortcutconfig");
      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();
      TrackList* tracks = song->tracks();
      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) {
            MidiTrack* track = dynamic_cast<MidiTrack*>(*it);
            if (track == 0 || 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)) {
                        audio->msgRemovePart(part, false);
                        }
                  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();
                        iEvent ie = el->lower_bound(t + len);
                        for (; ie != el->end();) {
                              iEvent i = ie;
                              ++ie;
                              audio->msgDeleteEvent(i->second, nPart, false);
                              }
                        audio->msgChangePart(part, nPart, false);
                        }
                  else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) {
                        //----------------------
                        // remove part middle
                        //----------------------

                        MidiPart* nPart = new MidiPart(*(MidiPart*)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));
                        audio->msgChangePart(part, nPart, false);
                        }
                  else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) {
                        // TODO: remove part head
                        }
                  else if (t >= rpos) {
                        MidiPart* nPart = new MidiPart(*(MidiPart*)part);
                        int nt = part->tick();
                        nPart->setTick(nt - (rpos -lpos));
                        audio->msgChangePart(part, nPart, false);
                        }
                  }
            }
      // 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();
      TrackList* tracks = song->tracks();
      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) {
            MidiTrack* track = dynamic_cast<MidiTrack*>(*it);
            //
            // process only non muted midi tracks
            //
            if (track == 0 || 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)) {
                        MidiPart* nPart = new MidiPart(*(MidiPart*)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);
                              }
                        audio->msgChangePart(part, nPart, false);
                        }
                  else if (t > lpos) {
                        MidiPart* nPart = new MidiPart(*(MidiPart*)part);
                        nPart->setTick(t + (rpos -lpos));
                        audio->msgChangePart(part, nPart, false);
                        }
                  }
            }
      // 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);
                        audio->msgChangePart(part, p1, false);
                        audio->msgAddPart(p2, false);
                        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;
      }

//---------------------------------------------------------
//   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);
      song->setRecordFlag(track, true);
      audio->msgBounce();
      }

//---------------------------------------------------------
//   bounceToFile
//---------------------------------------------------------

void MusE::bounceToFile()
      {
      if (checkRegionNotNull())
            return;
      SndFile* sf = getSndFile(0, this, 0);
      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, false);
      song->setRecordFlag(ao, true);
      audio->msgBounce();
      }

#ifdef HAVE_LADCCA
//---------------------------------------------------------
//   cca_idle_cb
//---------------------------------------------------------
#include <iostream>
void
MusE::cca_idle_cb ()
{
  cca_event_t * event;

  while ( (event = cca_get_event (cca_client)) )
    {
      switch (cca_event_get_type (event))
        {
        case CCA_Save_File:
          /* save file */
          save (cca_get_fqn (cca_event_get_string (event), "muse.med"), false);
          cca_send_event (cca_client, event);
          break;

        case CCA_Restore_File:
          /* load file */
          loadProjectFile (cca_get_fqn (cca_event_get_string (event), "muse.med"), false, true);
          cca_send_event (cca_client, event);
          break;

        case CCA_Quit:
          /* quit muse */
          std::cout << "Quit"
                    << std::endl;
          cca_event_destroy (event);
          break;

        default:
          std::cout << "Recieved unknown LADCCA event of type "
                    << cca_event_get_type (event)
                    << std::endl;
          cca_event_destroy (event);
          break;
        }
    }
}
#endif /* HAVE_LADCCA */

//---------------------------------------------------------
//   clearSong
//    return true if operation aborted
//    called with sequencer stopped
//---------------------------------------------------------

bool MusE::clearSong()
      {
      if (song->dirty) {
            int n = 0;
            n = QMessageBox::warning(this, appName,
               tr("The current Project contains unsaved data\n"
               "Load overwrites current Project:\n"
               "Save Current Project?"),
               tr("&Save"), tr("&Overwrite"), tr("&Abort"), 0, 2);
            switch (n) {
                  case 0:
                        if (!save())      // abort if save failed
                              return true;
                        break;
                  case 1:
                        break;
                  case 2:
                        return true;
                  default:
                        printf("InternalError: gibt %d\n", n);
                  }
            }
      if (audio->isPlaying()) {
            audio->msgPlay(false);
            while (audio->isPlaying())
                  qApp->processEvents();
            }

again:
      for (iToplevel i = toplevels.begin(); i != toplevels.end(); ++i) {
            Toplevel tl = *i;
            int obj = tl.object();
            switch (tl.type()) {
                  case Toplevel::CLIPLIST:
                  case Toplevel::MARKER:
                        break;
                  case Toplevel::PIANO_ROLL:
                  case Toplevel::LISTE:
                  case Toplevel::DRUM:
                  case Toplevel::MASTER:
                  case Toplevel::WAVE:
                  case Toplevel::LMASTER:
                        ((QWidget*)(obj))->close(true);
                        goto again;
                  }
            }
      song->clear(false);
      return false;
      }

//---------------------------------------------------------
//   startEditInstrument
//---------------------------------------------------------

void MusE::startEditInstrument()
      {
      printf("TODO\n");
      }

//---------------------------------------------------------
//   switchMixerAutomation
//---------------------------------------------------------

void MusE::switchMixerAutomation()
      {
      automation = !automation;
printf("automation = %d\n", automation);
      menuAutomation->setItemChecked(autoId, automation);
      }

//---------------------------------------------------------
//   clearAutomation
//---------------------------------------------------------

void MusE::clearAutomation()
      {
      printf("not implemented\n");
      }

//---------------------------------------------------------
//   takeAutomationSnapshot
//---------------------------------------------------------

void MusE::takeAutomationSnapshot()
      {
      int frame = song->cPos().frame();
      TrackList* tracks = song->tracks();
      for (iTrack i = tracks->begin(); i != tracks->end(); ++i) {
            if ((*i)->isMidiTrack())
                  continue;
            AudioTrack* track = (AudioTrack*)*i;
            CtrlListList* cll = track->controller();
            for (iCtrlList icl = cll->begin(); icl != cll->end(); ++icl) {
                  float val = icl->second->curVal();
                  icl->second->add(frame, val);
                  }
            }
      }

//---------------------------------------------------------
//   updateConfiguration
//    called whenever the configuration has changed
//---------------------------------------------------------

void MusE::updateConfiguration()
      {
      fileOpenAction->setAccel(shortcuts[SHRT_OPEN].key);
      fileNewAction->setAccel(shortcuts[SHRT_NEW].key);
      fileSaveAction->setAccel(shortcuts[SHRT_SAVE].key);

      menu_file->setAccel(shortcuts[SHRT_OPEN_RECENT].key, menu_ids[CMD_OPEN_RECENT]);
      menu_file->setAccel(shortcuts[SHRT_LOAD_TEMPLATE].key, menu_ids[CMD_LOAD_TEMPLATE]);
      menu_file->setAccel(shortcuts[SHRT_SAVE_AS].key, menu_ids[CMD_SAVE_AS]);
      menu_file->setAccel(shortcuts[SHRT_IMPORT_MIDI].key, menu_ids[CMD_IMPORT_MIDI]);
      menu_file->setAccel(shortcuts[SHRT_EXPORT_MIDI].key, menu_ids[CMD_EXPORT_MIDI]);
      menu_file->setAccel(shortcuts[SHRT_IMPORT_AUDIO].key, menu_ids[CMD_IMPORT_AUDIO]);
      menu_file->setAccel(shortcuts[SHRT_QUIT].key, menu_ids[CMD_QUIT]);

      menuEdit->setAccel(Key_Delete, CMD_DELETE);
      menuEdit->setAccel(shortcuts[SHRT_OPEN_DRUMS].key, menu_ids[CMD_OPEN_DRUMS]);
      menuEdit->setAccel(shortcuts[SHRT_OPEN_LIST].key, menu_ids[CMD_OPEN_LIST]);
      menuEdit->setAccel(shortcuts[SHRT_OPEN_MIDI_TRANSFORM].key, menu_ids[CMD_OPEN_MIDI_TRANSFORM]);

      midiEdit->setAccel(shortcuts[SHRT_TRANSPOSE].key, menu_ids[CMD_TRANSPOSE]);

      master->setAccel(shortcuts[SHRT_OPEN_GRAPHIC_MASTER].key, menu_ids[CMD_OPEN_GRAPHIC_MASTER]);
      master->setAccel(shortcuts[SHRT_OPEN_LIST_MASTER].key, menu_ids[CMD_OPEN_LIST_MASTER]);

      menuStructure->setAccel(shortcuts[SHRT_GLOBAL_CUT].key, menu_ids[CMD_GLOBAL_CUT]);
      menuStructure->setAccel(shortcuts[SHRT_GLOBAL_INSERT].key, menu_ids[CMD_GLOBAL_INSERT]);
      menuStructure->setAccel(shortcuts[SHRT_GLOBAL_SPLIT].key, menu_ids[CMD_GLOBAL_SPLIT]);
      menuStructure->setAccel(shortcuts[SHRT_COPY_RANGE].key, menu_ids[CMD_COPY_RANGE]);
      menuStructure->setAccel(shortcuts[SHRT_CUT_EVENTS].key, menu_ids[CMD_CUT_EVENTS]);

      menuView->setAccel(shortcuts[SHRT_OPEN_TRANSPORT].key, tr_id);
      menuView->setAccel(shortcuts[SHRT_OPEN_BIGTIME].key, bt_id);
      menuView->setAccel(shortcuts[SHRT_OPEN_MIXER].key, aid1);
//      menuView->setAccel(shortcuts[SHRT_OPEN_CLIPS].key, aid2);
      markerAction->setAccel(shortcuts[SHRT_OPEN_MARKER].key );

      menuSettings->setAccel(shortcuts[SHRT_GLOBAL_CONFIG].key, menu_ids[CMD_GLOBAL_CONFIG]);
      menuSettings->setAccel(shortcuts[SHRT_CONFIG_SHORTCUTS].key, menu_ids[CMD_CONFIG_SHORTCUTS]);
      menuSettings->setAccel(shortcuts[SHRT_CONFIG_METRONOME].key, menu_ids[CMD_CONFIG_METRONOME]);
      menuSettings->setAccel(shortcuts[SHRT_CONFIG_MIDISYNC].key, menu_ids[CMD_CONFIG_MIDISYNC]);
      menuSettings->setAccel(shortcuts[SHRT_APPEARANCE_SETTINGS].key, menu_ids[CMD_APPEARANCE_SETTINGS]);
      menuSettings->setAccel(shortcuts[SHRT_CONFIG_MIDI_PORTS].key, menu_ids[CMD_CONFIG_MIDI_PORTS]);
      menuSettings->setAccel(shortcuts[SHRT_CONFIG_AUDIO_PORTS].key, menu_ids[CMD_CONFIG_AUDIO_PORTS]);

      menu_functions->setAccel(shortcuts[SHRT_MIDI_EDIT_INSTRUMENTS].key, menu_ids[CMD_MIDI_EDIT_INSTRUMENTS]);
      menu_functions->setAccel(shortcuts[SHRT_MIDI_RESET].key, menu_ids[CMD_MIDI_RESET]);
      menu_functions->setAccel(shortcuts[SHRT_MIDI_INIT].key, menu_ids[CMD_MIDI_INIT]);
      menu_functions->setAccel(shortcuts[SHRT_MIDI_LOCAL_OFF].key, menu_ids[CMD_MIDI_LOCAL_OFF]);

      menu_audio->setAccel(shortcuts[SHRT_AUDIO_BOUNCE_TO_TRACK].key, menu_ids[CMD_AUDIO_BOUNCE_TO_TRACK]);
      menu_audio->setAccel(shortcuts[SHRT_AUDIO_BOUNCE_TO_FILE].key , menu_ids[CMD_AUDIO_BOUNCE_TO_FILE]);
      menu_audio->setAccel(shortcuts[SHRT_AUDIO_RESTART].key, menu_ids[CMD_AUDIO_RESTART]);

      menuAutomation->setAccel(shortcuts[SHRT_MIXER_AUTOMATION].key, autoId);
      menuAutomation->setAccel(shortcuts[SHRT_MIXER_SNAPSHOT].key, menu_ids[CMD_MIXER_SNAPSHOT]);
      menuAutomation->setAccel(shortcuts[SHRT_MIXER_AUTOMATION_CLEAR].key, menu_ids[CMD_MIXER_AUTOMATION_CLEAR]);

      menu_help->setAccel(menu_ids[CMD_OPEN_HELP], shortcuts[SHRT_OPEN_HELP].key);
      menu_help->setAccel(menu_ids[CMD_START_WHATSTHIS], shortcuts[SHRT_START_WHATSTHIS].key);
      pianoAction->setAccel(shortcuts[SHRT_OPEN_PIANO].key);

      select->setAccel(shortcuts[SHRT_SELECT_ALL].key, CMD_SELECT_ALL);

//      select->setAccel(shortcuts[SHRT_DESEL_PARTS].key, CMD_SELECT_NONE);
      select->setAccel(shortcuts[SHRT_SELECT_NONE].key, CMD_SELECT_NONE);

      select->setAccel(shortcuts[SHRT_SELECT_INVERT].key, CMD_SELECT_INVERT);
      select->setAccel(shortcuts[SHRT_SELECT_ILOOP].key, CMD_SELECT_ILOOP);
      select->setAccel(shortcuts[SHRT_SELECT_OLOOP].key, CMD_SELECT_OLOOP);
      select->setAccel(shortcuts[SHRT_SELECT_PRTSTRACK].key, CMD_SELECT_PARTS);
      follow->setAccel(shortcuts[SHRT_FOLLOW_JUMP].key, CMD_FOLLOW_JUMP);
      follow->setAccel(shortcuts[SHRT_FOLLOW_NO].key, CMD_FOLLOW_NO);
      follow->setAccel(shortcuts[SHRT_FOLLOW_CONTINUOUS].key, CMD_FOLLOW_CONTINUOUS);
      midiInputPlugins->setAccel(shortcuts[SHRT_MIDI_INPUT_TRANSPOSE].key, 0);
      midiInputPlugins->setAccel(shortcuts[SHRT_MIDI_INPUT_TRANSFORM].key, 1);
      midiInputPlugins->setAccel(shortcuts[SHRT_MIDI_INPUT_FILTER].key, 2);
      midiInputPlugins->setAccel(shortcuts[SHRT_MIDI_REMOTE_CONTROL].key, 3);
      midiInputPlugins->setAccel(shortcuts[SHRT_RANDOM_RHYTHM_GENERATOR].key, 4);

      addTrack->setAccel(shortcuts[SHRT_ADD_MIDI_TRACK].key, Track::MIDI);
      addTrack->setAccel(shortcuts[SHRT_ADD_DRUM_TRACK].key, Track::DRUM);
      addTrack->setAccel(shortcuts[SHRT_ADD_WAVE_TRACK].key, Track::WAVE);
      addTrack->setAccel(shortcuts[SHRT_ADD_AUDIO_OUTPUT].key, Track::AUDIO_OUTPUT);
      addTrack->setAccel(shortcuts[SHRT_ADD_AUDIO_GROUP].key, Track::AUDIO_GROUP);
      addTrack->setAccel(shortcuts[SHRT_ADD_AUDIO_INPUT].key, Track::AUDIO_INPUT);
      addTrack->setAccel(shortcuts[SHRT_ADD_AUDIO_AUX].key, Track::AUDIO_AUX);
      }

//---------------------------------------------------------
//   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, unsigned, bool)), bigtime, SLOT(setPos(int, unsigned, 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);
      menuView->setItemChecked(bt_id, on);
      }

//---------------------------------------------------------
//   toggleBigTime
//---------------------------------------------------------

void MusE::toggleBigTime()
      {
      showBigtime(!menuView->isItemChecked(bt_id));
      }

//---------------------------------------------------------
//   bigtimeClosed
//---------------------------------------------------------

void MusE::bigtimeClosed()
      {
      menuView->setItemChecked(bt_id, false);
      }

//---------------------------------------------------------
//   showMixer
//---------------------------------------------------------

void MusE::showMixer(bool on)
      {
      if (on && audioMixer == 0) {
            audioMixer = new AudioMixerApp(this);
            connect(audioMixer, SIGNAL(closed()), SLOT(mixerClosed()));
            audioMixer->resize(config.geometryMixer.size());
            audioMixer->move(config.geometryMixer.topLeft());
            }
      if (audioMixer)
            audioMixer->setShown(on);
      menuView->setItemChecked(aid1, on);
      }

//---------------------------------------------------------
//   toggleMixer
//---------------------------------------------------------

void MusE::toggleMixer()
      {
      showMixer(!menuView->isItemChecked(aid1));
      }

//---------------------------------------------------------
//   mixerClosed
//---------------------------------------------------------

void MusE::mixerClosed()
      {
      menuView->setItemChecked(aid1, false);
      }

QWidget* MusE::mixerWindow()     { return audioMixer; }
QWidget* MusE::transportWindow() { return transport; }
QWidget* MusE::bigtimeWindow()   { return bigtime; }

//---------------------------------------------------------
//   focusInEvent
//---------------------------------------------------------

void MusE::focusInEvent(QFocusEvent* ev)
      {
      if (audioMixer)
            audioMixer->raise();
      raise();
      QMainWindow::focusInEvent(ev);
      }

//---------------------------------------------------------
//   setUsedTool
//---------------------------------------------------------

void MusE::setUsedTool(int tool)
      {
      tools1->set(tool);
      }


