diff options
| author | Florian Jung <flo@windfisch.org> | 2011-12-14 15:08:02 +0000 | 
|---|---|---|
| committer | Florian Jung <flo@windfisch.org> | 2011-12-14 15:08:02 +0000 | 
| commit | c36a5508aa42e596b005425208054af9a60734b4 (patch) | |
| tree | fde0504e0c25b8f39ed6f5f7f7332943e4a95c7f /muse2/muse | |
| parent | 42126f3b398802eb24c8d9acd2591ef4dbe7257d (diff) | |
pulled fixes from release into trunk
Diffstat (limited to 'muse2/muse')
103 files changed, 4275 insertions, 2448 deletions
| diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index bd6bc560..148f3072 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -4,6 +4,7 @@  //  $Id: app.cpp,v 1.113.2.68 2009/12/21 14:51:51 spamatica Exp $  //  //  (C) Copyright 1999-2011 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -33,6 +34,8 @@  #include <QProgressDialog>  #include <QMdiArea>  #include <QMdiSubWindow> +#include <QSocketNotifier>   +#include <QString>  #include <iostream> @@ -55,6 +58,7 @@  #include "filedialog.h"  #include "gconfig.h"  #include "gui.h" +#include "helper.h"  #include "icons.h"  #include "instruments/editinstrument.h"  #include "listedit.h" @@ -84,8 +88,11 @@ extern void exitJackAudio();  extern void exitDummyAudio();  extern void exitOSC();  extern void exitMidiAlsa(); -} +extern void initMidiSequencer();    +extern void initAudio();            +extern void initAudioPrefetch();    +}  namespace MusEGui { @@ -94,12 +101,12 @@ namespace MusEGui {  static pthread_t watchdogThread;  //ErrorHandler *error; -  #define PROJECT_LIST_LEN  6  static QString* projectList[PROJECT_LIST_LEN];  #ifdef HAVE_LASH  #include <lash/lash.h> +#include <lo/lo_osc_types.h>  lash_client_t * lash_client = 0;  extern snd_seq_t * alsaSeq;  #endif /* HAVE_LASH */ @@ -171,14 +178,7 @@ bool MusE::seqStart()        if(MusEGlobal::realTimeScheduling)         {          { -          //pfprio = MusEGlobal::realTimePriority - 5; -          // p3.3.40            pfprio = MusEGlobal::realTimePriority + 1; -           -          //midiprio = MusEGlobal::realTimePriority - 2; -          // p3.3.37 -          //midiprio = MusEGlobal::realTimePriority + 1; -          // p3.3.40            midiprio = MusEGlobal::realTimePriority + 2;          }          } @@ -198,9 +198,6 @@ bool MusE::seqStart()        MusEGlobal::audioPrefetch->msgSeek(0, true); // force -      //MusEGlobal::midiSeqRunning = !midiSeq->start(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0); -      // Changed by Tim. p3.3.22 -      //MusEGlobal::midiSeq->start(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0);        MusEGlobal::midiSeq->start(midiprio);        int counter=0; @@ -224,7 +221,7 @@ bool MusE::seqStart()        }          return true;        } - +        //---------------------------------------------------------  //   stop  //--------------------------------------------------------- @@ -258,6 +255,7 @@ bool MusE::seqRestart()                  }            seqStop();            } +      if(!seqStart())          return false; @@ -299,7 +297,7 @@ void addProject(const QString& name)  //---------------------------------------------------------  //MusE::MusE(int argc, char** argv) : QMainWindow(0, "mainwindow") -MusE::MusE(int argc, char** argv) : QMainWindow() +MusE::MusE(int /*argc*/, char** /*argv*/) : QMainWindow()        {        // By T356. For LADSPA plugins in plugin.cpp        // QWidgetFactory::addWidgetFactory( new PluginWidgetFactory ); ddskrjo @@ -333,6 +331,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow()        progress              = 0;        activeTopWin          = NULL;        currentMenuSharingTopwin = NULL; +      waitingForTopwin      = NULL;        appName               = QString("MusE");        setWindowTitle(appName); @@ -346,8 +345,6 @@ MusE::MusE(int argc, char** argv) : QMainWindow()        MusEGlobal::heartBeatTimer = new QTimer(this);        MusEGlobal::heartBeatTimer->setObjectName("timer");        connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), MusEGlobal::song, SLOT(beat())); -       -              connect(this, SIGNAL(activeTopWinChanged(MusEGui::TopWin*)), SLOT(activeTopWinChangedSlot(MusEGui::TopWin*)));  #ifdef ENABLE_PYTHON @@ -460,7 +457,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow()        MusEGlobal::panicAction->setWhatsThis(tr("send note off to all midi channels"));        connect(MusEGlobal::panicAction, SIGNAL(activated()), MusEGlobal::song, SLOT(panic())); -      MusECore::initMidiInstruments(); +      MusECore::initMidiInstruments();          MusECore::initMidiPorts();        MusECore::initMidiDevices(); @@ -706,7 +703,7 @@ MusE::MusE(int argc, char** argv) : QMainWindow()        //rlimit lim;        //getrlimit(RLIMIT_RTPRIO, &lim);        //printf("RLIMIT_RTPRIO soft:%d hard:%d\n", lim.rlim_cur, lim.rlim_max);    // Reported 80, 80 even with non-RT kernel. -       +        if (MusEGlobal::realTimePriority < sched_get_priority_min(SCHED_FIFO))              MusEGlobal::realTimePriority = sched_get_priority_min(SCHED_FIFO);        else if (MusEGlobal::realTimePriority > sched_get_priority_max(SCHED_FIFO)) @@ -721,18 +718,19 @@ MusE::MusE(int argc, char** argv) : QMainWindow()              MusEGlobal::midiRTPrioOverride = sched_get_priority_max(SCHED_FIFO);        } -      // Changed by Tim. p3.3.17 -      //MusEGlobal::midiSeq       = new MusECore::MidiSeq(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0, "Midi"); -      MusEGlobal::midiSeq       = new MusECore::MidiSeq("Midi"); -      MusEGlobal::audio = new MusECore::Audio(); -      //MusEGlobal::audioPrefetch = new MusECore::AudioPrefetch(0, "Disc"); -      MusEGlobal::audioPrefetch = new MusECore::AudioPrefetch("Prefetch"); - +      MusECore::initMidiSequencer();    +      MusECore::initAudio();            +       +      // Moved here from Audio::Audio +      QSocketNotifier* ss = new QSocketNotifier(MusEGlobal::audio->getFromThreadFdr(), QSocketNotifier::Read, this);  +      connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int)));   +       +      MusECore::initAudioPrefetch();    +              //---------------------------------------------------        //    Popups        //--------------------------------------------------- -        // when adding a menu to the main window, remember adding it to        // either the leadingMenus or trailingMenus list!        // also do NOT use menuBar()->addMenu(QString&), but ALWAYS @@ -961,6 +959,11 @@ MusE::MusE(int argc, char** argv) : QMainWindow()        transport = new MusEGui::Transport(this, "transport");        bigtime   = 0; +      MusEGlobal::song->blockSignals(false); +       +      // Load start song moved to main.cpp     p4.0.41 REMOVE Tim. +      /* +              //---------------------------------------------------        //  load project        //    if no songname entered on command line: @@ -975,7 +978,8 @@ MusE::MusE(int argc, char** argv) : QMainWindow()              name = argv[0];        else if (MusEGlobal::config.startMode == 0) {              if (argc < 2) -                  name = projectList[0] ? *projectList[0] : QString("untitled"); +                  //name = projectList[0] ? *projectList[0] : QString("untitled"); +                  name = projectList[0] ? *projectList[0] : MusEGui::getUniqueUntitledName();  // p4.0.40              else                    name = argv[0];              printf("starting with selected song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); @@ -989,19 +993,47 @@ MusE::MusE(int argc, char** argv) : QMainWindow()              printf("starting with pre configured song %s\n", MusEGlobal::config.startSong.toLatin1().constData());              name = MusEGlobal::config.startSong;        } -      MusEGlobal::song->blockSignals(false); -      loadProjectFile(name, useTemplate, true); - +       +      // loadProjectFile(name, useTemplate, true);  //commented out by flo: see below (*) +      */ +              changeConfig(false);        QSettings settings("MusE", "MusE-qt");        restoreGeometry(settings.value("MusE/geometry").toByteArray());        //restoreState(settings.value("MusE/windowState").toByteArray()); -      MusEGlobal::song->update(); -       -      updateWindowMenu(); +      MusEGlobal::song->update(); // commented out by flo: will be done by the below (*) +      updateWindowMenu();         // same here + +      // Load start song moved to main.cpp     p4.0.41 REMOVE Tim. +      /* + +      // this is (*). +      // this is a really hackish workaround for the loading-on-startup problem. +      // i have absolutely no idea WHY it breaks when using loadProjectFile() +      // above, but it does on my machine (it doesn't on others!). +      // the problem can be worked around by delaying loading the song file. +      // i use hackishSongOpenTimer for this, which calls after 10ms a slot +      // which then does the actual loadProjectFile() call. +      // FIXME: please, if anyone finds the real problem, FIX it and +      //        remove that dirty, dirty workaround! +      hackishSongOpenFilename=name; +      hackishSongOpenUseTemplate=useTemplate; +      hackishSongOpenTimer=new QTimer(this); +      hackishSongOpenTimer->setInterval(10); +      hackishSongOpenTimer->setSingleShot(true); +      connect(hackishSongOpenTimer, SIGNAL(timeout()), this, SLOT(hackishSongOpenTimerTimeout())); +      hackishSongOpenTimer->start(); +      */        } +// Load start song moved to main.cpp     p4.0.41 REMOVE Tim. +//void MusE::hackishSongOpenTimerTimeout() +//{ +  ///loadProjectFile(hackishSongOpenFilename, hackishSongOpenUseTemplate, true);    +  //loadProjectFile(hackishSongOpenFilename, hackishSongOpenUseTemplate, !hackishSongOpenUseTemplate);    +//} +  MusE::~MusE()  {  } @@ -1015,6 +1047,44 @@ void MusE::setHeartBeat()        MusEGlobal::heartBeatTimer->start(1000/MusEGlobal::config.guiRefresh);        } +//--------------------------------------------------- +//  loadDefaultSong +//    if no songname entered on command line: +//    startMode: 0  - load last song +//               1  - load default template +//               2  - load configured start song +//--------------------------------------------------- + +void MusE::loadDefaultSong(int argc, char** argv) +{ +  QString name; +  bool useTemplate = false; +  if (argc >= 2) +        name = argv[0]; +  else if (MusEGlobal::config.startMode == 0) { +        if (argc < 2) +              //name = projectList[0] ? *projectList[0] : QString("untitled"); +              name = projectList[0] ? *projectList[0] : MusEGui::getUniqueUntitledName();  // p4.0.40 +        else +              name = argv[0]; +        printf("starting with selected song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); +        } +  else if (MusEGlobal::config.startMode == 1) { +        printf("starting with default template\n"); +        name = MusEGlobal::museGlobalShare + QString("/templates/default.med"); +        useTemplate = true; +        } +  else if (MusEGlobal::config.startMode == 2) { +        printf("starting with pre configured song %s\n", MusEGlobal::config.startSong.toLatin1().constData()); +        name = MusEGlobal::config.startSong; +  } +  //loadProjectFile(name, useTemplate, true);   +  loadProjectFile(name, useTemplate, !useTemplate);   +   +  //MusEGlobal::song->update();  +  //updateWindowMenu();          +} +        //---------------------------------------------------------  //   resetDevices  //--------------------------------------------------------- @@ -1156,7 +1226,8 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll                    QApplication::restoreOverrideCursor();                    return;                    } -            project.setFile("untitled"); +            //project.setFile("untitled"); +            project.setFile(MusEGui::getUniqueUntitledName());  // p4.0.40              MusEGlobal::museProject = MusEGlobal::museProjectInitPath;              }        else { @@ -1214,7 +1285,8 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll              }        if (!songTemplate) {              addProject(project.absoluteFilePath()); -            setWindowTitle(QString("MusE: Song: ") + project.completeBaseName()); +            //setWindowTitle(QString("MusE: Song: ") + project.completeBaseName()); +            setWindowTitle(QString("MusE: Song: ") + MusEGui::projectTitleFromFilename(project.absoluteFilePath()));              }        MusEGlobal::song->dirty = false;        progress->setValue(30); @@ -1236,7 +1308,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll              //  set the geometry if the mixer has already been created.              if(mixer1)              { -              //if(mixer1->geometry().size() != MusEGlobal::config.mixer1.geometry.size())   // p3.3.53 Moved below +              //if(mixer1->geometry().size() != MusEGlobal::config.mixer1.geometry.size())   // Moved below                //  mixer1->resize(MusEGlobal::config.mixer1.geometry.size());                if(mixer1->geometry().topLeft() != MusEGlobal::config.mixer1.geometry.topLeft()) @@ -1244,7 +1316,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll              }              if(mixer2)              { -              //if(mixer2->geometry().size() != MusEGlobal::config.mixer2.geometry.size())   // p3.3.53 Moved below +              //if(mixer2->geometry().size() != MusEGlobal::config.mixer2.geometry.size())   // Moved below                //  mixer2->resize(MusEGlobal::config.mixer2.geometry.size());                if(mixer2->geometry().topLeft() != MusEGlobal::config.mixer2.geometry.topLeft()) @@ -1273,7 +1345,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll        arrangerView->scoreNamingChanged(); // inform the score menus about the new scores and their names        progress->setValue(50); -      // p3.3.53 Try this AFTER the song update above which does a mixer update... Tested OK - mixers resize properly now. +      // Try this AFTER the song update above which does a mixer update... Tested OK - mixers resize properly now.        if (loadAll)         {          if(mixer1) @@ -1336,10 +1408,13 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll  void MusE::setUntitledProject()        {        setConfigDefaults(); -      QString name("untitled"); +      //QString name("untitled"); +      QString name(MusEGui::getUniqueUntitledName());  // p4.0.40 +        MusEGlobal::museProject = "./"; //QFileInfo(name).absolutePath();        project.setFile(name); -      setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +      //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +      setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(name)));        }  //--------------------------------------------------------- @@ -1391,14 +1466,14 @@ void MusE::loadTemplate()        if (!fn.isEmpty()) {              // MusEGlobal::museProject = QFileInfo(fn).absolutePath(); -            loadProjectFile(fn, true, true); +            //loadProjectFile(fn, true, true);              // With templates, don't clear midi ports.               // Any named ports in the template file are useless since they likely               //  would not be found on other users' machines.              // So keep whatever the user currently has set up for ports.                // Note that this will also keep the current window configurations etc.              //  but actually that's also probably a good thing. p4.0.17 Tim.  TESTING: Maybe some problems... -            //loadProjectFile(fn, true, false); +            loadProjectFile(fn, true, false);              setUntitledProject();              } @@ -1410,7 +1485,11 @@ void MusE::loadTemplate()  bool MusE::save()        { -      if (project.completeBaseName() == "untitled") +      //if (project.completeBaseName() == "untitled")    // p4.0.40 Must catch "untitled 1" "untitled 2" etc   +      //if (MusEGui::projectTitleFromFilename(project.absoluteFilePath()) == "untitled")                       +      //if (MusEGui::projectTitleFromFilename(project.absoluteFilePath()) == MusEGui::getUniqueUntitledName())   +      ///if (project.absoluteFilePath() == MusEGui::getUniqueUntitledName())   +      if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath )                return saveAs();        else              return save(project.filePath(), false); @@ -1542,7 +1621,7 @@ void MusE::closeEvent(QCloseEvent* event)        MusECore::exitMetronome();        // Make sure to delete the menu. ~routingPopupMenu() will NOT be called automatically. -      // Even though it is a child of MusE, it just passes MusE onto the underlying PopupMenus. p4.0.26 +      // Even though it is a child of MusE, it just passes MusE onto the underlying PopupMenus.         if(routingPopupMenu)          delete routingPopupMenu;             #if 0 @@ -1572,7 +1651,7 @@ void MusE::closeEvent(QCloseEvent* event)              }  #ifdef HAVE_LASH -      // Disconnect gracefully from LASH. Tim. p3.3.14 +      // Disconnect gracefully from LASH.         if(lash_client)        {          if(MusEGlobal::debugMsg) @@ -1590,7 +1669,6 @@ void MusE::closeEvent(QCloseEvent* event)          printf("MusE: Exiting OSC\n");        MusECore::exitOSC(); -      // p3.3.47        delete MusEGlobal::audioPrefetch;        delete MusEGlobal::audio;        delete MusEGlobal::midiSeq; @@ -1619,8 +1697,8 @@ void MusE::showMarker(bool flag)              markerView = new MusEGui::MarkerView(this);              connect(markerView, SIGNAL(closed()), SLOT(markerClosed())); -            toplevels.push_back(markerView);              markerView->show(); +            toplevels.push_back(markerView);              }        markerView->setVisible(flag);        viewMarkerAction->setChecked(flag); @@ -1642,6 +1720,20 @@ void MusE::markerClosed()          setCurrentMenuSharingTopwin(NULL);        updateWindowMenu(); + +      // focus the last activated topwin which is not the marker view +      QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); +      for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) +        if ((*lit)->isVisible() && (*lit)->widget() != markerView) +        { +          if (MusEGlobal::debugMsg) +            printf("bringing '%s' to front instead of closed arranger window\n",(*lit)->widget()->windowTitle().toAscii().data()); + +          bringToFront((*lit)->widget()); + +          break;  +        } +              }  //--------------------------------------------------------- @@ -1675,6 +1767,20 @@ void MusE::arrangerClosed()        {        viewArrangerAction->setChecked(false);        updateWindowMenu(); + +      // focus the last activated topwin which is not the arranger view +      QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); +      for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) +        if ((*lit)->isVisible() && (*lit)->widget() != arrangerView) +        { +          if (MusEGlobal::debugMsg) +            printf("bringing '%s' to front instead of closed arranger window\n",(*lit)->widget()->windowTitle().toAscii().data()); + +          bringToFront((*lit)->widget()); + +          break;  +        } +              }  //--------------------------------------------------------- @@ -1716,7 +1822,7 @@ MusEGui::RoutePopupMenu* MusE::getRoutingPopupMenu()  bool MusE::saveAs()        {        QString name; -      if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath ) { +      //if (MusEGlobal::museProject == MusEGlobal::museProjectInitPath )  // Use project dialog always now.          if (MusEGlobal::config.useProjectSaveDialog) {              MusEGui::ProjectCreateImpl pci(MusEGlobal::muse);              if (pci.exec() == QDialog::Rejected) { @@ -1737,10 +1843,11 @@ bool MusE::saveAs()            QMessageBox::warning(this,"Path error","Can't create project path", QMessageBox::Ok);            return false;          } -      } -      else { -        name = MusEGui::getSaveFileName(QString(""), MusEGlobal::med_file_save_pattern, this, tr("MusE: Save As")); -      } +      //} +      //else { +      //  name = MusEGui::getSaveFileName(QString(""), MusEGlobal::med_file_save_pattern, this, tr("MusE: Save As")); +      //} +              bool ok = false;        if (!name.isEmpty()) {              QString tempOldProj = MusEGlobal::museProject; @@ -1748,7 +1855,8 @@ bool MusE::saveAs()              ok = save(name, true);              if (ok) {                    project.setFile(name); -                  setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +                  //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +                  setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(name)));                    addProject(name);                    }              else @@ -1830,8 +1938,8 @@ void MusE::openInScoreEdit(MusEGui::ScoreEdit* destination, MusECore::PartList*  	if (destination==NULL) // if no destination given, create a new one  	{        destination = new MusEGui::ScoreEdit(this, 0, _arranger->cursorValue()); -      destination->show();        toplevels.push_back(destination); +      destination->show();        connect(destination, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        connect(destination, SIGNAL(name_changed()), arrangerView, SLOT(scoreNamingChanged()));        //connect(muse, SIGNAL(configChanged()), destination, SLOT(config_changed())); @@ -1866,10 +1974,10 @@ void MusE::startPianoroll(MusECore::PartList* pl, bool showDefaultCtrls)        {        MusEGui::PianoRoll* pianoroll = new MusEGui::PianoRoll(pl, this, 0, _arranger->cursorValue()); -      if(showDefaultCtrls)       // p4.0.12 +      if(showDefaultCtrls)                 pianoroll->addCtrl(); -      pianoroll->show();        toplevels.push_back(pianoroll); +      pianoroll->show();        connect(pianoroll, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        connect(MusEGlobal::muse, SIGNAL(configChanged()), pianoroll, SLOT(configChanged()));        updateWindowMenu(); @@ -1890,8 +1998,8 @@ void MusE::startListEditor()  void MusE::startListEditor(MusECore::PartList* pl)        {        MusEGui::ListEdit* listEditor = new MusEGui::ListEdit(pl); -      listEditor->show();        toplevels.push_back(listEditor); +      listEditor->show();        connect(listEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        connect(MusEGlobal::muse,SIGNAL(configChanged()), listEditor, SLOT(configChanged()));        updateWindowMenu(); @@ -1904,8 +2012,8 @@ void MusE::startListEditor(MusECore::PartList* pl)  void MusE::startMasterEditor()        {        MusEGui::MasterEdit* masterEditor = new MusEGui::MasterEdit(); -      masterEditor->show();        toplevels.push_back(masterEditor); +      masterEditor->show();        connect(masterEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        updateWindowMenu();        } @@ -1917,8 +2025,8 @@ void MusE::startMasterEditor()  void MusE::startLMasterEditor()        {        MusEGui::LMaster* lmaster = new MusEGui::LMaster(); -      lmaster->show();        toplevels.push_back(lmaster); +      lmaster->show();        connect(lmaster, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        connect(MusEGlobal::muse, SIGNAL(configChanged()), lmaster, SLOT(configChanged()));        updateWindowMenu(); @@ -1939,10 +2047,10 @@ void MusE::startDrumEditor()  void MusE::startDrumEditor(MusECore::PartList* pl, bool showDefaultCtrls)        {        MusEGui::DrumEdit* drumEditor = new MusEGui::DrumEdit(pl, this, 0, _arranger->cursorValue()); -      if(showDefaultCtrls)       // p4.0.12 +      if(showDefaultCtrls)                 drumEditor->addCtrl(); -      drumEditor->show();        toplevels.push_back(drumEditor); +      drumEditor->show();        connect(drumEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        connect(MusEGlobal::muse, SIGNAL(configChanged()), drumEditor, SLOT(configChanged()));        updateWindowMenu(); @@ -1966,8 +2074,8 @@ void MusE::startWaveEditor(MusECore::PartList* pl)        {        MusEGui::WaveEdit* waveEditor = new MusEGui::WaveEdit(pl);        waveEditor->show(); -      connect(MusEGlobal::muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged()));        toplevels.push_back(waveEditor); +      connect(MusEGlobal::muse, SIGNAL(configChanged()), waveEditor, SLOT(configChanged()));        connect(waveEditor, SIGNAL(isDeleting(MusEGui::TopWin*)), SLOT(toplevelDeleting(MusEGui::TopWin*)));        updateWindowMenu();        } @@ -2088,6 +2196,19 @@ void MusE::toplevelDeleting(MusEGui::TopWin* tl)                    {                      activeTopWin=NULL;                      emit activeTopWinChanged(NULL); + +                    // focus the last activated topwin which is not the deleting one +                    QList<QMdiSubWindow*> l = mdiArea->subWindowList(QMdiArea::StackingOrder); +                    for (QList<QMdiSubWindow*>::iterator lit=l.begin(); lit!=l.end(); lit++) +                      if ((*lit)->isVisible() && (*lit)->widget() != tl) +                      { +                        if (MusEGlobal::debugMsg) +                          printf("bringing '%s' to front instead of closed window\n",(*lit)->widget()->windowTitle().toAscii().data()); + +                        bringToFront((*lit)->widget()); + +                        break;  +                      }                    }                    if (tl == currentMenuSharingTopwin) @@ -2168,7 +2289,7 @@ void MusE::kbAccel(int key)              MusEGlobal::song->setPlay(true);              } -      // p4.0.10 Tim. Normally each editor window handles these, to inc by the editor's raster snap value. +      // Normally each editor window handles these, to inc by the editor's raster snap value.        // But users were asking for a global version - "they don't work when I'm in mixer or transport".        // Since no editor claimed the key event, we don't know a specific editor's snap setting,        //  so adopt a policy where the arranger is the 'main' raster reference, I guess... @@ -2649,7 +2770,8 @@ MusE::lash_idle_cb ()            int ok = save (ss.toAscii(), false);            if (ok) {              project.setFile(ss.toAscii()); -            setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +            //setWindowTitle(tr("MusE: Song: %1").arg(project.completeBaseName())); +            setWindowTitle(tr("MusE: Song: %1").arg(MusEGui::projectTitleFromFilename(project.absoluteFilePath())));              addProject(ss.toAscii());              MusEGlobal::museProject = QFileInfo(ss.toAscii()).absolutePath();            } @@ -3071,21 +3193,32 @@ void MusE::focusChanged(QWidget*, QWidget* now)    if (currentMenuSharingTopwin && (currentMenuSharingTopwin!=activeTopWin))      currentMenuSharingTopwin->storeInitialState(); - +  // if the activated widget is a QMdiSubWindow containing some TopWin +  if ( (dynamic_cast<QMdiSubWindow*>(ptr)!=0) && +       (dynamic_cast<MusEGui::TopWin*>( ((QMdiSubWindow*)ptr)->widget() )!=0) ) +  { +    waitingForTopwin=(MusEGui::TopWin*) ((QMdiSubWindow*)ptr)->widget(); +    return; +  }    while (ptr)    { +    if (MusEGlobal::heavyDebugMsg)   +      printf("focusChanged: at widget %p with type %s\n",ptr, typeid(*ptr).name()); +          if ( (dynamic_cast<MusEGui::TopWin*>(ptr)!=0) || // *ptr is a TopWin or a derived class           (ptr==this) )                      // the main window is selected        break;      ptr=dynamic_cast<QWidget*>(ptr->parent()); //in the unlikely case that ptr is a QObject, this returns NULL, which stops the loop    } +  MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(ptr);    // ptr is either NULL, this or the pointer to a TopWin -  if (ptr!=this) // if the main win is selected, don't treat that as "none", but also don't handle it +   +  // if the main win or some deleting topwin is selected, +  // don't treat that as "none", but also don't handle it +  if (ptr!=this && (!win || !win->deleting()) )    { -    MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(ptr); -          // now 'win' is either NULL or the pointer to the active TopWin      if (win!=activeTopWin)      { @@ -3233,6 +3366,26 @@ void MusE::shareMenuAndToolbarChanged(MusEGui::TopWin* win, bool val)    }  } +void MusE::topwinMenuInited(MusEGui::TopWin* topwin) +{ +  if (topwin==NULL) +    return; +     +  if (topwin == waitingForTopwin) +  { +    if (waitingForTopwin->deleting()) +    { +      waitingForTopwin=NULL; +    } +    else +    { +      activeTopWin=waitingForTopwin; +      waitingForTopwin=NULL; +      emit activeTopWinChanged(activeTopWin); +    } +  } +} +  void MusE::updateWindowMenu()  {    bool sep; @@ -3286,6 +3439,8 @@ void MusE::updateWindowMenu()  void MusE::bringToFront(QWidget* widget)  {    MusEGui::TopWin* win=dynamic_cast<MusEGui::TopWin*>(widget); +  if (!win) return; +      if (win->isMdiWin())    {      win->show(); @@ -3449,4 +3604,19 @@ void MusE::tileSubWindows()    }  } +QString MusE::projectTitle() const +{  +  return MusEGui::projectTitleFromFilename(project.fileName()); +} + +QString MusE::projectPath() const  +{  +  return MusEGui::projectPathFromFilename(project.absoluteFilePath());  +} + +QString MusE::projectExtension() const +{ +  return MusEGui::projectExtensionFromFilename(project.fileName());  +} +  } //namespace MusEGui diff --git a/muse2/muse/app.h b/muse2/muse/app.h index 27722e9a..184581dc 100644 --- a/muse2/muse/app.h +++ b/muse2/muse/app.h @@ -43,6 +43,7 @@ class QToolBar;  class QToolButton;  class QProgressDialog;  class QMdiArea; +class QTimer;  namespace MusECore {  class AudioOutput; @@ -91,7 +92,7 @@ class TopWin;  class Transport;  class VisibleTracks; -#define MENU_ADD_SYNTH_ID_BASE 0x1000 +#define MENU_ADD_SYNTH_ID_BASE 0x8000  //--------------------------------------------------------- @@ -128,6 +129,7 @@ class MusE : public QMainWindow        TopWin* activeTopWin;        TopWin* currentMenuSharingTopwin; +      TopWin* waitingForTopwin;        std::list<QToolBar*> requiredToolbars; //always displayed        std::list<QToolBar*> optionalToolbars; //only displayed when no toolbar-sharing window is active @@ -213,6 +215,10 @@ class MusE : public QMainWindow        MidiTransformerDialog* midiTransformerDialog;        QMenu* openRecent; +      //QTimer* hackishSongOpenTimer; +      //QString hackishSongOpenFilename; +      //bool hackishSongOpenUseTemplate; +        bool readMidi(FILE*);        void read(MusECore::Xml& xml, bool skipConfig, bool isTemplate);        void processTrack(MusECore::MidiTrack* track); @@ -327,6 +333,8 @@ class MusE : public QMainWindow        void arrangeSubWindowsColumns();        void tileSubWindows(); +      //void hackishSongOpenTimerTimeout(); +           public slots:        bool saveAs();        void bounceToFile(MusECore::AudioOutput* ao = 0); @@ -371,12 +379,14 @@ class MusE : public QMainWindow        void addMdiSubWindow(QMdiSubWindow*);        void shareMenuAndToolbarChanged(MusEGui::TopWin*, bool); +      void topwinMenuInited(MusEGui::TopWin*);        void updateWindowMenu();     public:        MusE(int argc, char** argv);        ~MusE(); +      void loadDefaultSong(int argc, char** argv);        Arranger* arranger() const { return _arranger; }        QRect configGeometryMain;        QProgressDialog *progress; @@ -384,10 +394,13 @@ class MusE : public QMainWindow        void kbAccel(int);        void changeConfig(bool writeFlag);        void seqStop(); -      bool seqStart(); +      bool seqStart();          void setHeartBeat();        void importController(int, MusECore::MidiPort*, int);        QString projectName() { return project.fileName(); } +      QString projectTitle() const; +      QString projectPath() const; +      QString projectExtension() const;        QWidget* mixer1Window();        QWidget* mixer2Window();        QWidget* transportWindow(); diff --git a/muse2/muse/arranger/alayout.cpp b/muse2/muse/arranger/alayout.cpp index a892356c..119da498 100644 --- a/muse2/muse/arranger/alayout.cpp +++ b/muse2/muse/arranger/alayout.cpp @@ -117,7 +117,7 @@ void TLLayout::setGeometry(const QRect &rect)        QSize s1 = li[1]->sizeHint();        QSize s2 = li[2]->sizeHint(); -      QSize s3 = li[3]->sizeHint(); +      //QSize s3 = li[3]->sizeHint();        QSize s4 = li[4]->sizeHint();        QSize s5 = li[5]->sizeHint(); diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp index ae753378..cb024070 100644 --- a/muse2/muse/arranger/arranger.cpp +++ b/muse2/muse/arranger/arranger.cpp @@ -569,27 +569,40 @@ void Arranger::songChanged(int type)        // Is it simply a midi controller value adjustment? Forget it.        if(type != SC_MIDI_CONTROLLER)        { -        unsigned endTick = MusEGlobal::song->len(); -        int offset  = AL::sigmap.ticksMeasure(endTick); -        hscroll->setRange(-offset, endTick + offset);  //DEBUG -        canvas->setOrigin(-offset, 0); -        time->setOrigin(-offset, 0); -   -        int bar, beat; -        unsigned tick; -        AL::sigmap.tickValues(endTick, &bar, &beat, &tick); -        if (tick || beat) -              ++bar; -        lenEntry->blockSignals(true); -        lenEntry->setValue(bar); -        lenEntry->blockSignals(false); -   -        if(type & SC_SONG_TYPE)    // p4.0.7 Tim. +        // TEST p4.0.36 Try these, may need more/less.  +        if(type & ( SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |  +           SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED))   +        { +          unsigned endTick = MusEGlobal::song->len(); +          int offset  = AL::sigmap.ticksMeasure(endTick); +          hscroll->setRange(-offset, endTick + offset);  //DEBUG +          canvas->setOrigin(-offset, 0); +          time->setOrigin(-offset, 0); +     +          int bar, beat; +          unsigned tick; +          AL::sigmap.tickValues(endTick, &bar, &beat, &tick); +          if (tick || beat) +                ++bar; +          lenEntry->blockSignals(true); +          lenEntry->setValue(bar); +          lenEntry->blockSignals(false); +        } +         +        if(type & SC_SONG_TYPE)                setMode(MusEGlobal::song->mtype()); -        trackSelectionChanged(); -        canvas->partsChanged(); -        typeBox->setCurrentIndex(int(MusEGlobal::song->mtype())); +        if(type & SC_SELECTION)       // TEST p4.0.36 Try this alone, may need more. +          trackSelectionChanged(); +         +        // Keep this light, partsChanged is a heavy move!       TEST p4.0.36 Try these, may need more. +        if(type & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |  +                   SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED |  +                   SC_SIG | SC_TEMPO)) // Maybe sig. Requires tempo. +          canvas->partsChanged(); +         +        //typeBox->setCurrentIndex(int(MusEGlobal::song->mtype()));  // REMOVE Tim.  Redundant. +                  if (type & SC_SIG)                time->redraw();          if (type & SC_TEMPO) @@ -616,6 +629,14 @@ void Arranger::songChanged(int type)              }               }           } +         +        // TEST p4.0.36 Try this +        if(type & ( //SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED |  +           SC_PART_INSERTED | SC_PART_REMOVED | SC_PART_MODIFIED |  +           SC_EVENT_INSERTED | SC_EVENT_REMOVED | SC_EVENT_MODIFIED)) //| +           //SC_SIG | SC_TEMPO))  // Maybe sig. and tempo. No, moved above. +        canvas->redraw(); +                }        updateTrackInfo(type); diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp index 3b726845..52be5194 100644 --- a/muse2/muse/arranger/arrangerview.cpp +++ b/muse2/muse/arranger/arrangerview.cpp @@ -37,7 +37,7 @@  #include <QMessageBox>  #include <QMimeData>  #include <QPushButton> -#include <QResizeEvent> +//#include <QResizeEvent>  #include <QScrollArea>  #include <QScrollBar>  #include <QSettings> @@ -129,6 +129,7 @@ ArrangerView::ArrangerView(QWidget* parent)    connect(muse, SIGNAL(configChanged()), arranger, SLOT(configChanged()));    connect(arranger, SIGNAL(setUsedTool(int)), editTools, SLOT(set(int)));    connect(arranger, SIGNAL(selectionChanged()), SLOT(selectionChanged())); +  connect(MusEGlobal::song, SIGNAL(songChanged(int)), visTracks, SLOT(updateVisibleTracksButtons())); @@ -167,8 +168,8 @@ ArrangerView::ArrangerView(QWidget* parent)    scoreSubmenu = new QMenu(tr("Score"), this);    scoreSubmenu->setIcon(QIcon(*scoreIconSet)); -  scoreAllInOneSubsubmenu = new QMenu(tr("all parts in one staff"), this); -  scoreOneStaffPerTrackSubsubmenu = new QMenu(tr("one staff per part"), this); +  scoreAllInOneSubsubmenu = new QMenu(tr("all tracks in one staff"), this); +  scoreOneStaffPerTrackSubsubmenu = new QMenu(tr("one staff per track"), this);    scoreSubmenu->addMenu(scoreAllInOneSubsubmenu);    scoreSubmenu->addMenu(scoreOneStaffPerTrackSubsubmenu); @@ -193,6 +194,10 @@ ArrangerView::ArrangerView(QWidget* parent)    strGlobalInsertAction = new QAction(tr("Global Insert"), this);    strGlobalSplitAction = new QAction(tr("Global Split"), this); +  strGlobalCutSelAction = new QAction(tr("Global Cut - selected tracks"), this); +  strGlobalInsertSelAction = new QAction(tr("Global Insert - selected tracks"), this); +  strGlobalSplitSelAction = new QAction(tr("Global Split - selected tracks"), this); +    //------------------------------------------------------------- @@ -246,7 +251,11 @@ ArrangerView::ArrangerView(QWidget* parent)      menuStructure->addAction(strGlobalCutAction);      menuStructure->addAction(strGlobalInsertAction);      menuStructure->addAction(strGlobalSplitAction); -   +    menuStructure->addSeparator(); +    menuStructure->addAction(strGlobalCutSelAction); +    menuStructure->addAction(strGlobalInsertSelAction); +    menuStructure->addAction(strGlobalSplitSelAction); +    QMenu* functions_menu = menuBar()->addMenu(tr("Functions")); @@ -341,6 +350,9 @@ ArrangerView::ArrangerView(QWidget* parent)    connect(strGlobalCutAction, SIGNAL(activated()), SLOT(globalCut()));    connect(strGlobalInsertAction, SIGNAL(activated()), SLOT(globalInsert()));    connect(strGlobalSplitAction, SIGNAL(activated()), SLOT(globalSplit())); +  connect(strGlobalCutSelAction, SIGNAL(activated()), SLOT(globalCutSel())); +  connect(strGlobalInsertSelAction, SIGNAL(activated()), SLOT(globalInsertSel())); +  connect(strGlobalSplitSelAction, SIGNAL(activated()), SLOT(globalSplitSel())); @@ -351,7 +363,7 @@ ArrangerView::ArrangerView(QWidget* parent)    connect(cb, SIGNAL(dataChanged()), SLOT(clipboardChanged()));    connect(cb, SIGNAL(selectionChanged()), SLOT(clipboardChanged())); - +  MusEGlobal::muse->topwinMenuInited(this);    // work around for probable QT/WM interaction bug.    // for certain window managers, e.g xfce, this window is @@ -368,7 +380,7 @@ ArrangerView::~ArrangerView()  void ArrangerView::closeEvent(QCloseEvent* e)  { -  emit deleted(static_cast<TopWin*>(this)); +  emit isDeleting(static_cast<TopWin*>(this));    emit closed();    e->accept();  } @@ -729,4 +741,9 @@ void ArrangerView::globalCut() { MusECore::globalCut(); }  void ArrangerView::globalInsert() { MusECore::globalInsert(); }  void ArrangerView::globalSplit() { MusECore::globalSplit(); } +// variants only applicable for selected tracks +void ArrangerView::globalCutSel() { MusECore::globalCut(true); } +void ArrangerView::globalInsertSel() { MusECore::globalInsert(true); } +void ArrangerView::globalSplitSel() { MusECore::globalSplit(true); } +  } // namespace MusEGui diff --git a/muse2/muse/arranger/arrangerview.h b/muse2/muse/arranger/arrangerview.h index de610bd6..c56767a6 100644 --- a/muse2/muse/arranger/arrangerview.h +++ b/muse2/muse/arranger/arrangerview.h @@ -89,7 +89,8 @@ class ArrangerView : public TopWin  		QMenu* master;  		QAction *strGlobalCutAction, *strGlobalInsertAction, *strGlobalSplitAction; -		QAction *trackMidiAction, *trackDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction; +    QAction *strGlobalCutSelAction, *strGlobalInsertSelAction, *strGlobalSplitSelAction; +    QAction *trackMidiAction, *trackDrumAction, *trackWaveAction, *trackAOutputAction, *trackAGroupAction;  		QAction *trackAInputAction, *trackAAuxAction;  		QAction *editCutAction, *editCopyAction, *editCopyRangeAction;  		QAction *editPasteAction, *editPasteCloneAction, *editPasteDialogAction, *editPasteCloneDialogAction; @@ -119,11 +120,14 @@ class ArrangerView : public TopWin  		void globalCut();  		void globalInsert();  		void globalSplit(); -		void cmd(int); +    void globalCutSel(); +    void globalInsertSel(); +    void globalSplitSel(); +    void cmd(int);                  void addNewTrack(QAction* action);  	signals: -		void deleted(MusEGui::TopWin*); +		void isDeleting(MusEGui::TopWin*);  		void closed();  	public slots: diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp index d19fa082..f190de3b 100644 --- a/muse2/muse/arranger/pcanvas.cpp +++ b/muse2/muse/arranger/pcanvas.cpp @@ -3,7 +3,7 @@  //  Linux Music Editor  //    $Id: pcanvas.cpp,v 1.48.2.26 2009/11/22 11:08:33 spamatica Exp $  //  (C) Copyright 1999 Werner Schweer (ws@seh.de) -//  (C) Copyright 2011 Tim E. Real (terminator356 on users DOT sourceforge DOT net) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -302,12 +302,9 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp      QPoint newpos = raster(QPoint(nx, ny));      selectItem(ci, true); -    MusECore::UndoOp operation=moveItem(ci, newpos, dtype); -    if (operation.type != MusECore::UndoOp::DoNothing) -    { +    bool result=moveItem(operations, ci, newpos, dtype); +    if (result)      	ci->move(newpos); -      operations.push_back(operation); -    }      if(moving.size() == 1) {            itemReleased(curItem, newpos); @@ -326,37 +323,41 @@ void PartCanvas::moveCanvasItems(CItemList& items, int dp, int dx, DragType dtyp  //---------------------------------------------------------  // Changed by T356. -MusECore::UndoOp PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragType t) +bool PartCanvas::moveItem(MusECore::Undo& operations, CItem* item, const QPoint& newpos, DragType t)        { -      MusECore::UndoOp result;        NPart* npart    = (NPart*) item;        MusECore::Part* spart     = npart->part();        MusECore::Track* track    = npart->track(); +      MusECore::Track* dtrack=NULL;        unsigned dtick  = newpos.x();        unsigned ntrack = y2pitch(item->mp().y());        MusECore::Track::TrackType type = track->type();        if (tracks->index(track) == ntrack && (dtick == spart->tick())) { -            return MusECore::UndoOp(MusECore::UndoOp::DoNothing); +            return false;              }        if (ntrack >= tracks->size()) {              ntrack = tracks->size();              if (MusEGlobal::debugMsg)                  printf("PartCanvas::moveItem - add new track\n"); -            MusECore::Track* newTrack = MusEGlobal::song->addTrack(type);  // Add at end of list. +            dtrack = MusEGlobal::song->addTrack(operations, type);  // Add at end of list. +              if (type == MusECore::Track::WAVE) {                    MusECore::WaveTrack* st = (MusECore::WaveTrack*) track; -                  MusECore::WaveTrack* dt = (MusECore::WaveTrack*) newTrack; +                  MusECore::WaveTrack* dt = (MusECore::WaveTrack*) dtrack;                    dt->setChannels(st->channels());                    }              emit tracklistChanged();              } -      MusECore::Track* dtrack = tracks->index(ntrack); -      if (dtrack->type() != type) { -            QMessageBox::critical(this, QString("MusE"), -               tr("Cannot copy/move/clone to different Track-Type")); -            return MusECore::UndoOp(MusECore::UndoOp::DoNothing); +      else +      {       +            dtrack = tracks->index(ntrack); +            if (dtrack->type() != type) { +                  QMessageBox::critical(this, QString("MusE"), +                     tr("Cannot copy/move/clone to different Track-Type")); +                  return false; +                  }              } - +              MusECore::Part* dpart;        bool clone = (t == MOVE_CLONE || (t == MOVE_COPY && spart->events()->arefCount() > 1)); @@ -397,22 +398,24 @@ MusECore::UndoOp PartCanvas::moveItem(CItem* item, const QPoint& newpos, DragTyp        if (t == MOVE_COPY || t == MOVE_CLONE) {              // These will not increment ref count, and will not chain clones...               // TODO FINDMICH: is this still correct (by flo93)? i doubt it! -            result=MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart); +            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::AddPart,dpart));              }        else if (t == MOVE_MOVE) {              dpart->setSelected(spart->selected());              // These will increment ref count if not a clone, and will chain clones...              // TODO FINDMICH: is this still correct (by flo93)? i doubt it! -            result=MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false); +            operations.push_back(MusECore::UndoOp(MusECore::UndoOp::ModifyPart,spart, dpart, true, false));              spart->setSelected(false);              } -      // else // will never happen -> result will always be defined +      // else // will never happen -> operations will never be empty        if (MusEGlobal::song->len() < (dpart->lenTick() + dpart->tick())) -            MusEGlobal::song->setLen(dpart->lenTick() + dpart->tick()); - -      return result; +            operations.push_back(  MusECore::UndoOp(MusECore::UndoOp::ModifySongLen,  +                                                    dpart->lenTick() + dpart->tick(), +                                                    MusEGlobal::song->len() )  ); +       +      return true;        }  //--------------------------------------------------------- @@ -883,8 +886,8 @@ void PartCanvas::mousePress(QMouseEvent* event)              default:                    if (item)                        emit trackChanged(item->part()->track()); -                  else -                      emit trackChanged(NULL); +                  //else -- don't see the point of removing track selection, commenting out (rj) +                  //    emit trackChanged(NULL);                    break;              case CutTool:                    if (item) splitItem(item, pt); @@ -1193,7 +1196,7 @@ void PartCanvas::keyPress(QKeyEvent* event)              //If we're at topmost, leave              if (!track) { -              printf("no track above!\n"); +              //printf("no track above!\n");                    return;                  }              int middle = curItem->x() + curItem->part()->lenTick()/2; @@ -1327,17 +1330,25 @@ void PartCanvas::keyPress(QKeyEvent* event)              curItem = newItem;              selectItem(newItem, true); -            //Check if we've hit the upper or lower boundaries of the window. If so, set a new position +            //Check if we've hit the left, right, upper or lower boundaries of the window. If so, scroll to new position.              if (newItem->x() < mapxDev(0)) { -                  int curpos = pos[0]; -                  setPos(0,newItem->x(),true); -                  setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled +                  emit horizontalScroll(rmapx(newItem->x() - xorg) - 10);  // Leave some room. +                  } +            else if (newItem->x() + newItem->width() > mapxDev(width())) { +                  int mx = rmapx(newItem->x()); +                  int newx = mx + rmapx(newItem->width()) - width(); +                  emit horizontalScroll( (newx > mx ? mx - 10 : newx + 10) - rmapx(xorg) ); +                  } +                   +            if (newItem->y() < mapyDev(0)) { +                  int my = rmapy(newItem->y()); +                  int newy = my + rmapy(newItem->height()) - height(); +                  emit verticalScroll( (newy < my ? my - 10 : newy + 10) - rmapy(yorg) );                    } -            else if (newItem->x() > mapxDev(width())) { -                  int curpos = pos[0]; -                  setPos(0,newItem->x(),true); -                  setPos(0,curpos,false); //Dummy to put the current position back once we've scrolled +            else if (newItem->y() + newItem->height() > mapyDev(height())) { +                  emit verticalScroll( rmapy(newItem->y() + newItem->height() - yorg) - height() + 10);                    } +                                redraw();              }        } @@ -2299,9 +2310,9 @@ void PartCanvas::drawMidiPart(QPainter& p, const QRect&, MusECore::EventList* ev      //else      //  color_brightness=64;  // otherwise use dark color       if (brightness >= 12000 && !pt->selected()) -      color_brightness=64; // 96;    // too bright: use dark color  +      color_brightness=54; // 96;    // too bright: use dark color      else -      color_brightness=190; //160;   // too dark: use lighter color  +      color_brightness=200; //160;   // too dark: use lighter color    }    else      color_brightness=80; @@ -3207,9 +3218,13 @@ void PartCanvas::viewDropEvent(QDropEvent* event)                  if (!track) { // we need to create a track for this drop                      if (text.endsWith(".mpt", Qt::CaseInsensitive)) { -                        track = MusEGlobal::song->addTrack(MusECore::Track::MIDI);    // Add at end of list. +                        MusECore::Undo operations; +                        track = MusEGlobal::song->addTrack(operations, MusECore::Track::MIDI);    // Add at end of list. +                        MusEGlobal::song->applyOperationGroup(operations);                      } else { -                        track = MusEGlobal::song->addTrack(MusECore::Track::WAVE);    // Add at end of list. +                        MusECore::Undo operations; +                        track = MusEGlobal::song->addTrack(operations, MusECore::Track::WAVE);    // Add at end of list. +                        MusEGlobal::song->applyOperationGroup(operations);                      }                  }                  if (track->type() == MusECore::Track::WAVE && @@ -3634,7 +3649,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, MusECore::AudioTra        {          double y;             if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume -          y = dbToVal(cl->curVal()); // represent volume between 0 and 1 +          //printf("log conversion val=%f min=%f max=%f\n", cl->curVal(), min, max); +          y = logToVal(cl->curVal(), min, max); // represent volume between 0 and 1            if (y < 0) y = 0.0;          }          else  @@ -3647,7 +3663,8 @@ void PartCanvas::drawAutomation(QPainter& p, const QRect& rr, MusECore::AudioTra          {              double y = ic->second.val;               if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume -              y = dbToVal(y); // represent volume between 0 and 1 +              //printf("log conversion val=%f min=%f max=%f\n", cl->curVal(), min, max); +              y = logToVal(y, min, max); // represent volume between 0 and 1                if (y < 0) y = 0.0;              }              else  @@ -3746,7 +3763,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo          {            double y;               if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume -            y = dbToVal(cl->curVal()); // represent volume between 0 and 1 +            y = logToVal(cl->curVal(), min, max); // represent volume between 0 and 1              if (y < 0) y = 0.0;            }            else  @@ -3759,7 +3776,7 @@ void PartCanvas::checkAutomation(MusECore::Track * t, const QPoint &pointer, boo            {               double y = ic->second.val;               if (cl->valueType() == MusECore::VAL_LOG ) { // use db scale for volume -                y = dbToVal(y); // represent volume between 0 and 1 +                y = logToVal(y, min, max); // represent volume between 0 and 1                 if (y < 0) y = 0;               }               else  @@ -3951,7 +3968,8 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint)      automation.currentCtrlList->range(&min,&max);      double cvval;          if (automation.currentCtrlList->valueType() == MusECore::VAL_LOG  ) { // use db scale for volume -       cvval = valToDb(yfraction); +       printf("log conversion val=%f min=%f max=%f\n", yfraction, min, max); +       cvval = valToLog(yfraction, min, max);         //printf("calc yfraction = %f v=%f ",yfraction,cvval);         if (cvval< min) cvval=min;         if (cvval>max) cvval=max; @@ -3984,13 +4002,45 @@ void PartCanvas::processAutomationMovements(QPoint pos, bool addPoint)  } -double PartCanvas::dbToVal(double inDb) +//--------------------------------------------------------- +// +//  logToVal +//   - represent logarithmic value on linear scale from 0 to 1 +// +//--------------------------------------------------------- +double PartCanvas::logToVal(double inLog, double min, double max)  { -    return (20.0*MusECore::fast_log10(inDb)+60.0) / 70.0; +    //printf("logToVal inLog %f :", inLog); +    if (inLog < min) inLog = min; +    if (inLog > max) inLog = max; +    double linMin = 20.0*MusECore::fast_log10(min); +    double linMax = 20.0*MusECore::fast_log10(max); +    double linVal = 20.0*MusECore::fast_log10(inLog); + +    double outVal = (linVal-linMin) / (linMax - linMin); +    // printf("inLog %f outVal %f linVal %f min %f max %f dbMin %f dbMax %f\n", inLog, outVal, linVal, min, max, linMin, linMax); + +    return outVal;  } -double PartCanvas::valToDb(double inV) + +//--------------------------------------------------------- +// +//  valToLog +//   - represent value from 0 to 1 as logarithmic value between min and max +// +//--------------------------------------------------------- +double PartCanvas::valToLog(double inV, double min, double max)  { -    return exp10((inV*70.0-60.0)/20.0); +    double linMin = 20.0*MusECore::fast_log10(min); +    double linMax = 20.0*MusECore::fast_log10(max); + +    double linVal = (inV * (linMax - linMin)) + linMin; +    double outVal = exp10((linVal)/20.0); + +    //printf("::valToLog inV %f outVal %f linVal %f min %f max %f\n", inV, outVal, linVal, min, max); +    if (outVal > max) outVal = max; +    if (outVal < min) outVal = min; +    return outVal;  }  //--------------------------------------------------------- diff --git a/muse2/muse/arranger/pcanvas.h b/muse2/muse/arranger/pcanvas.h index 78b88a5c..34395688 100644 --- a/muse2/muse/arranger/pcanvas.h +++ b/muse2/muse/arranger/pcanvas.h @@ -119,7 +119,7 @@ class PartCanvas : public Canvas {        virtual void newItem(CItem*,bool);        virtual bool deleteItem(CItem*);        virtual void moveCanvasItems(CItemList&, int, int, DragType); -      virtual MusECore::UndoOp moveItem(CItem*, const QPoint&, DragType); +      virtual bool moveItem(MusECore::Undo& operations, CItem*, const QPoint&, DragType);        virtual void updateSong(DragType, int);        virtual void startDrag(CItem*, DragType); @@ -148,8 +148,8 @@ class PartCanvas : public Canvas {        void checkAutomation(MusECore::Track * t, const QPoint& pointer, bool addNewCtrl);        void processAutomationMovements(QPoint pos, bool addPoint); -      double dbToVal(double inDb); -      double valToDb(double inV); +      double logToVal(double inLog, double min, double max); +      double valToLog(double inV, double min, double max);     protected:        virtual void drawCanvas(QPainter&, const QRect&); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index 1e3ad419..620a24b7 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -62,6 +62,7 @@  #include "synth.h"  #include "config.h"  #include "popupmenu.h" +#include "menutitleitem.h"  #ifdef DSSI_SUPPORT  #include "dssihost.h" @@ -392,7 +393,7 @@ void TList::paint(const QRect& r)                                              countVisible++;                                      }                                      //int count = ((MusECore::AudioTrack*)track)->controller()->size(); //commented out by flo: gives a "unused variable" warning -                                    s.sprintf(" %d(%d) visible",countVisible, countAll); +                                    s.sprintf(" %d(%d) %s",countVisible, countAll, tr("visible").toAscii().data());                                      } @@ -584,12 +585,17 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y)        switch(t->type()) {              case MusECore::Track::MIDI:              case MusECore::Track::DRUM: +            // FINDMICHJETZT: this is a notice for flo's experimental +            //                branch! don't forget NEW_DRUM here! +            //                please don't remove this. i'll do it when +            //                the time is there.              case MusECore::Track::AUDIO_SOFTSYNTH:               {                    MusECore::MidiTrack* track = (MusECore::MidiTrack*)t;                    //QPopupMenu* p = MusECore::midiPortsPopup(0);                    MusECore::MidiDevice* md = 0; +                  int potential_new_port_no=-1;                    int port = -1;                     if(t->type() == MusECore::Track::AUDIO_SOFTSYNTH)                     { @@ -602,25 +608,158 @@ void TList::portsPopupMenu(MusECore::Track* t, int x, int y)                      port = track->outPort();                    QMenu* p = MusECore::midiPortsPopup(this, port);     // 0, port); +                   +                  if (t->type()==MusECore::Track::MIDI || t->type()==MusECore::Track::DRUM) //FINDMICHJETZT +                  { +                    // extend that menu a bit + + +                    // find first free port number +                    // do not permit numbers already used in other tracks! +                    // except if it's only used in this track. +                    int no; +                    for (no=0;no<MIDI_PORTS;no++) +                      if (MusEGlobal::midiPorts[no].device()==NULL) +                      { +                        MusECore::ciTrack it; +                        for (it=MusEGlobal::song->tracks()->begin(); it!=MusEGlobal::song->tracks()->end(); it++) +                        { +                          MusECore::MidiTrack* mt=dynamic_cast<MusECore::MidiTrack*>(*it); +                          if (mt && mt!=t && mt->outPort()==no) +                            break; +                        } +                        if (it == MusEGlobal::song->tracks()->end()) +                          break; +                      } +                   +                    if (no==MIDI_PORTS) +                    { +                      delete p; +                      printf("THIS IS VERY UNLIKELY TO HAPPEN: no free midi ports! you have used all %i!\n",MIDI_PORTS); +                      break; +                    } +                     +                     +                    potential_new_port_no=no; +                    typedef std::map<std::string, int > asmap; +                    typedef std::map<std::string, int >::iterator imap; +                     +                    asmap mapALSA; +                    asmap mapJACK; +                     +                    int aix = 0x10000000; +                    int jix = 0x20000000; +                    for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  +                    { +                      if((*i)->deviceType() == MusECore::MidiDevice::ALSA_MIDI) +                      { +                        // don't add devices which are used somewhere +                        int j; +                        for (j=0;j<MIDI_PORTS;j++) +                          if (MusEGlobal::midiPorts[j].device() == *i) +                            break; +                             +                        if (j==MIDI_PORTS) mapALSA.insert( std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), aix) ); +                         +                        ++aix; +                      }   +                      else if((*i)->deviceType() == MusECore::MidiDevice::JACK_MIDI) +                      { +                        // don't add devices which are used somewhere +                        int j; +                        for (j=0;j<MIDI_PORTS;j++) +                          if (MusEGlobal::midiPorts[j].device() == *i) +                            break; + +                        if (j==MIDI_PORTS) mapJACK.insert( std::pair<std::string, int> (std::string((*i)->name().toLatin1().constData()), jix) ); +                        ++jix; +                      } +                    } + +                    if (!mapALSA.empty() || !mapJACK.empty()) +                    { +                      QMenu* pup = p->addMenu(tr("Unused Devices")); +                      QAction* act; +                       +                       +                      if (!mapALSA.empty()) +                      { +                        pup->addAction(new MusEGui::MenuTitleItem("ALSA:", pup)); +                         +                        for(imap i = mapALSA.begin(); i != mapALSA.end(); ++i)  +                        { +                          int idx = i->second; +                          QString s(i->first.c_str()); +                          MusECore::MidiDevice* md = MusEGlobal::midiDevices.find(s, MusECore::MidiDevice::ALSA_MIDI); +                          if(md) +                          { +                            if(md->deviceType() != MusECore::MidiDevice::ALSA_MIDI)   +                              continue; +                               +                            act = pup->addAction(md->name()); +                            act->setData(idx); +                          }   +                        } +                      } +                       +                      if (!mapALSA.empty() && !mapJACK.empty()) +                        pup->addSeparator(); +                       +                      if (!mapJACK.empty()) +                      { +                        pup->addAction(new MusEGui::MenuTitleItem("JACK:", pup)); +                         +                        for(imap i = mapJACK.begin(); i != mapJACK.end(); ++i)  +                        { +                          int idx = i->second; +                          QString s(i->first.c_str()); +                          MusECore::MidiDevice* md = MusEGlobal::midiDevices.find(s, MusECore::MidiDevice::JACK_MIDI); +                          if(md) +                          { +                            if(md->deviceType() != MusECore::MidiDevice::JACK_MIDI)   +                              continue; +                               +                            act = pup->addAction(md->name()); +                            act->setData(idx); +                          }   +                        } +                      } +                    } +                  } +                   +                                      QAction* act = p->exec(mapToGlobal(QPoint(x, y)), 0);                    if(!act)                     {                      delete p;                      break;                    }   -                     +                   +                  QString acttext=act->text();                    int n = act->data().toInt();                    delete p;                    if(n < 0)              // Invalid item.                      break; -                  if(n >= MIDI_PORTS)    // Show port config dialog. +                  if(n == MIDI_PORTS)    // Show port config dialog.                    {                      MusEGlobal::muse->configMidiPorts();                      break;                    } +                  else if (n & 0x30000000) +                  { +                    int typ; +                    if (n & 0x10000000) +                      typ = MusECore::MidiDevice::ALSA_MIDI; +                    else +                      typ = MusECore::MidiDevice::JACK_MIDI; +                    MusECore::MidiDevice* sdev = MusEGlobal::midiDevices.find(acttext, typ); + +                    MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[potential_new_port_no], sdev); +                    n=potential_new_port_no; +                  }                    // Changed by T356.                    //track->setOutPort(n);                    //MusEGlobal::audio->msgSetTrackOutPort(track, n); @@ -1049,7 +1188,7 @@ void TList::mousePressEvent(QMouseEvent* ev)                    if(act)                    {                      t = MusEGlobal::song->addNewTrack(act);  // Add at end of list. -                    if(t) +                    if(t && t->isVisible())                      {                        MusEGlobal::song->deselectTracks();                        t->setSelected(true); @@ -1064,13 +1203,13 @@ void TList::mousePressEvent(QMouseEvent* ev)                    //delete synp;                    delete p;              } -            else if (button == Qt::LeftButton) { +            /*else if (button == Qt::LeftButton) {                if (!ctrl)                 {                  MusEGlobal::song->deselectTracks();                  emit selectionChanged(0);                }   -            } +            }*/              return;              } @@ -1108,7 +1247,8 @@ void TList::mousePressEvent(QMouseEvent* ev)              return;              } -      mode = START_DRAG; + +      mode = NORMAL;        switch (col) {                case COL_CLEF: @@ -1137,8 +1277,8 @@ void TList::mousePressEvent(QMouseEvent* ev)                    }                    delete p;                  } -                  break; +                                case COL_AUTOMATION:                  {                  if (!t->isMidiTrack()) { @@ -1174,6 +1314,8 @@ void TList::mousePressEvent(QMouseEvent* ev)              case COL_RECORD:                    { +                      mode = START_DRAG; +                                              bool val = !(t->recordFlag());                        if (button == Qt::LeftButton) {                          if (!t->isMidiTrack()) { @@ -1212,6 +1354,7 @@ void TList::mousePressEvent(QMouseEvent* ev)                    }                    break;              case COL_NONE: +                  mode = START_DRAG;                    break;              case COL_CLASS:                    if (t->isMidiTrack()) @@ -1232,9 +1375,10 @@ void TList::mousePressEvent(QMouseEvent* ev)                    //MusEGlobal::audio->msgUpdateSoloStates(); // p4.0.14                    //MusEGlobal::song->update(SC_ROUTE);       // -                                      break; +                                case COL_MUTE: +                  mode = START_DRAG;                    // p3.3.29                    if ((button == Qt::RightButton) || (((QInputEvent*)ev)->modifiers() & Qt::ShiftModifier))                      t->setOff(!t->off()); @@ -1248,11 +1392,13 @@ void TList::mousePressEvent(QMouseEvent* ev)                    MusEGlobal::song->update(SC_MUTE);                    break;              case COL_SOLO: +                  mode = START_DRAG;                    MusEGlobal::audio->msgSetSolo(t, !t->solo());                    MusEGlobal::song->update(SC_SOLO);                    break;              case COL_NAME: +                  mode = START_DRAG;                    if (button == Qt::LeftButton) {                          if (!ctrl) {                                MusEGlobal::song->deselectTracks(); @@ -1327,11 +1473,13 @@ void TList::mousePressEvent(QMouseEvent* ev)                    break;              case COL_TIMELOCK: +                  mode = START_DRAG;                    t->setLocked(!t->locked());                    break;              case COL_OCHANNEL:                    { +                    mode = START_DRAG; // or not? (flo)                      int delta = 0;                      if (button == Qt::RightButton)                         delta = 1; @@ -1397,6 +1545,9 @@ void TList::mousePressEvent(QMouseEvent* ev)                      }                          }                    break; +             +            default: +                  mode = START_DRAG;            }                redraw();        } diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp index fd90c2c2..0b1574cc 100644 --- a/muse2/muse/audio.cpp +++ b/muse2/muse/audio.cpp @@ -25,8 +25,6 @@  #include <cmath>  #include <errno.h> -#include <QSocketNotifier> -  #include "app.h"  #include "song.h"  #include "node.h" @@ -51,10 +49,18 @@  namespace MusEGlobal {  MusECore::Audio* audio;  MusECore::AudioDevice* audioDevice;   // current audio device in use -extern unsigned int volatile midiExtSyncTicks;   // p3.3.25 +extern unsigned int volatile midiExtSyncTicks;     }  namespace MusECore { +   +   +void initAudio()    +{ +      MusEGlobal::audio = new Audio(); +} + +    extern double curTime();  //static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; @@ -166,8 +172,11 @@ Audio::Audio()              exit(-1);              }        sigFd = filedes[1]; -      QSocketNotifier* ss = new QSocketNotifier(filedes[0], QSocketNotifier::Read); -      MusEGlobal::song->connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int))); +      sigFdr = filedes[0]; + +      // Moved to MusE::MusE +      //QSocketNotifier* ss = new QSocketNotifier(filedes[0], QSocketNotifier::Read); +      //MusEGlobal::song->connect(ss, SIGNAL(activated(int)), MusEGlobal::song, SLOT(seqSignal(int)));        }  //--------------------------------------------------------- @@ -182,7 +191,9 @@ bool Audio::start()        //process(MusEGlobal::segmentSize);   // warm up caches        state = STOP;        _loopCount = 0; -      MusEGlobal::muse->setHeartBeat(); +       +      MusEGlobal::muse->setHeartBeat();   +              if (MusEGlobal::audioDevice) {            //_running = true;            //MusEGlobal::audioDevice->start(); @@ -221,9 +232,11 @@ bool Audio::start()        // shall we really stop JACK transport and locate to        // saved position? -      MusEGlobal::audioDevice->stopTransport(); +      MusEGlobal::audioDevice->stopTransport();   +              //MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos().frame()); -      MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos()); +      MusEGlobal::audioDevice->seekTransport(MusEGlobal::song->cPos());    +              return true;        } @@ -531,6 +544,26 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)        // Pre-process the metronome.        ((AudioTrack*)metronome)->preProcessAlways(); +      // Process Aux tracks first. +      for(ciTrack it = tl->begin(); it != tl->end(); ++it)  +      { +        if((*it)->isMidiTrack()) +          continue; +        track = (AudioTrack*)(*it); +        if(!track->processed() && track->type() == Track::AUDIO_AUX) +        { +          //printf("Audio::process1 Do aux: track:%s\n", track->name().toLatin1().constData());   +          channels = track->channels(); +          // Just a dummy buffer. +          float* buffer[channels]; +          float data[frames * channels]; +          for (int i = 0; i < channels; ++i) +                buffer[i] = data + i * frames; +          //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1()); +          track->copyData(samplePos, channels, -1, -1, frames, buffer); +        } +      }       +              OutputList* ol = MusEGlobal::song->outputs();        for (ciAudioOutput i = ol->begin(); i != ol->end(); ++i)           (*i)->process(samplePos, offset, frames); @@ -548,8 +581,11 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)          track = (AudioTrack*)(*it);          // Ignore unprocessed tracks which have an output route, because they will be processed by           //  whatever track(s) they are routed to. -        if(!track->processed() && track->noOutRoute() && (track->type() != Track::AUDIO_OUTPUT)) +        //if(!track->processed() && track->noOutRoute() && (track->type() != Track::AUDIO_OUTPUT)) +        // No, do all. +        if(!track->processed() && (track->type() != Track::AUDIO_OUTPUT))          { +          //printf("Audio::process1 track:%s\n", track->name().toLatin1().constData());             channels = track->channels();            // Just a dummy buffer.            float* buffer[channels]; diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h index 8d89be78..3c4eb17d 100644 --- a/muse2/muse/audio.h +++ b/muse2/muse/audio.h @@ -166,7 +166,9 @@ class Audio {        int fromThreadFdw, fromThreadFdr;  // message pipe        int sigFd;              // pipe fd for messages to gui - +      //QSocketNotifier* _socketNotifier; +      int sigFdr; +              // record values:        Pos startRecordPos;        Pos endRecordPos; @@ -189,8 +191,12 @@ class Audio {     public:        Audio(); -      virtual ~Audio() {} +      virtual ~Audio() { }  +      // Access to message pipe (like from gui namespace), otherwise audio would need to depend on gui. +      int getFromThreadFdw() { return sigFd; }  +      int getFromThreadFdr() { return sigFdr; }   +              void process(unsigned frames);        bool sync(int state, unsigned frame);        void shutdown(); diff --git a/muse2/muse/audioprefetch.cpp b/muse2/muse/audioprefetch.cpp index 9406911f..1fcb7cef 100644 --- a/muse2/muse/audioprefetch.cpp +++ b/muse2/muse/audioprefetch.cpp @@ -39,7 +39,11 @@ MusECore::AudioPrefetch* audioPrefetch;  namespace MusECore { -// Added by Tim. p3.3.20 +void initAudioPrefetch()   +{ +  MusEGlobal::audioPrefetch = new AudioPrefetch("Prefetch"); +} +  //#define AUDIOPREFETCH_DEBUG  enum { PREFETCH_TICK, PREFETCH_SEEK @@ -140,6 +144,7 @@ void AudioPrefetch::msgTick()        {        PrefetchMsg msg;        msg.id  = PREFETCH_TICK; +      msg.pos = 0; // seems to be unused, was uninitalized.        while (sendMsg1(&msg, sizeof(msg))) {              printf("AudioPrefetch::msgTick(): send failed!\n");              } diff --git a/muse2/muse/audiotrack.cpp b/muse2/muse/audiotrack.cpp index b674e20c..aceacc75 100644 --- a/muse2/muse/audiotrack.cpp +++ b/muse2/muse/audiotrack.cpp @@ -107,7 +107,7 @@ AudioTrack::AudioTrack(TrackType t)        _automationType = AUTO_OFF;        //setChannels(1);        setChannels(2); -      addController(new CtrlList(AC_VOLUME,"Volume",0.0,3.16 /* roughly 10 db */, VAL_LOG)); +      addController(new CtrlList(AC_VOLUME,"Volume",0.001,3.163 /* roughly 10 db */, VAL_LOG));        addController(new CtrlList(AC_PAN, "Pan", -1.0, 1.0, VAL_LINEAR));        addController(new CtrlList(AC_MUTE,"Mute",0.0,1.0, VAL_LINEAR, true /*dont show in arranger */)); @@ -1610,8 +1610,40 @@ void AudioAux::read(Xml& xml)  //   getData  //--------------------------------------------------------- -bool AudioAux::getData(unsigned /*pos*/, int ch, unsigned /*samples*/, float** data) +bool AudioAux::getData(unsigned pos, int ch, unsigned samples, float** data)        { +      // Make sure all the aux-supporting tracks are processed first so aux data is gathered.    p4.0.37 +      TrackList* tl = MusEGlobal::song->tracks(); +      AudioTrack* track; +      for(ciTrack it = tl->begin(); it != tl->end(); ++it)  +      { +        if((*it)->isMidiTrack()) +          continue; +        track = (AudioTrack*)(*it); +        // If there are any Aux route paths to the track, defer processing until the second main track processing pass.   +        if(!track->processed() && track->hasAuxSend() && !track->auxRefCount()) +        { +          int chans = track->channels(); +          // Just a dummy buffer. +          float* buff[chans]; +          float buff_data[samples * chans]; +          for (int i = 0; i < chans; ++i) +                buff[i] = buff_data + i * samples; +           +          //printf("AudioAux::getData name:%s\n    calling copyData on:%s auxRefCount:%d\n",  +          //       name().toLatin1().constData(), track->name().toLatin1().constData(), track->auxRefCount());  +           +          track->copyData(pos, chans, -1, -1, samples, buff); +           +          /* float* buff[ch]; +          float buff_data[samples * ch]; +          for (int i = 0; i < ch; ++i) +                buff[i] = buff_data + i * samples; +          //printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1()); +          track->copyData(pos, ch, -1, -1, samples, buff);  */ +        } +      }       +          for (int i = 0; i < ch; ++i)              data[i] = buffer[i % channels()];        return true; diff --git a/muse2/muse/cliplist/cliplist.cpp b/muse2/muse/cliplist/cliplist.cpp index 1055f449..60041dae 100644 --- a/muse2/muse/cliplist/cliplist.cpp +++ b/muse2/muse/cliplist/cliplist.cpp @@ -32,6 +32,7 @@  #include "wave.h"  #include "xml.h"  #include "ui_cliplisteditorbase.h" +#include "app.h"  namespace MusEGui { @@ -168,6 +169,7 @@ ClipListEdit::ClipListEdit(QWidget* parent)        connect(editor->len, SIGNAL(valueChanged(const MusECore::Pos&)), SLOT(lenChanged(const MusECore::Pos&)));        updateList(); +      MusEGlobal::muse->topwinMenuInited(this);        }  ClipListEdit::~ClipListEdit() diff --git a/muse2/muse/cobject.cpp b/muse2/muse/cobject.cpp index 80fc7eae..50586d45 100644 --- a/muse2/muse/cobject.cpp +++ b/muse2/muse/cobject.cpp @@ -50,7 +50,7 @@ bool TopWin::initInited=false;  TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlags f)                   : QMainWindow(parent, f)  { -        _isDeleting = false; +	_isDeleting = false;  	if (initInited==false)  		initConfiguration(); @@ -78,7 +78,10 @@ TopWin::TopWin(ToplevelType t, QWidget* parent, const char* name, Qt::WindowFlag  	mdisubwin=NULL;  	_sharesToolsAndMenu=_defaultSubwin[_type] ? _sharesWhenSubwin[_type] : _sharesWhenFree[_type];  	if (_defaultSubwin[_type]) +	{  		setIsMdiWin(true); +		_savedToolbarState=_toolbarNonsharedInit[_type]; +	}  	if (_sharesToolsAndMenu)  		menuBar()->hide(); @@ -125,7 +128,11 @@ void TopWin::readStatus(MusECore::Xml& xml)  					if (!sharesToolsAndMenu())  					{  						if (!restoreState(QByteArray::fromHex(xml.parse1().toAscii()))) -						 fprintf(stderr,"ERROR: couldn't restore toolbars. however, this is not really a problem.\n"); +						{ +							fprintf(stderr,"ERROR: couldn't restore toolbars. trying default configuration...\n"); +							if (!restoreState(_toolbarNonsharedInit[_type])) +								fprintf(stderr,"ERROR: couldn't restore default toolbars. this is not really a problem.\n"); +						}  					}  					else  					{ @@ -565,4 +572,15 @@ void TopWin::resize(const QSize& s)  	resize(s.width(), s.height());  } +TopWin* ToplevelList::findType(TopWin::ToplevelType type) const +{ +	for (ciToplevel i = begin(); i != end(); ++i)  +	{ +		if((*i)->type() == type)  +			return (*i); +	}   +	return 0; +} + +  } // namespace MusEGui diff --git a/muse2/muse/cobject.h b/muse2/muse/cobject.h index 309d8424..f6ea2ce1 100644 --- a/muse2/muse/cobject.h +++ b/muse2/muse/cobject.h @@ -141,9 +141,21 @@ class TopWin : public QMainWindow        }; -typedef std::list <TopWin*> ToplevelList; -typedef ToplevelList::iterator iToplevel; -typedef ToplevelList::const_iterator ciToplevel; +//--------------------------------------------------------- +//   ToplevelList +//--------------------------------------------------------- + +//typedef std::list <TopWin*> ToplevelList; +//typedef ToplevelList::iterator iToplevel; +//typedef ToplevelList::const_iterator ciToplevel; + +typedef std::list<TopWin*>::iterator iToplevel; +typedef std::list<TopWin*>::const_iterator ciToplevel; + +class ToplevelList : public std::list<TopWin* > { +   public: +        TopWin* findType(TopWin::ToplevelType) const; +      };  } // namespace MusEGui diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp index c11adf7b..ea2b33f3 100644 --- a/muse2/muse/conf.cpp +++ b/muse2/muse/conf.cpp @@ -220,7 +220,7 @@ static void readPortChannel(Xml& xml, int midiPort)  //   readConfigMidiPort  //--------------------------------------------------------- -static void readConfigMidiPort(Xml& xml) +static void readConfigMidiPort(Xml& xml, bool skipConfig)        {        int idx = 0;        QString device; @@ -234,11 +234,9 @@ static void readConfigMidiPort(Xml& xml)        // FIXME: TODO: Make this user-configurable!        QString instrument("GM");  +      int rwFlags = 3;        int openFlags = 1; -      bool thruFlag = false; -      //int dic = 0; -      //int doc = 0; -      int dic = -1;   // p4.0.17 +      int dic = -1;           int doc = -1;        MidiSyncInfo tmpSi; @@ -251,6 +249,19 @@ static void readConfigMidiPort(Xml& xml)              QString tag = xml.s1();              switch (token) {                    case Xml::TagStart: +                         +                        // skipConfig added so it doesn't overwrite midi ports.   p4.0.41 Tim. +                        // Try to keep the controller information. But, this may need to be moved below.   +                        // Also may want to try to keep sync info, but that's a bit risky, so let's not for now. +                        if (tag == "channel") { +                              readPortChannel(xml, idx); +                              break; +                              } +                        else if (skipConfig){ +                              xml.skip(tag); +                              break; +                              } +                                                        if (tag == "name")                                device = xml.parse1();                          else if (tag == "type") @@ -262,6 +273,8 @@ static void readConfigMidiPort(Xml& xml)                                }                          else if (tag == "openFlags")                                openFlags = xml.parseInt(); +                        else if (tag == "rwFlags")             // Jack midi devs need this.   p4.0.41 +                              rwFlags = xml.parseInt();                          else if (tag == "defaultInChans")                                dic = xml.parseInt();                           else if (tag == "defaultOutChans") @@ -270,16 +283,15 @@ static void readConfigMidiPort(Xml& xml)                                tmpSi.read(xml);                          else if (tag == "instrument") {                                instrument = xml.parse1(); -                              // Moved by Tim. -                              //MusEGlobal::midiPorts[idx].setInstrument( +                              //MusEGlobal::midiPorts[idx].setInstrument(    // Moved below                                //   registerMidiInstrument(instrument)                                //   );                                }                          else if (tag == "midithru") -                              thruFlag = xml.parseInt(); // obsolete -                        else if (tag == "channel") { -                              readPortChannel(xml, idx); -                              } +                              xml.parseInt(); // obsolete +                        //else if (tag == "channel") { +                        //      readPortChannel(xml, idx);   // Moved above +                        //      }                          else                                xml.unknown("MidiDevice");                          break; @@ -290,6 +302,10 @@ static void readConfigMidiPort(Xml& xml)                          break;                    case Xml::TagEnd:                          if (tag == "midiport") { +                               +                              if(skipConfig)      // p4.0.41 +                                return; +                                                              //if (idx > MIDI_PORTS) {                                if (idx < 0 || idx >= MIDI_PORTS) {                                      fprintf(stderr, "bad midi port %d (>%d)\n", @@ -305,9 +321,8 @@ static void readConfigMidiPort(Xml& xml)                                if(!dev && type == MidiDevice::JACK_MIDI)                                {                                  if(MusEGlobal::debugMsg) -                                  fprintf(stderr, "readConfigMidiPort: creating jack midi device %s\n", device.toLatin1().constData()); -                                //dev = MidiJackDevice::createJackMidiDevice(device, openFlags); -                                dev = MidiJackDevice::createJackMidiDevice(device);  // p3.3.55 +                                  fprintf(stderr, "readConfigMidiPort: creating jack midi device %s with rwFlags:%d\n", device.toLatin1().constData(), rwFlags); +                                dev = MidiJackDevice::createJackMidiDevice(device, rwFlags);                                  }                                if(MusEGlobal::debugMsg && !dev) @@ -315,7 +330,7 @@ static void readConfigMidiPort(Xml& xml)                                MidiPort* mp = &MusEGlobal::midiPorts[idx]; -                              mp->setInstrument(registerMidiInstrument(instrument));  // By Tim. +                              mp->setInstrument(registerMidiInstrument(instrument));                                  if(dic != -1)                      // p4.0.17 Leave them alone unless set by song.                                  mp->setDefaultInChannels(dic);                                if(doc != -1) @@ -480,7 +495,7 @@ static void loadConfigMetronom(Xml& xml)  //   readSeqConfiguration  //--------------------------------------------------------- -static void readSeqConfiguration(Xml& xml) +static void readSeqConfiguration(Xml& xml, bool skipConfig)        {        for (;;) {              Xml::Token token = xml.parse(); @@ -492,7 +507,7 @@ static void readSeqConfiguration(Xml& xml)                          if (tag == "metronom")                                loadConfigMetronom(xml);                          else if (tag == "midiport") -                              readConfigMidiPort(xml); +                              readConfigMidiPort(xml, skipConfig);                          else if (tag == "rcStop")                                MusEGlobal::rcStopNote = xml.parseInt();                          else if (tag == "rcEnable") @@ -542,7 +557,7 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                             midiport configuration and VOLUME.                          */                          if (tag == "sequencer") { -                              readSeqConfiguration(xml); +                              readSeqConfiguration(xml, readOnlySequencer);                                break;                                }                          else if (readOnlySequencer) { @@ -580,8 +595,10 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                                   MidiTrack::setVisible((bool)xml.parseInt());                          else if (tag == "inputTracksVisible")                                   AudioInput::setVisible((bool)xml.parseInt()); -                        else if (tag == "outputTracksVisible") +                        else if (tag == "outputTracksVisible") { +                                 printf("output track set from config!\n");                                   AudioOutput::setVisible((bool)xml.parseInt()); +                        }                          else if (tag == "synthTracksVisible")                                   SynthI::setVisible((bool)xml.parseInt());                          else if (tag == "bigtimeVisible") @@ -624,7 +641,18 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                                MusEGlobal::config.geometryTransport = readGeometry(xml, tag);                          else if (tag == "geometryBigTime")                                MusEGlobal::config.geometryBigTime = readGeometry(xml, tag); - +                        else if (tag == "Mixer") { +                              if(mixers == 0) +                                MusEGlobal::config.mixer1.read(xml); +                              else   +                                MusEGlobal::config.mixer2.read(xml); +                              ++mixers; +                              } +                        else if (tag == "geometryMain") +                              MusEGlobal::config.geometryMain = readGeometry(xml, tag); +                               +                        // don't insert else if(...) clauses between +                        // this line and "Global config stuff begins here".                          else if (!doReadGlobalConfig) {                                xml.skip(tag);                                break; @@ -636,9 +664,6 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                          // ---- Global config stuff begins here ---- -                        else if (tag == "geometryMain") -                              MusEGlobal::config.geometryMain = readGeometry(xml, tag); -                          else if (tag == "theme")                                MusEGlobal::config.style = xml.parse1();                          else if (tag == "styleSheetFile") @@ -847,20 +872,6 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                                MusEGlobal::config.canvasBgPixmap = xml.parse1();                          else if (tag == "canvasCustomBgList")                                MusEGlobal::config.canvasCustomBgList = xml.parse1().split(";", QString::SkipEmptyParts); -                         -                        //else if (tag == "mixer1") -                        //      MusEGlobal::config.mixer1.read(xml); -                        //else if (tag == "mixer2") -                        //      MusEGlobal::config.mixer2.read(xml); -                        else if (tag == "Mixer") -                        { -                              if(mixers == 0) -                                MusEGlobal::config.mixer1.read(xml); -                              else   -                                MusEGlobal::config.mixer2.read(xml); -                              ++mixers; -                        } -                                                  else if (tag == "bigtimeForegroundcolor")                                MusEGlobal::config.bigTimeForegroundColor = readColor(xml);                          else if (tag == "bigtimeBackgroundcolor") @@ -932,8 +943,8 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                                MusEGlobal::config.minControlProcessPeriod = xml.parseUInt();                          else if (tag == "guiRefresh")                                MusEGlobal::config.guiRefresh = xml.parseInt(); -                        else if (tag == "userInstrumentsDir") -                              MusEGlobal::config.userInstrumentsDir = xml.parse1(); +                        else if (tag == "userInstrumentsDir")                        // Obsolete +                              MusEGlobal::config.userInstrumentsDir = xml.parse1();  // Keep for compatibility                           else if (tag == "startMode")                                MusEGlobal::config.startMode = xml.parseInt();                          else if (tag == "startSong") @@ -950,6 +961,10 @@ void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig                                MusEGlobal::config.leftMouseButtonCanDecrease = xml.parseInt();                          else if (tag == "rangeMarkerWithoutMMB")                                MusEGlobal::config.rangeMarkerWithoutMMB = xml.parseInt(); +                        else if (tag == "addHiddenTracks") +                              MusEGlobal::config.addHiddenTracks = xml.parseInt(); +                        else if (tag == "unhideTracks") +                              MusEGlobal::config.unhideTracks = xml.parseInt();                          // ---- the following only skips obsolete entries ----                          else if ((tag == "arranger") || (tag == "geometryPianoroll") || (tag == "geometryDrumedit")) @@ -1173,7 +1188,6 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)                    if (dev) {                          xml.strTag(level, "name",   dev->name()); -                        // p3.3.38                          //if(dynamic_cast<MidiJackDevice*>(dev))                          if(dev->deviceType() != MidiDevice::ALSA_MIDI)                            //xml.intTag(level, "type", MidiDevice::JACK_MIDI); @@ -1183,6 +1197,9 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)                          // openFlags was read before, but never written here.                          //xml.intTag(level, "record", dev->rwFlags() & 0x2 ? 1 : 0);                          xml.intTag(level, "openFlags", dev->openFlags()); +                         +                        if(dev->deviceType() == MidiDevice::JACK_MIDI) +                          xml.intTag(level, "rwFlags", dev->rwFlags());   // Need this. Jack midi devs are created by app.   p4.0.41                           }                    mport->syncInfo().write(level, xml);                    // write out registered controller for all channels @@ -1249,9 +1266,8 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const        xml.intTag(level, "dummyAudioBufSize", MusEGlobal::config.dummyAudioBufSize);        xml.intTag(level, "dummyAudioSampleRate", MusEGlobal::config.dummyAudioSampleRate);        xml.uintTag(level, "minControlProcessPeriod", MusEGlobal::config.minControlProcessPeriod); -        xml.intTag(level, "guiRefresh", MusEGlobal::config.guiRefresh); -      xml.strTag(level, "userInstrumentsDir", MusEGlobal::config.userInstrumentsDir); +              // Removed by Orcan. 20101220        //xml.strTag(level, "helpBrowser", config.helpBrowser);        xml.intTag(level, "extendedMidi", MusEGlobal::config.extendedMidi); @@ -1287,6 +1303,17 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const        xml.intTag(level, "leftMouseButtonCanDecrease", MusEGlobal::config.leftMouseButtonCanDecrease);        xml.intTag(level, "rangeMarkerWithoutMMB", MusEGlobal::config.rangeMarkerWithoutMMB); +      xml.intTag(level, "unhideTracks", MusEGlobal::config.unhideTracks); +      xml.intTag(level, "addHiddenTracks", MusEGlobal::config.addHiddenTracks); + +      xml.intTag(level, "waveTracksVisible",  MusECore::WaveTrack::visible()); +      xml.intTag(level, "auxTracksVisible",  MusECore::AudioAux::visible()); +      xml.intTag(level, "groupTracksVisible",  MusECore::AudioGroup::visible()); +      xml.intTag(level, "midiTracksVisible",  MusECore::MidiTrack::visible()); +      xml.intTag(level, "inputTracksVisible",  MusECore::AudioInput::visible()); +      xml.intTag(level, "outputTracksVisible",  MusECore::AudioOutput::visible()); +      xml.intTag(level, "synthTracksVisible",  MusECore::SynthI::visible()); +        //for (int i = 0; i < 6; ++i) {        for (int i = 0; i < NUM_FONTS; ++i) {              char buffer[32]; @@ -1339,7 +1366,6 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const        xml.colorTag(level, "auxTrackBg",    MusEGlobal::config.auxTrackBg);        xml.colorTag(level, "synthTrackBg",  MusEGlobal::config.synthTrackBg); -      // Removed by Tim. p3.3.6        //xml.intTag(level, "txSyncPort", txSyncPort);        //xml.intTag(level, "rxSyncPort", rxSyncPort);        xml.intTag(level, "mtctype", MusEGlobal::mtcType); @@ -1366,11 +1392,8 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const        xml.intTag(level, "bigtimeVisible", MusEGlobal::config.bigTimeVisible);        xml.intTag(level, "transportVisible", MusEGlobal::config.transportVisible); -      //xml.intTag(level, "mixerVisible", MusEGlobal::config.mixerVisible);  // Obsolete        xml.intTag(level, "mixer1Visible", MusEGlobal::config.mixer1Visible);        xml.intTag(level, "mixer2Visible", MusEGlobal::config.mixer2Visible); -      //MusEGlobal::config.mixer1.write(level, xml, "mixer1"); -      //MusEGlobal::config.mixer2.write(level, xml, "mixer2");        MusEGlobal::config.mixer1.write(level, xml);        MusEGlobal::config.mixer2.write(level, xml); @@ -1423,20 +1446,9 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const        xml.intTag(level, "midiFilterCtrl3",  MusEGlobal::midiFilterCtrl3);        xml.intTag(level, "midiFilterCtrl4",  MusEGlobal::midiFilterCtrl4); -      xml.intTag(level, "waveTracksVisible",  MusECore::WaveTrack::visible()); -      xml.intTag(level, "auxTracksVisible",  MusECore::AudioAux::visible()); -      xml.intTag(level, "groupTracksVisible",  MusECore::AudioGroup::visible()); -      xml.intTag(level, "midiTracksVisible",  MusECore::MidiTrack::visible()); -      xml.intTag(level, "inputTracksVisible",  MusECore::AudioInput::visible()); -      xml.intTag(level, "outputTracksVisible",  MusECore::AudioOutput::visible()); -      xml.intTag(level, "synthTracksVisible",  MusECore::SynthI::visible()); -      // Removed by Tim. p3.3.6 -              //xml.intTag(level, "txDeviceId", txDeviceId);        //xml.intTag(level, "rxDeviceId", rxDeviceId); -      // Changed by Tim. p3.3.6 -              //xml.intTag(level, "txSyncPort", txSyncPort);        /*        // To keep old muse versions happy... @@ -1458,8 +1470,6 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const        }        */ -      // Added by Tim. p3.3.6 -              //xml.tag(level++, "midiSyncInfo");        //for(iMusECore::MidiDevice id = MusECore::MusEGlobal::midiDevices.begin(); id != MusECore::MusEGlobal::midiDevices.end(); ++id)         //{ @@ -1487,8 +1497,6 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const        xml.intTag(level, "bigtimeVisible",   viewBigtimeAction->isChecked());        xml.intTag(level, "transportVisible", viewTransportAction->isChecked()); -      //xml.intTag(level, "markerVisible",    viewMarkerAction->isChecked()); // Obsolete (done by song's toplevel list) -      //xml.intTag(level, "mixerVisible",     menuView->isItemChecked(aid1));  // Obsolete        xml.geometryTag(level, "geometryMain", this); // FINDME: maybe remove this? do we want                                                      // the main win to jump around when loading? @@ -1497,18 +1505,13 @@ void MusE::writeConfiguration(int level, MusECore::Xml& xml) const        if (bigtime)              xml.geometryTag(level, "geometryBigTime", bigtime); -      //if (audioMixer) -      //      xml.geometryTag(level, "geometryMixer", audioMixer);   // Obsolete        xml.intTag(level, "mixer1Visible",    viewMixerAAction->isChecked());        xml.intTag(level, "mixer2Visible",    viewMixerBAction->isChecked());        if (mixer1) -            //mixer1->write(level, xml, "mixer1");              mixer1->write(level, xml);        if (mixer2) -            //mixer2->write(level, xml, "mixer2");              mixer2->write(level, xml); -      //_arranger->writeStatus(level, xml);  // Obsolete.  done by song's toplevel list. arrangerview also handles arranger.        writeSeqConfiguration(level, xml, true);        MusEGui::write_function_dialog_config(level, xml); @@ -1646,18 +1649,12 @@ namespace MusEGlobal {  //   write  //--------------------------------------------------------- -//void MixerConfig::write(MusECore::Xml& xml, const char* name)  void MixerConfig::write(int level, MusECore::Xml& xml) -//void MixerConfig::write(int level, MusECore::Xml& xml, const char* name)        { -      //xml.stag(QString(name)); -      //xml.tag(level++, name.toLatin1().constData());        xml.tag(level++, "Mixer"); -      //xml.tag(level++, name); -       +        xml.strTag(level, "name", name); -      //xml.tag("geometry",       geometry);        xml.qrectTag(level, "geometry", geometry);        xml.intTag(level, "showMidiTracks",   showMidiTracks); @@ -1669,19 +1666,14 @@ void MixerConfig::write(int level, MusECore::Xml& xml)        xml.intTag(level, "showAuxTracks",    showAuxTracks);        xml.intTag(level, "showSyntiTracks",  showSyntiTracks); -      //xml.etag(name); -      //xml.etag(level, name.toLatin1().constData());        xml.etag(level, "Mixer"); -      //xml.etag(level, name);        }  //---------------------------------------------------------  //   read  //--------------------------------------------------------- -//void MixerConfig::read(QDomNode node)  void MixerConfig::read(MusECore::Xml& xml) -//void MixerConfig::read(MusECore::Xml& xml, const QString& name)        {        for (;;) {              MusECore::Xml::Token token(xml.parse()); diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp index 00914b36..d45dd370 100644 --- a/muse2/muse/confmport.cpp +++ b/muse2/muse/confmport.cpp @@ -183,22 +183,25 @@ void MPConfig::changeDefOutputRoutes(QAction* act)          MusEGlobal::audio->msgUpdateSoloStates();          MusEGlobal::song->update(SC_ROUTE);                              #else -        int ch = 0; -        for( ; ch < MIDI_CHANNELS; ++ch) -          if(defch & (1 << ch)) break; -            -        MusEGlobal::audio->msgIdle(true); -        for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) -        { -          // Leave drum track channel at current setting. -          if((*it)->type() == MusECore::Track::DRUM) -            (*it)->setOutPortAndUpdate(no); -          else -            (*it)->setOutPortAndChannelAndUpdate(no, ch); -        }   -        MusEGlobal::audio->msgIdle(false); -        MusEGlobal::audio->msgUpdateSoloStates(); -        MusEGlobal::song->update(SC_MIDI_TRACK_PROP);                     +        for(int ch = 0; ch < MIDI_CHANNELS; ++ch) +          if(defch & (1 << ch)) +          {  +            MusEGlobal::audio->msgIdle(true); +            for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +            { +              // Leave drum track channel at current setting. +              if((*it)->type() == MusECore::Track::DRUM) +                (*it)->setOutPortAndUpdate(no); +              else +                (*it)->setOutPortAndChannelAndUpdate(no, ch); +            }   +            MusEGlobal::audio->msgIdle(false); +            MusEGlobal::audio->msgUpdateSoloStates(); +            MusEGlobal::song->update(SC_MIDI_TRACK_PROP);                     + +            // Stop at the first output channel found. +            break; +          }            #endif        }      }   @@ -902,8 +905,105 @@ void MPConfig::rbClicked(QTableWidgetItem* item)                            sdev = 0;                        }     +                      int allch = (1 << MIDI_CHANNELS) - 1;   +                      MusECore::MidiTrackList* mtl = MusEGlobal::song->midis(); + +                      // Remove track routes to/from an existing port already using the selected device... +                      if(sdev)  +                      { +                        for(int i = 0; i < MIDI_PORTS; ++i)  +                        { +                          if(MusEGlobal::midiPorts[i].device() == sdev)  +                          { +                            for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                              MusEGlobal::audio->msgRemoveRoute(MusECore::Route(i, allch), MusECore::Route(*it, allch)); + +                            // Turn on if and when multiple output routes are supported. +                        #if 0 +                            for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                              MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); +                             +                            //MusEGlobal::audio->msgUpdateSoloStates(); +                            //MusEGlobal::song->update(SC_ROUTE);                     +                        #endif +                         +                            break; +                          } +                        } +                      } +                       +                      // Remove all track routes to/from this port... +                      for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                        // Remove all routes from this port to the tracks. +                        MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); +                      // Turn on if and when multiple output routes are supported. +                  #if 0 +                      for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                        MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); + +                      //MusEGlobal::audio->msgUpdateSoloStates(); +                      //MusEGlobal::song->update(SC_ROUTE);                     +                  #endif +                                              MusEGlobal::midiSeq->msgSetMidiDevice(port, sdev);  		      MusEGlobal::muse->changeConfig(true);     // save configuration file +                       +                      // Add all track routes to/from this port... +                      if(sdev) +                      {   +                        int chbits = MusEGlobal::midiPorts[no].defaultInChannels(); +                        // Do not add input routes to synths. +                        if(!sdev->isSynti())   +                        { +                          for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                          { +                            // Remove all routes from this port to the tracks first. +                            //MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); +                            // Now connect all the specified routes. +                            if(chbits) +                              MusEGlobal::audio->msgAddRoute(MusECore::Route(no, chbits), MusECore::Route(*it, chbits)); +                          }   +                        } +                        chbits = MusEGlobal::midiPorts[no].defaultOutChannels(); +                        // Turn on if and when multiple output routes are supported. +                    #if 0 +                        for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                        { +                          // Remove all routes from this port to the tracks first. +                          //MusEGlobal::audio->msgRemoveRoute(MusECore::Route(no, allch), MusECore::Route(*it, allch)); +                          // Now connect all the specified routes. +                          if(chbits) +                            MusEGlobal::audio->msgAddRoute(MusECore::Route(no, chbits), MusECore::Route(*it, chbits)); +                        }   +                        //MusEGlobal::audio->msgUpdateSoloStates(); +                        //MusEGlobal::song->update(SC_ROUTE);                     +                    #else +                        for(int ch = 0; ch < MIDI_CHANNELS; ++ch) +                          if(chbits & (1 << ch))  +                          {     +                            MusEGlobal::audio->msgIdle(true); +                            for(MusECore::iMidiTrack it = mtl->begin(); it != mtl->end(); ++it) +                            { +                              // Leave drum track channel at current setting. +                              if((*it)->type() == MusECore::Track::DRUM) +                                (*it)->setOutPortAndUpdate(no); +                              else +                                (*it)->setOutPortAndChannelAndUpdate(no, ch); +                            }   +                            MusEGlobal::audio->msgIdle(false); +                            //MusEGlobal::audio->msgUpdateSoloStates(); +                            //MusEGlobal::song->update(SC_MIDI_TRACK_PROP);                     +                             +                            // Stop at the first output channel found. +                            break; +                          }    +                    #endif +                      } +                       +                      //MusEGlobal::audio->msgUpdateSoloStates(); +                      ////MusEGlobal::song->update(SC_ROUTE);                     +                       +                      MusEGlobal::audio->msgUpdateSoloStates();                        MusEGlobal::song->update();                      }                      } @@ -1061,7 +1161,8 @@ MPConfig::MPConfig(QWidget* parent)        //popup      = 0;        instrPopup = 0;        defpup = 0; -      _showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first. +      //_showAliases = -1; // 0: Show first aliases, if available. Nah, stick with -1: none at first. +      _showAliases = 0; // 0: Show first aliases, if available.         QStringList columnnames;        columnnames << tr("Port") @@ -1125,8 +1226,7 @@ void MPConfig::songChanged(int flags)        // Is it simply a midi controller value adjustment? Forget it.        //if(flags == SC_MIDI_CONTROLLER)        //  return; -      // No need for anything but this, yet. -      if(!(flags & SC_CONFIG)) +      if(!(flags & (SC_CONFIG | SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED)))          return;        // Get currently selected index... @@ -1299,32 +1399,29 @@ void MPConfig::songChanged(int flags)        synthList->clear();        for (std::vector<MusECore::Synth*>::iterator i = MusEGlobal::synthis.begin();           i != MusEGlobal::synthis.end(); ++i) { -            //s = (*i)->baseName(); -            //s = (*i)->name(); -              QTreeWidgetItem* item = new QTreeWidgetItem(synthList); -            //item->setText(0, s);              item->setText(0, QString((*i)->baseName())); +            item->setText(1, MusECore::synthType2String((*i)->synthType()));              s.setNum((*i)->instances()); -            item->setText(1, s); -	    item->setTextAlignment(1, Qt::AlignHCenter); -            //item->setText(2, QString((*i)->baseName())); -            item->setText(2, QString((*i)->name())); +            item->setText(2, s); +            //item->setTextAlignment(2, Qt::AlignHCenter); +            item->setText(3, QString((*i)->name())); -            item->setText(3, QString((*i)->version())); -            item->setText(4, QString((*i)->description())); +            item->setText(4, QString((*i)->version())); +            item->setText(5, QString((*i)->description()));              }        instanceList->clear();        MusECore::SynthIList* sl = MusEGlobal::song->syntis();        for (MusECore::iSynthI si = sl->begin(); si != sl->end(); ++si) {              QTreeWidgetItem* iitem = new QTreeWidgetItem(instanceList);              iitem->setText(0, (*si)->name()); +            iitem->setText(1, MusECore::synthType2String((*si)->synth()->synthType()));              if ((*si)->midiPort() == -1)                    s = tr("<none>");              else                    s.setNum((*si)->midiPort() + 1); -            iitem->setText(1, s); -	    iitem->setTextAlignment(1, Qt::AlignHCenter); +            iitem->setText(2, s); +	    //iitem->setTextAlignment(2, Qt::AlignHCenter);              }        synthList->resizeColumnToContents(1);        mdevView->resizeColumnsToContents(); @@ -1345,7 +1442,10 @@ void MPConfig::addInstanceClicked()        QTreeWidgetItem* item = synthList->currentItem();        if (item == 0)              return; -      MusECore::SynthI *si = MusEGlobal::song->createSynthI(item->text(0), item->text(2)); // Add at end of list. +      // Add at end of list. +      MusECore::SynthI *si = MusEGlobal::song->createSynthI(item->text(0),  +                                                            item->text(3),  +                                                            MusECore::string2SynthType(item->text(1)));         if(!si)          return; @@ -1374,8 +1474,9 @@ void MPConfig::removeInstanceClicked()        MusECore::SynthIList* sl = MusEGlobal::song->syntis();        MusECore::iSynthI ii;        for (ii = sl->begin(); ii != sl->end(); ++ii) { -            if ((*ii)->iname() == item->text(0)) -                  break; +            if( (*ii)->iname() == item->text(0) &&  +                 MusECore::synthType2String((*ii)->synth()->synthType()) == item->text(1) ) +              break;              }        if (ii == sl->end()) {              printf("synthesizerConfig::removeInstanceClicked(): synthi not found\n"); diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp index f55eea5d..60e19ba7 100644 --- a/muse2/muse/ctrl/ctrlcanvas.cpp +++ b/muse2/muse/ctrl/ctrlcanvas.cpp @@ -1928,7 +1928,7 @@ void CtrlCanvas::drawOverlay(QPainter& p)             //p.setFont(MusEGlobal::config.fonts[3]);             //p.setPen(Qt::black);             //p.drawText(width()/2-100,height()/2-10, "Use shift + pencil or line tool to draw new events"); -           p.drawText(2 , y * 2, "Use shift + pencil or line tool to draw new events"); +           p.drawText(2 , y * 2, "Drawing hint: Hold Ctrl to affect only existing events");             }        } diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp index 3b6f5a20..4687f17f 100644 --- a/muse2/muse/driver/alsamidi.cpp +++ b/muse2/muse/driver/alsamidi.cpp @@ -48,6 +48,7 @@ static int alsaSeqFdo = -1;  snd_seq_t* alsaSeq = 0;  static snd_seq_addr_t musePort; +static snd_seq_addr_t announce_adr;  //---------------------------------------------------------  //   MidiAlsaDevice @@ -85,42 +86,55 @@ QString MidiAlsaDevice::open()        QString estr;        int wer = 0;        int rer = 0; + +      snd_seq_port_info_t *pinfo; +      snd_seq_port_info_alloca(&pinfo); +      //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); +      snd_seq_port_info_set_addr(pinfo, &adr); + +      int cap = snd_seq_port_info_get_capability(pinfo);        // subscribe for writing        if (_openFlags & 1)         { -            snd_seq_port_subscribe_set_sender(subs, &musePort); -            snd_seq_port_subscribe_set_dest(subs, &adr); -            // Not already subscribed (or error)? Then try subscribing. -            if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) -            { -              //int error = snd_seq_subscribe_port(alsaSeq, subs); -              wer = snd_seq_subscribe_port(alsaSeq, subs); -              //if (error < 0) -              if(wer < 0) -                    //return QString("Play: ")+QString(snd_strerror(error)); -                    estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" ")); -            }         -            if(!wer) +            if(cap & SND_SEQ_PORT_CAP_SUBS_WRITE) +            {   +              snd_seq_port_subscribe_set_sender(subs, &musePort); +              snd_seq_port_subscribe_set_dest(subs, &adr); +              // Not already subscribed (or error)? Then try subscribing. +              if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) +              { +                //int error = snd_seq_subscribe_port(alsaSeq, subs); +                wer = snd_seq_subscribe_port(alsaSeq, subs); +                //if (error < 0) +                if(wer < 0) +                      //return QString("Play: ")+QString(snd_strerror(error)); +                      estr += (QString("Play: ") + QString(snd_strerror(wer)) + QString(" ")); +              }         +            }   +            if(!wer && (cap & SND_SEQ_PORT_CAP_WRITE))                _writeEnable = true;              }        // subscribe for reading        if (_openFlags & 2)         { -            snd_seq_port_subscribe_set_dest(subs, &musePort); -	          snd_seq_port_subscribe_set_sender(subs, &adr); -            // Not already subscribed (or error)? Then try subscribing. -            if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) -            { -              //int error = snd_seq_subscribe_port(alsaSeq, subs); -              rer = snd_seq_subscribe_port(alsaSeq, subs); -              //if (error < 0) -              if(rer < 0) -                    //return QString("Rec: ") + QString(snd_strerror(error)); -                    estr += (QString("Rec: ") + QString(snd_strerror(rer))); -            }         -            if(!rer) +            if(cap & SND_SEQ_PORT_CAP_SUBS_READ) +            {   +              snd_seq_port_subscribe_set_dest(subs, &musePort); +                    snd_seq_port_subscribe_set_sender(subs, &adr); +              // Not already subscribed (or error)? Then try subscribing. +              if(snd_seq_get_port_subscription(alsaSeq, subs) < 0) +              { +                //int error = snd_seq_subscribe_port(alsaSeq, subs); +                rer = snd_seq_subscribe_port(alsaSeq, subs); +                //if (error < 0) +                if(rer < 0) +                      //return QString("Rec: ") + QString(snd_strerror(error)); +                      estr += (QString("Rec: ") + QString(snd_strerror(rer))); +              } +            }   +            if(!rer && (cap & SND_SEQ_PORT_CAP_READ))                _readEnable = true;              } @@ -141,6 +155,16 @@ void MidiAlsaDevice::close()        // Allocated on stack, no need to call snd_seq_port_subscribe_free() later.        snd_seq_port_subscribe_alloca(&subs); +      int wer = 0; +      int rer = 0; + +      snd_seq_port_info_t *pinfo; +      snd_seq_port_info_alloca(&pinfo); +      //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); +      snd_seq_port_info_set_addr(pinfo, &adr); + +      int cap = snd_seq_port_info_get_capability(pinfo); +        // This function appears to be called only by MidiPort::setMidiDevice(),         //  which closes then opens the device.        // Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags. @@ -160,37 +184,49 @@ void MidiAlsaDevice::close()        //if (_openFlags & 1) {        //if (!(_openFlags & 1))         { -            snd_seq_port_subscribe_set_sender(subs, &musePort); -            snd_seq_port_subscribe_set_dest(subs, &adr); -             -            // Already subscribed? Then unsubscribe. -            if(!snd_seq_get_port_subscription(alsaSeq, subs)) -            { -              if(!snd_seq_unsubscribe_port(alsaSeq, subs)) -                _writeEnable = false;       -              else -                printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for writing\n"); +            if(cap & SND_SEQ_PORT_CAP_SUBS_WRITE) +            {   +              snd_seq_port_subscribe_set_sender(subs, &musePort); +              snd_seq_port_subscribe_set_dest(subs, &adr); +               +              // Already subscribed? Then unsubscribe. +              if(!snd_seq_get_port_subscription(alsaSeq, subs)) +              { +                wer = snd_seq_unsubscribe_port(alsaSeq, subs); +                //if(!wer) +                //  _writeEnable = false;       +                //else +                if(wer < 0) +                  printf("MidiAlsaDevice::close Error unsubscribing alsa midi port %d:%d for writing: %s\n", adr.client, adr.port, snd_strerror(wer)); +              }    +              //else +                //_writeEnable = false;                    }    -            else -              _writeEnable = false;       +            _writeEnable = false;              }        //if (_openFlags & 2) {        //if (!(_openFlags & 2))         { -            snd_seq_port_subscribe_set_dest(subs, &musePort); -            snd_seq_port_subscribe_set_sender(subs, &adr); -             -            // Already subscribed? Then unsubscribe. -            if(!snd_seq_get_port_subscription(alsaSeq, subs)) -            { -              if(!snd_seq_unsubscribe_port(alsaSeq, subs)) -                _readEnable = false;       -              else   -                printf("MidiAlsaDevice::close Error unsubscribing alsa midi port for reading\n"); -            }   -            else -              _readEnable = false;       +            if(cap & SND_SEQ_PORT_CAP_SUBS_READ) +            {   +              snd_seq_port_subscribe_set_dest(subs, &musePort); +              snd_seq_port_subscribe_set_sender(subs, &adr); +               +              // Already subscribed? Then unsubscribe. +              if(!snd_seq_get_port_subscription(alsaSeq, subs)) +              { +                rer = snd_seq_unsubscribe_port(alsaSeq, subs); +                //if(!rer) +                //  _readEnable = false;       +                //else   +                if(rer < 0) +                  printf("MidiAlsaDevice::close Error unsubscribing alsa midi port %d:%d for reading: %s\n", adr.client, adr.port, snd_strerror(rer)); +              }   +              //else +              //  _readEnable = false;       +            }    +            _readEnable = false;              }  } @@ -698,6 +734,13 @@ bool initMidiAlsa()        snd_seq_client_info_set_client(cinfo, -1);        while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) { +            const char* cname = snd_seq_client_info_get_name(cinfo); +            //printf( "ALSA client name: %s\n", cname);   +             +            // Put Midi Through and user clients after others. Insert other unwanted clients here:          // p4.0.41 +            if(snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT || strcmp("Midi Through", cname) == 0)                    +              continue; +                          snd_seq_port_info_t *pinfo;              snd_seq_port_info_alloca(&pinfo);              snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); @@ -705,6 +748,8 @@ bool initMidiAlsa()              while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) {                    unsigned int capability = snd_seq_port_info_get_capability(pinfo); +                  if (capability & SND_SEQ_PORT_CAP_NO_EXPORT)  // Ignore ports like "qjackctl" or "port".    p4.0.41 +                    continue;                    if ((capability & outCap) == 0) {                            const char *name = snd_seq_port_info_get_name(pinfo);                            if (strcmp("Timer", name) == 0 ||  @@ -726,29 +771,52 @@ bool initMidiAlsa()                             adr.client, adr.port,                             flags, capability);                    MusEGlobal::midiDevices.add(dev); -                   -                  /* -                  // Experimental... Need to list 'sensible' devices first and ignore unwanted ones... -                  // Add instance last in midi device list. -                  for(int i = 0; i < MIDI_PORTS; ++i)  -                  { -                    MidiPort* mp  = &MusEGlobal::midiPorts[i]; -                    if(mp->device() == 0)  -                    { -                      // midiSeq might not be initialzed yet! -                      //MusEGlobal::midiSeq->msgSetMidiDevice(mp, dev); -                      mp->setMidiDevice(dev); -                       -                      //muse->changeConfig(true);     // save configuration file -                      //update(); -                      break; -                    }                    } -                  */ -                   +            } + +      snd_seq_client_info_set_client(cinfo, -1);   // Reset +      while (snd_seq_query_next_client(alsaSeq, cinfo) >= 0) { +            const char* cname = snd_seq_client_info_get_name(cinfo); +            //printf( "ALSA client name: %s\n", cname);   +             +            // Put Midi Through and user clients after others. Insert other unwanted clients here:          // p4.0.41 +            if( !(snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT || strcmp("Midi Through", cname) == 0) )                    +              continue; +             +            snd_seq_port_info_t *pinfo; +            snd_seq_port_info_alloca(&pinfo); +            snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); +            snd_seq_port_info_set_port(pinfo, -1); + +            while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) { +                  unsigned int capability = snd_seq_port_info_get_capability(pinfo); +                  if (capability & SND_SEQ_PORT_CAP_NO_EXPORT)  // Ignore ports like "qjackctl" or "port".    p4.0.41 +                    continue; +                  if ((capability & outCap) == 0) { +                          const char *name = snd_seq_port_info_get_name(pinfo); +                          if (strcmp("Timer", name) == 0 ||  +                              strcmp("Announce", name) == 0 ||  +                              strcmp("Receiver", name) == 0) +                                continue; +                          } +                  snd_seq_addr_t adr = *snd_seq_port_info_get_addr(pinfo); +                  MidiAlsaDevice* dev = new MidiAlsaDevice(adr, QString(snd_seq_port_info_get_name(pinfo))); +                  int flags = 0; +                  if (capability & outCap) +                        flags |= 1; +                  if (capability & inCap) +                        flags |= 2; +                  dev->setrwFlags(flags); +                  if (MusEGlobal::debugMsg) +                        printf("ALSA port add: <%s>, %d:%d flags %d 0x%0x\n", +                           snd_seq_port_info_get_name(pinfo), +                           adr.client, adr.port, +                           flags, capability); +                  MusEGlobal::midiDevices.add(dev);                    }              } -       +             +                    //snd_seq_set_client_name(alsaSeq, "MusE Sequencer");        snd_seq_set_client_name(alsaSeq, MusEGlobal::audioDevice->clientName()); @@ -783,14 +851,14 @@ bool initMidiAlsa()        //    alsa port changes        //----------------------------------------- -      snd_seq_addr_t aadr; -      aadr.client = SND_SEQ_CLIENT_SYSTEM; -      aadr.port   = SND_SEQ_PORT_SYSTEM_ANNOUNCE; +      //snd_seq_addr_t aadr; +      announce_adr.client = SND_SEQ_CLIENT_SYSTEM; +      announce_adr.port   = SND_SEQ_PORT_SYSTEM_ANNOUNCE;        snd_seq_port_subscribe_t* subs;        snd_seq_port_subscribe_alloca(&subs);        snd_seq_port_subscribe_set_dest(subs, &musePort); -      snd_seq_port_subscribe_set_sender(subs, &aadr); +      snd_seq_port_subscribe_set_sender(subs, &announce_adr);        error = snd_seq_subscribe_port(alsaSeq, subs);        if (error < 0) {              printf("Alsa: Subscribe System failed: %s", snd_strerror(error)); @@ -807,12 +875,35 @@ bool initMidiAlsa()  void exitMidiAlsa()  {    if(alsaSeq) -  {   -    int error = snd_seq_close(alsaSeq);  // FIXME Hm, this did not get rid of a buch of valgrind leaks. -    if(error < 0)  +  {  +    int error = 0; +    snd_seq_port_subscribe_t* subs; +    // Allocated on stack, no need to call snd_seq_port_subscribe_free() later. +    snd_seq_port_subscribe_alloca(&subs); +     +    snd_seq_port_info_t *pinfo; +    snd_seq_port_info_alloca(&pinfo); +    //snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); +    snd_seq_port_info_set_addr(pinfo, &announce_adr); + +    snd_seq_port_subscribe_set_dest(subs, &musePort); +    snd_seq_port_subscribe_set_sender(subs, &announce_adr); +     +    // Already subscribed? Then unsubscribe. +    if(!snd_seq_get_port_subscription(alsaSeq, subs))      { -      fprintf(stderr, "Could not close ALSA sequencer: %s\n", snd_strerror(error)); -    } +      error = snd_seq_unsubscribe_port(alsaSeq, subs); +      if(error < 0) +        printf("MusE: exitMidiAlsa: Error unsubscribing alsa midi Announce port %d:%d for reading: %s\n", announce_adr.client, announce_adr.port, snd_strerror(error)); +    }    +     +    error = snd_seq_delete_simple_port(alsaSeq, musePort.port); +    if(error < 0)  +      fprintf(stderr, "MusE: Could not delete ALSA simple port: %s\n", snd_strerror(error)); +     +    error = snd_seq_close(alsaSeq);   +    if(error < 0)  +      fprintf(stderr, "MusE: Could not close ALSA sequencer: %s\n", snd_strerror(error));    }    } @@ -852,7 +943,9 @@ void alsaScanMidiPorts()              snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));              snd_seq_port_info_set_port(pinfo, -1);              while (snd_seq_query_next_port(alsaSeq, pinfo) >= 0) { -		      unsigned int capability = snd_seq_port_info_get_capability(pinfo); +                  unsigned int capability = snd_seq_port_info_get_capability(pinfo); +                  if (capability & SND_SEQ_PORT_CAP_NO_EXPORT)  // Ignore ports like "qjackctl" or "port".    p4.0.41 +                    continue;                    if (((capability & outCap) == 0)                       && ((capability & inCap) == 0))                          continue; @@ -902,6 +995,8 @@ void alsaScanMidiPorts()        //        //  check for devices to add        // +      // TODO: Possibly auto-add them to available midi ports.    p4.0.41             +      //        for (std::list<AlsaPort>::iterator k = portList.begin(); k != portList.end(); ++k) {              iMidiDevice i = MusEGlobal::midiDevices.begin();  // printf("ALSA port: <%s>\n", k->name); @@ -922,6 +1017,8 @@ void alsaScanMidiPorts()  // printf("add device\n");                    }              } +             +                    }  //--------------------------------------------------------- diff --git a/muse2/muse/driver/jack.cpp b/muse2/muse/driver/jack.cpp index 733353d8..421152a7 100644 --- a/muse2/muse/driver/jack.cpp +++ b/muse2/muse/driver/jack.cpp @@ -735,7 +735,11 @@ void JackAudioDevice::connectJackMidiPorts()        {          RouteList* rl = md->outRoutes();          for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        {   +          if(r->type != Route::JACK_ROUTE)   +            continue;            connect(port, r->jackPort); +        }          }          } @@ -748,7 +752,11 @@ void JackAudioDevice::connectJackMidiPorts()        {          RouteList* rl = md->inRoutes();          for (ciRoute r = rl->begin(); r != rl->end(); ++r)  +        {   +          if(r->type != Route::JACK_ROUTE)   +            continue;            connect(r->jackPort, port); +        }        }          }        } @@ -939,6 +947,8 @@ void JackAudioDevice::graphChanged()                    for (int i = 0;i < 20;i++) {                          erased = false;                          for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                              if(irl->type != Route::JACK_ROUTE)   +                                continue;                                if (irl->channel != channel)                                      continue;                                QString name = irl->name(); @@ -977,6 +987,8 @@ void JackAudioDevice::graphChanged()                          while (*pn) {                                bool found = false;                                for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                    if(irl->type != Route::JACK_ROUTE)   +                                      continue;                                      if (irl->channel != channel)                                            continue;                                      QString name = irl->name(); @@ -1027,6 +1039,8 @@ void JackAudioDevice::graphChanged()                    for (int i = 0; i < 20 ; i++) {                          erased = false;                          for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                              if(irl->type != Route::JACK_ROUTE)   +                                continue;                                if (irl->channel != channel)                                      continue;                                QString name = irl->name(); @@ -1064,6 +1078,8 @@ void JackAudioDevice::graphChanged()                          while (*pn) {                                bool found = false;                                for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                    if(irl->type != Route::JACK_ROUTE)   +                                      continue;                                      if (irl->channel != channel)                                            continue;                                      QString name = irl->name(); @@ -1139,6 +1155,8 @@ void JackAudioDevice::graphChanged()                        {                              erased = false;                              for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                  if(irl->type != Route::JACK_ROUTE)   +                                    continue;                                    //if (irl->channel != channel)                                    //      continue;                                    QString name = irl->name(); @@ -1181,6 +1199,8 @@ void JackAudioDevice::graphChanged()                              while (*pn) {                                    bool found = false;                                    for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                        if(irl->type != Route::JACK_ROUTE)   +                                          continue;                                          //if (irl->channel != channel)                                          //      continue;                                          QString name = irl->name(); @@ -1239,6 +1259,8 @@ void JackAudioDevice::graphChanged()                        {                              erased = false;                              for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                  if(irl->type != Route::JACK_ROUTE)   +                                    continue;                                    //if (irl->channel != channel)                                    //      continue;                                    QString name = irl->name(); @@ -1280,6 +1302,8 @@ void JackAudioDevice::graphChanged()                              while (*pn) {                                    bool found = false;                                    for (ciRoute irl = rl->begin(); irl != rl->end(); ++irl) { +                                        if(irl->type != Route::JACK_ROUTE)   +                                          continue;                                          //if (irl->channel != channel)                                          //      continue;                                          QString name = irl->name(); @@ -1482,6 +1506,8 @@ void JackAudioDevice::start(int /*priority*/)                    RouteList* rl = ai->inRoutes();                    void* port = ai->jackPort(ch);                    for (ciRoute ir = rl->begin(); ir != rl->end(); ++ir) { +                        if(ir->type != Route::JACK_ROUTE)   +                          continue;                          if (ir->channel == ch)                                connect(ir->jackPort, port);                          } @@ -1495,6 +1521,8 @@ void JackAudioDevice::start(int /*priority*/)                    RouteList* rl = ai->outRoutes();                    void* port = ai->jackPort(ch);                    for (ciRoute r = rl->begin(); r != rl->end(); ++r) { +                        if(r->type != Route::JACK_ROUTE)   +                          continue;                          if (r->channel == ch) {                                connect(port, r->jackPort);                                } @@ -1603,6 +1631,107 @@ int JackAudioDevice::frameDelay() const  #endif  //--------------------------------------------------------- +//   getJackPorts +//--------------------------------------------------------- + +void JackAudioDevice::getJackPorts(const char** ports, std::list<QString>& name_list, bool midi, bool physical, int aliases) +      { +      if (JACK_DEBUG) +            printf("JackAudioDevice::getJackPorts()\n"); +      //std::list<QString> clientList; +      //if(!checkJackClient(_client)) return clientList; +      //if(!checkJackClient(_client)) return; +      QString qname; +      //const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; +      //const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); +      //const char** ports = jack_get_ports(_client, 0, type, jflags); +       +      QString cname(jack_get_client_name(_client)); +       +      for (const char** p = ports; p && *p; ++p) { +            jack_port_t* port = jack_port_by_name(_client, *p); +            //int flags = jack_port_flags(port); +            //if (!(flags & JackPortIsInput)) +            //      continue; +            //char buffer[128]; +             +            int port_flags = jack_port_flags(port); +            //printf("JackAudioDevice::getJackPorts port: %s flags: %d\n", *p, port_flags);  + +            // Ignore our own client ports. +            if(jack_port_is_mine(_client, port)) +            { +              if(MusEGlobal::debugMsg) +                printf("JackAudioDevice::getJackPorts ignoring own port: %s\n", *p); +              continue;          +            } +             +            int nsz = jack_port_name_size(); +            char buffer[nsz]; + +            bool mthrough = false; +             +            if(midi) +            {   +              strncpy(buffer, *p, nsz); +              char a2[nsz];  +              char* al[2]; +              al[0] = buffer; +              al[1] = a2; +              int na = jack_port_get_aliases(port, al); +              if(na >= 1) +              { +                qname = QString(al[0]); +                    //printf("Checking port name for: %s\n", (QString("alsa_pcm:") + cname + QString("/")).toLatin1().constData());   +                // Ignore our own ALSA client! +                if(qname.startsWith(QString("alsa_pcm:") + cname + QString("/"))) +                  continue; +                // Put Midi Through after all others. +                mthrough = qname.startsWith(QString("alsa_pcm:Midi-Through/"));   +                //if((physical && mthrough) || (!physical && !mthrough)) +                //if(physical && mthrough) +                //  continue; +              }     +            }   +            // Put physical/terminal ports before others. +            bool is_phys = (port_flags & (JackPortIsTerminal | JackPortIsPhysical)) && !mthrough; +            if((physical && !is_phys) || (!physical && is_phys)) +              continue; +             + +            strncpy(buffer, *p, nsz); +            if((aliases == 0) || (aliases == 1))  +            { +              char a2[nsz];  +              char* al[2]; +              al[0] = buffer; +              al[1] = a2; +              int na = jack_port_get_aliases(port, al);   +              int a = aliases; +              if(a >= na) +              { +                a = na; +                if(a > 0) +                  a--; +              }     +              qname = QString(al[a]); +            } +            else +              qname = QString(buffer); +             +            //clientList.push_back(QString(buffer)); +            name_list.push_back(qname); +            } +             +      // p3.3.37 +      //if(ports) +        //free(ports);       +      //  jack_free(ports);  // p4.0.29 +       +      //return clientList; +      } +       +//---------------------------------------------------------  //   outputPorts  //--------------------------------------------------------- @@ -1612,9 +1741,11 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)              printf("JackAudioDevice::outputPorts()\n");        std::list<QString> clientList;        if(!checkJackClient(_client)) return clientList; -      QString qname;        const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;        const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput); +       +      /* +      QString qname;        for (const char** p = ports; p && *p; ++p) {              jack_port_t* port = jack_port_by_name(_client, *p);              //int flags = jack_port_flags(port); @@ -1666,12 +1797,15 @@ std::list<QString> JackAudioDevice::outputPorts(bool midi, int aliases)              //clientList.push_back(QString(buffer));              clientList.push_back(qname);              } -             -      // p3.3.37 -      if(ports) -        //free(ports);       -        jack_free(ports);  // p4.0.29 +      */ +      if(ports) +      { +        getJackPorts(ports, clientList, midi, true, aliases);   // Get physical ports first. +        getJackPorts(ports, clientList, midi, false, aliases);  // Get non-physical ports last. +        jack_free(ports);   +      } +                return clientList;        } @@ -1683,11 +1817,14 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)        {        if (JACK_DEBUG)              printf("JackAudioDevice::inputPorts()\n"); +              std::list<QString> clientList;        if(!checkJackClient(_client)) return clientList; -      QString qname;        const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE;        const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); +       +      /* +      QString qname;        for (const char** p = ports; p && *p; ++p) {              jack_port_t* port = jack_port_by_name(_client, *p);              //int flags = jack_port_flags(port); @@ -1739,12 +1876,15 @@ std::list<QString> JackAudioDevice::inputPorts(bool midi, int aliases)              //clientList.push_back(QString(buffer));              clientList.push_back(qname);              } -             -      // p3.3.37 -      if(ports) -        //free(ports);       -        jack_free(ports);  // p4.0.29 +      */ +      if(ports) +      { +        getJackPorts(ports, clientList, midi, true, aliases);   // Get physical ports first. +        getJackPorts(ports, clientList, midi, false, aliases);  // Get non-physical ports last. +        jack_free(ports);   +      } +                return clientList;        } diff --git a/muse2/muse/driver/jackaudio.h b/muse2/muse/driver/jackaudio.h index bd78d481..c4d37db9 100644 --- a/muse2/muse/driver/jackaudio.h +++ b/muse2/muse/driver/jackaudio.h @@ -50,6 +50,7 @@ class JackAudioDevice : public AudioDevice {        // Free-running frame counter incremented always in process.        jack_nframes_t _frameCounter;  +      void getJackPorts(const char** ports, std::list<QString>& name_list, bool midi, bool physical, int aliases);        static int processAudio(jack_nframes_t frames, void*);     public: diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp index 92120dbb..2e4e6d35 100644 --- a/muse2/muse/dssihost.cpp +++ b/muse2/muse/dssihost.cpp @@ -99,6 +99,7 @@ static void scanDSSILib(QFileInfo& fi) // ddskrjo removed const for argument            // That way we cover all bases - effect plugins and synths.             // Non-synths will show up in the ladspa effect dialog, while synths will show up here...            // There should be nothing left out... +          // TIP: Until we add programs to plugins, comment these four checks to load dssi effects as synths, in order to have programs.             if(descr->run_synth ||                                descr->run_synth_adding ||              descr->run_multiple_synths || @@ -498,6 +499,9 @@ bool DssiSynthIF::init(DssiSynth* s)        int inports = synth->_inports;        if(inports != 0)        { +        posix_memalign((void**)&audioInSilenceBuf, 16, sizeof(float) * MusEGlobal::segmentSize); +        memset(audioInSilenceBuf, 0, sizeof(float) * MusEGlobal::segmentSize); +                  audioInBuffers = new float*[inports];          for(int k = 0; k < inports; ++k)          { @@ -723,6 +727,7 @@ DssiSynthIF::DssiSynthIF(SynthI* s)        controls = 0;        controlsOut = 0;        audioInBuffers = 0; +      audioInSilenceBuf = 0;        audioOutBuffers = 0;        } @@ -785,6 +790,9 @@ DssiSynthIF::~DssiSynthIF()          delete[] audioInBuffers;        }   +      if(audioInSilenceBuf) +        free(audioInSilenceBuf); +              if(audioOutBuffers)        {          for(unsigned long i = 0; i < synth->_outports; ++i)  @@ -1420,7 +1428,7 @@ bool DssiSynthIF::processEvent(const MusECore::MidiPlayEvent& e, snd_seq_event_t  //   getData  //--------------------------------------------------------- -MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MPEventList* el, MusECore::iMPEvent i, unsigned pos, int ports, unsigned n, float** buffer) +MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MPEventList* el, MusECore::iMPEvent start_event, unsigned pos, int ports, unsigned nframes, float** buffer)  {    //#ifdef DSSI_DEBUG     //  fprintf(stderr, "DssiSynthIF::getData elsize:%d pos:%d ports:%d samples:%d processed already?:%d\n", el->size(), pos, ports, n, synti->processed()); @@ -1440,19 +1448,11 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP    // All ports must be connected to something!    unsigned long nop, k; -  // First, copy the given input buffers to our local input buffers. -  //np = portsin > synth->_inports ? synth->_inports : portsin; -  //for(k = 0; k < np; ++k) -  //  memcpy(audioInBuffers[k], inbuffer[k], sizeof(float) * n); -  //for(; k < portsin; ++k) -  //  memset(audioInBuffers[k], 0, sizeof(float) * n);    // Watch our limits.    //willyfoobar-2011-02-13    //old code//np = ports > synth->_outports ? synth->_outports : ports;    nop = ((unsigned long) ports) > synth->_outports ? synth->_outports : ((unsigned long) ports); -  // TODO Number of inports requested? -  //nip = ((unsigned long) iports) > synth->_inports ? synth->_inports : ((unsigned long) iports);    const DSSI_Descriptor* dssi = synth->dssi;    const LADSPA_Descriptor* descr = dssi->LADSPA_Plugin; @@ -1484,18 +1484,109 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP    // Note for dssi-vst this MUST equal MusEGlobal::audio period. It doesn't like broken-up runs (it stutters),     //  even with fixed sizes. Could be a Wine + Jack thing, wanting a full Jack buffer's length.    //unsigned long fixedsize = 2048;    -  unsigned long fixedsize = n;      +  unsigned long fixedsize = nframes;         // For now, the fixed size is clamped to the MusEGlobal::audio buffer size.    // TODO: We could later add slower processing over several cycles -    //  so that users can select a small MusEGlobal::audio period but a larger control period.  -  if(fixedsize > n) -    fixedsize = n; +  if(fixedsize > nframes) +    fixedsize = nframes;    unsigned long min_per = MusEGlobal::config.minControlProcessPeriod;   -  if(min_per > n) -    min_per = n; +  if(min_per > nframes) +    min_per = nframes; +   +  // +  // p4.0.38 Handle inputs... +  // +  if(!((MusECore::AudioTrack*)synti)->noInRoute())  +  { +    RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes(); +    iRoute i = irl->begin(); +    if(i->track->isMidiTrack()) +    { +      //if(MusEGlobal::debugMsg) +        //printf("DssiSynthIF::getData: Error: First route is a midi track route!\n");    +    } +    else +    { +      int ch     = i->channel       == -1 ? 0 : i->channel; +      int remch  = i->remoteChannel == -1 ? 0 : i->remoteChannel; +      int chs    = i->channels      == -1 ? 0 : i->channels; +       +      if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports) +      {   +        //printf("DssiSynthIF::getData calling copyData on %s ch:%d remch:%d chs:%d\n", i->track->name().toLatin1().constData(), ch, remch, chs);   +         +        int h = remch + chs; +        for(int j = remch; j < h; ++j) +        { +          //printf(" setting used idx:%d\n", j);   +          synth->iUsedIdx[j] = true; +        } +         +        ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); +      } +    }   +   +    ++i; +    for(; i != irl->end(); ++i) +    { +      if(i->track->isMidiTrack()) +      { +        //if(MusEGlobal::debugMsg) +        //  printf("DssiSynthIF::getData: Error: Route is a midi track route!\n");      +        continue; +      } + +      int ch     = i->channel       == -1 ? 0 : i->channel; +      int remch  = i->remoteChannel == -1 ? 0 : i->remoteChannel; +      int chs    = i->channels      == -1 ? 0 : i->channels; +      if((unsigned)ch < synth->_inports && (unsigned)(ch + chs) <= synth->_inports) +      {   +        //printf("DssiSynthIF::getData calling addData on %s ch:%d remch:%d chs:%d\n", i->track->name().toLatin1().constData(), ch, remch, chs);   + +        bool u1 = synth->iUsedIdx[remch]; +        if(chs >= 2)  +        { +          bool u2 = synth->iUsedIdx[remch + 1]; +          if(u1 && u2) +            ((MusECore::AudioTrack*)i->track)->addData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); +          else +          if(!u1 && !u2) +            ((MusECore::AudioTrack*)i->track)->copyData(pos, chs, ch, -1, nframes, &audioInBuffers[remch]); +          else  +          {   +            if(u1)  +              ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]); +            else +              ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, 1, nframes, &audioInBuffers[remch]); + +            if(u2)   +              ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]); +            else +              ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch + 1, 1, nframes, &audioInBuffers[remch + 1]); +          }   +        } +        else +        { +            if(u1)  +              ((MusECore::AudioTrack*)i->track)->addData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]); +            else +              ((MusECore::AudioTrack*)i->track)->copyData(pos, 1, ch, -1, nframes, &audioInBuffers[remch]); +        } +           +        int h = remch + chs; +        for(int j = remch; j < h; ++j) +        { +          //printf(" setting used idx:%d\n", j);   +          synth->iUsedIdx[j] = true; +        } +      } +    } +  }   +      // Process automation control values now.    // TODO: This needs to be respect frame resolution. Put this inside the sample loop below.    if(MusEGlobal::automation && synti && synti->automationType() != AUTO_OFF && id() != -1) @@ -1507,11 +1598,11 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP      }          } -  while(sample < n) +  while(sample < nframes)    {      //unsigned long nsamp = n;      //unsigned long nsamp = n - sample; -    unsigned long nsamp = usefixedrate ? fixedsize : n - sample; +    unsigned long nsamp = usefixedrate ? fixedsize : nframes - sample;      bool found = false;      unsigned long frame = 0;       unsigned long index = 0; @@ -1525,7 +1616,7 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        // The events happened in the last period or even before that. Shift into this period with + n. This will sync with MusEGlobal::audio.         // If the events happened even before current frame - n, make sure they are counted immediately as zero-frame.        //evframe = (pos + frameOffset > v.frame + n) ? 0 : v.frame - pos - frameOffset + n;  -      evframe = (syncFrame > v.frame + n) ? 0 : v.frame - syncFrame + n;  +      evframe = (syncFrame > v.frame + nframes) ? 0 : v.frame - syncFrame + nframes;         // Protection. Observed this condition. Why? Supposed to be linear timestamps.        if(found && evframe < frame)        { @@ -1545,7 +1636,7 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        //if(v.frame < startPos || v.frame >= (endPos + frameOffset)          //if(evframe < sample || evframe >= n          //if(evframe < sample || evframe >= (n + frameOffset) -      if(evframe >= n +      if(evframe >= nframes           //|| (found && v.frame != frame)             //|| (!usefixedrate && found && !v.unique && v.frame != frame)             //|| (found && !v.unique && evframe != frame)   @@ -1567,6 +1658,31 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        index = v.idx;        // Set the ladspa control port value.        controls[v.idx].val = v.value; +       +      // Need to update the automation value, otherwise it overwrites later with the last MusEGlobal::automation value. +      if(id() != -1) +      { +        // Since we are now in the audio thread context, there's no need to send a message, +        //  just modify directly. +        //MusEGlobal::audio->msgSetPluginCtrlVal(_track, genACnum(_id, k), controls[k].val); +        synti->setPluginCtrlVal(genACnum(id(), v.idx), v.value); +         +        // Record automation. +        // NO! Take care of this immediately in the OSC control handler, because we don't want  +        //  any delay. +        // OTOH Since this is the actual place and time where the control ports values +        //  are set, best to reflect what happens here to automation. +        // However for dssi-vst it might be best to handle it that way. +         +        //AutomationType at = _track->automationType(); +        // TODO: Taken from our native gui control handlers.  +        // This may need modification or may cause problems -  +        //  we don't have the luxury of access to the dssi gui controls ! +        //if(at == AUTO_WRITE || (MusEGlobal::audio->isPlaying() && at == AUTO_TOUCH)) +        //  enableController(k, false); +        //_track->recordAutomation(id, v.value); +      }   +            }      // Process automation control values now. @@ -1583,8 +1699,8 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP      if(found && !usefixedrate)        //nsamp = frame - sample + 1;        nsamp = frame - sample; -    if(sample + nsamp >= n)         // Safety check. -      nsamp = n - sample;  +    if(sample + nsamp >= nframes)         // Safety check. +      nsamp = nframes - sample;       //printf("DssiSynthIF::getData n:%d frame:%lu sample:%lu nsamp:%lu pos:%d fOffset:%d syncFrame:%lu loopcount:%d\n",       //       n, frame, sample, nsamp, pos, frameOffset, syncFrame, loopcount);   // REMOVE Tim. @@ -1596,10 +1712,10 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP      nevents = 0;      // Process event list events... -    for(; i != el->end(); ++i)  +    for(; start_event != el->end(); ++start_event)       {        //if(i->time() >= (endPos + frameOffset))  // NOTE: frameOffset? Tested, examined printouts of times: Seems OK for playback. -      if(i->time() >= (pos + sample + nsamp + frameOffset))  // frameOffset? Test again... +      if(start_event->time() >= (pos + sample + nsamp + frameOffset))  // frameOffset? Test again...          break;        #ifdef DSSI_DEBUG  @@ -1611,40 +1727,40 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        if(synti->midiPort() != -1)        {          MusECore::MidiPort* mp = &MusEGlobal::midiPorts[synti->midiPort()]; -        if(i->type() == MusECore::ME_CONTROLLER)  +        if(start_event->type() == MusECore::ME_CONTROLLER)           { -          int da = i->dataA(); -          int db = i->dataB(); +          int da = start_event->dataA(); +          int db = start_event->dataB();            db = mp->limitValToInstrCtlRange(da, db); -          if(!mp->setHwCtrlState(i->channel(), da, db)) +          if(!mp->setHwCtrlState(start_event->channel(), da, db))              continue;          }          else -        if(i->type() == MusECore::ME_PITCHBEND)  +        if(start_event->type() == MusECore::ME_PITCHBEND)           { -          int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, i->dataA()); -          if(!mp->setHwCtrlState(i->channel(), MusECore::CTRL_PITCH, da)) +          int da = mp->limitValToInstrCtlRange(MusECore::CTRL_PITCH, start_event->dataA()); +          if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PITCH, da))              continue;          }          else -        if(i->type() == MusECore::ME_PROGRAM)  +        if(start_event->type() == MusECore::ME_PROGRAM)           { -          if(!mp->setHwCtrlState(i->channel(), MusECore::CTRL_PROGRAM, i->dataA())) +          if(!mp->setHwCtrlState(start_event->channel(), MusECore::CTRL_PROGRAM, start_event->dataA()))              continue;          }        }        // Returns false if the event was not filled. It was handled, but some other way. -      if(processEvent(*i, &events[nevents])) +      if(processEvent(*start_event, &events[nevents]))        {          // Time-stamp the event.   p4.0.15 Tim. -        int ft = i->time() - frameOffset - pos; +        int ft = start_event->time() - frameOffset - pos;          if(ft < 0)            ft = 0;          //if (ft >= (int)MusEGlobal::segmentSize)           if (ft >= int(sample + nsamp))           { -          printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", i->time(), pos, frameOffset, ft, sample, nsamp); +          printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d sample:%lu nsamp:%lu\n", start_event->time(), pos, frameOffset, ft, sample, nsamp);            ///if (ft > (int)MusEGlobal::segmentSize)              //ft = MusEGlobal::segmentSize - 1;              ft = sample + nsamp - 1; @@ -1696,61 +1812,6 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        }        } -    /* -    // -    // p3.3.39 Handle inputs... -    // -    //if((MusEGlobal::song->bounceTrack != this) && !noInRoute())  -    if(!((MusECore::AudioTrack*)synti)->noInRoute())  -    { -      RouteList* irl = ((MusECore::AudioTrack*)synti)->inRoutes(); -      iRoute i = irl->begin(); -      if(!i->track->isMidiTrack()) -      { -        //if(MusEGlobal::debugMsg) -          printf("DssiSynthIF::getData: Error: First route is a midi track route!\n"); -      } -      else -      { -        int ch     = i->channel       == -1 ? 0 : i->channel; -        int remch  = i->remoteChannel == -1 ? 0 : i->remoteChannel; -        int chs    = i->channels      == -1 ? 0 : i->channels; -         -        // TODO: -        //if(ch >= synth->_inports) -        //iUsedIdx[ch] = true; -        //if(chs == 2) -        //  iUsedIdx[ch + 1] = true; -         -        //((MusECore::AudioTrack*)i->track)->copyData(framePos, channels, nframe, bp); -        ((MusECore::AudioTrack*)i->track)->copyData(pos, ports,  -                                        //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,  -                                        i->channel,  -                                        i->channels, -                                        n, bp); -      } -       -      //unsigned pos, int ports, unsigned n, float** buffer     -       -      ++i; -      for(; i != irl->end(); ++i) -      { -        if(i->track->isMidiTrack()) -        { -          //if(MusEGlobal::debugMsg) -            printf("DssiSynthIF::getData: Error: Route is a midi track route!\n"); -          continue; -        } -        //((MusECore::AudioTrack*)i->track)->addData(framePos, channels, nframe, bp); -        ((MusECore::AudioTrack*)i->track)->addData(framePos, channels,  -                                          //(i->track->type() == Track::AUDIO_SOFTSYNTH && i->channel != -1) ? i->channel : 0,  -                                          i->channel,  -                                          i->channels, -                                          nframe, bp); -      } -    }   -    */   -            k = 0;      // Connect the given buffers directly to the ports, up to a max of synth ports.      for(; k < nop; ++k) @@ -1758,9 +1819,21 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP      // Connect the remaining ports to some local buffers (not used yet).      for(; k < synth->_outports; ++k)        descr->connect_port(handle, synth->oIdx[k], audioOutBuffers[k] + sample); -    // Just connect all inputs to some local buffers (not used yet). TODO: Support inputs.  +    // Connect all inputs either to some local buffers, or a silence buffer.       for(k = 0; k < synth->_inports; ++k) -      descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample); +    {   +      //printf(" k:%d synth->iIdx[k]:%d\n", k, synth->iIdx[k]);   +      if(synth->iUsedIdx[k]) +      { +        synth->iUsedIdx[k] = false; // Reset +        descr->connect_port(handle, synth->iIdx[k], audioInBuffers[k] + sample); +      } +      else +      { +        //printf(" input used size:%ld idx:%ld = %d silencing...\n", synth->iUsedIdx.size(), k, synth->iUsedIdx[k]);   +        descr->connect_port(handle, synth->iIdx[k], audioInSilenceBuf + sample); +      }   +    }      // Run the synth for a period of time. This processes events and gets/fills our local buffers...      if(synth->dssi->run_synth) @@ -1772,10 +1845,10 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP        snd_seq_event_t* ev = events;        synth->dssi->run_multiple_synths(1, &handle, nsamp, &ev, &nevents);      } +    // TIP: Until we add programs to plugins, uncomment these four checks to load dssi effects as synths, in order to have programs.       //else       //if(synth->dssi->LADSPA_Plugin->run)               //{ -    //  // Just a test, worked OK.      //  synth->dssi->LADSPA_Plugin->run(handle, nsamp);           //} @@ -1783,14 +1856,13 @@ MusECore::iMPEvent DssiSynthIF::getData(MusECore::MidiPort* /*mp*/, MusECore::MP      loopcount++;       // REMOVE Tim.    } -  return i; +  return start_event;  }  //---------------------------------------------------------  //   putEvent  //--------------------------------------------------------- -//bool DssiSynthIF::putEvent(const MidiEvent& ev)  bool DssiSynthIF::putEvent(const MusECore::MidiPlayEvent& ev)        {        #ifdef DSSI_DEBUG  @@ -2033,16 +2105,37 @@ int DssiSynthIF::oscControl(unsigned long port, float value)      fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%lu\n", cport);    } -  MusECore::ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport); -  if(ip != synth->port2MidiCtlMap.end()) +  // Record automation: +  // Take care of this immediately, because we don't want the silly delay associated with  +  //  processing the fifo one-at-a-time in the apply(). +  // NOTE: With some vsts we don't receive control events until the user RELEASES a control.  +  // So the events all arrive at once when the user releases a control. +  // That makes this pretty useless... But what the heck... +  if(id() != -1)    { +    //int id = genACnum(_id, cport); +    unsigned long pid = genACnum(id(), cport); +    AutomationType at = synti->automationType(); +   +    // TODO: Taken from our native gui control handlers.  +    // This may need modification or may cause problems -  +    //  we don't have the luxury of access to the dssi gui controls ! +    if(at == AUTO_WRITE || (MusEGlobal::audio->isPlaying() && at == AUTO_TOUCH)) +      enableController(cport, false); +       +    synti->recordAutomation(pid, value); +  }  +    +  //MusECore::ciMidiCtl2LadspaPort ip = synth->port2MidiCtlMap.find(cport); +  //if(ip != synth->port2MidiCtlMap.end()) +  //{      // TODO: TODO: Update midi MusE's midi controller knobs, sliders, boxes etc with a call to the midi port's setHwCtrlState() etc.      // But first we need a ladspa2MidiValue() function!  ...       //      //      //float val = ladspa2MidiValue(ld, i, ?, ?);  -  } +  //}    return 0;  } @@ -2064,8 +2157,8 @@ int DssiSynthIF::oscMidi(int a, int b, int c)        {          MusECore::MidiPlayEvent event(0, port, channel, a, b, c); -        #ifdef DSSI_DEBUG  -        printf(stderr, "DssiSynthIF::oscMidi midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB());   +        #ifdef DSSI_DEBUG    +        printf("DssiSynthIF::oscMidi midi event chn:%d a:%d b:%d\n", event.channel(), event.dataA(), event.dataB());            #endif          MusEGlobal::midiPorts[port].sendEvent(event); @@ -2329,7 +2422,8 @@ QString DssiSynthIF::name() const                            { return synti->nam  QString DssiSynthIF::lib() const                             { return synth ? synth->completeBaseName() : QString(); }  QString DssiSynthIF::dirPath() const                         { return synth ? synth->absolutePath() : QString(); }  QString DssiSynthIF::fileName() const                        { return synth ? synth->fileName() : QString(); } -MusECore::AudioTrack* DssiSynthIF::track()                  { return (MusECore::AudioTrack*)synti; } +QString DssiSynthIF::titlePrefix() const                     { return QString(); } +MusECore::AudioTrack* DssiSynthIF::track()                   { return (MusECore::AudioTrack*)synti; }  void DssiSynthIF::enableController(unsigned long i, bool v)  { controls[i].enCtrl = v; }   bool DssiSynthIF::controllerEnabled(unsigned long i) const   { return controls[i].enCtrl; }    bool DssiSynthIF::controllerEnabled2(unsigned long i) const  { return controls[i].en2Ctrl; }    diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h index 9b00b642..2836d72e 100644 --- a/muse2/muse/dssihost.h +++ b/muse2/muse/dssihost.h @@ -76,7 +76,8 @@ class DssiSynth : public Synth {        unsigned long _portCount, _inports, _outports, _controlInPorts, _controlOutPorts;        std::vector<unsigned long> iIdx;  // Audio input index to port number.        std::vector<unsigned long> oIdx;  // Audio output index to port number. -      std::vector<bool> iUsedIdx;       // During process, tells whether an audio input port was used by any input routes. +      //std::vector<bool> iUsedIdx;       // During process, tells whether an audio input port was used by any input routes. +      std::vector<int> iUsedIdx;       // During process, tells whether an audio input port was used by any input routes.        std::vector<unsigned long> rpIdx; // Port number to control input index. Item is -1 if it's not a control input.        MusECore::MidiCtl2LadspaPortMap midiCtl2PortMap;   // Maps midi controller numbers to DSSI port numbers.        MusECore::MidiCtl2LadspaPortMap port2MidiCtlMap;   // Maps DSSI port numbers to midi controller numbers. @@ -88,6 +89,8 @@ class DssiSynth : public Synth {     public:        DssiSynth(QFileInfo&, const DSSI_Descriptor*); // removed const for QFileInfo        virtual ~DssiSynth(); +      virtual Type synthType() const { return DSSI_SYNTH; } +        virtual void incInstances(int);        virtual SynthIF* createSIF(SynthI*); @@ -122,6 +125,7 @@ class DssiSynthIF : public SynthIF, public PluginIBase        float** audioInBuffers;        float** audioOutBuffers; +      float*  audioInSilenceBuf; // Just all zeros all the time, so we don't have to clear for silence.     public:        DssiSynthIF(SynthI* s); @@ -195,6 +199,7 @@ class DssiSynthIF : public SynthIF, public PluginIBase        QString lib() const;                    QString dirPath() const;        QString fileName() const; +      QString titlePrefix() const;        MusECore::AudioTrack* track();                  void enableController(unsigned long /*i*/, bool v = true);              bool controllerEnabled(unsigned long /*i*/) const;           diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp index bb9f42f4..0abbbd76 100644 --- a/muse2/muse/gconfig.cpp +++ b/muse2/muse/gconfig.cpp @@ -129,8 +129,8 @@ GlobalConfigValues config = {        -60.0,                        // double minSlider;        false,                        // use Jack freewheel        20,                           // int guiRefresh; -      QString(""),                  // userInstrumentsDir -      //QString(""),                  // helpBrowser; // Obsolete +      QString(""),                  // userInstrumentsDir  // Obsolete. Must keep for compatibility. +      //QString(""),                // helpBrowser; // Obsolete        true,                         // extendedMidi        384,                          // division for smf export        QString(""),                  // copyright string for smf export @@ -187,7 +187,12 @@ GlobalConfigValues config = {        64,                           // minControlProcessPeriod        false,                        // popupsDefaultStayOpen        false,                        // leftMouseButtonCanDecrease -      false                         // rangeMarkerWithoutMMB +      false,                        // rangeMarkerWithoutMMB +      true,                         // addHiddenTracks +      true                          // unhideTracks +      }; +//GlobalConfigValues globalConfig = config; +      } // namespace MusEGlobal diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h index d9038ea1..95b88170 100644 --- a/muse2/muse/gconfig.h +++ b/muse2/muse/gconfig.h @@ -109,7 +109,7 @@ struct GlobalConfigValues {        double minSlider;        bool freewheelMode;        int guiRefresh; -      QString userInstrumentsDir; +      QString userInstrumentsDir;  // Obsolete. Must keep for compatibility.        bool extendedMidi;      // extended smf format        int midiDivision;       // division for smf export @@ -164,6 +164,9 @@ struct GlobalConfigValues {        bool popupsDefaultStayOpen;        bool leftMouseButtonCanDecrease;        bool rangeMarkerWithoutMMB; +      bool addHiddenTracks; +      bool unhideTracks; +        }; diff --git a/muse2/muse/globals.cpp b/muse2/muse/globals.cpp index 05ba1011..d50ea1eb 100644 --- a/muse2/muse/globals.cpp +++ b/muse2/muse/globals.cpp @@ -165,6 +165,12 @@ const char* med_file_save_pattern[] = {        QT_TRANSLATE_NOOP("file_patterns", "All Files (*)"),        0        }; +const char* project_create_file_save_pattern[] = { +      QT_TRANSLATE_NOOP("file_patterns", "Uncompressed med Files (*.med)"), +      QT_TRANSLATE_NOOP("file_patterns", "gzip compressed med Files (*.med.gz)"), +      QT_TRANSLATE_NOOP("file_patterns", "bzip2 compressed med Files (*.med.bz2)"), +      0 +      };  const char* image_file_pattern[] = {        QT_TRANSLATE_NOOP("file_patterns", "(*.jpg *.gif *.png)"), diff --git a/muse2/muse/globals.h b/muse2/muse/globals.h index ae624fb8..7563c171 100644 --- a/muse2/muse/globals.h +++ b/muse2/muse/globals.h @@ -94,6 +94,7 @@ extern const char* midi_file_pattern[];  extern const char* midi_file_save_pattern[];  extern const char* med_file_pattern[];  extern const char* med_file_save_pattern[]; +extern const char* project_create_file_save_pattern[];  extern const char* image_file_pattern[];  //extern const char* ctrl_file_pattern[];  extern const char* part_file_pattern[]; diff --git a/muse2/muse/helper.cpp b/muse2/muse/helper.cpp index 682bfe8e..f560fbfb 100644 --- a/muse2/muse/helper.cpp +++ b/muse2/muse/helper.cpp @@ -20,6 +20,8 @@  //  //========================================================= +#include <list> +  #include "helper.h"  #include "part.h"  #include "track.h" @@ -28,8 +30,22 @@  #include "icons.h"  #include "synth.h"  #include "functions.h" +#include "gconfig.h" + +#include "driver/jackmidi.h" +#include "route.h" +#include "mididev.h" +#include "globaldefs.h" +#include "audio.h" +#include "audiodev.h" +#include "midiseq.h"  #include <QApplication> +#include <QDir> +#include <QFileInfo> +#include <QFileDialog> +#include <QString> +//#include <QTemporaryFile>  #ifdef DSSI_SUPPORT  #include "dssihost.h" @@ -118,170 +134,56 @@ QMenu* populateAddSynth(QWidget* parent)    //typedef std::multimap<std::string, int, addSynth_cmp_str >::iterator imap;    typedef std::multimap<std::string, int >::iterator imap; -  MusECore::MessSynth* synMESS   = 0; -  QMenu* synpMESS = 0; -  asmap mapMESS; - -  #ifdef DSSI_SUPPORT -  MusECore::DssiSynth* synDSSI   = 0; -  QMenu* synpDSSI = 0; -  asmap mapDSSI; -  #endif                   -  #ifdef VST_SUPPORT -  MusECore::VstSynth*  synVST    = 0; -  QMenu* synpVST  = 0; -  asmap mapVST; -  #endif                   +  int ntypes = MusECore::Synth::SYNTH_TYPE_END; +  asmap smaps[ntypes]; +  QMenu* mmaps[ntypes]; +  for(int itype = 0; itype < ntypes; ++itype) +    mmaps[itype] = 0; -  // Not necessary, but what the heck. -  QMenu* synpOther = 0; -  asmap mapOther; +  MusECore::Synth* synth; +  MusECore::Synth::Type type; -  //const int synth_base_id = 0x1000;    int ii = 0;    for(std::vector<MusECore::Synth*>::iterator i = MusEGlobal::synthis.begin(); i != MusEGlobal::synthis.end(); ++i)     { -    synMESS = dynamic_cast<MusECore::MessSynth*>(*i); -    if(synMESS) -    { -      mapMESS.insert( std::pair<std::string, int> (std::string(synMESS->description().toLower().toLatin1().constData()), ii) ); -    } -    else -    { -       -      #ifdef DSSI_SUPPORT -      synDSSI = dynamic_cast<MusECore::DssiSynth*>(*i); -      if(synDSSI) -      { -        mapDSSI.insert( std::pair<std::string, int> (std::string(synDSSI->description().toLower().toLatin1().constData()), ii) ); -      } -      else -      #endif                       -       -      { -        #ifdef VST_SUPPORT -        synVST = dynamic_cast<MusECore::VstSynth*>(*i); -        if(synVST) -        { -          mapVST.insert( std::pair<std::string, int> (std::string(synVST->description().toLower().toLatin1().constData()), ii) ); -        } -        else -        #endif                       -         -        { -          mapOther.insert( std::pair<std::string, int> (std::string((*i)->description().toLower().toLatin1().constData()), ii) ); -        } -      } -    } +    synth = *i; +    type = synth->synthType(); +    if(type >= ntypes) +      continue;  +    smaps[type].insert( std::pair<std::string, int> (std::string(synth->description().toLower().toLatin1().constData()), ii) );      ++ii;    }    int sz = MusEGlobal::synthis.size(); -  for(imap i = mapMESS.begin(); i != mapMESS.end(); ++i)  -  { -    int idx = i->second; -    if(idx > sz)           // Sanity check -      continue; -    MusECore::Synth* s = MusEGlobal::synthis[idx]; -    if(s) +  for(int itype = 0; itype < ntypes; ++itype) +  {   +    for(imap i = smaps[itype].begin(); i != smaps[itype].end(); ++i)       { -      // No MESS sub-menu yet? Create it now. -      if(!synpMESS) -        synpMESS = new QMenu(parent); -      QAction* sM = synpMESS->addAction(s->description() + " <" + s->name() + ">"); -      sM->setData(MENU_ADD_SYNTH_ID_BASE + idx); -    }   -  } -   -  #ifdef DSSI_SUPPORT -  for(imap i = mapDSSI.begin(); i != mapDSSI.end(); ++i)  -  { -    int idx = i->second; -    if(idx > sz)            -      continue; -    MusECore::Synth* s = MusEGlobal::synthis[idx]; -    if(s) -    { -      // No DSSI sub-menu yet? Create it now. -      if(!synpDSSI) -        synpDSSI = new QMenu(parent); -      //synpDSSI->insertItem(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">", MENU_ADD_SYNTH_ID_BASE + idx); -      QAction* sD = synpDSSI->addAction(s->description() + " <" + s->name() + ">"); -      sD->setData(MENU_ADD_SYNTH_ID_BASE + idx); -    }   -  } -  #endif -   -  #ifdef VST_SUPPORT -  for(imap i = mapVST.begin(); i != mapVST.end(); ++i)  -  { -    int idx = i->second; -    if(idx > sz)            -      continue; -    Synth* s = MusEGlobal::synthis[idx]; -    if(s) -    { -      // No VST sub-menu yet? Create it now. -      if(!synpVST) -        synpVST = new QMenu(parent); -      QAction* sV = synpVST->addAction(s->description() + " <" + "@default", s->name() + ">"); -      sV->setData(MENU_ADD_SYNTH_ID_BASE + idx); -    }   -  } -  #endif -   -  for(imap i = mapOther.begin(); i != mapOther.end(); ++i)  -  { -    int idx = i->second; -    if(idx > sz)           -      continue; -    MusECore::Synth* s = MusEGlobal::synthis[idx]; -    // No Other sub-menu yet? Create it now. -    if(!synpOther) -      synpOther = new QMenu(parent); -    //synpOther->insertItem(QT_TRANSLATE_NOOP("@default", s->description()) + " <" + QT_TRANSLATE_NOOP("@default", s->name()) + ">", MENU_ADD_SYNTH_ID_BASE + idx); -    QAction* sO = synpOther->addAction(s->description() + " <" + s->name() + ">"); -    sO->setData(MENU_ADD_SYNTH_ID_BASE + idx); -  } -   -  if(synpMESS) -  { -    synpMESS->setIcon(*synthIcon); -    synpMESS->setTitle("MESS"); -    synp->addMenu(synpMESS); -  } -   -  #ifdef DSSI_SUPPORT -  if(synpDSSI) -  { -    synpDSSI->setIcon(*synthIcon); -    synpDSSI->setTitle("DSSI"); -    synp->addMenu(synpDSSI); -  }   -  #endif -   -  #ifdef VST_SUPPORT -  if(synpVST) -  { -    synpVST->setIcon(*synthIcon); -    synpVST->setTitle("FST"); -    synp->addMenu(synpVST); -  }   -  #endif -   -  if(synpOther) -  { -    synpOther->setIcon(*synthIcon); -    synpOther->setTitle(QObject::tr("Other")); -    synp->addMenu(synpOther); +      int idx = i->second; +      if(idx > sz)           // Sanity check +        continue; +      synth = MusEGlobal::synthis[idx]; +      if(synth) +      { +        // No sub-menu yet? Create it now. +        if(!mmaps[itype]) +        {   +          mmaps[itype] = new QMenu(parent); +          mmaps[itype]->setIcon(*synthIcon); +          mmaps[itype]->setTitle(MusECore::synthType2String((MusECore::Synth::Type)itype)); +          synp->addMenu(mmaps[itype]); +        }   +        QAction* act = mmaps[itype]->addAction(synth->description() + " <" + synth->name() + ">"); +        act->setData( MENU_ADD_SYNTH_ID_BASE * (itype + 1) + idx ); +      }   +    }    } -   +    return synp;  } -  //---------------------------------------------------------  //   populateAddTrack  //    this is also used in "mixer" @@ -290,19 +192,27 @@ QMenu* populateAddSynth(QWidget* parent)  QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll)        {        QActionGroup* grp = new QActionGroup(addTrack); +      if (MusEGlobal::config.addHiddenTracks) +        populateAll=true; -      QAction* midi = addTrack->addAction(QIcon(*addtrack_addmiditrackIcon), +      if (populateAll || MusECore::MidiTrack::visible()) { +        QAction* midi = addTrack->addAction(QIcon(*addtrack_addmiditrackIcon),                                            qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Midi Track"))); -      midi->setData(MusECore::Track::MIDI); -      grp->addAction(midi); -      QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon), +        midi->setData(MusECore::Track::MIDI); +        grp->addAction(midi); +      } +      if (populateAll || MusECore::MidiTrack::visible()) { +        QAction* drum = addTrack->addAction(QIcon(*addtrack_drumtrackIcon),                                            qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Drum Track"))); -      drum->setData(MusECore::Track::DRUM); -      grp->addAction(drum); -      QAction* wave = addTrack->addAction(QIcon(*addtrack_wavetrackIcon), +        drum->setData(MusECore::Track::DRUM); +        grp->addAction(drum); +      } +      if (populateAll || MusECore::WaveTrack::visible()) { +        QAction* wave = addTrack->addAction(QIcon(*addtrack_wavetrackIcon),                                            qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Wave Track"))); -      wave->setData(MusECore::Track::WAVE); -      grp->addAction(wave); +       wave->setData(MusECore::Track::WAVE); +       grp->addAction(wave); +      }        if (populateAll || MusECore::AudioOutput::visible()) {          QAction* aoutput = addTrack->addAction(QIcon(*addtrack_audiooutputIcon), @@ -332,20 +242,47 @@ QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll)          grp->addAction(aaux);        } -      // Create a sub-menu and fill it with found synth types. Make addTrack the owner. -      QMenu* synp = populateAddSynth(addTrack); -      synp->setIcon(*synthIcon); -      synp->setTitle(qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Synth"))); +      if (populateAll || MusECore::SynthI::visible()) { +        // Create a sub-menu and fill it with found synth types. Make addTrack the owner. +        QMenu* synp = populateAddSynth(addTrack); +        synp->setIcon(*synthIcon); +        synp->setTitle(qApp->translate("@default", QT_TRANSLATE_NOOP("@default", "Add Synth"))); + +        // Add the sub-menu to the given menu. +        addTrack->addMenu(synp); +      } -      // Add the sub-menu to the given menu. -      addTrack->addMenu(synp); -              //QObject::connect(addTrack, SIGNAL(triggered(QAction *)), MusEGlobal::song, SLOT(addNewTrack(QAction *)));        return grp;        } +   +//--------------------------------------------------------- +//   getFilterExtension +//--------------------------------------------------------- -} // namespace MusEGui +QString getFilterExtension(const QString &filter) +{ +  // +  // Return the first extension found. Must contain at least one * character. +  // +   +  int pos = filter.indexOf('*'); +  if(pos == -1) +    return QString();  +   +  QString filt; +  int len = filter.length(); +  ++pos; +  for( ; pos < len; ++pos) +  { +    QChar c = filter[pos]; +    if((c == ')') || (c == ';') || (c == ',') || (c == ' ')) +      break;  +    filt += filter[pos]; +  } +  return filt; +}  QStringList localizedStringListFromCharArray(const char** array, const char* context)  { @@ -355,3 +292,374 @@ QStringList localizedStringListFromCharArray(const char** array, const char* con    return temp;  } + +QString browseProjectFolder(QWidget* parent) +{ +  QString path; +  if(!MusEGlobal::config.projectBaseFolder.isEmpty()) +  {   +    QDir d(MusEGlobal::config.projectBaseFolder); +    path = d.absolutePath(); +  } +   +  QString dir = QFileDialog::getExistingDirectory(parent, qApp->tr("Select project directory"), path); +  if(dir.isEmpty()) +    dir = MusEGlobal::config.projectBaseFolder; +  //  projDirLineEdit->setText(dir); +  //return QFileDialog::getExistingDirectory(this, qApp.tr("Select project directory"), path); +  return dir; +} + +QString projectTitleFromFilename(QString filename) +{ +  int idx; +  idx = filename.lastIndexOf(".med.bz2", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".med.gz", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".med", -1, Qt::CaseInsensitive); +    +  if(idx != -1) +    filename.truncate(idx); +   +  QFileInfo fi(filename); + +  //return fi.baseName(); +  return fi.fileName(); +} + +QString projectPathFromFilename(QString filename) +{ +  QFileInfo fi(filename); +  return QDir::cleanPath(fi.absolutePath()); +} + +QString projectExtensionFromFilename(QString filename) +{ +  int idx; +  idx = filename.lastIndexOf(".med.bz2", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".med.gz", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".med", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".bz2", -1, Qt::CaseInsensitive); +  if(idx == -1) +    idx = filename.lastIndexOf(".gz", -1, Qt::CaseInsensitive); +    +  return (idx == -1) ? QString() : filename.right(filename.size() - idx); +} + +QString getUniqueUntitledName() +{ +  QString filename("untitled"); +  //QTemporaryFile tf(MusEGlobal::config.projectBaseFolder +"/" + s + "XXXXXX.med"); +  //if(tf.open()) +  //  s = MusEGui::projectTitleFromFilename(tf.fileName()); +   +  QString fbase(MusEGlobal::config.projectBaseFolder); +   +  QString nfb = fbase; +  if(MusEGlobal::config.projectStoreInFolder)  +    nfb += "/" + filename; +  QFileInfo fi(nfb + "/" + filename + ".med");  // TODO p4.0.40 Check other extensions. +  if(!fi.exists()) +    //return filename; +    return fi.filePath(); + +  // Find a new filename +  QString nfn = filename;   +  int idx; +  for (idx=2; idx<10000; idx++) { +      QString num = QString::number(idx); +      nfn = filename + "_" + num; +      nfb = fbase; +      if(MusEGlobal::config.projectStoreInFolder)  +        nfb += "/" + nfn; +      QFileInfo fi(nfb + "/" + nfn + ".med"); +      if(!fi.exists()) +        //break; +        return fi.filePath(); +  }     + +  //if(idx >= 10000) +    printf("MusE error: Could not make untitled project name (10000 or more untitled projects in project dir - clean up!\n"); +   +  //return nfn; +     +  nfb = fbase; +  if(MusEGlobal::config.projectStoreInFolder)  +    nfb += "/" + filename; +  return nfb + "/" + filename + ".med"; +} + + +#if 1 + +// ------------------------------------------------------------------------------------------------------- +// populateMidiPorts() +// This version creats separate devices for input and output ports.  +// It does not attempt to pair them together. +// ------------------------------------------------------------------------------------------------------- +void populateMidiPorts() +{ +  if(!MusEGlobal::checkAudioDevice()) +    return; + +  MusECore::MidiDevice* dev = 0; +   +  int port_num = 0; +   +  // If Jack is running, prefer Jack midi devices over ALSA. +  if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::JACK_AUDIO)   +  { +    std::list<QString> sl; +    sl = MusEGlobal::audioDevice->inputPorts(true, 1);  // Ask for second aliases. +    for(std::list<QString>::iterator i = sl.begin(); i != sl.end(); ++i) +    { +      dev = MusECore::MidiJackDevice::createJackMidiDevice(*i, 1);  +      if(dev) +      { +        //printf("populateMidiPorts Created jack writeable device: %s\n", dev->name().toLatin1().constData());  +        //dev->setOpenFlags(1); +        MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +        MusECore::Route srcRoute(dev, -1); +        MusECore::Route dstRoute(*i, true, -1, MusECore::Route::JACK_ROUTE); +        MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); +        if(++port_num == MIDI_PORTS) +          return; +      }   +    } +     +    sl = MusEGlobal::audioDevice->outputPorts(true, 1); // Ask for second aliases. +    for(std::list<QString>::iterator i = sl.begin(); i != sl.end(); ++i) +    { +      dev = MusECore::MidiJackDevice::createJackMidiDevice(*i, 2);  +      if(dev) +      { +        //printf("populateMidiPorts Created jack readable device: %s\n", dev->name().toLatin1().constData());  +        //dev->setOpenFlags(2); +        MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +        MusECore::Route srcRoute(*i, false, -1, MusECore::Route::JACK_ROUTE); +        MusECore::Route dstRoute(dev, -1); +        MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); +        if(++port_num == MIDI_PORTS) +          return; +      }   +    } +  } +  else +  // If Jack is not running, use ALSA devices. +  if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::DUMMY_AUDIO)   +  { +    for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  +    { +      if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) +        continue; +      dev = *i; +      // Select only sensible devices first - not thru etc. +      //if( ... ) +      //  continue; +       +      //dev->setOpenFlags(1); +      MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +         +      if(++port_num == MIDI_PORTS) +        return; +    } + +    //for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  +    //{ +    //  if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) +    //    continue; +    //  // Select the ones ignored in the first pass. +    //  if(!  ... ) +    //    continue; +    //     +    //  dev->setOpenFlags(1); +    //  MusEGlobal::midiSeq->msgSetMidiDevice(port_num, dev); +    //     +    //  if(++port_num == MIDI_PORTS) +    //    return; +    //} +  } +     +  //MusEGlobal::muse->changeConfig(true);     // save configuration file +  //MusEGlobal::song->update(); +   +} + +#else + +// ------------------------------------------------------------------------------------------------------- +// populateMidiPorts() +// This version worked somewhat well with system devices.  +// But no, it is virtually impossible to tell from the names whether ports should be paired. +// There is too much room for error - what markers to look for ("capture_"/"playback_") etc. +// It works kind of OK with 'seq' Jack Midi ALSA devices, but not for 'raw' which have a different +//  naming structure ("in-hw-0-0-0"/"out-hw-0-0-0"). +// It also fails to combine if the ports were named by a client app, for example another instance of MusE. +// ------------------------------------------------------------------------------------------------------- + +void populateMidiPorts() +{ +  if(!MusEGlobal::checkAudioDevice()) +    return; + +  MusECore::MidiDevice* dev = 0; +   +  int port_num = 0; +   +  // If Jack is running, prefer Jack midi devices over ALSA. +  if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::JACK_AUDIO)   +  { +    std::list<QString> wsl; +    std::list<QString> rsl; +    //wsl = MusEGlobal::audioDevice->inputPorts(true, 1);  // Ask for second aliases. +    wsl = MusEGlobal::audioDevice->inputPorts(true, 0);  // Ask for first aliases. +    //rsl = MusEGlobal::audioDevice->outputPorts(true, 1); // Ask for second aliases. +    rsl = MusEGlobal::audioDevice->outputPorts(true, 0); // Ask for first aliases. + +    for(std::list<QString>::iterator wi = wsl.begin(); wi != wsl.end(); ++wi) +    { +      QString ws = *wi; +      int y = ws.lastIndexOf("_"); +      if(y >= 1) +      {   +        int x = ws.lastIndexOf("_", y-1); +        if(x >= 0) +          ws.remove(x, y - x); +      } +       +       +      bool match_found = false; +      for(std::list<QString>::iterator ri = rsl.begin(); ri != rsl.end(); ++ri) +      { +        QString rs = *ri; +        int y = rs.lastIndexOf("_"); +        if(y >= 1) +        {   +          int x = rs.lastIndexOf("_", y-1); +          if(x >= 0) +            rs.remove(x, y - x); +        } +         +        // Do we have a matching pair? +        if(rs == ws) +        { +          // Would like to remove the client name, but no, we need it as a distinguishing identifier. +          //int z = ws.indexOf(":"); +          //if(z >= 0) +          //  ws.remove(0, z + 1); +           +          dev = MusECore::MidiJackDevice::createJackMidiDevice(ws, 3);  +          if(dev) +          { +            //printf("populateMidiPorts Created jack writeable/readable device: %s\n", dev->name().toLatin1().constData());  +            //dev->setOpenFlags(1); +            MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +            MusECore::Route devRoute(dev, -1); +            MusECore::Route wdstRoute(*wi, true, -1, MusECore::Route::JACK_ROUTE); +            MusECore::Route rsrcRoute(*ri, false, -1, MusECore::Route::JACK_ROUTE); +            MusEGlobal::audio->msgAddRoute(devRoute, wdstRoute); +            MusEGlobal::audio->msgAddRoute(rsrcRoute, devRoute); +            if(++port_num == MIDI_PORTS) +              return; +          }   +           +          rsl.erase(ri);  // Done with this read port. Remove. +          match_found = true; +          break; +        } +      }   +       +      if(!match_found) +      { +        // No match was found. Create a single writeable device. +        QString s = *wi; +        // Would like to remove the client name, but no, we need it as a distinguishing identifier. +        //int z = s.indexOf(":"); +        //if(z >= 0) +        //  s.remove(0, z + 1); +        dev = MusECore::MidiJackDevice::createJackMidiDevice(s, 1);  +        if(dev) +        { +          //printf("populateMidiPorts Created jack writeable device: %s\n", dev->name().toLatin1().constData());  +          //dev->setOpenFlags(1); +          MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +          MusECore::Route srcRoute(dev, -1); +          MusECore::Route dstRoute(*wi, true, -1, MusECore::Route::JACK_ROUTE); +          MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); +          if(++port_num == MIDI_PORTS) +            return; +        }   +      } +    } + +    // Create the remaining readable ports as single readable devices. +    for(std::list<QString>::iterator ri = rsl.begin(); ri != rsl.end(); ++ri) +    { +      QString s = *ri; +      // Would like to remove the client name, but no, we need it as a distinguishing identifier. +      //int z = s.indexOf(":"); +      //if(z >= 0) +      //  s.remove(0, z + 1); +      dev = MusECore::MidiJackDevice::createJackMidiDevice(s, 2);  +      if(dev) +      { +        //printf("populateMidiPorts Created jack readable device: %s\n", dev->name().toLatin1().constData());  +        //dev->setOpenFlags(2); +        MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +        MusECore::Route srcRoute(*ri, false, -1, MusECore::Route::JACK_ROUTE); +        MusECore::Route dstRoute(dev, -1); +        MusEGlobal::audio->msgAddRoute(srcRoute, dstRoute); +        if(++port_num == MIDI_PORTS) +          return; +      }   +    } +  } +  else +  // If Jack is not running, use ALSA devices. +  if(MusEGlobal::audioDevice->deviceType() == MusECore::AudioDevice::DUMMY_AUDIO)   +  { +    for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  +    { +      if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) +        continue; +      dev = *i; +      // Select only sensible devices first - not thru etc. +      //if( ... ) +      //  continue; +       +      //dev->setOpenFlags(1); +      MusEGlobal::midiSeq->msgSetMidiDevice(&MusEGlobal::midiPorts[port_num], dev); +         +      if(++port_num == MIDI_PORTS) +        return; +    } + +    //for(MusECore::iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)  +    //{ +    //  if((*i)->deviceType() != MusECore::MidiDevice::ALSA_MIDI) +    //    continue; +    //  // Select the ones ignored in the first pass. +    //  if(!  ... ) +    //    continue; +    //     +    //  dev->setOpenFlags(1); +    //  MusEGlobal::midiSeq->msgSetMidiDevice(port_num, dev); +    //     +    //  if(++port_num == MIDI_PORTS) +    //    return; +    //} +  } +     +  //MusEGlobal::muse->changeConfig(true);     // save configuration file +  //MusEGlobal::song->update(); +   +} +#endif   // populateMidiPorts + + +} // namespace MusEGui + diff --git a/muse2/muse/helper.h b/muse2/muse/helper.h index e1bf93de..f9c9a78c 100644 --- a/muse2/muse/helper.h +++ b/muse2/muse/helper.h @@ -42,8 +42,15 @@ bool any_event_selected(const std::set<Part*>&, bool in_range=false);  namespace MusEGui {  QMenu* populateAddSynth(QWidget* parent);  QActionGroup* populateAddTrack(QMenu* addTrack, bool populateAll=false); +QStringList localizedStringListFromCharArray(const char** array, const char* context); +QString getFilterExtension(const QString &filter); +QString browseProjectFolder(QWidget* parent = 0); +QString projectTitleFromFilename(QString filename); +QString projectPathFromFilename(QString filename); +QString projectExtensionFromFilename(QString filename); +QString getUniqueUntitledName(); +void populateMidiPorts();  }  -QStringList localizedStringListFromCharArray(const char** array, const char* context);  #endif diff --git a/muse2/muse/instruments/editinstrument.cpp b/muse2/muse/instruments/editinstrument.cpp index 742e0626..b90b872e 100644 --- a/muse2/muse/instruments/editinstrument.cpp +++ b/muse2/muse/instruments/editinstrument.cpp @@ -407,27 +407,10 @@ void EditInstrument::saveAs()        if(!QDir(MusEGlobal::museUserInstruments).exists())        { -        if(QMessageBox::question(this, -            tr("MusE:"), -            tr("The user instrument directory\n%1\ndoes not exist yet. Create it now?\n").arg(MusEGlobal::museUserInstruments) + -              tr("(You can change the user instruments directory at Settings->Global Settings->Midi)"), -            QMessageBox::Ok | QMessageBox::Default, -            QMessageBox::Cancel | QMessageBox::Escape, -            Qt::NoButton) == QMessageBox::Ok) -        { -          if(QDir().mkdir(MusEGlobal::museUserInstruments)) -            printf("Created user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); -          else -          { -            printf("Unable to create user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); -            QMessageBox::critical(this, tr("MusE:"), tr("Unable to create user instrument directory '%1'").arg(MusEGlobal::museUserInstruments)); -            //return; -            path = MusEGlobal::museUser; -          } -        }  -        else  -        //  return;   -          path = MusEGlobal::museUser; +        printf("MusE Error! User instrument directory: %s does not exist. Should be created at startup!\n", MusEGlobal::museUserInstruments.toLatin1().constData()); +         +        //path = MusEGlobal::museUser; +        //path = MusEGlobal::configPath;          }        //if (instrument->filePath().isEmpty()) @@ -699,27 +682,10 @@ void EditInstrument::fileSaveAs()        if(!QDir(MusEGlobal::museUserInstruments).exists())        { -        if(QMessageBox::question(this, -            tr("MusE:"), -            tr("The user instrument directory\n%1\ndoes not exist yet. Create it now?\n").arg(MusEGlobal::museUserInstruments) + -              tr("(You can change the user instruments directory at Settings->Global Settings->Midi)"), -            QMessageBox::Ok | QMessageBox::Default, -            QMessageBox::Cancel | QMessageBox::Escape, -            Qt::NoButton) == QMessageBox::Ok) -        { -          if(QDir().mkdir(MusEGlobal::museUserInstruments)) -            printf("Created user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); -          else -          { -            printf("Unable to create user instrument directory: %s\n", MusEGlobal::museUserInstruments.toLatin1().constData()); -            QMessageBox::critical(this, tr("MusE:"), tr("Unable to create user instrument directory '%1'").arg(MusEGlobal::museUserInstruments)); -            //return; -            path = MusEGlobal::museUser; -          } -        }  -        else  -        //  return;   -          path = MusEGlobal::museUser; +        printf("MusE Error! User instrument directory: %s does not exist. Should be created at startup!\n", MusEGlobal::museUserInstruments.toLatin1().constData()); +         +        //path = MusEGlobal::museUser; +        //path = MusEGlobal::configPath;          }        path += QString("/%1.idf").arg(so); diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index 8e8bb6c3..22ed3737 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -936,8 +936,69 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru  //   populatePatchPopup  //--------------------------------------------------------- +void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MType songType, bool drum) +      { +      menu->clear(); +      int mask = 0; +      bool drumchan = chan == 9; +      switch (songType) { +            case MT_XG: mask = 4; break; +            case MT_GS: mask = 2; break; +            case MT_GM:  +              if(drumchan) +              { +                int id = (0xff << 16) + (0xff << 8) + 0x00;  // First patch +                QAction* act = menu->addAction(gmdrumname); +                //act->setCheckable(true); +                act->setData(id); +                return; +              }   +              mask = 1;  +              break; +            case MT_UNKNOWN:  mask = 7; break; +            } +      if (pg.size() > 1) { +            for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) { +                  PatchGroup* pgp = *i; +                  //QMenu* pm = menu->addMenu(pgp->name); +                  MusEGui::PopupMenu* pm = new MusEGui::PopupMenu(pgp->name, menu, menu->stayOpen());  // Use the parent stayOpen here. +                  menu->addMenu(pm); +                  pm->setFont(MusEGlobal::config.fonts[0]); +                  const PatchList& pl = pgp->patches; +                  for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { +                        const Patch* mp = *ipl; +                        if ((mp->typ & mask) &&  +                            ((drum && songType != MT_GM) ||  +                            (mp->drum == drumchan)) )   +                            { +                              int id = ((mp->hbank & 0xff) << 16) +                                         + ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff); +                              QAction* act = pm->addAction(mp->name); +                              //act->setCheckable(true); +                              act->setData(id); +                            } +                               +                        } +                  } +            } +      else if (pg.size() == 1 ){ +            // no groups +            const PatchList& pl = pg.front()->patches; +            for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { +                  const Patch* mp = *ipl; +                  if (mp->typ & mask) { +                        int id = ((mp->hbank & 0xff) << 16) +                                 + ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff); +                        QAction* act = menu->addAction(mp->name); +                        //act->setCheckable(true); +                        act->setData(id); +                        } +                  } +            } +  } // namespace MusECore +/*  namespace MusEGui {  void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* menu, int chan, MType songType, bool drum) @@ -1000,5 +1061,6 @@ void populatePatchPopup(MusECore::MidiInstrument* midiInstrument, PopupMenu* men                    }              }        } +*/        } // namespace MusEGui diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index 3a645d7f..385e67b4 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -143,7 +143,7 @@ class MidiInstrument {        virtual void reset(int, MType);        virtual QString getPatchName(int,int,MType,bool);        //virtual void populatePatchPopup(QMenu*, int, MType, bool); -      //virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool); +      virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool);        void read(Xml&);        void write(int level, Xml&); @@ -171,8 +171,8 @@ extern void removeMidiInstrument(const MidiInstrument* instr);  } // namespace MusECore -namespace MusEGui { -extern void populatePatchPopup(MusECore::MidiInstrument*, PopupMenu*, int, MType, bool); -} +//namespace MusEGui { +//extern void populatePatchPopup(MusECore::MidiInstrument*, PopupMenu*, int, MType, bool); +//}  #endif diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp index bca5729b..214f74c2 100644 --- a/muse2/muse/liste/editevent.cpp +++ b/muse2/muse/liste/editevent.cpp @@ -871,20 +871,17 @@ void EditCtrlDialog::instrPopup()        int port    = track->outPort();        MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument(); -      ///instr->populatePatchPopup(pop, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM);        //QMenu* pup = new QMenu(this);        MusEGui::PopupMenu* pup = new MusEGui::PopupMenu(this); -      populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); +      //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); +      instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); -      ///if(pop->actions().count() == 0) -      ///  return;        if(pup->actions().count() == 0)        {          delete pup;          return;        }   -      ///QAction* rv = pop->exec(patchName->mapToGlobal(QPoint(10,5)));        QAction* rv = pup->exec(patchName->mapToGlobal(QPoint(10,5)));        if (rv) {              val = rv->data().toInt(); diff --git a/muse2/muse/liste/listedit.cpp b/muse2/muse/liste/listedit.cpp index f6a77b85..6795cedb 100644 --- a/muse2/muse/liste/listedit.cpp +++ b/muse2/muse/liste/listedit.cpp @@ -45,6 +45,7 @@  #include "event.h"  #include "midiport.h"  #include "midictrl.h" +#include "app.h"  namespace MusEGui { @@ -616,6 +617,8 @@ ListEdit::ListEdit(MusECore::PartList* pl)        initShortcuts();        setWindowTitle("MusE: List Editor"); +       +      MusEGlobal::muse->topwinMenuInited(this);        }  //--------------------------------------------------------- diff --git a/muse2/muse/main.cpp b/muse2/muse/main.cpp index 0353d0d6..d946bf00 100644 --- a/muse2/muse/main.cpp +++ b/muse2/muse/main.cpp @@ -24,6 +24,8 @@  #include <QApplication>  #include <QDir>  #include <QFile> +#include <QFileInfo> +#include <QFileInfoList>  #include <QKeyEvent>  #include <QMessageBox>  #include <QLocale> @@ -31,6 +33,8 @@  #include <QTimer>  #include <QTranslator>  #include <QIcon> +#include <QString> +#include <QStringList>  #include <sys/mman.h>  #include <alsa/asoundlib.h> @@ -41,6 +45,7 @@  #include "audiodev.h"  #include "gconfig.h"  #include "globals.h" +#include "helper.h"  #include "icons.h"  #include "sync.h"  #include "functions.h" @@ -267,9 +272,38 @@ int main(int argc, char* argv[])        if (! cPath.exists())              cPath.mkpath("."); +      // Create user templates dir if it doesn't exist +      QDir utemplDir = QDir(MusEGlobal::configPath + QString("/templates")); +      if(!utemplDir.exists()) +      {   +        utemplDir.mkpath("."); +        // Support old versions: Copy existing templates over. +        QDir old_utemplDir = QDir(QString(getenv("HOME")) + QString("/templates")); +        // printf(" old templates dir:%s\n", (QString(getenv("HOME")) + QString("/templates")).toLatin1().constData());  +        if(old_utemplDir.exists()) +        { +          //printf(" found old templates dir\n");  +          // We really just want these, even though it's possible other filenames were saved. +          // Another application might have used that directory. +          QStringList flt; flt << "*.med" << "*.med.gz" << "*.med.bz2" << "*.mid" << "*.midi" << "*.kar"; +          old_utemplDir.setNameFilters(flt); +           +          QFileInfoList fil = old_utemplDir.entryInfoList(); +          QFileInfo fi; +          foreach(fi, fil) +          { +            QString fn = fi.fileName(); +            QFile f(fi.absoluteFilePath()); +            f.copy(utemplDir.absolutePath() + "/" + fn); +            //printf(" copy old template to:%s result:%d\n", QString(utemplPath.absolutePath() + "/" + fn).toLatin1().constData(), rv);  +          } +        } +      } +              QFile cConf (MusEGlobal::configName);        QFile cConfTempl (MusEGlobal::museGlobalShare + QString("/templates/MusE.cfg")); -      if (! cConf.exists()) +      bool cConfExists = cConf.exists(); +      if (!cConfExists)        {          printf ("creating new config...\n");          if (cConfTempl.copy(MusEGlobal::configName)) @@ -303,10 +337,51 @@ int main(int argc, char* argv[])        MusEGui::init_function_dialogs(MusEGlobal::muse);        MusEGui::initShortCuts(); +        MusECore::readConfiguration(); -      MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; +      // Need to put a sane default here because we can't use ~ in the file name string. +      if(!cConfExists) +        MusEGlobal::config.projectBaseFolder = MusEGlobal::museUser + QString("/MusE"); +      //MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; +       +      // Create user instruments dir if it doesn't exist +      { +        QString uinstrPath = MusEGlobal::configPath + QString("/instruments"); +        QDir uinstrDir = QDir(uinstrPath); +        if(!uinstrDir.exists()) +          uinstrDir.mkpath("."); +         +        if(!MusEGlobal::config.userInstrumentsDir.isEmpty() && MusEGlobal::config.userInstrumentsDir != uinstrPath)  // Only if it is different. +        { +          // Support old versions: Copy existing instruments over. +          QDir old_uinstrDir(MusEGlobal::config.userInstrumentsDir); +          //printf(" old instruments dir:%s\n", MusEGlobal::config.userInstrumentsDir.toLatin1().constData());  +          if(old_uinstrDir.exists()) +          { +            //printf(" found old instruments dir\n");  +            QStringList flt; flt << "*.idf"; +            old_uinstrDir.setNameFilters(flt); +             +            QFileInfoList fil = old_uinstrDir.entryInfoList(); +            QFileInfo fi; +            foreach(fi, fil) +            { +              QString fn = fi.fileName(); +              QFile f(fi.absoluteFilePath()); +              QFile newf(uinstrDir.absolutePath() + "/" + fn); +              if(!newf.exists()) +              {   +                f.copy(newf.fileName()); +                //printf(" copy old instrument to:%s result:%d\n", newf.fileName().toLatin1().constData(), rv);  +              }   +            } +          } +        }   +        MusEGlobal::museUserInstruments = uinstrPath; +      } +              if (MusEGlobal::config.useDenormalBias)            printf("Denormal protection enabled.\n");        // SHOW MUSE SPLASH SCREEN @@ -324,7 +399,7 @@ int main(int argc, char* argv[])                    stimer->start(6000);                    }              } -       +        int i;        QString optstr("ahvdDmMsP:Y:l:py"); @@ -393,6 +468,7 @@ int main(int argc, char* argv[])        }        */ +              AL::initDsp();        if (MusEGlobal::debugMsg) @@ -438,8 +514,7 @@ int main(int argc, char* argv[])        else              MusEGlobal::realTimeScheduling = MusEGlobal::audioDevice->isRealtime(); -       -      // What unreliable nonsense. With Jack2 this reports true even if it is not running realtime.  +      // ??? With Jack2 this reports true even if it is not running realtime.         // Jack says: "Cannot use real-time scheduling (RR/10)(1: Operation not permitted)". The kernel is non-RT.        // I cannot seem to find a reliable answer to the question, even with dummy audio and system calls.        //if (MusEGlobal::debugMsg)  @@ -448,11 +523,7 @@ int main(int argc, char* argv[])        MusEGlobal::useJackTransport.setValue(true);        // setup the prefetch fifo length now that the segmentSize is known -      // Changed by Tim. p3.3.17 -      // Changed to 4 *, JUST FOR TEST!!!        MusEGlobal::fifoLength = 131072 / MusEGlobal::segmentSize; -      //MusEGlobal::fifoLength = (131072 / MusEGlobal::segmentSize) * 4; -              argc -= optind;        ++argc; @@ -498,7 +569,6 @@ int main(int argc, char* argv[])        if(MusEGlobal::loadDSSI)              MusECore::initDSSI(); -      // p3.3.39        MusECore::initOSC();        MusEGui::initIcons(); @@ -517,21 +587,19 @@ int main(int argc, char* argv[])                    ++it;                    }              } - +                    MusEGlobal::muse = new MusEGui::MusE(argc, &argv[optind]);        app.setMuse(MusEGlobal::muse);        MusEGlobal::muse->setWindowIcon(*MusEGui::museIcon); -       -      // Added by Tim. p3.3.22        if (!MusEGlobal::debugMode) {              if (mlockall(MCL_CURRENT | MCL_FUTURE))                    perror("WARNING: Cannot lock memory:");              }        MusEGlobal::muse->show(); -      MusEGlobal::muse->seqStart(); - +      MusEGlobal::muse->seqStart();   +        #ifdef HAVE_LASH        {          MusEGui::lash_client = 0; @@ -542,14 +610,28 @@ int main(int argc, char* argv[])            MusEGui::lash_client = lash_init (lash_args, muse_name, lash_flags, LASH_PROTOCOL(2,0));            lash_alsa_client_id (MusEGui::lash_client, snd_seq_client_id (MusECore::alsaSeq));            if (!noAudio) { -                // p3.3.38 -                //char *jack_name = ((JackAudioDevice*)MusEGlobal::audioDevice)->getJackName();                  const char *jack_name = MusEGlobal::audioDevice->clientName();                  lash_jack_client_name (MusEGui::lash_client, jack_name);            }                }        }  #endif /* HAVE_LASH */ + +      //-------------------------------------------------- +      // Auto-fill the midi ports, if appropriate.         p4.0.41 +      //-------------------------------------------------- +      if(argc < 2 && MusEGlobal::config.startMode == 1) +      {   +        MusEGui::populateMidiPorts(); +        //MusEGlobal::muse->changeConfig(true);     // save configuration file +        //MusEGlobal::song->update(); +      } + +      //-------------------------------------------------- +      // Load the default song.                             +      //-------------------------------------------------- +      MusEGlobal::muse->loadDefaultSong(argc, &argv[optind]);    // p4.0.41 +              QTimer::singleShot(100, MusEGlobal::muse, SLOT(showDidYouKnowDialog()));        int rv = app.exec(); diff --git a/muse2/muse/marker/markerview.cpp b/muse2/muse/marker/markerview.cpp index bc9e48b9..39ce4fc0 100644 --- a/muse2/muse/marker/markerview.cpp +++ b/muse2/muse/marker/markerview.cpp @@ -26,6 +26,7 @@  #include "markerview.h"  #include "xml.h"  #include "globals.h" +#include "app.h"  #include "sync.h"  #include "icons.h"  #include "song.h" @@ -157,7 +158,7 @@ void MarkerItem::setTick(unsigned v)  void MarkerView::closeEvent(QCloseEvent* e)        { -      emit deleted(static_cast<TopWin*>(this)); +      emit isDeleting(static_cast<TopWin*>(this));        emit closed();        e->accept();        } @@ -296,6 +297,8 @@ MarkerView::MarkerView(QWidget* parent)        updateList(); +      MusEGlobal::muse->topwinMenuInited(this); +        // work around for probable QT/WM interaction bug.        // for certain window managers, e.g xfce, this window is        // is displayed although not specifically set to show(); diff --git a/muse2/muse/marker/markerview.h b/muse2/muse/marker/markerview.h index b50ab7a4..06e22daf 100644 --- a/muse2/muse/marker/markerview.h +++ b/muse2/muse/marker/markerview.h @@ -96,7 +96,7 @@ class MarkerView : public TopWin {        void songChanged(int);     signals: -      void deleted(MusEGui::TopWin*); +      void isDeleting(MusEGui::TopWin*);        void closed();     public: diff --git a/muse2/muse/master/lmaster.cpp b/muse2/muse/master/lmaster.cpp index 52b488d0..f461e1d3 100644 --- a/muse2/muse/master/lmaster.cpp +++ b/muse2/muse/master/lmaster.cpp @@ -27,6 +27,7 @@  #include "xml.h"  #include "song.h"  #include "globals.h" +#include "app.h"  #include "audio.h"  //#include "posedit.h"  //#include "sigedit.h" @@ -286,6 +287,7 @@ LMaster::LMaster()        connect(keyButton, SIGNAL(clicked()), SLOT(insertKey()));        initShortcuts(); +      MusEGlobal::muse->topwinMenuInited(this);        }  //--------------------------------------------------------- diff --git a/muse2/muse/master/masteredit.cpp b/muse2/muse/master/masteredit.cpp index 191f82ab..f6169766 100644 --- a/muse2/muse/master/masteredit.cpp +++ b/muse2/muse/master/masteredit.cpp @@ -37,6 +37,7 @@  #include "doublelabel.h"  ///#include "sigedit.h"  #include "globals.h" +#include "app.h"  #include <values.h> @@ -269,6 +270,7 @@ MasterEdit::MasterEdit()        connect(canvas, SIGNAL(timeChanged(unsigned)),   SLOT(setTime(unsigned)));        initTopwinState(); +      MusEGlobal::muse->topwinMenuInited(this);        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/drumedit.cpp b/muse2/muse/midiedit/drumedit.cpp index b07ebbbe..52e63da0 100644 --- a/muse2/muse/midiedit/drumedit.cpp +++ b/muse2/muse/midiedit/drumedit.cpp @@ -53,6 +53,7 @@  #include "vscale.h"  #include "swidget.h"  #include "globals.h" +#include "app.h"  #include "icons.h"  #include "filedialog.h"  #include "drummap.h" @@ -535,6 +536,7 @@ DrumEdit::DrumEdit(MusECore::PartList* pl, QWidget* parent, const char* name, un        initTopwinState(); +      MusEGlobal::muse->topwinMenuInited(this);        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp index 9189d177..80d901bb 100644 --- a/muse2/muse/midiedit/ecanvas.cpp +++ b/muse2/muse/midiedit/ecanvas.cpp @@ -3,6 +3,7 @@  //  Linux Music Editor  //    $Id: ecanvas.cpp,v 1.8.2.6 2009/05/03 04:14:00 terminator356 Exp $  //  (C) Copyright 2001 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -325,54 +326,54 @@ void EventCanvas::keyPress(QKeyEvent* event)              }        // Select items by key (PianoRoll & DrumEditor)        else if (key == shortcuts[SHRT_SEL_RIGHT].key || key == shortcuts[SHRT_SEL_RIGHT_ADD].key) { -            iCItem i, iRightmost; -	    CItem* rightmost = NULL; -            //Get the rightmost selected note (if any) -            for (i = items.begin(); i != items.end(); ++i) { -                  if (i->second->isSelected()) { -                        iRightmost = i; rightmost = i->second; -                        } -                  } -               if (rightmost) { -                     iCItem temp = iRightmost; temp++; -                     //If so, deselect current note and select the one to the right -                     if (temp != items.end()) { -                           if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) -                                 deselectAll(); - -                           iRightmost++; -                           iRightmost->second->setSelected(true); -                           updateSelection(); -                           } -                     } -               //if (rightmost && mapx(rightmost->event().tick()) > width()) for some reason this doesn't this doesnt move the event in view -               //   emit followEvent(rightmost->x()); - +              rciCItem i; +              for (i = items.rbegin(); i != items.rend(); ++i)  +                if (i->second->isSelected())  +                  break; + +              if(i == items.rend()) +                i = items.rbegin(); +               +              if(i != items.rbegin()) +                --i; +              if(i->second) +              { +                if (key != shortcuts[SHRT_SEL_RIGHT_ADD].key) +                      deselectAll(); +                CItem* sel = i->second; +                sel->setSelected(true); +                updateSelection(); +                if (sel->x() + sel->width() > mapxDev(width()))  +                {   +                  int mx = rmapx(sel->x());   +                  int newx = mx + rmapx(sel->width()) - width(); +                  // Leave a bit of room for the specially-drawn drum notes. But good for piano too. +                  emit horizontalScroll( (newx > mx ? mx - 10: newx + 10) - rmapx(xorg) ); +                }   +              }              }        //Select items by key: (PianoRoll & DrumEditor)        else if (key == shortcuts[SHRT_SEL_LEFT].key || key == shortcuts[SHRT_SEL_LEFT_ADD].key) { -            iCItem i, iLeftmost; -            CItem* leftmost = NULL; -            if (items.size() > 0 ) { -                  for (i = items.end(), i--; i != items.begin(); i--) { -                        if (i->second->isSelected()) { -                              iLeftmost = i; leftmost = i->second; -                              } -                        } -                    if (leftmost) { -                          if (iLeftmost != items.begin()) { -                                //Add item -                                if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) -                                      deselectAll(); -       -                                iLeftmost--; -                                iLeftmost->second->setSelected(true); -                                updateSelection(); -                                } -                          } -                    //if (leftmost && mapx(leftmost->event().tick())< 0 ) for some reason this doesn't this doesnt move the event in view -                    //  emit followEvent(leftmost->x()); -                  } +              ciCItem i; +              for (i = items.begin(); i != items.end(); ++i)  +                if (i->second->isSelected())  +                  break; + +              if(i == items.end()) +                i = items.begin(); +               +              if(i != items.begin()) +                --i; +              if(i->second) +              { +                if (key != shortcuts[SHRT_SEL_LEFT_ADD].key) +                      deselectAll(); +                CItem* sel = i->second; +                sel->setSelected(true); +                updateSelection(); +                if (sel->x() <= mapxDev(0))  +                  emit horizontalScroll(rmapx(sel->x() - xorg) - 10);  // Leave a bit of room. +              }              }        else if (key == shortcuts[SHRT_INC_PITCH].key) {              modifySelected(NoteInfo::VAL_PITCH, 1); diff --git a/muse2/muse/midiedit/pianoroll.cpp b/muse2/muse/midiedit/pianoroll.cpp index 926f4212..8c2a7a87 100644 --- a/muse2/muse/midiedit/pianoroll.cpp +++ b/muse2/muse/midiedit/pianoroll.cpp @@ -56,6 +56,7 @@  #include "tb1.h"  #include "utils.h"  #include "globals.h" +#include "app.h"  #include "gconfig.h"  #include "icons.h"  #include "audio.h" @@ -532,6 +533,7 @@ PianoRoll::PianoRoll(MusECore::PartList* pl, QWidget* parent, const char* name,        }        initTopwinState(); +      MusEGlobal::muse->topwinMenuInited(this);        }  //--------------------------------------------------------- diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index b06f2487..51e1cafc 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -166,6 +166,15 @@ QColor* mycolors; // array [NUM_MYCOLORS]  set<QString> ScoreEdit::names; +int ScoreCanvas::_quant_power2_init=3; +int ScoreCanvas::_pixels_per_whole_init=300; +int ScoreCanvas::note_velo_init=64; +int ScoreCanvas::note_velo_off_init=64; +int ScoreCanvas::new_len_init=0; +ScoreCanvas::coloring_mode_t ScoreCanvas::coloring_mode_init=COLOR_MODE_BLACK; +bool ScoreCanvas::preamble_contains_timesig_init=true; +bool ScoreCanvas::preamble_contains_keysig_init=true; +  //---------------------------------------------------------  //   ScoreEdit @@ -293,8 +302,22 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	len_actions->addAction(n32_action);  	len_actions->addAction(nlast_action); -	nlast_action->setChecked(true); -	menu_command(CMD_NOTELEN_LAST); +	switch (ScoreCanvas::new_len_init) +	{ +		case 0: nlast_action->setChecked(true); menu_command(CMD_NOTELEN_LAST); break; +		case 1: n1_action->setChecked(true); menu_command(CMD_NOTELEN_1); break; +		case 2: n2_action->setChecked(true); menu_command(CMD_NOTELEN_2); break; +		case 4: n4_action->setChecked(true); menu_command(CMD_NOTELEN_4); break; +		case 8: n8_action->setChecked(true); menu_command(CMD_NOTELEN_8); break; +		case 16: n16_action->setChecked(true); menu_command(CMD_NOTELEN_16); break; +		case 32: n32_action->setChecked(true); menu_command(CMD_NOTELEN_32); break; +		default: +			cerr << "ERROR: THIS SHOULD NEVER HAPPEN. newLen is invalid in ScoreEdit::ScoreEdit.\n" << +							"       (newLen="<<ScoreCanvas::new_len_init<<"; the only valid values are 0,1,2,4,8,16 and 32)\n" << +							"       however, don't worry, this is no major problem, using 0 instead" << endl; +			nlast_action->setChecked(true); +			menu_command(CMD_NOTELEN_LAST); +	}  	note_settings_toolbar->addSeparator(); @@ -316,7 +339,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	connect(velo_spinbox, SIGNAL(editingFinished()), SLOT(velo_box_changed()));  	connect(this,SIGNAL(velo_changed(int)), score_canvas, SLOT(set_velo(int)));  	note_settings_toolbar->addWidget(velo_spinbox); -	velo_spinbox->setValue(64); +	velo_spinbox->setValue(ScoreCanvas::note_velo_init);  	note_settings_toolbar->addWidget(new QLabel(tr("Off-Velocity:"), note_settings_toolbar));  	velo_off_spinbox = new QSpinBox(this); @@ -327,7 +350,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	connect(velo_off_spinbox, SIGNAL(editingFinished()), SLOT(velo_off_box_changed()));  	connect(this,SIGNAL(velo_off_changed(int)), score_canvas, SLOT(set_velo_off(int)));  	note_settings_toolbar->addWidget(velo_off_spinbox); -	velo_off_spinbox->setValue(64); +	velo_off_spinbox->setValue(ScoreCanvas::note_velo_off_init); @@ -336,13 +359,16 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	quant_toolbar->addWidget(new QLabel(tr("Quantisation:"), quant_toolbar));  	quant_combobox = new QComboBox(this);  	quant_combobox->addItem("2");  // if you add or remove items from -	quant_combobox->addItem("4");  // here, also change quant_mapper[] -	quant_combobox->addItem("8");  // in ScoreCanvas::set_quant()! +	quant_combobox->addItem("4");  // here, also change all code regarding +	quant_combobox->addItem("8");  // _quant_power2 and _quant_power2_init  	quant_combobox->addItem("16"); // and MAX_QUANT_POWER (must be log2(largest_value))  	quant_combobox->addItem("32"); +	quant_combobox->setCurrentIndex(score_canvas->quant_power2()-1); +	// the above is intendedly executed BEFORE connecting. otherwise this would +	// destroy pixels_per_whole_init!  	connect(quant_combobox, SIGNAL(currentIndexChanged(int)), score_canvas, SLOT(set_quant(int)));  	quant_toolbar->addWidget(quant_combobox); -	quant_combobox->setCurrentIndex(2); +	  	quant_toolbar->addSeparator(); @@ -353,7 +379,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	connect(px_per_whole_spinbox, SIGNAL(valueChanged(int)), score_canvas, SLOT(set_pixels_per_whole(int)));  	connect(score_canvas, SIGNAL(pixels_per_whole_changed(int)), px_per_whole_spinbox, SLOT(setValue(int)));  	quant_toolbar->addWidget(px_per_whole_spinbox); -	px_per_whole_spinbox->setValue(300); +	px_per_whole_spinbox->setValue(ScoreCanvas::_pixels_per_whole_init);  	QMenu* edit_menu = menuBar()->addMenu(tr("&Edit"));       @@ -454,8 +480,18 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  			menu_mapper->setMapping(color_velo_action, CMD_COLOR_VELO);  			menu_mapper->setMapping(color_part_action, CMD_COLOR_PART); -			color_black_action->setChecked(true); -			menu_command(CMD_COLOR_BLACK); +			switch (ScoreCanvas::coloring_mode_init) +			{ +				case 0: color_black_action->setChecked(true); menu_command(CMD_COLOR_BLACK); break; +				case 1: color_velo_action->setChecked(true); menu_command(CMD_COLOR_VELO); break; +				case 2: color_part_action->setChecked(true); menu_command(CMD_COLOR_PART); break; +				default: +					cerr << "ERROR: THIS SHOULD NEVER HAPPEN. noteColor is invalid in ScoreEdit::ScoreEdit.\n" << +									"       (noteColor="<<ScoreCanvas::coloring_mode_init<<"; the only valid values are 0,1 and 2)\n" << +									"       however, don't worry, this is no major problem, using 0 instead" << endl; +					color_black_action->setChecked(true); +					menu_command(CMD_COLOR_BLACK); +			}  		QMenu* preamble_menu = settings_menu->addMenu(tr("Set up &preamble"));  			preamble_keysig_action = preamble_menu->addAction(tr("Display &key signature")); @@ -466,8 +502,8 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  			preamble_keysig_action->setCheckable(true);  			preamble_timesig_action->setCheckable(true); -			preamble_keysig_action->setChecked(true); -			preamble_timesig_action->setChecked(true); +			preamble_keysig_action->setChecked(ScoreCanvas::preamble_contains_keysig_init); +			preamble_timesig_action->setChecked(ScoreCanvas::preamble_contains_timesig_init);  		QAction* set_name_action = settings_menu->addAction(tr("Set Score &name"), menu_mapper, SLOT(map()));  		menu_mapper->setMapping(set_name_action, CMD_SET_NAME); @@ -503,6 +539,7 @@ ScoreEdit::ScoreEdit(QWidget* parent, const char* name, unsigned initPos)  	apply_velo=true;  	initTopwinState(); +	MusEGlobal::muse->topwinMenuInited(this);  }  void ScoreEdit::init_shortcuts() @@ -587,7 +624,7 @@ bool ScoreEdit::set_name(QString newname, bool emit_signal, bool emergency_name)  ScoreEdit::~ScoreEdit()  { -	 +	names.erase(name);  }  void ScoreEdit::velo_box_changed() @@ -602,9 +639,9 @@ void ScoreEdit::velo_off_box_changed()  void ScoreEdit::song_changed(int flags)  { -        if(_isDeleting)  // Ignore while while deleting to prevent crash. -          return; -         +	if(_isDeleting)  // Ignore while while deleting to prevent crash. +		return; +	       	if (flags & (SC_SELECTION | SC_EVENT_MODIFIED | SC_EVENT_REMOVED))  	{  		map<MusECore::Event*, MusECore::Part*> selection=get_events(score_canvas->get_all_parts(),1); @@ -673,8 +710,9 @@ void ScoreEdit::viewport_height_changed(int height)  void ScoreEdit::closeEvent(QCloseEvent* e)  { -        _isDeleting = true;  // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. -         +	_isDeleting = true;  // Set flag so certain signals like songChanged, which may cause crash during delete, can be ignored. +	names.erase(name); +	       	QSettings settings("MusE", "MusE-qt");  	//settings.setValue("ScoreEdit/geometry", saveGeometry());  	settings.setValue("ScoreEdit/windowState", saveState()); @@ -692,8 +730,8 @@ void ScoreEdit::menu_command(int cmd)  		{  			bool ok;  			QString newname = QInputDialog::getText(this, tr("Enter the new score title"), -                                          tr("Enter the new score title"), QLineEdit::Normal, -                                          name, &ok); +			                                    tr("Enter the new score title"), QLineEdit::Normal, +			                                    name, &ok);  			if (ok)  			{  				if (!set_name(newname)) @@ -1059,7 +1097,23 @@ void ScoreEdit::read_configuration(MusECore::Xml& xml)  		switch (token)  		{  			case MusECore::Xml::TagStart: -				if (tag == "topwin") +				if (tag=="quantPowerInit") +					ScoreCanvas::_quant_power2_init=xml.parseInt(); +				else if (tag=="pxPerWholeInit") +					ScoreCanvas::_pixels_per_whole_init=xml.parseInt(); +				else if (tag=="newNoteVeloInit") +					ScoreCanvas::note_velo_init=xml.parseInt(); +				else if (tag=="newNoteVeloOffInit") +					ScoreCanvas::note_velo_off_init=xml.parseInt(); +				else if (tag=="newLenInit") +					ScoreCanvas::new_len_init=xml.parseInt(); +				else if (tag=="noteColorInit") +					ScoreCanvas::coloring_mode_init=(ScoreCanvas::coloring_mode_t)xml.parseInt(); +				else if (tag=="preambleContainsKeysig") +					ScoreCanvas::preamble_contains_keysig_init=xml.parseInt(); +				else if (tag=="preambleContainsTimesig") +					ScoreCanvas::preamble_contains_timesig_init=xml.parseInt(); +				else if (tag == "topwin")  					TopWin::readConfiguration(SCORE, xml);  				else  					xml.unknown("ScoreEdit"); @@ -1079,7 +1133,18 @@ void ScoreEdit::read_configuration(MusECore::Xml& xml)  void ScoreEdit::write_configuration(int level, MusECore::Xml& xml)  {  	xml.tag(level++, "scoreedit"); + +	xml.intTag(level, "quantPowerInit", ScoreCanvas::_quant_power2_init); +	xml.intTag(level, "pxPerWholeInit", ScoreCanvas::_pixels_per_whole_init); +	xml.intTag(level, "newNoteVeloInit", ScoreCanvas::note_velo_init); +	xml.intTag(level, "newNoteVeloOffInit", ScoreCanvas::note_velo_off_init); +	xml.intTag(level, "newLenInit", ScoreCanvas::new_len_init); +	xml.intTag(level, "noteColorInit", ScoreCanvas::coloring_mode_init); +	xml.intTag(level, "preambleContainsKeysig", ScoreCanvas::preamble_contains_keysig_init); +	xml.intTag(level, "preambleContainsTimesig", ScoreCanvas::preamble_contains_timesig_init); +	  	TopWin::writeConfiguration(SCORE, level, xml); +  	xml.etag(level, "scoreedit");  } @@ -1216,22 +1281,20 @@ ScoreCanvas::ScoreCanvas(ScoreEdit* pr, QWidget* parent_widget) : View(parent_wi  	dragged_event_part=NULL;  	last_len=384; -	new_len=-1; +	new_len=-1; // will be initalized with new_len_init by ScoreEdit::ScoreEdit(); -	set_quant(2); //this is actually unneccessary, as while -	              //initalizing the quant_combobox, this gets -	              //called again. but for safety... -	set_pixels_per_whole(300); //same as above. but safety rocks +	_quant_power2=_quant_power2_init; // ScoreEdit relies on this to be done! +	_pixels_per_whole_init = _pixels_per_whole_init; -	set_velo(64); -	set_velo_off(64); +	note_velo=note_velo_init; +	note_velo_off_init=note_velo_off_init;  	dragging_staff=false; -	coloring_mode=COLOR_MODE_BLACK; -	preamble_contains_keysig=true; -	preamble_contains_timesig=true; +	coloring_mode=coloring_mode_init; +	preamble_contains_keysig=preamble_contains_keysig_init; +	preamble_contains_timesig=preamble_contains_timesig_init;  	x_scroll_speed=0; @@ -1455,7 +1518,7 @@ void ScoreCanvas::song_changed(int flags)  {  	if(parent && parent->deleting())  // Ignore while while deleting to prevent crash.  		return; -         +	       	if (flags & (SC_PART_MODIFIED | SC_PART_REMOVED | SC_PART_INSERTED | SC_TRACK_REMOVED))  	{  		update_parts(); @@ -1534,7 +1597,7 @@ void color_image(QImage& img, const QColor& color)  {  	uchar* ptr=img.bits();  	//int bytes=img.byteCount(); -        int bytes=img.bytesPerLine() * img.height();   // By Tim. For older Qt versions. Tested OK on Qt4.5. +	int bytes=img.bytesPerLine() * img.height();   // By Tim. For older Qt versions. Tested OK on Qt4.5.  	int r,g,b;  	color.getRgb(&r,&g,&b); @@ -4280,16 +4343,16 @@ void ScoreCanvas::menu_command(int cmd)  {  	switch (cmd)  	{ -		case CMD_COLOR_BLACK:  coloring_mode=COLOR_MODE_BLACK; redraw(); break; -		case CMD_COLOR_PART:   coloring_mode=COLOR_MODE_PART;  redraw(); break; -		case CMD_COLOR_VELO:   coloring_mode=COLOR_MODE_VELO;  redraw(); break; -		case CMD_NOTELEN_1:    new_len=TICKS_PER_WHOLE/ 1; break; -		case CMD_NOTELEN_2:    new_len=TICKS_PER_WHOLE/ 2; break; -		case CMD_NOTELEN_4:    new_len=TICKS_PER_WHOLE/ 4; break; -		case CMD_NOTELEN_8:    new_len=TICKS_PER_WHOLE/ 8; break; -		case CMD_NOTELEN_16:   new_len=TICKS_PER_WHOLE/16; break; -		case CMD_NOTELEN_32:   new_len=TICKS_PER_WHOLE/32; break; -		case CMD_NOTELEN_LAST: new_len=-1; break; +		case CMD_COLOR_BLACK:  coloring_mode_init=coloring_mode=COLOR_MODE_BLACK; redraw(); break; +		case CMD_COLOR_PART:   coloring_mode_init=coloring_mode=COLOR_MODE_PART;  redraw(); break; +		case CMD_COLOR_VELO:   coloring_mode_init=coloring_mode=COLOR_MODE_VELO;  redraw(); break; +		case CMD_NOTELEN_1:    new_len_init= 1; new_len=TICKS_PER_WHOLE/ 1; break; +		case CMD_NOTELEN_2:    new_len_init= 2; new_len=TICKS_PER_WHOLE/ 2; break; +		case CMD_NOTELEN_4:    new_len_init= 4; new_len=TICKS_PER_WHOLE/ 4; break; +		case CMD_NOTELEN_8:    new_len_init= 8; new_len=TICKS_PER_WHOLE/ 8; break; +		case CMD_NOTELEN_16:   new_len_init=16; new_len=TICKS_PER_WHOLE/16; break; +		case CMD_NOTELEN_32:   new_len_init=32; new_len=TICKS_PER_WHOLE/32; break; +		case CMD_NOTELEN_LAST: new_len_init= 0; new_len=-1; break;  		default:   			cerr << "ERROR: ILLEGAL FUNCTION CALL: ScoreCanvas::menu_command called with unknown command ("<<cmd<<")"<<endl; @@ -4299,23 +4362,24 @@ void ScoreCanvas::menu_command(int cmd)  void ScoreCanvas::preamble_keysig_slot(bool state)  {  	preamble_contains_keysig=state; +	preamble_contains_keysig_init=state;  	redraw();  }  void ScoreCanvas::preamble_timesig_slot(bool state)  {  	preamble_contains_timesig=state; +	preamble_contains_timesig_init=state;  	redraw();  }  void ScoreCanvas::set_quant(int val)  { -	int quant_mapper[]={1,2,3,4,5}; - -	if ((val>=0) && (val<signed(sizeof(quant_mapper)/sizeof(*quant_mapper)))) +	if ((val>=0) && (val<5))  	{  		int old_len=quant_len(); -		_quant_power2=quant_mapper[val]; +		_quant_power2=val+1; +		_quant_power2_init=_quant_power2;  		set_pixels_per_whole(pixels_per_whole() * quant_len() / old_len ); @@ -4342,6 +4406,7 @@ void ScoreCanvas::set_pixels_per_whole(int val)  	// zero!)  	_pixels_per_whole=val; +	_pixels_per_whole_init=val;  	for (list<staff_t>::iterator it=staves.begin(); it!=staves.end(); it++)  		it->calc_item_pos(); @@ -4383,6 +4448,7 @@ void ScoreCanvas::maybe_close_if_empty()  void ScoreCanvas::set_velo(int velo)  {  	note_velo=velo; +	note_velo_init=velo;  	if (parent->get_apply_velo())  		modify_velocity(get_all_parts(),1, 0,velo); @@ -4391,6 +4457,7 @@ void ScoreCanvas::set_velo(int velo)  void ScoreCanvas::set_velo_off(int velo)  {  	note_velo_off=velo; +	note_velo_off_init=velo;  	if (parent->get_apply_velo())  		modify_off_velocity(get_all_parts(),1, 0,velo); @@ -4586,24 +4653,23 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo  /* BUGS and potential bugs   *   o tied notes don't work properly when there's a key-change in   *     between, for example, when a cis is tied to a des - *   o schedule_all_same_len_parts: if there are two clones A and B, - *     and both A and B get scheduled to be expanded (because we - *     have one event from A and one event from B), this causes a bug, - *     because after A (and B) got resized, the B-resize is invalid! - *   o when changing toolbarstate when sharing and immediately after that + * > o when changing toolbarstate when sharing and immediately after that   *     changing "share" status, the changed state isn't stored + *     (could be solved by storing the current window when quitting/saving whatever)   *   ? pasting in editors sometimes fails oO? ( ERROR: reading eventlist   *     from clipboard failed. ignoring this one... ) [ not reproducible ] - * > o non-mdi topwin states aren't restored when launching muse2 somefile.med   * ! o using super glue while a score editor displaying the glued parts   *     is open lets muse segfault. this may or may not be fixed in   *     the release branch :/   *    * CURRENT TODO   * > o fix valgrind problems (the two "FINDMICHJETZT" lines in scoreedit.cpp) - * > o newly created windows have to be focussed! + * > o add a songposition scrollbar-toolbar (in different sizes) + *     this might be equivalent to "redo transport menu" (below). + * > o add toolbar(s) for tempo- etc spinboxes from the transport window    *   * IMPORTANT TODO + *   o support edge-scrolling when opening a lasso   *   o add "dotted quarter" quantize option (for 6/8 beat)   *   o ticks-to-quarter spinboxes   *   o mirror most menus to an additional right-click context menu to avoid the long mouse pointer @@ -4628,6 +4694,7 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo   *   o thin out: remove unneeded ctrl messages   *   * less important stuff + *   o allow "fixating" toolbars?   *   o quantize-templates (everything is forced into a specified   *                         rhythm)   *   o part-templates (you specify some notes and a control-chord; @@ -4639,8 +4706,6 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo   *       calc_pos_add_list must be called before calc_item_pos then,   *       and calc_item_pos must respect the pos_add_list instead of   *       keeping its own pos_add variable (which is only an optimisation) - *   o support edge-scrolling when opening a lasso - *   o save more configuration stuff (quant, color)   *    * really unimportant nice-to-haves   *   o support in-song clef-changes @@ -4653,10 +4718,6 @@ void ScoreCanvas::add_new_parts(const std::map< MusECore::Part*, std::set<MusECo   *    *    * stuff for the other muse developers - *   o update translations - *   o remove ambiguous translation: "offset"="zeitversatz" - *     this is ambigous in mod. note len and WRONG in mod. velo dialogs - *   *   o process accurate timesignatures from muse's list (has to be implemented first in muse)   *      ( (2+2+3)/4 or (3+2+2)/4 instead of 7/4 )   */ diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index baea78e3..37765dda 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -668,8 +668,20 @@ class ScoreCanvas : public MusEGui::View  		void move_staff_below(list<staff_t>::iterator dest, list<staff_t>::iterator src);  		void cleanup_staves();  		void maybe_close_if_empty(); -		 + +// defaults  ---------------------------------------------------------- +	public: +		enum coloring_mode_t {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO}; +		static int _quant_power2_init; +		static int _pixels_per_whole_init; +		static int note_velo_init, note_velo_off_init; +		static int new_len_init; +		static coloring_mode_t coloring_mode_init; +		static bool preamble_contains_timesig_init; +		static bool preamble_contains_keysig_init; +  // member variables --------------------------------------------------- +	private:  		int _quant_power2;  		int _pixels_per_whole; @@ -746,7 +758,7 @@ class ScoreCanvas : public MusEGui::View  		bool srec;  		bool held_notes[128]; -		enum {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_VELO} coloring_mode; +		coloring_mode_t coloring_mode;  		bool preamble_contains_keysig;  		bool preamble_contains_timesig; @@ -776,38 +788,38 @@ class ScoreCanvas : public MusEGui::View  		void add_new_parts(const std::map< MusECore::Part*, std::set<MusECore::Part*> >&); -   public slots: -      void x_scroll_event(int); -      void y_scroll_event(int); -      void song_changed(int); -      void fully_recalculate(); -			void goto_tick(int,bool); -			void pos_changed(int i, unsigned u, bool b); -			void heartbeat_timer_event(); -			 -			void set_tool(int); -			void set_quant(int); -			void menu_command(int); -			void preamble_keysig_slot(bool); -			void preamble_timesig_slot(bool); -			void set_pixels_per_whole(int); +	public slots: +		void x_scroll_event(int); +		void y_scroll_event(int); +		void song_changed(int); +		void fully_recalculate(); +		void goto_tick(int,bool); +		void pos_changed(int i, unsigned u, bool b); +		void heartbeat_timer_event(); -			void set_velo(int); -			void set_velo_off(int); +		void set_tool(int); +		void set_quant(int); +		void menu_command(int); +		void preamble_keysig_slot(bool); +		void preamble_timesig_slot(bool); +		void set_pixels_per_whole(int); -			void set_steprec(bool); -			 -			void update_parts(); //re-populates the set<MusECore::Part*>s from the set<int>s +		void set_velo(int); +		void set_velo_off(int); + +		void set_steprec(bool); + +		void update_parts(); //re-populates the set<MusECore::Part*>s from the set<int>s  	signals: -			void xscroll_changed(int); -			void yscroll_changed(int); -			void viewport_width_changed(int); -			void canvas_width_changed(int); -			void preamble_width_changed(int); -			void viewport_height_changed(int); -			void canvas_height_changed(int); -			void pixels_per_whole_changed(int); -			void pos_add_changed(); +		void xscroll_changed(int); +		void yscroll_changed(int); +		void viewport_width_changed(int); +		void canvas_width_changed(int); +		void preamble_width_changed(int); +		void viewport_height_changed(int); +		void canvas_height_changed(int); +		void pixels_per_whole_changed(int); +		void pos_add_changed();  	protected:  		virtual void draw(QPainter& p, const QRect& rect); diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp index 19fef51b..b7d1d7b7 100644 --- a/muse2/muse/midiport.cpp +++ b/muse2/muse/midiport.cpp @@ -332,8 +332,8 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort)        {          MusECore::MidiDevice* md = MusEGlobal::midiPorts[pi].device();          //if(md && !md->isSynti() && (md->rwFlags() & 1)) -        //if(md && (md->rwFlags() & 1))    -        if(md && (md->rwFlags() & 1 || md->isSynti()) )   +        if(md && (md->rwFlags() & 1))    +        //if(md && (md->rwFlags() & 1 || md->isSynti()) )  // Revert. Hm, why synths? Only writeable ports.  p4.0.41            break;        }        if(pi == MIDI_PORTS) @@ -352,8 +352,12 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort)        for (int i = 0; i < MIDI_PORTS; ++i) {              MidiPort* port = &MusEGlobal::midiPorts[i]; +            MusECore::MidiDevice* md = port->device(); +            //if(md && !(md->rwFlags() & 1 || md->isSynti()) && (i != checkPort))   +            if(md && !(md->rwFlags() & 1) && (i != checkPort))                     // Only writeable ports, or current one. +              continue;              name.sprintf("%d:%s", port->portno()+1, port->portname().toLatin1().constData()); -            if(port->device() || (i == checkPort))    +            if(md || (i == checkPort))                 {                  act = p->addAction(name);                act->setData(i); @@ -361,7 +365,7 @@ QMenu* midiPortsPopup(QWidget* parent, int checkPort)                act->setChecked(i == checkPort);              }   -            if(!port->device()) +            if(!md)              {                if(!subp)                  // No submenu yet? Create it now.                { diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp index e31db7c7..1e46db11 100644 --- a/muse2/muse/midiseq.cpp +++ b/muse2/muse/midiseq.cpp @@ -44,6 +44,7 @@  #include "synth.h"  #include "song.h"  #include "gconfig.h" +#include <lo/lo_osc_types.h>  namespace MusEGlobal {  MusECore::MidiSeq* midiSeq; @@ -54,6 +55,12 @@ namespace MusECore {  int MidiSeq::ticker = 0; +void initMidiSequencer()    +{ +      //MusEGlobal::midiSeq       = new MidiSeq(MusEGlobal::realTimeScheduling ? MusEGlobal::realTimePriority : 0, "Midi"); +      MusEGlobal::midiSeq       = new MidiSeq("Midi"); +} +  //---------------------------------------------------------  //   readMsg  //--------------------------------------------------------- @@ -819,16 +826,16 @@ void MidiSeq::msgMsg(int id)  void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device)        { -      MusECore::AudioMsg msg; -      msg.id = MusECore::SEQM_IDLE; -      msg.a  = true; -      Thread::sendMsg(&msg); - -      port->setMidiDevice(device); +        MusECore::AudioMsg msg; +        msg.id = MusECore::SEQM_IDLE; +        msg.a  = true; +        Thread::sendMsg(&msg); +         +        port->setMidiDevice(device); -      msg.id = MusECore::SEQM_IDLE; -      msg.a  = false; -      Thread::sendMsg(&msg); +        msg.id = MusECore::SEQM_IDLE; +        msg.a  = false; +        Thread::sendMsg(&msg);        }  // This does not appear to be used anymore. Was called in Audio::process1, now Audio::processMidi is called directly. p4.0.15 Tim. diff --git a/muse2/muse/mixer/amixer.cpp b/muse2/muse/mixer/amixer.cpp index 731af9a4..439a92b9 100644 --- a/muse2/muse/mixer/amixer.cpp +++ b/muse2/muse/mixer/amixer.cpp @@ -169,7 +169,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MusEGlobal::MixerConfig* c)        setWindowIcon(*museIcon);        QMenu* menuConfig = menuBar()->addMenu(tr("&Create")); -      MusEGui::populateAddTrack(menuConfig); +      MusEGui::populateAddTrack(menuConfig,true);        connect(menuConfig, SIGNAL(triggered(QAction *)), MusEGlobal::song, SLOT(addNewTrack(QAction *)));        QMenu* menuView = menuBar()->addMenu(tr("&View")); diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index 10f281fb..9c393a1a 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -147,6 +147,7 @@ void AudioStrip::songChanged(int val)          // Set the strip label's font.          //label->setFont(MusEGlobal::config.fonts[1]);          setLabelFont(); +        setLabelText();                  // Adjust minimum volume slider and label values.          slider->setRange(MusEGlobal::config.minSlider-0.1, 10.0); @@ -203,7 +204,17 @@ void AudioStrip::songChanged(int val)                    pre->setChecked(src->prefader());                    pre->blockSignals(false);                    } -            } +             +            // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!  +            // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.  +            int rc = track->auxRefCount(); +            int n = auxKnob.size(); +            for (int idx = 0; idx < n; ++idx)  +            {   +              auxKnob[idx]->setEnabled( rc == 0 ); +              auxLabel[idx]->setEnabled( rc == 0 ); +            }   +          }        if (val & SC_AUX) {              int n = auxKnob.size();              for (int idx = 0; idx < n; ++idx) { @@ -333,11 +344,14 @@ void AudioStrip::updateOffState()              stereo->setEnabled(val);        label->setEnabled(val); +      // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!  +      // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.  +      bool ae = track->auxRefCount() == 0 && val;        int n = auxKnob.size();        for (int i = 0; i < n; ++i)         { -        auxKnob[i]->setEnabled(val); -        auxLabel[i]->setEnabled(val); +        auxKnob[i]->setEnabled(ae); +        auxLabel[i]->setEnabled(ae);        }        if (pre) @@ -348,12 +362,12 @@ void AudioStrip::updateOffState()              solo->setEnabled(val);        if (mute)              mute->setEnabled(val); -      if (autoType) -            autoType->setEnabled(val); -      if (iR) -            iR->setEnabled(val); -      if (oR) -            oR->setEnabled(val); +      //if (autoType) +      //      autoType->setEnabled(val); +      //if (iR) +      //      iR->setEnabled(val); +      //if (oR) +      //      oR->setEnabled(val);        if (off) {              off->blockSignals(true);              off->setChecked(track->off()); @@ -799,6 +813,12 @@ AudioStrip::AudioStrip(QWidget* parent, MusECore::AudioTrack* at)                    double val = MusECore::fast_log10(t->auxSend(idx))*20.0;                    ak->setValue(val);                    al->setValue(val); +                   +                  // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!  +                  // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.  +                  int rc = track->auxRefCount(); +                  ak->setEnabled( rc == 0 ); +                  al->setEnabled( rc == 0 );                    }              }        else { diff --git a/muse2/muse/mixer/mstrip.cpp b/muse2/muse/mixer/mstrip.cpp index 2e51feb9..dc495aa6 100644 --- a/muse2/muse/mixer/mstrip.cpp +++ b/muse2/muse/mixer/mstrip.cpp @@ -448,9 +448,8 @@ void MidiStrip::updateOffState()        // TODO: Disabled for now.        //if (autoType)        //      autoType->setEnabled(val); -      if (iR) -            iR->setEnabled(val); -      // TODO: Disabled for now. +      //if (iR) +      //      iR->setEnabled(val);        //if (oR)        //      oR->setEnabled(val);        if (off) { @@ -504,6 +503,7 @@ void MidiStrip::songChanged(int val)          // Set the strip label's font.          //label->setFont(MusEGlobal::config.fonts[1]);          setLabelFont(); +        setLabelText();                }        } diff --git a/muse2/muse/mixer/strip.cpp b/muse2/muse/mixer/strip.cpp index b87c4629..c26a9a15 100644 --- a/muse2/muse/mixer/strip.cpp +++ b/muse2/muse/mixer/strip.cpp @@ -29,6 +29,8 @@  #include <QColor>  #include <QVBoxLayout>  #include <QFrame> +#include <QMouseEvent> +#include <QMenu>  #include "globals.h"  #include "gconfig.h" @@ -161,7 +163,8 @@ void Strip::setLabelText()        //gradient.setColorAt(0, c.darker());        //gradient.setColorAt(0, c);        //gradient.setColorAt(1, c.darker()); -      gradient.setColorAt(0, c.lighter()); +      gradient.setColorAt(0, c); +      gradient.setColorAt(0.5, c.lighter());        gradient.setColorAt(1, c);        //palette.setBrush(QPalette::Button, gradient);        //palette.setBrush(QPalette::Window, gradient); @@ -303,6 +306,23 @@ void Strip::resizeEvent(QResizeEvent* ev)    setLabelText();      setLabelFont();  }   -       + +void Strip::mousePressEvent(QMouseEvent* ev) +{ +  if (ev->button() == Qt::RightButton) { +    QMenu* menu = new QMenu; +    menu->addAction(tr("Remove track?")); +    QPoint pt = QCursor::pos(); +    QAction* act = menu->exec(pt, 0); +    if (!act) +    { +      delete menu; +      return; +    } +    MusEGlobal::song->removeTrack0(track); +    MusEGlobal::audio->msgUpdateSoloStates(); +  } +} +  } // namespace MusEGui diff --git a/muse2/muse/mixer/strip.h b/muse2/muse/mixer/strip.h index 5b3b541b..d0cde1a6 100644 --- a/muse2/muse/mixer/strip.h +++ b/muse2/muse/mixer/strip.h @@ -73,6 +73,7 @@ class Strip : public QFrame {        MusEGui::ComboBox* autoType;        void setLabelText();        virtual void resizeEvent(QResizeEvent*); +      virtual void mousePressEvent(QMouseEvent *);     private slots:        void recordToggled(bool); diff --git a/muse2/muse/node.cpp b/muse2/muse/node.cpp index dd41ba10..cb77f939 100644 --- a/muse2/muse/node.cpp +++ b/muse2/muse/node.cpp @@ -4,6 +4,7 @@  //  $Id: node.cpp,v 1.36.2.25 2009/12/20 05:00:35 terminator356 Exp $  //  //  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -25,6 +26,8 @@  #include <sndfile.h>  #include <stdlib.h> +#include <QString> +  #include "node.h"  #include "globals.h"  #include "gconfig.h" @@ -44,7 +47,6 @@  //#define NODE_DEBUG   //#define FIFO_DEBUG  -// Added by Tim. p3.3.18  //#define METRONOME_DEBUG   namespace MusECore { @@ -162,10 +164,19 @@ void Track::updateInternalSoloStates()  void MidiTrack::updateInternalSoloStates()  { -      if(this == _tmpSoloChainTrack) -        return; -       -      Track::updateInternalSoloStates(); +  if(_nodeTraversed)         // Anti circular mechanism. +  { +    fprintf(stderr, "MidiTrack::updateInternalSoloStates %s :\n  MusE Warning: Please check your routes: Circular path found!\n", name().toLatin1().constData());  +    return;                          +  }   +  //if(this == _tmpSoloChainTrack)   +  //  return; +   +  _nodeTraversed = true;  +   +  Track::updateInternalSoloStates(); +   +  _nodeTraversed = false;  // Reset.  } @@ -175,40 +186,61 @@ void MidiTrack::updateInternalSoloStates()  void AudioTrack::updateInternalSoloStates()  { -      if(this == _tmpSoloChainTrack) -        return; -       -      Track::updateInternalSoloStates(); -       -      if(_tmpSoloChainDoIns) +  if(_nodeTraversed)         // Anti circular mechanism. +  { +    fprintf(stderr, "AudioTrack::updateInternalSoloStates %s :\n  MusE Warning: Please check your routes: Circular path found!\n", name().toLatin1().constData());  +    return;                          +  }   +  //if(this == _tmpSoloChainTrack)   +  //  return; +   +  _nodeTraversed = true;  + +  Track::updateInternalSoloStates(); +   +  if(_tmpSoloChainDoIns) +  { +    if(type() == AUDIO_SOFTSYNTH) +    { +      const MusECore::MidiTrackList* ml = MusEGlobal::song->midis(); +      for(MusECore::ciMidiTrack im = ml->begin(); im != ml->end(); ++im)        { -        if(type() == AUDIO_SOFTSYNTH) -        { -          const MusECore::MidiTrackList* ml = MusEGlobal::song->midis(); -          for(MusECore::ciMidiTrack im = ml->begin(); im != ml->end(); ++im) -          { -            MusECore::MidiTrack* mt = *im; -            if(mt->outPort() >= 0 && mt->outPort() == ((SynthI*)this)->midiPort()) -              mt->updateInternalSoloStates(); -          } -        } -         -        const RouteList* rl = inRoutes(); -        for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) -        { -          if(ir->type == Route::TRACK_ROUTE) -            ir->track->updateInternalSoloStates(); -        } +        MusECore::MidiTrack* mt = *im; +        if(mt->outPort() >= 0 && mt->outPort() == ((SynthI*)this)->midiPort()) +          mt->updateInternalSoloStates();        } -      else -      {   -        const RouteList* rl = outRoutes(); -        for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) +    } +     +    const RouteList* rl = inRoutes(); +    for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) +    { +      if(ir->type == Route::TRACK_ROUTE) +        ir->track->updateInternalSoloStates(); +      else   +      // Support Midi Port -> Audio Input solo chains. p4.0.37 Tim. +      if(ir->type == Route::MIDI_PORT_ROUTE)     +      { +        const MidiTrackList* ml = MusEGlobal::song->midis(); +        for(ciMidiTrack im = ml->begin(); im != ml->end(); ++im)          { -          if(ir->type == Route::TRACK_ROUTE) -            ir->track->updateInternalSoloStates(); +          MidiTrack* mt = *im; +          if(mt->outPort() == ir->midiPort && ((1 << mt->outChannel()) & ir->channel) ) +            mt->updateInternalSoloStates();          } -      }   +      } +    } +  } +  else +  {   +    const RouteList* rl = outRoutes(); +    for(ciRoute ir = rl->begin(); ir != rl->end(); ++ir) +    { +      if(ir->type == Route::TRACK_ROUTE) +        ir->track->updateInternalSoloStates(); +    } +  }   +   +  _nodeTraversed = false; // Reset.  } @@ -221,6 +253,8 @@ void MidiTrack::updateSoloStates(bool noDec)    if(noDec && !_solo)      return; +  _nodeTraversed = true;  // Anti circular mechanism. +      _tmpSoloChainTrack = this;    _tmpSoloChainDoIns = false;    _tmpSoloChainNoDec = noDec; @@ -244,6 +278,8 @@ void MidiTrack::updateSoloStates(bool noDec)        }        }    } +   +  _nodeTraversed = false; // Reset.  } @@ -256,6 +292,8 @@ void AudioTrack::updateSoloStates(bool noDec)    if(noDec && !_solo)      return; +  _nodeTraversed = true;  // Anti circular mechanism. +    _tmpSoloChainTrack = this;    _tmpSoloChainNoDec = noDec;    updateSoloState(); @@ -301,6 +339,8 @@ void AudioTrack::updateSoloStates(bool noDec)          ir->track->updateInternalSoloStates();      }    }   +   +  _nodeTraversed = false; // Reset.  } @@ -327,7 +367,6 @@ void Track::setOff(bool val)  //   copyData  //--------------------------------------------------------- -//void AudioTrack::copyData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)  void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)  {    //Changed by T356. 12/12/09.  @@ -336,60 +375,51 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s    // Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing.    // Previously only WaveTrack used them. (Changed WaveTrack as well). +  #ifdef NODE_DEBUG +  printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().toLatin1().constData(), processed()); +  #endif +      if(srcStartChan == -1)      srcStartChan = 0; -  int srcChans = (srcChannels == -1) ? channels() : srcChannels; +  int trackChans = channels(); +  int srcChans = (srcChannels == -1) ? trackChans : srcChannels;    int srcTotalOutChans = totalOutChannels();    if(channels() == 1)      srcTotalOutChans = 1; -  #ifdef NODE_DEBUG -  printf("MusE: AudioTrack::copyData name:%s processed:%d\n", name().toLatin1().constData(), processed()); -  #endif -      // Special consideration for metronome: It is not part of the track list,    //  and it has no in or out routes, yet multiple output tracks may call addData on it !    // We can't tell how many output tracks call it, so we can only assume there might be more than one.    // Not strictly necessary here because only addData is ever called, but just to be consistent... -  //bool usedirectbuf = (outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT); -  bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); +  //bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome);    int i; -  // p3.3.38 -  //float* buffer[srcChannels];    float* buffer[srcTotalOutChans]; +  float data[nframes * srcTotalOutChans]; -   -  //float data[nframes * srcChannels]; -  //for(i = 0; i < srcChannels; ++i) -  //      buffer[i] = data + i * nframes; -            // precalculate stereo volume    double vol[2];    double _volume = volume();    double _pan = pan();    vol[0] = _volume * (1.0 - _pan);    vol[1] = _volume * (1.0 + _pan); -  float meter[srcChans]; +  float meter[trackChans];    // Have we been here already during this process cycle?    if(processed())    {      // If there is only one (or no) output routes, it's an error - we've been called more than once per process cycle! +    // No, this is no longer an error, it's deliberate. Processing no longer done in 'chains', now done randomly.  p4.0.37      #ifdef NODE_DEBUG -    if(usedirectbuf) -      printf("MusE: AudioTrack::copyData Error! One or no out routes, but already processed! Copying local buffers anyway...\n"); +    printf("MusE: AudioTrack::copyData name:%s already processed _haveData:%d\n", name().toLatin1().constData(), _haveData);      #endif      // Is there already some data gathered from a previous call during this process cycle?      if(_haveData)      {        // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. -      //for(i = 0; i < srcChannels; ++i) -      //  buffer[i] = outBuffers[i]; -      // p3.3.38        for(i = 0; i < srcTotalOutChans; ++i)          buffer[i] = outBuffers[i];      } @@ -413,29 +443,16 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s    {      // First time here during this process cycle.  -    // Point the input buffers at a temporary stack buffer. -    //float data[nframes * srcChannels]; -    //for(i = 0; i < srcChannels; ++i) -    //    buffer[i] = data + i * nframes; -    // p3.3.38 -    float data[nframes * srcTotalOutChans]; -    for(i = 0; i < srcTotalOutChans; ++i) -        buffer[i] = data + i * nframes; -   -    // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.  -    // For ex. if this is an audio input, Jack will set the pointers for us in AudioInput::getData! -    // p3.3.29 1/27/10 Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times, -    //  so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is ! -    //if(!getData(pos, srcChannels, nframes, buffer) || off() || (isMute() && !_prefader))  -    //if(off() || !getData(pos, srcChannels, nframes, buffer) || (isMute() && !_prefader))  -    // p3.3.38 -    if(off() || !getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader))  -    { +    _haveData = false;  // Reset. +    _processed = true;  // Set this now. + +    if(off())   +    {          #ifdef NODE_DEBUG -      printf("MusE: AudioTrack::copyData name:%s dstChannels:%d zeroing buffers\n", name().toLatin1().constData(), dstChannels); +      printf("MusE: AudioTrack::copyData name:%s dstChannels:%d Off, zeroing buffers\n", name().toLatin1().constData(), dstChannels);        #endif -      // No data was available. Zero the supplied buffers. +      // Track is off. Zero the supplied buffers.        unsigned int q;        for(i = 0; i < dstChannels; ++i)         { @@ -448,13 +465,12 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s            memset(dstBuffer[i], 0, sizeof(float) * nframes);        }   -      for(i = 0; i < srcChans; ++i)  +      _efxPipe->apply(0, nframes, 0);  // Just process controls only, not audio (do not 'run').     + +      for(i = 0; i < trackChans; ++i)         { -        //_meter[i] = 0;          _meter[i] = 0.0; -         -        /* -        if(!usedirectbuf) +        /*if(!usedirectbuf)          {            if(MusEGlobal::config.useDenormalBias)             { @@ -463,22 +479,49 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s            }            else                  memset(outBuffers[i], 0, sizeof(float) * nframes); -        } -        */ +        } */        } -      _haveData = false; -      _processed = true; +      //_haveData = false; +      //_processed = true; +      //_isProcessing = false;  // Unblock.        return;      } +     +    // Point the input buffers at a temporary stack buffer. +    for(i = 0; i < srcTotalOutChans; ++i) +        buffer[i] = data + i * nframes; +   +    // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.  +    // For ex. if this is an audio input, Jack will set the pointers for us in AudioInput::getData! +    // Don't do any processing at all if off. Whereas, mute needs to be ready for action at all times, +    //  so still call getData before it. Off is NOT meant to be toggled rapidly, but mute is ! +    if(!getData(pos, srcTotalOutChans, nframes, buffer) || (isMute() && !_prefader))  +    { +      #ifdef NODE_DEBUG +      printf("MusE: AudioTrack::copyData name:%s srcTotalOutChans:%d zeroing buffers\n", name().toLatin1().constData(), srcTotalOutChans); +      #endif +       +      // No data was available. Track is not off. Zero the working buffers and continue on. +      unsigned int q; +      for(i = 0; i < srcTotalOutChans; ++i) +      {   +        if(MusEGlobal::config.useDenormalBias)  +        { +          for(q = 0; q < nframes; ++q) +            buffer[i][q] = MusEGlobal::denormalBias; +        }  +        else +          memset(buffer[i], 0, sizeof(float) * nframes); +      }   +    }      //---------------------------------------------------      // apply plugin chain      //--------------------------------------------------- -    // p3.3.41      //fprintf(stderr, "AudioTrack::copyData %s efx apply srcChans:%d\n", name().toLatin1().constData(), srcChans); -    _efxPipe->apply(srcChans, nframes, buffer); +    _efxPipe->apply(trackChans, nframes, buffer);         //---------------------------------------------------      // aux sends @@ -525,18 +568,16 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s      if(_prefader)       { -      for(i = 0; i < srcChans; ++i)  +      for(i = 0; i < trackChans; ++i)           {          float* p = buffer[i];          meter[i] = 0.0;          for(unsigned k = 0; k < nframes; ++k)           { -          double f = fabs(*p); +          double f = fabs(*p++);            if(f > meter[i])              meter[i] = f; -          ++p;          } -        //_meter[i] = lrint(meter[i] * 32767.0);          _meter[i] = meter[i];          if(_meter[i] > _peak[i])            _peak[i] = _meter[i]; @@ -570,20 +611,19 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s            else                  memset(outBuffers[i], 0, sizeof(float) * nframes);          } -      } -      */   +      } */ +       -      _haveData = false; -      _processed = true; +      if(!_prefader)  +        for(i = 0; i < trackChans; ++i) // Must process ALL channels, even if unconnected. Only max 2 channels. +          _meter[i] = 0.0; +        return;      }      // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them.  -    if(!usedirectbuf) +    //if(!usedirectbuf)      { -      //for(i = 0; i < srcChannels; ++i) -      //  AL::dsp->cpy(outBuffers[i], buffer[i], nframes); -      // p3.3.38        for(i = 0; i < srcTotalOutChans; ++i)          AL::dsp->cpy(outBuffers[i], buffer[i], nframes);      } @@ -606,9 +646,9 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s        else           memset(dstBuffer[i], 0, sizeof(float) * nframes);      }         -    _processed = true;      return;    } +    // Force a source range to fit actual available total out channels.    if((srcStartChan + srcChans) > srcTotalOutChans)       srcChans = srcTotalOutChans - srcStartChan; @@ -618,132 +658,94 @@ void AudioTrack::copyData(unsigned pos, int dstChannels, int srcStartChan, int s    //    postfader metering    //--------------------------------------------------- -     -  if(srcChans == dstChannels)  +  #ifdef NODE_DEBUG +  printf("MusE: AudioTrack::copyData trackChans:%d srcTotalOutChans:%d srcStartChan:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcStartChan, srcChans, dstChannels); +  #endif +       +  if(!_prefader)     { -    if(_prefader)  +    for(int c = 0; c < trackChans; ++c)           { -      for(int c = 0; c < dstChannels; ++c)  +      meter[c] = 0.0; +      double v = (trackChans == 1 ? _volume : vol[c]);         +      float* sp = buffer[c]; +      for(unsigned k = 0; k < nframes; ++k)         { -        // p3.3.38 -        //float* sp = buffer[c]; -        float* sp = buffer[c + srcStartChan]; -         -        float* dp = dstBuffer[c]; -        for(unsigned k = 0; k < nframes; ++k) -          *dp++ = (*sp++ * vol[c]); +        float val = *sp++ * v;  // If the track is mono pan has no effect on meters. +        double f = fabs(val); +        if(f > meter[c]) +          meter[c] = f;        } -    } -    else  +      _meter[c] = meter[c]; +      if(_meter[c] > _peak[c]) +        _peak[c] = _meter[c]; +    }   +  } +     +  if(srcChans == dstChannels)  +  { +    for(int c = 0; c < dstChannels; ++c)       { -      for(int c = 0; c < dstChannels; ++c)  -      { -        meter[c] = 0.0; -         -        // p3.3.38 -        //float* sp = buffer[c]; -        float* sp = buffer[c + srcStartChan]; -         -        float* dp = dstBuffer[c]; -        //printf("2 dstBuffer[c]=%d\n",long(dstBuffer[c])); -        for(unsigned k = 0; k < nframes; ++k)  -        { -          float val = *sp++ * vol[c]; -          *dp++ = val; -          double f = fabs(val); -          if(f > meter[c]) -            meter[c] = f; -        } -        //_meter[c] = lrint(meter[c] * 32767.0); -        _meter[c] = meter[c]; -        if(_meter[c] > _peak[c]) -          _peak[c] = _meter[c]; -      } +      double v; +      if(srcStartChan > 2)      // Don't apply pan or volume to extra channels above 2. +        //v = _volume; +        v = 1.0; +      else +      if(srcChans >= 2)         // If 2 channels apply pan normally. +        v = vol[c]; +      else +      if(trackChans < 2)        // If 1 channel and track is 1 channel, don't apply pan. +        v = _volume; +      else +        v = vol[srcStartChan];  // Otherwise 1 channel but track is 2 channels. Apply the channel volume. +       +      float* sp = buffer[c + srcStartChan]; +      float* dp = dstBuffer[c]; +      for(unsigned k = 0; k < nframes; ++k) +        //*dp++ = (*sp++ * vol[c]); +        *dp++ = (*sp++ * v);      }    }    else if(srcChans == 1 && dstChannels == 2)     { -    // p3.3.38 -    //float* sp = buffer[0]; -    float* sp = buffer[srcStartChan]; -     -    if(_prefader)  +    for(int c = 0; c < dstChannels; ++c)       { -      for(int c = 0; c < dstChannels; ++c)  -      { -        float* dp = dstBuffer[c]; -        for(unsigned k = 0; k < nframes; ++k) -          *dp++ = (*sp++ * vol[c]); -      } -    } -    else  -    { -      meter[0] = 0.0; -      for(unsigned k = 0; k < nframes; ++k)  -      { -        float val = *sp++; -        double f = fabs(val) * _volume; -        if(f > meter[0]) -          meter[0] = f; -        *(dstBuffer[0] + k) = val * vol[0]; -        *(dstBuffer[1] + k) = val * vol[1]; -      } -      //_meter[0] = lrint(meter[0] * 32767.0); -      _meter[0] = meter[0]; -      if(_meter[0] > _peak[0]) -        _peak[0] = _meter[0]; +      double v; +      if(srcStartChan > 2)      // Don't apply pan or volume to extra channels above 2. +        //v = _volume; +        v = 1.0; +      else +      if(trackChans <= 1)       // If track is mono apply pan. +        v = vol[c]; +      else +        v = vol[srcStartChan];  // Otherwise track is stereo, apply the same channel volume to both. +       +      float* sp = buffer[srcStartChan]; +      float* dp = dstBuffer[c]; +      for(unsigned k = 0; k < nframes; ++k) +        //*dp++ = (*sp++ * vol[c]); +        *dp++ = (*sp++ * v);      }    }    else if(srcChans == 2 && dstChannels == 1)     { -    // p3.3.38 -    //float* sp1 = buffer[0]; -    //float* sp2 = buffer[1]; +    //double v1 = (srcStartChan > 2 ? _volume : vol[srcStartChan]);       // Don't apply pan to extra channels above 2. +    //double v2 = (srcStartChan > 2 ? _volume : vol[srcStartChan + 1]);   //  +    double v1 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan]);             // Don't apply pan or volume to extra channels above 2. +    double v2 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan + 1]);         //  +    float* dp = dstBuffer[0];      float* sp1 = buffer[srcStartChan];      float* sp2 = buffer[srcStartChan + 1]; -     -    if(_prefader)  -    { -      float* dp = dstBuffer[0]; -      for(unsigned k = 0; k < nframes; ++k) -        *dp++ = (*sp1++ * vol[0] + *sp2++ * vol[1]); -    } -    else  -    { -      float* dp = dstBuffer[0]; -      meter[0] = 0.0; -      meter[1] = 0.0; -      for(unsigned k = 0; k < nframes; ++k)  -      { -        float val1 = *sp1++ * vol[0]; -        float val2 = *sp2++ * vol[1]; -        double f1 = fabs(val1); -        if(f1 > meter[0]) -          meter[0] = f1; -        double f2 = fabs(val2); -        if(f2 > meter[1]) -          meter[1] = f2; -        *dp++ = (val1 + val2); -      } -      //_meter[0] = lrint(meter[0] * 32767.0); -      _meter[0] = meter[0]; -      if(_meter[0] > _peak[0]) -        _peak[0] = _meter[0]; -      //_meter[1] = lrint(meter[1] * 32767.0); -      _meter[1] = meter[1]; -      if(_meter[1] > _peak[1]) -        _peak[1] = _meter[1]; -    } +    for(unsigned k = 0; k < nframes; ++k) +      //*dp++ = (*sp1++ * vol[0] + *sp2++ * vol[1]); +      *dp++ = (*sp1++ * v1 + *sp2++ * v2);    } -         -  _processed = true;  }  //---------------------------------------------------------  //   addData  //--------------------------------------------------------- -//void AudioTrack::addData(unsigned pos, int dstChannels, unsigned nframes, float** dstBuffer)  void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int srcChannels, unsigned nframes, float** dstBuffer)  {    //Changed by T356. 12/12/09.  @@ -752,21 +754,21 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr    // Make better use of AudioTrack::outBuffers as a post-effect pre-volume cache system for multiple calls here during processing.    // Previously only WaveTrack used them. (Changed WaveTrack as well). -  //Added by Tim. p3.3.16    #ifdef NODE_DEBUG    printf("MusE: AudioTrack::addData name:%s processed:%d\n", name().toLatin1().constData(), processed());    #endif -  if (off()) -  { -    _processed = true; -    return; -  }  +  //if (off()) +  //{ +  //  _processed = true; +  //  return; +  //}     if(srcStartChan == -1)      srcStartChan = 0; -  int srcChans = (srcChannels == -1) ? channels() : srcChannels; +  int trackChans = channels(); +  int srcChans = (srcChannels == -1) ? trackChans : srcChannels;    int srcTotalOutChans = totalOutChannels();    if(channels() == 1)      srcTotalOutChans = 1; @@ -774,18 +776,12 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr    // Special consideration for metronome: It is not part of the track list,    //  and it has no in or out routes, yet multiple output tracks may call addData on it !    // We can't tell how many output tracks call it, so we can only assume there might be more than one. -  //bool usedirectbuf = (outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT); -  bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome); +  //bool usedirectbuf = ((outRoutes()->size() <= 1) || (type() == AUDIO_OUTPUT)) && (this != metronome);    int i; -  // p3.3.38 -  //float* buffer[srcChannels];    float* buffer[srcTotalOutChans]; -   -  //float data[nframes * srcChannels]; -  //for (i = 0; i < srcChannels; ++i) -  //      buffer[i] = data + i * nframes; +  float data[nframes * srcTotalOutChans];    // precalculate stereo volume    double vol[2]; @@ -793,105 +789,96 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr    double _pan = pan();    vol[0] = _volume * (1.0 - _pan);    vol[1] = _volume * (1.0 + _pan); -  float meter[srcChans]; +  //float meter[srcChans]; +  float meter[trackChans];    // Have we been here already during this process cycle?    if(processed())    {      // If there is only one (or no) output routes, it's an error - we've been called more than once per process cycle! +    // No, this is no longer an error, it's deliberate. Processing no longer done in 'chains', now done randomly.  p4.0.37      #ifdef NODE_DEBUG -    if(usedirectbuf) -      printf("MusE: AudioTrack::addData Error! One or no out routes, but already processed! Copying local buffers anyway...\n"); +    printf("MusE: AudioTrack::addData name:%s already processed _haveData:%d\n", name().toLatin1().constData(), _haveData);      #endif      // Is there already some data gathered from a previous call during this process cycle?      if(_haveData)      {        // Point the input buffers at our local cached 'pre-volume' buffers. They need processing, so continue on after. -      //for(i = 0; i < srcChannels; ++i) -      //  buffer[i] = outBuffers[i]; -      // p3.3.38        for(i = 0; i < srcTotalOutChans; ++i)          buffer[i] = outBuffers[i];      }      else +    {          // No data was available from a previous call during this process cycle. Nothing to add, just return.        return;   +    }      }    else    {      // First time here during this process cycle.  -    // Point the input buffers at a temporary stack buffer. -    //float data[nframes * srcChannels]; -    //for(i = 0; i < srcChannels; ++i) -    //  buffer[i] = data + i * nframes; -    // p3.3.38 -    float data[nframes * srcTotalOutChans]; -    for(i = 0; i < srcTotalOutChans; ++i) -        buffer[i] = data + i * nframes; -   +    _haveData = false;  // Reset. +    _processed = true;  // Set this now. -    // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.  -    // For ex. if this is an audio input, Jack will set the pointers for us. -    //if(!getData(pos, srcChannels, nframes, buffer))  -    // p3.3.38 -    if(!getData(pos, srcTotalOutChans, nframes, buffer))  -    { -      // No data was available. Nothing to add, but zero our local buffers and the meters. -      for(i = 0; i < srcChans; ++i) +    if(off())   +    {   +      #ifdef NODE_DEBUG +      printf("MusE: AudioTrack::addData name:%s dstChannels:%d Track is Off \n", name().toLatin1().constData(), dstChannels); +      #endif +       +      //  Nothing to zero or add... +       +      _efxPipe->apply(0, nframes, 0);  // Track is off. Just process controls only, not audio (do not 'run').     + +      for(i = 0; i < trackChans; ++i)         { -        // If we're using local buffers, we must zero them so that the next thing requiring them  -        //  during this process cycle will see zeros. -        /* -        if(!usedirectbuf) +        _meter[i] = 0.0; +        /*if(!usedirectbuf)          {            if(MusEGlobal::config.useDenormalBias)             { -            for(unsigned int q = 0; q < nframes; ++q) +            for(q = 0; q < nframes; ++q)                outBuffers[i][q] = MusEGlobal::denormalBias; -          }   -          else +          } +          else                  memset(outBuffers[i], 0, sizeof(float) * nframes); -        } -        */   -           -        //_meter[i] = 0; -        _meter[i] = 0.0; -      }       -       -      _haveData = false; -      _processed = true; +        } */ +      }        return;      } - -    /* -    // p3.3.41 Added. -    unsigned int q; -    for(i = 0; i < srcChans; ++i)  +       +    // Point the input buffers at a temporary stack buffer. +    for(i = 0; i < srcTotalOutChans; ++i) +        buffer[i] = data + i * nframes; +   +    // getData can use the supplied buffers, or change buffer to point to its own local buffers or Jack buffers etc.  +    // For ex. if this is an audio input, Jack will set the pointers for us. +    if(!getData(pos, srcTotalOutChans, nframes, buffer))       { -      if(MusEGlobal::config.useDenormalBias)  -      { -        for(q = 0; q < nframes; ++q) +      // No data was available. Track is not off. Zero the working buffers and continue on. +      unsigned int q; +      for(i = 0; i < srcTotalOutChans; ++i) +      {   +        if(MusEGlobal::config.useDenormalBias)           { -          if(q & 1) -            buffer[i][q] -= MusEGlobal::denormalBias; -          else -            buffer[i][q] += MusEGlobal::denormalBias; -        }   -      }  -    }   -    */ -     +          for(q = 0; q < nframes; ++q) +            buffer[i][q] = MusEGlobal::denormalBias; +        }  +        else +          memset(buffer[i], 0, sizeof(float) * nframes); +      }   +    } +      //---------------------------------------------------      // apply plugin chain      //--------------------------------------------------- -    // p3.3.41      //fprintf(stderr, "AudioTrack::addData %s efx apply srcChans:%d nframes:%ld %e %e %e %e\n",       //        name().toLatin1().constData(), srcChans, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); -    _efxPipe->apply(srcChans, nframes, buffer); -    // p3.3.41 +     +    _efxPipe->apply(trackChans, nframes, buffer);    +          //fprintf(stderr, "AudioTrack::addData after efx: %e %e %e %e\n",       //        buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]); @@ -940,18 +927,16 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr      if(_prefader)       { -      for(i = 0; i < srcChans; ++i)  +      for(i = 0; i < trackChans; ++i)         {          float* p = buffer[i];          meter[i] = 0.0;          for(unsigned k = 0; k < nframes; ++k)           { -          double f = fabs(*p); +          double f = fabs(*p++);            if(f > meter[i])              meter[i] = f; -          ++p;          } -        //_meter[i] = lrint(meter[i] * 32767.0);          _meter[i] = meter[i];          if(_meter[i] > _peak[i])            _peak[i] = _meter[i]; @@ -961,8 +946,7 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr      if(isMute())      {        // If we're using local buffers, we must zero them. -      /* -      if(!usedirectbuf) +      /* if(!usedirectbuf)        {          for(i = 0; i < srcChannels; ++i)          { @@ -974,20 +958,19 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr            else              memset(outBuffers[i], 0, sizeof(float) * nframes);          }     -      }   -      */ +      } */  -      _haveData = false; -      _processed = true; +      if(!_prefader)  +        //for(i = 0; i < srcChans; ++i)  +        for(i = 0; i < trackChans; ++i)    +          _meter[i] = 0.0; +                return;      }      // If we're using local cached 'pre-volume' buffers, copy the input buffers (as they are right now: post-effect pre-volume) back to them.  -    if(!usedirectbuf) +    //if(!usedirectbuf)      { -      //for(i = 0; i < srcChannels; ++i) -      //  AL::dsp->cpy(outBuffers[i], buffer[i], nframes); -      // p3.3.38        for(i = 0; i < srcTotalOutChans; ++i)          AL::dsp->cpy(outBuffers[i], buffer[i], nframes);      } @@ -1010,9 +993,9 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr        else           memset(dstBuffer[i], 0, sizeof(float) * nframes);      }         -    _processed = true;      return;    } +      // Force a source range to fit actual available total out channels.    if((srcStartChan + srcChans) > srcTotalOutChans)       srcChans = srcTotalOutChans - srcStartChan; @@ -1022,123 +1005,88 @@ void AudioTrack::addData(unsigned pos, int dstChannels, int srcStartChan, int sr    //    postfader metering    //--------------------------------------------------- -  if(srcChans == dstChannels)  +  #ifdef NODE_DEBUG +  printf("MusE: AudioTrack::addData trackChans:%d srcTotalOutChans:%d srcChans:%d dstChannels:%d\n", trackChans, srcTotalOutChans, srcChans, dstChannels); +  #endif +       +  if(!_prefader)     { -    if(_prefader)  +    for(int c = 0; c < trackChans; ++c)           { -      for(int c = 0; c < dstChannels; ++c)  +      meter[c] = 0.0; +      double v = (trackChans == 1 ? _volume : vol[c]);         +      float* sp = buffer[c]; +      for(unsigned k = 0; k < nframes; ++k)         { -        // p3.3.38 -        //float* sp = buffer[c]; -        float* sp = buffer[c + srcStartChan]; -         -        float* dp = dstBuffer[c]; -        for(unsigned k = 0; k < nframes; ++k) -          *dp++ += (*sp++ * vol[c]); +        float val = *sp++ * v;  // If the track is mono pan has no effect on meters. +        double f = fabs(val); +        if(f > meter[c]) +          meter[c] = f;        } -    } -    else  +      _meter[c] = meter[c]; +      if(_meter[c] > _peak[c]) +        _peak[c] = _meter[c]; +    }   +  } +   +  if(srcChans == dstChannels)  +  { +    for(int c = 0; c < dstChannels; ++c)       { -      for(int c = 0; c < dstChannels; ++c)  -      { -        meter[c] = 0.0; -        // p3.3.38 -        //float* sp = buffer[c]; -        float* sp = buffer[c + srcStartChan]; -         -        float* dp = dstBuffer[c]; -        for(unsigned k = 0; k < nframes; ++k)  -        { -          float val = *sp++ * vol[c]; -          *dp++ += val; -          double f = fabs(val); -          if (f > meter[c]) -                meter[c] = f; -        } -        //_meter[c] = lrint(meter[c] * 32767.0); -        _meter[c] = meter[c]; -        if(_meter[c] > _peak[c]) -          _peak[c] = _meter[c]; -      } +      double v; +      if(srcStartChan > 2)      // Don't apply pan or volume to extra channels above 2. +        //v = _volume; +        v = 1.0; +      else +      if(srcChans >= 2)         // If 2 channels apply pan normally. +        v = vol[c]; +      else +      if(trackChans < 2)        // If 1 channel and track is 1 channel, don't apply pan. +        v = _volume; +      else +        v = vol[srcStartChan];  // Otherwise 1 channel but track is 2 channels. Apply the channel volume. +       +      float* sp = buffer[c + srcStartChan]; +      float* dp = dstBuffer[c]; +      for(unsigned k = 0; k < nframes; ++k) +        //*dp++ += (*sp++ * vol[c]); +        *dp++ += (*sp++ * v);      }    }    else if(srcChans == 1 && dstChannels == 2)     { -    // p3.3.38 -    float* sp = buffer[srcStartChan]; -     -    if(_prefader)  +    for(int c = 0; c < dstChannels; ++c)       { -      for(int c = 0; c < dstChannels; ++c)  -      { -        float* dp = dstBuffer[c]; -        //float* sp = buffer[0]; -        for(unsigned k = 0; k < nframes; ++k) -          *dp++ += (*sp++ * vol[c]); -      } -    } -    else  -    { -      //float* sp = buffer[0]; -      meter[0]  = 0.0; -      for(unsigned k = 0; k < nframes; ++k)  -      { -        float val = *sp++; -        double f = fabs(val) * _volume; -        if(f > meter[0]) -          meter[0] = f; -        *(dstBuffer[0] + k) += val * vol[0]; -        *(dstBuffer[1] + k) += val * vol[1]; -      } -      //_meter[0] = lrint(meter[0] * 32767.0); -      _meter[0] = meter[0]; -      if(_meter[0] > _peak[0]) -        _peak[0] = _meter[0]; +      double v; +      if(srcStartChan > 2)      // Don't apply pan or volume to extra channels above 2. +        //v = _volume; +        v = 1.0; +      else +      if(trackChans <= 1)       // If track is mono apply pan. +        v = vol[c]; +      else +        v = vol[srcStartChan];  // Otherwise track is stereo, apply the same channel volume to both. +       +      float* sp = buffer[srcStartChan]; +      float* dp = dstBuffer[c]; +      for(unsigned k = 0; k < nframes; ++k) +        //*dp++ += (*sp++ * vol[c]); +        *dp++ += (*sp++ * v);      }    }    else if(srcChans == 2 && dstChannels == 1)     { -    // p3.3.38 -    //float* sp1 = buffer[0]; -    //float* sp2 = buffer[1]; +    //double v1 = (srcStartChan > 2 ? _volume : vol[srcStartChan]);       // Don't apply pan to extra channels above 2. +    //double v2 = (srcStartChan > 2 ? _volume : vol[srcStartChan + 1]);   //  +    double v1 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan]);             // Don't apply pan or volume to extra channels above 2. +    double v2 = (srcStartChan > 2 ? 1.0 : vol[srcStartChan + 1]);         //       float* sp1 = buffer[srcStartChan];      float* sp2 = buffer[srcStartChan + 1]; -     -    if(_prefader)  -    { -      float* dp = dstBuffer[0]; -      for(unsigned k = 0; k < nframes; ++k) -        *dp++ += (*sp1++ * vol[0] + *sp2++ * vol[1]); -    } -    else  -    { -      float* dp = dstBuffer[0]; -      meter[0] = 0.0; -      meter[1] = 0.0; -      for(unsigned k = 0; k < nframes; ++k)  -      { -        float val1 = *sp1++ * vol[0]; -        float val2 = *sp2++ * vol[1]; -        double f1 = fabs(val1); -        if(f1 > meter[0]) -          meter[0] = f1; -        double f2 = fabs(val2); -        if(f2 > meter[1]) -          meter[1] = f2; -        *dp++ += (val1 + val2); -      } -      //_meter[0] = lrint(meter[0] * 32767.0); -      _meter[0] = meter[0]; -      if(_meter[0] > _peak[0]) -        _peak[0] = _meter[0]; -      //_meter[1] = lrint(meter[1] * 32767.0); -      _meter[1] = meter[1]; -      if(_meter[1] > _peak[1]) -        _peak[1] = _meter[1]; -    } +    float* dp = dstBuffer[0]; +    for(unsigned k = 0; k < nframes; ++k) +      //*dp++ += (*sp1++ * vol[0] + *sp2++ * vol[1]); +      *dp++ += (*sp1++ * v1 + *sp2++ * v2);    } -   -  _processed = true;  }  //--------------------------------------------------------- @@ -1300,15 +1248,12 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b        printf("    calling copyData on %s...\n", ir->track->name().toLatin1().constData());        #endif -      // p3.3.38 -      //((AudioTrack*)ir->track)->copyData(pos, channels, nframes, buffer);        ((AudioTrack*)ir->track)->copyData(pos, channels,                                            //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0,                                           ir->channel,                                           ir->channels,                                           nframes, buffer); -      // p3.3.41        //fprintf(stderr, "AudioTrack::getData %s data: nframes:%ld %e %e %e %e\n", name().toLatin1().constData(), nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]);        ++ir; @@ -1320,8 +1265,6 @@ bool AudioTrack::getData(unsigned pos, int channels, unsigned nframes, float** b              if(ir->track->isMidiTrack())                continue; -            // p3.3.38 -            //((AudioTrack*)ir->track)->addData(pos, channels, nframes, buffer);              ((AudioTrack*)ir->track)->addData(pos, channels,                                                 //(ir->track->type() == Track::AUDIO_SOFTSYNTH && ir->channel != -1) ? ir->channel : 0,                                                ir->channel, @@ -1344,12 +1287,11 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe              void* jackPort = jackPorts[ch];              //float* jackbuf = 0; -            //if (jackPort) { -            // p3.3.41 Do not get buffers of unconnected client ports. Causes repeating leftover data, can be loud, or DC ! +            // Do not get buffers of unconnected client ports. Causes repeating leftover data, can be loud, or DC !              if (jackPort && MusEGlobal::audioDevice->connections(jackPort))               {                    //buffer[ch] = MusEGlobal::audioDevice->getBuffer(jackPort, nframes); -                  // p3.3.41 If the client port buffer is also used by another channel (connected to the same jack port),  +                  // If the client port buffer is also used by another channel (connected to the same jack port),                     //  don't directly set pointer, copy the data instead.                     // Otherwise the next channel will interfere - it will overwrite the buffer !                    // Verified symptoms: Can't use a splitter. Mono noise source on a stereo track sounds in mono. Etc... @@ -1366,8 +1308,6 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe                    {                        for (unsigned int i=0; i < nframes; i++)                                buffer[ch][i] += MusEGlobal::denormalBias; -                       -                      // p3.3.41                        //fprintf(stderr, "AudioInput::getData %s Jack port %p efx apply channels:%d nframes:%ld %e %e %e %e\n",                         //        name().toLatin1().constData(), jackPort, channels, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]);                    } @@ -1384,8 +1324,6 @@ bool AudioInput::getData(unsigned, int channels, unsigned nframes, float** buffe                                memset(buffer[ch], 0, nframes * sizeof(float));                    } -                  // p3.3.41 -                  //fprintf(stderr, "AudioInput::getData %s No Jack port efx apply channels:%d nframes:%ld %e %e %e %e\n",                     //        name().toLatin1().constData(), channels, nframes, buffer[0][0], buffer[0][1], buffer[0][2], buffer[0][3]);              }        } @@ -1524,7 +1462,7 @@ void AudioTrack::record()                    return;                    }              if (_recFile) { -                  // Line removed by Tim. p3.3.8 Oct 28, 2009 +                  // Line removed by Tim. Oct 28, 2009                    //_recFile->seek(pos, 0);                    //                    // Fix for recorded waves being shifted ahead by an amount @@ -1570,7 +1508,6 @@ void AudioTrack::record()                    if( (pos >= fr) && (!MusEGlobal::song->punchout() || (!MusEGlobal::song->loop() && pos < MusEGlobal::song->rPos().frame())) )                    {                      pos -= fr; -                    // Added by Tim. p3.3.8                      //int position = _recFile->seek(0, SEEK_CUR);                      //printf("AudioTrack::record loopcnt:%d lframe:%d newpos:%d curpos:%d start:%d end:%d\n", MusEGlobal::audio->loopCount(), MusEGlobal::audio->loopFrame(), pos, position, MusEGlobal::audio->getStartRecordPos().frame(), MusEGlobal::audio->getEndRecordPos().frame()); @@ -1614,7 +1551,6 @@ void AudioOutput::processInit(unsigned nframes)  void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)  { -      //Added by Tim. p3.3.16        #ifdef NODE_DEBUG        printf("MusE: AudioOutput::process name:%s processed:%d\n", name().toLatin1().constData(), processed());        #endif @@ -1622,9 +1558,6 @@ void AudioOutput::process(unsigned pos, unsigned offset, unsigned n)        for (int i = 0; i < _channels; ++i) {              buffer1[i] = buffer[i] + offset;        } -       -      // p3.3.38 -      //copyData(pos, _channels, n, buffer1);        copyData(pos, _channels, -1, -1, n, buffer1);  } @@ -1666,17 +1599,13 @@ void AudioOutput::processWrite()                          putFifo(_channels, _nframes, buffer);                    }              } -      // Changed by Tim. p3.3.18 +      // Changed by Tim.         //if (MusEGlobal::audioClickFlag && MusEGlobal::song->click()) {        if (sendMetronome() && MusEGlobal::audioClickFlag && MusEGlobal::song->click()) { -            // Added by Tim. p3.3.18              #ifdef METRONOME_DEBUG              printf("MusE: AudioOutput::processWrite Calling metronome->addData frame:%u channels:%d frames:%lu\n", MusEGlobal::audio->pos().frame(), _channels, _nframes);              #endif -     -            // p3.3.38 -            //metronome->addData(MusEGlobal::audio->pos().frame(), _channels, _nframes, buffer);              metronome->addData(MusEGlobal::audio->pos().frame(), _channels, -1, -1, _nframes, buffer);              }        } @@ -1721,7 +1650,6 @@ Fifo::~Fifo()        {        for (int i = 0; i < nbuffer; ++i)        { -        // p3.3.45          if(buffer[i]->buffer)          {            //printf("Fifo::~Fifo freeing buffer\n"); @@ -1742,7 +1670,6 @@ Fifo::~Fifo()  bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos)        { -      // Added by Tim. p3.3.17        #ifdef FIFO_DEBUG        printf("FIFO::put segs:%d samples:%lu pos:%u\n", segs, samples, pos);        #endif @@ -1765,7 +1692,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos)              // Changed by Tim. p3.3.15              //b->buffer  = new float[n];              posix_memalign((void**)&(b->buffer), 16, sizeof(float) * n); -            // p3.3.45              if(!b->buffer)              {                printf("Fifo::put could not allocate buffer segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1774,7 +1700,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos)              b->maxSize = n;              } -      // p3.3.45        if(!b->buffer)        {          printf("Fifo::put no buffer! segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1798,7 +1723,6 @@ bool Fifo::put(int segs, unsigned long samples, float** src, unsigned pos)  bool Fifo::get(int segs, unsigned long samples, float** dst, unsigned* pos)        { -      // Added by Tim. p3.3.17        #ifdef FIFO_DEBUG        printf("FIFO::get segs:%d samples:%lu\n", segs, samples);        #endif @@ -1808,7 +1732,6 @@ bool Fifo::get(int segs, unsigned long samples, float** dst, unsigned* pos)              return true;              }        FifoBuffer* b = buffer[ridx]; -      // p3.3.45        if(!b->buffer)        {          printf("Fifo::get no buffer! segs:%d samples:%lu b->pos:%u\n", segs, samples, b->pos); @@ -1844,7 +1767,6 @@ void Fifo::remove()  bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned pos)        { -      // Added by Tim. p3.3.17        #ifdef FIFO_DEBUG        printf("Fifo::getWriteBuffer segs:%d samples:%lu pos:%u\n", segs, samples, pos);        #endif @@ -1866,7 +1788,6 @@ bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned              // Changed by Tim. p3.3.15              //b->buffer = new float[n];              posix_memalign((void**)&(b->buffer), 16, sizeof(float) * n); -            // p3.3.45              if(!b->buffer)              {                printf("Fifo::getWriteBuffer could not allocate buffer segs:%d samples:%lu pos:%u\n", segs, samples, pos); @@ -1875,8 +1796,6 @@ bool Fifo::getWriteBuffer(int segs, unsigned long samples, float** buf, unsigned              b->maxSize = n;              } -       -      // p3.3.45        if(!b->buffer)        {          printf("Fifo::getWriteBuffer no buffer! segs:%d samples:%lu pos:%u\n", segs, samples, pos); diff --git a/muse2/muse/osc.cpp b/muse2/muse/osc.cpp index 6959803e..7daeb9ff 100644 --- a/muse2/muse/osc.cpp +++ b/muse2/muse/osc.cpp @@ -841,7 +841,8 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin        arguments << oscUrl                  << filePath                  << name -                << QString("channel-1"); +                //<< QString("channel-1"); +                << (titlePrefix() + label);        #ifdef OSC_DEBUG         fprintf(stderr, "OscIF::oscInitGui starting QProcess\n"); @@ -885,7 +886,8 @@ bool OscIF::oscInitGui(const QString& typ, const QString& baseName, const QStrin                   oscUrl.toLatin1().constData(),                   filePath.toLatin1().constData(),                   name.toLatin1().constData(), -                 "channel 1", (void*)0); +                 //"channel 1", (void*)0); +                 label.toLatin1().constData(), (void*)0);          // Should not return after execlp. If so it's an error.          fprintf(stderr, "exec %s %s %s %s %s failed: %s\n", @@ -941,13 +943,13 @@ void OscIF::oscShowGui(bool v)        }          //for (int i = 0; i < 5; ++i) { -      for (int i = 0; i < 10; ++i) {    // Give it a wee bit more time? +      for (int i = 0; i < 20; ++i) {    // Give it a wee bit more time?              if (_uiOscPath)                    break;              sleep(1);              }        if (_uiOscPath == 0) { -            printf("OscIF::oscShowGui(): no _uiOscPath. Error: Timeout - synth gui did not start within 10 seconds.\n"); +            printf("OscIF::oscShowGui(): no _uiOscPath. Error: Timeout - synth gui did not start within 20 seconds.\n");              return;              } @@ -1091,10 +1093,14 @@ bool OscDssiIF::oscInitGui()                             _oscSynthIF->dssiSynth()->name(), _oscSynthIF->dssiSynthI()->name(),                              _oscSynthIF->dssiSynth()->fileName(), _oscSynthIF->dssi_ui_filename());   } + +QString OscDssiIF::titlePrefix() const  +{  +  return _oscSynthIF ? _oscSynthIF->titlePrefix() : QString();  +}  #endif   // DSSI_SUPPORT -  //---------------------------------------------------------  //   OscEffectIF::  //   oscSetPluginI @@ -1165,6 +1171,11 @@ bool OscEffectIF::oscInitGui()                             _oscPluginI->plugin()->fileName(), _oscPluginI->dssi_ui_filename());    } +QString OscEffectIF::titlePrefix() const  +{  +  return _oscPluginI ? _oscPluginI->titlePrefix() : QString();  +} +  #else //OSC_SUPPORT  void initOSC() {} diff --git a/muse2/muse/osc.h b/muse2/muse/osc.h index 30df03cb..e3f1a26d 100644 --- a/muse2/muse/osc.h +++ b/muse2/muse/osc.h @@ -74,6 +74,8 @@ class OscIF        virtual bool oscInitGui() { return false; }        virtual void oscShowGui(bool);        virtual bool oscGuiVisible() const; +       +      virtual QString titlePrefix() const { return QString(); }  };  class OscEffectIF : public OscIF @@ -95,6 +97,8 @@ class OscEffectIF : public OscIF        virtual int oscConfigure(lo_arg**);        virtual bool oscInitGui(); +       +      virtual QString titlePrefix() const;   };  #ifdef DSSI_SUPPORT @@ -117,6 +121,8 @@ class OscDssiIF : public OscIF        virtual int oscConfigure(lo_arg**);        virtual bool oscInitGui(); +       +      virtual QString titlePrefix() const;   };  #endif // DSSI_SUPPORT diff --git a/muse2/muse/part.cpp b/muse2/muse/part.cpp index eb5b1af6..da01a5d5 100644 --- a/muse2/muse/part.cpp +++ b/muse2/muse/part.cpp @@ -750,6 +750,18 @@ WavePart::WavePart(const WavePart& p) : Part(p)  Part::~Part()        { +      if (_prevClone!=this || _nextClone!=this) +      { +        printf("THIS MIGHT BE A HINT FOR BUGS: Part isn't unchained in ~Part()! i'll do that now. this is\n" +               "not an actual bug, actually that manual unchain should be unneccessary if this was coded\n" +               "properly. but as it wasn't, and the unchain was always done manually, this might be an\n" +               "indicator that it have been forgotten. either your computer will explode in 3..2..1..now,\n" +               "or you can ignore this message.\n" +               "\n"); +         +        unchainClone(this); +      } +                _events->incRef(-1);        if (_events->refCount() <= 0)              delete _events; diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp index 2bdd0317..227a9daf 100644 --- a/muse2/muse/plugin.cpp +++ b/muse2/muse/plugin.cpp @@ -1573,65 +1573,60 @@ bool Pipeline::nativeGuiVisible(int idx)  //---------------------------------------------------------  //   apply +//   If ports is 0, just process controllers only, not audio (do not 'run').  //--------------------------------------------------------- -//void Pipeline::apply(int ports, unsigned long nframes, float** buffer1)  void Pipeline::apply(unsigned long ports, unsigned long nframes, float** buffer1)  {        // prepare a second set of buffers in case a plugin is not        // capable of inPlace processing - -      // Removed by Tim. p3.3.15        //float* buffer2[ports];        //float data[nframes * ports];        //for (int i = 0; i < ports; ++i)        //      buffer2[i] = data + i * nframes; -      // p3.3.41 -      //fprintf(stderr, "Pipeline::apply data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]); +      //fprintf(stderr, "Pipeline::apply data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]);          bool swap = false;        for (iPluginI ip = begin(); ip != end(); ++ip) {              PluginI* p = *ip; -            if (p && p->on()) { -                  if (p->inPlaceCapable())  -                  { -                        if (swap) -                              //p->connect(ports, buffer2, buffer2); -                              //p->connect(ports, buffer, buffer); -                              p->apply(nframes, ports, buffer, buffer);     // p4.0.21 -                        else -                              //p->connect(ports, buffer1, buffer1); -                              p->apply(nframes, ports, buffer1, buffer1);   // -                  } -                  else  -                  { -                        if (swap) -                              //p->connect(ports, buffer2, buffer1); -                              //p->connect(ports, buffer, buffer1); -                              p->apply(nframes, ports, buffer, buffer1);    // -                        else -                              //p->connect(ports, buffer1, buffer2); -                              //p->connect(ports, buffer1, buffer); -                              p->apply(nframes, ports, buffer1, buffer);    // -                        swap = !swap; -                  } -                  //p->apply(nframes);                                      // Rem. p4.0.21 -                  } +             +            if(p) +            { +              //if (p && p->on()) { +              if (p->on())  +              { +                //fprintf(stderr, "Pipeline::apply PluginI:%p on:%d\n", p, p->on());  +                if (p->inPlaceCapable())  +                { +                      if (swap) +                            p->apply(nframes, ports, buffer, buffer);      +                      else +                            p->apply(nframes, ports, buffer1, buffer1);    +                } +                else  +                { +                      if (swap) +                            p->apply(nframes, ports, buffer, buffer1);     +                      else +                            p->apply(nframes, ports, buffer1, buffer);     +                      swap = !swap; +                } +              } +              else +              { +                p->apply(nframes, 0, 0, 0); // Do not process (run) audio, process controllers only.     +              }              } -      if (swap)  +      } +      if (ports != 0 && swap)         { -            //for (int i = 0; i < ports; ++i) -            for (unsigned long i = 0; i < ports; ++i)    // p4.0.21 +            for (unsigned long i = 0; i < ports; ++i)                        //memcpy(buffer1[i], buffer2[i], sizeof(float) * nframes);                    //memcpy(buffer1[i], buffer[i], sizeof(float) * nframes);                    AL::dsp->cpy(buffer1[i], buffer[i], nframes);        } -       -      // p3.3.41 -      //fprintf(stderr, "Pipeline::apply after data: nframes:%lu %e %e %e %e\n", nframes, buffer1[0][0], buffer1[0][1], buffer1[0][2], buffer1[0][3]); -        }  //--------------------------------------------------------- @@ -2439,6 +2434,7 @@ void PluginI::showGui()        if (_plugin) {              if (_gui == 0)                      makeGui(); +            _gui->setWindowTitle(titlePrefix() + name());              if (_gui->isVisible())                      _gui->hide();              else @@ -2558,7 +2554,17 @@ void PluginI::enable2AllControllers(bool v)  }  //--------------------------------------------------------- +//   titlePrefix +//--------------------------------------------------------- + +QString PluginI::titlePrefix() const     +{  +  return _track->name() + QString(": ");  +} + +//---------------------------------------------------------  //   apply +//   If ports is 0, just process controllers only, not audio (do not 'run').  //---------------------------------------------------------  /* @@ -2653,7 +2659,6 @@ void PluginI::apply(unsigned long n)  */  #if 1 -// p4.0.21  void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut)  {        // Process control value changes. @@ -2769,7 +2774,6 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float**            //controls[v.idx].val = v.value;            controls[v.idx].tmpVal = v.value; -          /*            // Need to update the automation value, otherwise it overwrites later with the last MusEGlobal::automation value.            if(_track && _id != -1)            { @@ -2795,7 +2799,6 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float**              //  enableController(k, false);              //_track->recordAutomation(id, v.value);            }   -          */          }          // Now update the actual values from the temporary values... @@ -2813,20 +2816,23 @@ void PluginI::apply(unsigned long n, unsigned long ports, float** bufIn, float**            nsamp = n - sample;           //printf("PluginI::apply ports:%lu n:%lu frame:%lu sample:%lu nsamp:%lu syncFrame:%lu loopcount:%d\n",  -        //      ports, n, frame, sample, nsamp, syncFrame, loopcount);   // REMOVE Tim. +        //      ports, n, frame, sample, nsamp, syncFrame, loopcount);             // Don't allow zero-length runs. This could/should be checked in the control loop instead.          // Note this means it is still possible to get stuck in the top loop (at least for a while).          if(nsamp == 0)            continue; -        connect(ports, sample, bufIn, bufOut); +        if(ports != 0) +        {   +          connect(ports, sample, bufIn, bufOut); -        for(int i = 0; i < instances; ++i) -        { -          //fprintf(stderr, "PluginI::apply handle %d\n", i); -          _plugin->apply(handle[i], nsamp); -        }       +          for(int i = 0; i < instances; ++i) +          { +            //fprintf(stderr, "PluginI::apply handle %d\n", i); +            _plugin->apply(handle[i], nsamp); +          }       +        }          sample += nsamp;          loopcount++;       // REMOVE Tim. @@ -3444,7 +3450,8 @@ PluginGui::PluginGui(MusECore::PluginIBase* p)        params = 0;        paramsOut = 0;        plugin = p; -      setWindowTitle(plugin->name()); +      //setWindowTitle(plugin->name()); +      setWindowTitle(plugin->titlePrefix() + plugin->name());        QToolBar* tools = addToolBar(tr("File Buttons")); @@ -4106,16 +4113,18 @@ void PluginGui::save()  void PluginGui::bypassToggled(bool val)        { +      setWindowTitle(plugin->titlePrefix() + plugin->name());        plugin->setOn(val);        MusEGlobal::song->update(SC_ROUTE);        }  //--------------------------------------------------------- -//   songChanged +//   setOn  //---------------------------------------------------------  void PluginGui::setOn(bool val)        { +      setWindowTitle(plugin->titlePrefix() + plugin->name());        onOff->blockSignals(true);        onOff->setChecked(val);        onOff->blockSignals(false); @@ -4208,11 +4217,11 @@ void PluginGui::updateControls()         } -      if(!MusEGlobal::automation) -        return; -      AutomationType at = plugin->track()->automationType(); -      if(at == AUTO_OFF) -        return; +      //if(!MusEGlobal::automation) +      //  return; +      //AutomationType at = plugin->track()->automationType(); +      //if(at == AUTO_OFF) +      //  return;        if (params) {              //for (int i = 0; i < plugin->parameters(); ++i) {              for (unsigned long i = 0; i < plugin->parameters(); ++i) {      // p4.0.21 diff --git a/muse2/muse/plugin.h b/muse2/muse/plugin.h index 717f98b6..044fd863 100644 --- a/muse2/muse/plugin.h +++ b/muse2/muse/plugin.h @@ -72,18 +72,6 @@ class Xml;  class MidiController; -/* -//--------------------------------------------------------- -//   PluginBase -//--------------------------------------------------------- - -class PluginBase  -{ -   protected: -      void range(unsigned long i, float*, float*) const; -}; -*/    -     //---------------------------------------------------------  //   Plugin  //--------------------------------------------------------- @@ -155,13 +143,11 @@ class Plugin {              if (plugin && plugin->cleanup)                    plugin->cleanup(handle);              } -      //void connectPort(LADSPA_Handle handle, int port, float* value) { -      void connectPort(LADSPA_Handle handle, unsigned long port, float* value) {     // p4.0.21 +      void connectPort(LADSPA_Handle handle, unsigned long port, float* value) {                   if(plugin)                plugin->connect_port(handle, port, value);              } -      //void apply(LADSPA_Handle handle, int n) { -      void apply(LADSPA_Handle handle, unsigned long n) {                            // p4.0.21 +      void apply(LADSPA_Handle handle, unsigned long n) {                                          if(plugin)                plugin->run(handle, n);              } @@ -170,12 +156,10 @@ class Plugin {        int oscConfigure(LADSPA_Handle /*handle*/, const char* /*key*/, const char* /*value*/);        #endif -      //int ports() { return plugin ? plugin->PortCount : 0; }        unsigned long ports() { return _portCount; }        LADSPA_PortDescriptor portd(unsigned long k) const {              return plugin ? plugin->PortDescriptors[k] : 0; -            //return _portDescriptors[k];              }        LADSPA_PortRangeHint range(unsigned long i) { @@ -184,8 +168,7 @@ class Plugin {              return plugin->PortRangeHints[i];              } -      //double defaultValue(unsigned long port) const; -      float defaultValue(unsigned long port) const; // p4.0.21      +      float defaultValue(unsigned long port) const;         void range(unsigned long i, float*, float*) const;        CtrlValueType ctrlValueType(unsigned long /*i*/) const;        CtrlList::Mode ctrlMode(unsigned long /*i*/) const; @@ -202,20 +185,6 @@ class Plugin {        unsigned long controlInPorts() const  { return _controlInPorts; }        unsigned long controlOutPorts() const { return _controlOutPorts; }        bool inPlaceCapable() const           { return _inPlaceCapable; } -       -      /* -      bool isLog(int k) const { -            LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; -            return LADSPA_IS_HINT_LOGARITHMIC(r.HintDescriptor); -            } -      bool isBool(int k) const { -            return LADSPA_IS_HINT_TOGGLED(plugin->PortRangeHints[pIdx[k]].HintDescriptor); -            } -      bool isInt(int k) const { -            LADSPA_PortRangeHint r = plugin->PortRangeHints[pIdx[k]]; -            return LADSPA_IS_HINT_INTEGER(r.HintDescriptor); -            } -      */              };  typedef std::list<Plugin>::iterator iPlugin; @@ -266,21 +235,18 @@ class PluginIBase        ~PluginIBase();         virtual bool on() const = 0;               virtual void setOn(bool /*val*/) = 0;    -      //virtual int pluginID() = 0; -      virtual unsigned long pluginID() = 0;        // p4.0.21 +      virtual unsigned long pluginID() = 0;                virtual int id() = 0;        virtual QString pluginLabel() const = 0;          virtual QString name() const = 0;        virtual QString lib() const = 0;        virtual QString dirPath() const = 0;        virtual QString fileName() const = 0; +      virtual QString titlePrefix() const = 0;        virtual AudioTrack* track() = 0;           -      //virtual void enableController(int /*i*/, bool /*v*/ = true) = 0;  -      //virtual bool controllerEnabled(int /*i*/) const = 0;           -      //virtual bool controllerEnabled2(int /*i*/) const = 0;           -      virtual void enableController(unsigned long /*i*/, bool /*v*/ = true) = 0;   // p4.0.21 +      virtual void enableController(unsigned long /*i*/, bool /*v*/ = true) = 0;           virtual bool controllerEnabled(unsigned long /*i*/) const = 0;                  virtual bool controllerEnabled2(unsigned long /*i*/) const = 0;                  virtual void updateControllers() = 0; @@ -288,12 +254,7 @@ class PluginIBase        virtual void writeConfiguration(int /*level*/, Xml& /*xml*/) = 0;        virtual bool readConfiguration(Xml& /*xml*/, bool /*readPreset*/=false) = 0; -      //virtual int parameters() const = 0;           -      //virtual void setParam(int /*i*/, double /*val*/) = 0;  -      //virtual double param(int /*i*/) const = 0;         -      //virtual const char* paramName(int /*i*/) = 0;      -      //virtual LADSPA_PortRangeHint range(int /*i*/) = 0;  -      virtual unsigned long parameters() const = 0;                  // p4.0.21 +      virtual unsigned long parameters() const = 0;                          virtual unsigned long parametersOut() const = 0;        virtual void setParam(unsigned long /*i*/, float /*val*/) = 0;        virtual float param(unsigned long /*i*/) const = 0;             @@ -307,8 +268,6 @@ class PluginIBase        virtual CtrlList::Mode ctrlMode(unsigned long /*i*/) const = 0;        QString dssi_ui_filename() const; -      //virtual void showGui(bool) = 0;         // p4.0.20 -      //virtual void showNativeGui(bool) = 0;   //        MusEGui::PluginGui* gui() const { return _gui; }        void deleteGui();  }; @@ -353,7 +312,6 @@ class PluginBase  #define AUDIO_IN (LADSPA_PORT_AUDIO  | LADSPA_PORT_INPUT)  #define AUDIO_OUT (LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT) -//class PluginI {  class PluginI : public PluginIBase {        Plugin* _plugin;        int channel; @@ -365,10 +323,8 @@ class PluginI : public PluginIBase {        Port* controls;        Port* controlsOut; -      //int controlPorts; -      //int controlOutPorts; -      unsigned long controlPorts;      // p4.0.21 -      unsigned long controlOutPorts;   //  +      unsigned long controlPorts;       +      unsigned long controlOutPorts;            ///PluginGui* _gui;        bool _on; @@ -400,26 +356,17 @@ class PluginI : public PluginIBase {        void setTrack(AudioTrack* t)  { _track = t; }        AudioTrack* track()           { return _track; } -      //int pluginID()                { return _plugin->id(); } -      unsigned long pluginID()           { return _plugin->id(); }    // p4.0.21 +      unsigned long pluginID()      { return _plugin->id(); }            void setID(int i);        int id()                      { return _id; }        void updateControllers();        bool initPluginInstance(Plugin*, int channels);        void setChannels(int); -      //void connect(int ports, float** src, float** dst); -      //void apply(int n); -      //void connect(unsigned ports, float** src, float** dst);    -      //void apply(unsigned n);    -      void connect(unsigned long ports, unsigned long offset, float** src, float** dst); // p4.0.21 -      void apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut);   //  - -      //void enableController(int i, bool v = true)   { controls[i].enCtrl = v; } -      //bool controllerEnabled(int i) const           { return controls[i].enCtrl; } -      //void enable2Controller(int i, bool v = true)  { controls[i].en2Ctrl = v; } -      //bool controllerEnabled2(int i) const          { return controls[i].en2Ctrl; } -      void enableController(unsigned long i, bool v = true)   { controls[i].enCtrl = v; }      // p4.0.21 +      void connect(unsigned long ports, unsigned long offset, float** src, float** dst);  +      void apply(unsigned long n, unsigned long ports, float** bufIn, float** bufOut);     + +      void enableController(unsigned long i, bool v = true)   { controls[i].enCtrl = v; }              bool controllerEnabled(unsigned long i) const           { return controls[i].enCtrl; }           void enable2Controller(unsigned long i, bool v = true)  { controls[i].en2Ctrl = v; }             bool controllerEnabled2(unsigned long i) const          { return controls[i].en2Ctrl; }   @@ -434,6 +381,7 @@ class PluginI : public PluginIBase {        QString lib() const            { return _plugin->lib(); }        QString dirPath() const        { return _plugin->dirPath(); }        QString fileName() const       { return _plugin->fileName(); } +      QString titlePrefix() const;        #ifdef OSC_SUPPORT        OscEffectIF& oscIF() { return _oscif; } @@ -453,8 +401,7 @@ class PluginI : public PluginIBase {        void writeConfiguration(int level, Xml& xml);        bool readConfiguration(Xml& xml, bool readPreset=false);        bool loadControl(Xml& xml); -      //bool setControl(const QString& s, double val); -      bool setControl(const QString& s, float val);    // p4.0.21 +      bool setControl(const QString& s, float val);            void showGui();        void showGui(bool);        bool isDssiPlugin() const { return _plugin->isDssiPlugin(); }   @@ -464,20 +411,8 @@ class PluginI : public PluginIBase {        bool guiVisible();        bool nativeGuiVisible(); -      //int parameters() const           { return controlPorts; } -      //void setParam(int i, double val) { controls[i].tmpVal = val; } -      //double param(int i) const        { return controls[i].val; } -      //double defaultValue(unsigned int param) const; -      //const char* paramName(int i)     { return _plugin->portName(controls[i].idx); } -      //LADSPA_PortDescriptor portd(int i) const { return _plugin->portd(controls[i].idx); } -      //void range(int i, float* min, float* max) const { _plugin->range(controls[i].idx, min, max); } -      //bool isAudioIn(int k) { return (_plugin->portd(k) & AUDIO_IN) == AUDIO_IN; } -      //bool isAudioOut(int k) { return (_plugin->portd(k) & AUDIO_OUT) == AUDIO_OUT; } -      //LADSPA_PortRangeHint range(int i) { return _plugin->range(controls[i].idx); } -      // p4.0.21        unsigned long parameters() const           { return controlPorts; }            unsigned long parametersOut() const           { return controlOutPorts; } -      //void setParam(unsigned i, float val) { controls[i].tmpVal = val; }        void setParam(unsigned long i, float val);          float param(unsigned long i) const        { return controls[i].val; }               float paramOut(unsigned long i) const        { return controlsOut[i].val; } @@ -500,8 +435,6 @@ class PluginI : public PluginIBase {  //    chain of connected efx inserts  //--------------------------------------------------------- -//const int PipelineDepth = 4;  // Moved to globaldefs.h -  class Pipeline : public std::vector<PluginI*> {        float* buffer[MAX_CHANNELS]; @@ -525,8 +458,7 @@ class Pipeline : public std::vector<PluginI*> {        void deleteAllGuis();        bool guiVisible(int);        bool nativeGuiVisible(int); -      //void apply(int ports, unsigned long nframes, float** buffer); -      void apply(unsigned long ports, unsigned long nframes, float** buffer);  // p4.0.21 +      void apply(unsigned long ports, unsigned long nframes, float** buffer);          void move(int idx, bool up);        bool empty(int idx) const;        void setChannels(int); @@ -537,11 +469,6 @@ typedef Pipeline::const_iterator ciPluginI;  extern void initPlugins(); -//extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, int port, float* val); -//extern void ladspaControlRange(const LADSPA_Descriptor* plugin, int i, float* min, float* max); -//extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, int port, int ctlnum, int* min, int* max, int* def); -//extern float midi2LadspaValue(const LADSPA_Descriptor* plugin, int port, int ctlnum, int val); -// p4.0.21  extern bool ladspaDefaultValue(const LADSPA_Descriptor* plugin, unsigned long port, float* val);  extern void ladspaControlRange(const LADSPA_Descriptor* plugin, unsigned long port, float* min, float* max);  extern bool ladspa2MidiControlValues(const LADSPA_Descriptor* plugin, unsigned long port, int ctlnum, int* min, int* max, int* def); @@ -593,8 +520,7 @@ struct GuiWidgets {              };        QWidget* widget;        int type; -      //int param; -      unsigned long param;   // p4.0.21 +      unsigned long param;           };  //--------------------------------------------------------- @@ -604,13 +530,11 @@ struct GuiWidgets {  class PluginGui : public QMainWindow {        Q_OBJECT -      //PluginI* plugin;        // plugin instance        MusECore::PluginIBase* plugin;        // plugin instance        GuiParam* params;        GuiParam* paramsOut; -      //int nobj;                -      unsigned long nobj;             // number of widgets in gw      // p4.0.21 +      unsigned long nobj;             // number of widgets in gw              GuiWidgets* gw;        QAction* onOff; @@ -640,7 +564,6 @@ class PluginGui : public QMainWindow {        void heartBeat();     public: -      //PluginGui(MusECore::PluginI*);        PluginGui(MusECore::PluginIBase*);        ~PluginGui(); diff --git a/muse2/muse/remote/pyapi.cpp b/muse2/muse/remote/pyapi.cpp index 645c639e..de8f15ef 100644 --- a/muse2/muse/remote/pyapi.cpp +++ b/muse2/muse/remote/pyapi.cpp @@ -1129,7 +1129,9 @@ bool Song::event(QEvent* _e)                    break;                    }              case QPybridgeEvent::SONG_ADD_TRACK: -                  MusEGlobal::song->addTrack((Track::TrackType)e->getP1());  // Add at end of list. +                  MusECore::Undo operations; +                  MusEGlobal::song->addTrack(operations, (Track::TrackType)e->getP1());  // Add at end of list. +                  MusEGlobal::song->applyOperationGroup(operations);                    break;              case QPybridgeEvent::SONG_CHANGE_TRACKNAME: {                    Track* t = this->findTrack(e->getS1()); diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp index f00c6d6c..1d494fb0 100644 --- a/muse2/muse/route.cpp +++ b/muse2/muse/route.cpp @@ -4,6 +4,7 @@  //  $Id: route.cpp,v 1.18.2.3 2008/05/21 00:28:52 terminator356 Exp $  //  //  (C) Copyright 2003-2004 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -37,8 +38,6 @@  //#define ROUTE_DEBUG  -//#define ROUTE_MIDIPORT_NAME_PREFIX       "MusE MidiPort " -  namespace MusECore {  const QString ROUTE_MIDIPORT_NAME_PREFIX = "MusE MidiPort "; @@ -57,9 +56,7 @@ Route::Route(void* t, int ch)        type     = JACK_ROUTE;        } -//Route::Route(AudioTrack* t, int ch)  Route::Route(Track* t, int ch, int chans) -//Route::Route(Track* t, int ch)        {        track    = t;        midiPort = -1; @@ -69,7 +66,6 @@ Route::Route(Track* t, int ch, int chans)        type     = TRACK_ROUTE;        } -//Route::Route(MidiJackDevice* d)  Route::Route(MidiDevice* d, int ch)  {        device   = d;   @@ -77,19 +73,10 @@ Route::Route(MidiDevice* d, int ch)        channel  = ch;        channels = -1;        remoteChannel = -1; -      /* -      //if(dynamic_cast<MidiJackDevice*>(d)) -      if(d->deviceType() == MidiDevice::JACK_MIDI) -        type    = JACK_MIDI_ROUTE; -      else   -      //if(dynamic_cast<MidiAlsaDevice*>(d)) -      if(d->deviceType() == MidiDevice::ALSA_MIDI) -        type    = ALSA_MIDI_ROUTE; -      */          type    = MIDI_DEVICE_ROUTE;   } -Route::Route(int port, int ch)  // p3.3.49 +Route::Route(int port, int ch)    {        track    = 0;        midiPort = port;  @@ -99,16 +86,12 @@ Route::Route(int port, int ch)  // p3.3.49        type    = MIDI_PORT_ROUTE;       } -//Route::Route(const QString& s, bool dst, int ch)  Route::Route(const QString& s, bool dst, int ch, int rtype)      { -      //Route node(name2route(s, dst));        Route node(name2route(s, dst, rtype));        channel  = node.channel;        if(channel == -1)          channel = ch; -      //if(channels == -1) -      //  channels = chans;        channels = node.channels;        remoteChannel = node.remoteChannel;        type = node.type; @@ -123,14 +106,6 @@ Route::Route(const QString& s, bool dst, int ch, int rtype)          jackPort = node.jackPort;          midiPort = -1;        } -      /* -      else -      if (type == JACK_MIDI_ROUTE) -            device = node.device; -      else -      if (type == ALSA_MIDI_ROUTE) -            device = node.device; -      */        else        if(type == MIDI_DEVICE_ROUTE)          { @@ -138,10 +113,10 @@ Route::Route(const QString& s, bool dst, int ch, int rtype)          midiPort = -1;        }          else -      if(type == MIDI_PORT_ROUTE)     // p3.3.49 +      if(type == MIDI_PORT_ROUTE)            {          track = 0; -        midiPort = node.midiPort;     // +        midiPort = node.midiPort;            }        } @@ -179,31 +154,20 @@ void addRoute(Route src, Route dst)  //         dst.type, dst.channel, dst.name().toLatin1().constData());        if (src.type == Route::JACK_ROUTE)         {            -            //if (dst.type != TRACK_ROUTE)  -            //{ -            //      fprintf(stderr, "addRoute: bad route 1\n"); -                  // exit(-1); -            //      return; -            //} -                          if (dst.type == Route::TRACK_ROUTE)               {                if (dst.track->type() != Track::AUDIO_INPUT)                 {                    fprintf(stderr, "addRoute: source is jack, dest:%s is track but not audio input\n", dst.track->name().toLatin1().constData()); -                  //exit(-1);                    return;                }                if (dst.channel < 0)                 {                    fprintf(stderr, "addRoute: source is jack, dest:%s is track but invalid channel:%d\n", dst.track->name().toLatin1().constData(), dst.channel); -                  //exit(-1);                    return;                } -              //src.channel = src.dstChannel = dst.channel;                src.channel = dst.channel; -              //src.channels = dst.channels = 1;                RouteList* inRoutes = dst.track->inRoutes();                for (ciRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)                 { @@ -221,28 +185,11 @@ void addRoute(Route src, Route dst)                inRoutes->push_back(src);              }                else -            //if (dst.type == Route::JACK_MIDI_ROUTE)               if (dst.type == Route::MIDI_DEVICE_ROUTE)  -            //if (dst.type == Route::MIDI_PORT_ROUTE)      // p3.3.49              { -              //MidiDevice *md = MusEGlobal::midiPorts[dst.midiPort].device(); -              //if(dst.device->deviceType() == MidiDevice::JACK_MIDI) -              //if(!md) -              //{ -              //  fprintf(stderr, "addRoute: source is Jack, but no destination port device\n"); -              //  return; -              //} -                              if(dst.device->deviceType() == MidiDevice::JACK_MIDI) -              //if(md->deviceType() == MidiDevice::JACK_MIDI)                {                  src.channel = dst.channel; -                //src.channel = -1; -                //src.channel = 0; -                //src.channel = src.dstChannel = dst.channel; -                //src.channels = dst.channels = 1; -                //dst.channel = -1; -                                  RouteList* routes = dst.device->inRoutes();                  for (ciRoute i = routes->begin(); i != routes->end(); ++i)                   { @@ -262,45 +209,32 @@ void addRoute(Route src, Route dst)                else                {                  fprintf(stderr, "addRoute: source is Jack, but destination is not jack midi - type:%d\n", dst.device->deviceType()); -                // exit(-1);                  return;                }              }                else              {                fprintf(stderr, "addRoute: source is Jack, but destination is not track or midi - type:%d \n", dst.type); -              // exit(-1);                return;              }        }        else if (dst.type == Route::JACK_ROUTE)         { -            //if (src.type != TRACK_ROUTE)  -            //{ -            //      fprintf(stderr, "addRoute: bad route 3\n"); -                  // exit(-1); -            //      return; -            //} -                          if (src.type == Route::TRACK_ROUTE)               {                if (src.track->type() != Track::AUDIO_OUTPUT)                 {                      fprintf(stderr, "addRoute: destination is jack, source is track but not audio output\n"); -                    // exit(-1);                      return;                }                if (src.channel < 0)                 {                      fprintf(stderr, "addRoute: destination is jack, source:%s is track but invalid channel:%d\n", src.track->name().toLatin1().constData(), src.channel); -                    // exit(-1);                      return;                }                RouteList* outRoutes = src.track->outRoutes(); -              //dst.channel = dst.dstChannel = src.channel;                dst.channel = src.channel; -              //dst.channels = src.channels = 1;                for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)                 { @@ -318,17 +252,11 @@ void addRoute(Route src, Route dst)                outRoutes->push_back(dst);              }              else -            //if (src.type == Route::JACK_MIDI_ROUTE)               if (src.type == Route::MIDI_DEVICE_ROUTE)               {                if(src.device->deviceType() == MidiDevice::JACK_MIDI)                {                  dst.channel = src.channel; -                //dst.channel = -1; -                //src.channel = -1; -                //dst.channel = dst.dstChannel = src.channel; -                //dst.channels = src.channels = 1; -                                  RouteList* routes = src.device->outRoutes();                  for (ciRoute i = routes->begin(); i != routes->end(); ++i)                   { @@ -348,18 +276,16 @@ void addRoute(Route src, Route dst)                else                  {                  fprintf(stderr, "addRoute: destination is Jack, but source is not jack midi - type:%d\n", src.device->deviceType()); -                // exit(-1);                  return;                }              }              else              {                fprintf(stderr, "addRoute: destination is Jack, but source is not track or midi - type:%d \n", src.type); -              // exit(-1);                return;              }        } -      else if(src.type == Route::MIDI_PORT_ROUTE)  // p3.3.49 +      else if(src.type == Route::MIDI_PORT_ROUTE)          {              if(dst.type != Route::TRACK_ROUTE)              { @@ -367,66 +293,18 @@ void addRoute(Route src, Route dst)                return;              } -            // p4.0.14 -            /* -            if(dst.track->type() == Track::AUDIO_INPUT) -            { -              if(src.channel < 1 || src.channel >= (1 << MIDI_CHANNELS)) -              { -                fprintf(stderr, "addRoute: source is midi port:%d, but channel mask:%d out of range\n", src.midiPort, src.channel); -                return; -              } -               -              MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort]; -              //src.channel = dst.channel = -1; -              RouteList* outRoutes = mp->outRoutes(); -              iRoute ir = outRoutes->begin();                                       -              for ( ; ir != outRoutes->end(); ++ir)  -              { -                //if (*i == dst)    // route already there -                ir->dump();  -                if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track)     // Does a route to the track exist? -                { -                  //#ifdef ROUTE_DEBUG -                  fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s out route already exists. ir->channel:%d |= dst.channel:%d\n",  -                    src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, dst.channel);   -                  //#endif -                  ir->channel |= dst.channel;    // Bitwise OR the desired channel bit with the existing bit mask. -                  break; -                  //return; -                }       -              } -              if(ir == outRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.  -                outRoutes->push_back(dst); -             -              RouteList* inRoutes = dst.track->inRoutes(); -               -              ir = inRoutes->begin(); -              for ( ; ir != inRoutes->end(); ++ir)          -              { -                if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort)  // Does a route to the midi port exist? -                { -                  fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s in route already exists. ir->channel:%d |= src.channel:%d\n",  -                    src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, src.channel);   -                  ir->channel |= src.channel;    // Bitwise OR the desired channel bit with the existing bit mask. -                  break; -                }       -              } -              if(ir == inRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.  -                inRoutes->push_back(src); -             -              return; -            } -            */ -                          MidiPort *mp = &MusEGlobal::midiPorts[src.midiPort]; -            // p4.0.17 Do not allow ports with synth midi devices to connect to audio ins! -            if(dst.track->type() == Track::AUDIO_INPUT && mp->device() && mp->device()->isSynti()) -            { -              fprintf(stderr, "addRoute: destination is audio in, but source midi port:%d is synth device\n", src.midiPort); +            // Do not allow ports with synth midi devices to connect to audio ins!   p4.0.17  +            //if(dst.track->type() == Track::AUDIO_INPUT && mp->device() && mp->device()->isSynti()) +            //{ +            //  fprintf(stderr, "addRoute: destination is audio in, but source midi port:%d is synth device\n", src.midiPort); +            //  return; +            //} +            // Actually, do not allow synth ports to connect to any track. It may be useful in some cases,  +            //  may be desired later, but for now it's just a routing hassle.  p4.0.35  +            if(mp->device() && mp->device()->isSynti())                return; -            }              if(dst.channel < 1 || dst.channel >= (1 << MIDI_CHANNELS))              { @@ -443,46 +321,39 @@ void addRoute(Route src, Route dst)              src.channel = dst.channel;              RouteList* outRoutes = mp->outRoutes(); -            //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -            iRoute ir = outRoutes->begin();                                      // p3.3.50 +            iRoute ir = outRoutes->begin();                                                    for ( ; ir != outRoutes->end(); ++ir)               { -              //if (*i == dst)    // route already there -              if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track)     // p3.3.50 Does a route to the track exist? +              if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track)     // Does a route to the track exist?                { -                //#ifdef ROUTE_DEBUG -                //fprintf(stderr, "addRoute: src midi port:%d dst track:%s route already exists.\n", src.midiPort, dst.track->name().toLatin1().constData()); -                //#endif -                ir->channel |= dst.channel;    // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. +                ir->channel |= dst.channel;    // Bitwise OR the desired channel bit with the existing bit mask.                  break; -                 -                //return;                }                    }              #ifdef ROUTE_DEBUG              fprintf(stderr, "addRoute: src midi port:%d dst track name:%s pushing dst and src routes\n", src.midiPort, dst.track->name().toLatin1().constData());              #endif -            if(ir == outRoutes->end())    // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with.  +            if(ir == outRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.                 outRoutes->push_back(dst);              RouteList* inRoutes = dst.track->inRoutes(); -            // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. +            // Make sure only one single route, with a channel mask, can ever exist.              ir = inRoutes->begin();              for ( ; ir != inRoutes->end(); ++ir)                       { -              if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort)  // p3.3.50 Does a route to the midi port exist? +              if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort)  // Does a route to the midi port exist?                { -                ir->channel |= src.channel;    // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. +                ir->channel |= src.channel;    // Bitwise OR the desired channel bit with the existing bit mask.                  break;                }                    } -            if(ir == inRoutes->end())    // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with.  +            if(ir == inRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.                 inRoutes->push_back(src);        } -      else if(dst.type == Route::MIDI_PORT_ROUTE)  // p3.3.49 +      else if(dst.type == Route::MIDI_PORT_ROUTE)          {              if(src.type != Route::TRACK_ROUTE)              { @@ -495,7 +366,6 @@ void addRoute(Route src, Route dst)                return;              } -                          //MidiDevice *md = MusEGlobal::midiPorts[dst.midiPort].device();              //if(!md)              //{ @@ -506,24 +376,17 @@ void addRoute(Route src, Route dst)              dst.channel = src.channel;              RouteList* outRoutes = src.track->outRoutes(); -            //for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -            iRoute ir = outRoutes->begin();                                      // p3.3.50 +            iRoute ir = outRoutes->begin();                                                    for ( ; ir != outRoutes->end(); ++ir)               { -              //if (*i == dst)    // route already there -              if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort)     // p3.3.50 Does a route to the midi port exist? +              if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == dst.midiPort)     // Does a route to the midi port exist?                { -                //#ifdef ROUTE_DEBUG -                //fprintf(stderr, "addRoute: dst midi port:%d src track:%s route already exists.\n", dst.midiPort, src.track->name().toLatin1().constData()); -                //#endif -                //return; -                 -                ir->channel |= dst.channel;    // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. +                ir->channel |= dst.channel;    // Bitwise OR the desired channel bit with the existing bit mask.                  break;                }                    } -            if(ir == outRoutes->end())    // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with.  +            if(ir == outRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.                 outRoutes->push_back(dst);              MidiPort *mp = &MusEGlobal::midiPorts[dst.midiPort]; @@ -533,167 +396,97 @@ void addRoute(Route src, Route dst)              #endif              RouteList* inRoutes = mp->inRoutes(); -            // p3.3.50 Make sure only one single route, with a channel mask, can ever exist. +            // Make sure only one single route, with a channel mask, can ever exist.              ir = inRoutes->begin();              for ( ; ir != inRoutes->end(); ++ir)                       { -              if (ir->type == Route::TRACK_ROUTE && ir->track == src.track)  // p3.3.50 Does a route to the track exist? +              if (ir->type == Route::TRACK_ROUTE && ir->track == src.track)  // Does a route to the track exist?                { -                ir->channel |= src.channel;    // p3.3.50 Bitwise OR the desired channel bit with the existing bit mask. +                ir->channel |= src.channel;    // Bitwise OR the desired channel bit with the existing bit mask.                  break;                }                    } -            if(ir == inRoutes->end())    // p3.3.50 Only if route not found, add the route, with the requested channel bits as mask to start with.  +            if(ir == inRoutes->end())    // Only if route not found, add the route, with the requested channel bits as mask to start with.                 inRoutes->push_back(src); -              //inRoutes->insert(inRoutes->begin(), src);        }        else         { -        if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)  // p3.3.49 +        if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)            {            fprintf(stderr, "addRoute: source or destination are not track routes\n");            return;          } -        // Removed p3.3.49 -        /* -        //if ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) -        if(src.type == Route::MIDI_DEVICE_ROUTE) -        {            -            //src.channel = src.dstChannel = dst.dstChannel = dst.channel; -            src.channel = dst.channel; -            //src.channels = dst.channels = 1; -            RouteList* outRoutes = src.device->outRoutes(); -            #ifdef ROUTE_DEBUG -            fprintf(stderr, "addRoute: src name: %s looking for existing dest in out routes...\n", src.device->name().toLatin1().constData()); -            #endif -            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -            { -                  if (*i == dst)    // route already there -                  { -                        //#ifdef ROUTE_DEBUG -                        fprintf(stderr, "addRoute: src Jack or ALSA midi route already exists.\n"); -                        //#endif -                        return; -                  }       -            } -            #ifdef ROUTE_DEBUG -            fprintf(stderr, "addRoute: src midi dst name: %s pushing destination and source routes\n", dst.track->name().toLatin1().constData()); -            #endif -             -            outRoutes->push_back(dst); -            RouteList* inRoutes = dst.track->inRoutes(); -            inRoutes->push_back(src); -        }           -        else -        */ +        RouteList* outRoutes = src.track->outRoutes(); -        {            -            ///if(dst.type == Route::MIDI_DEVICE_ROUTE)  // Removed p3.3.49 -            //{ -            ///  dst.channel = src.channel; -              //src.channel = src.dstChannel = dst.dstChannel = dst.channel; -              //src.channels = dst.channels = 1; -            //} -            //else -            //{ -              //src.channel = src.dstChannel = dst.dstChannel = dst.channel; -              //src.channels = dst.channels = 1; -            //} -               -            RouteList* outRoutes = src.track->outRoutes(); -             -            // -            // Must enforce to ensure channel and channels are valid if defaults of -1 passed. -            // -            if(src.track->type() == Track::AUDIO_SOFTSYNTH) -            { -              if(src.channel == -1) -                src.channel = 0; -              if(src.channels == -1) -                src.channels = src.track->channels();   -              //if(dst.type == Route::TRACK_ROUTE)      // p3.3.49 Removed -              //{ -                //if(dst.channel == -1) -                //  dst.channel = 0; -                //if(dst.channels == -1) -                  // Yes, that's correct: dst channels = src track channels. -                //  dst.channels = src.track->channels();   -                dst.channel = src.channel; -                dst.channels = src.channels; -                dst.remoteChannel = src.remoteChannel; -              //} -            } -            //if(dst.type == Route::TRACK_ROUTE && dst.track->type() == Track::AUDIO_SOFTSYNTH) -            //{ -            //  if(dst.channel == -1) -            //    dst.channel = 0; -            //  if(dst.channels == -1) -                // Yes, that's correct: dst channels = src track channels. -            //    dst.channels = src.track->channels();   -            //} -             -            for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -            { -                  if (*i == dst)    // route already there -                  // TODO: -                  //if (i->type == dst.type && i->channel == dst.channel)     +        // +        // Must enforce to ensure channel and channels are valid if defaults of -1 passed. +        // +        if(src.track->type() == Track::AUDIO_SOFTSYNTH) +        { +          if(src.channel == -1) +            src.channel = 0; +          if(src.channels == -1) +            src.channels = src.track->channels();   +          dst.channel = src.channel; +          dst.channels = src.channels; +          dst.remoteChannel = src.remoteChannel; +        } +         +        for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  +        { +              if (*i == dst)    // route already there +              // TODO: +              //if (i->type == dst.type && i->channel == dst.channel)     +              { +                //if(i->type == Route::TRACK_ROUTE) +                { +                  //if(i->track == dst.track)                    { -                    //if(i->type == Route::TRACK_ROUTE) +                    //if(i->channels == dst.channels)                      { -                      //if(i->track == dst.track) -                      { -                        //if(i->channels == dst.channels) -                        { -                          //#ifdef ROUTE_DEBUG -                          fprintf(stderr, "addRoute: src track route already exists.\n"); -                          //#endif -                          return; -                        } -                        //else -                        //{ -                         -                        //} -                      } +                      //#ifdef ROUTE_DEBUG +                      fprintf(stderr, "addRoute: src track route already exists.\n"); +                      //#endif +                      return;                      } -                  }       -            } -            outRoutes->push_back(dst); -            RouteList* inRoutes; -             -            // Removed p3.3.49 -            /* -            //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) -            if(dst.type == Route::MIDI_DEVICE_ROUTE) -            { -              #ifdef ROUTE_DEBUG -              fprintf(stderr, "addRoute: src track dst midi name: %s pushing destination and source routes\n", dst.device->name().toLatin1().constData()); -              #endif -              inRoutes = dst.device->inRoutes(); -            }   -            else   -            */ -             -            { -              #ifdef ROUTE_DEBUG -              //fprintf(stderr, "addRoute: src track ch:%d chs:%d  dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().toLatin1().constData()); -              fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d  dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n",  -                src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData()); -              //fprintf(stderr, "addRoute: src track ch:%d  dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().toLatin1().constData()); -              #endif -              inRoutes = dst.track->inRoutes(); -            }   -               -             -            // -            // make sure AUDIO_AUX is processed last -            // -            if (src.track->type() == Track::AUDIO_AUX) -                  inRoutes->push_back(src); -            else -                  inRoutes->insert(inRoutes->begin(), src); -        }           +                    //else +                    //{ +                     +                    //} +                  } +                } +              }       +        } +        outRoutes->push_back(dst); +        RouteList* inRoutes; +         +        #ifdef ROUTE_DEBUG +        //fprintf(stderr, "addRoute: src track ch:%d chs:%d  dst track ch:%d chs:%d name: %s pushing destination and source routes\n", src.channel, src.channels, dst.channel, dst.channels, dst.track->name().toLatin1().constData()); +        fprintf(stderr, "addRoute: src track ch:%d chs:%d remch:%d  dst track ch:%d chs:%d remch:%d name: %s pushing dest and source routes\n",  +          src.channel, src.channels, src.remoteChannel, dst.channel, dst.channels, dst.remoteChannel, dst.track->name().toLatin1().constData()); +        //fprintf(stderr, "addRoute: src track ch:%d  dst track ch:%d name: %s pushing destination and source routes\n", src.channel, dst.channel, dst.track->name().toLatin1().constData()); +        #endif +        inRoutes = dst.track->inRoutes(); +         +        // +        // make sure AUDIO_AUX is processed last +        // +        if (src.track->type() == Track::AUDIO_AUX)       // REMOVE Tim. This special aux code may not be useful or needed now. +              inRoutes->push_back(src);                  // +        else +              inRoutes->insert(inRoutes->begin(), src); +         +        // Is the source an Aux Track or else does it have Aux Tracks routed to it? +        // Update the destination track's aux ref count, and all tracks it is routed to. +        if(src.track->auxRefCount()) +            //dst.track->updateAuxStates( src.track->auxRefCount() ); +            src.track->updateAuxRoute( src.track->auxRefCount(), dst.track ); +        else  +        if(src.track->type() == Track::AUDIO_AUX) +            //dst.track->updateAuxStates( 1 ); +            src.track->updateAuxRoute( 1, dst.track );        }  } @@ -709,12 +502,6 @@ void removeRoute(Route src, Route dst)        if (src.type == Route::JACK_ROUTE)         { -            //if (dst.type != TRACK_ROUTE)  -            //{ -            //      fprintf(stderr, "removeRoute: bad route 1\n"); -                  // exit(-1); -            //      return; -            //}              if(!dst.isValid())              {                printf("removeRoute: source is jack, invalid destination\n"); @@ -726,7 +513,6 @@ void removeRoute(Route src, Route dst)                if (dst.track->type() != Track::AUDIO_INPUT)                 {                      fprintf(stderr, "removeRoute: source is jack, destination is track but not audio input\n"); -                    // exit(-1);                      return;                }                RouteList* inRoutes = dst.track->inRoutes(); @@ -741,7 +527,6 @@ void removeRoute(Route src, Route dst)                }              }                else -            //if (dst.type == Route::JACK_MIDI_ROUTE)               if (dst.type == Route::MIDI_DEVICE_ROUTE)               {                RouteList* routes = dst.device->inRoutes(); @@ -758,18 +543,11 @@ void removeRoute(Route src, Route dst)              else              {                    fprintf(stderr, "removeRoute: source is jack, destination unknown\n"); -                  // exit(-1);                    return;              }        }        else if (dst.type == Route::JACK_ROUTE)         { -            //if (src.type != TRACK_ROUTE)  -            //{ -            //      fprintf(stderr, "removeRoute: bad route 3\n"); -                  // exit(-1); -            //      return; -            //}              if(!src.isValid())              {                printf("removeRoute: destination is jack, invalid source\n"); @@ -781,7 +559,6 @@ void removeRoute(Route src, Route dst)                if (src.track->type() != Track::AUDIO_OUTPUT)                 {                      fprintf(stderr, "removeRoute: destination is jack, source is track but not audio output\n"); -                    // exit(-1);                      return;                }                RouteList* outRoutes = src.track->outRoutes(); @@ -795,7 +572,6 @@ void removeRoute(Route src, Route dst)                }              }                else -            //if (src.type == Route::JACK_MIDI_ROUTE)               if (src.type == Route::MIDI_DEVICE_ROUTE)               {                RouteList* routes = src.device->outRoutes(); @@ -811,11 +587,10 @@ void removeRoute(Route src, Route dst)              else              {                    fprintf(stderr, "removeRoute: destination is jack, source unknown\n"); -                  // exit(-1);                    return;              }        } -      else if(src.type == Route::MIDI_PORT_ROUTE)  // p3.3.49 +      else if(src.type == Route::MIDI_PORT_ROUTE)          {          if(dst.type != Route::TRACK_ROUTE)          { @@ -829,19 +604,18 @@ void removeRoute(Route src, Route dst)            RouteList* outRoutes = mp->outRoutes();            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)             { -            //if (*i == dst)  -            if(i->type == Route::TRACK_ROUTE && i->track == dst.track)  // p3.3.50 Is there a route to the track? +            if(i->type == Route::TRACK_ROUTE && i->track == dst.track)  // Is there a route to the track?              {                //printf("i->channel:%x dst.channel:%x\n", i->channel, dst.channel);    -              i->channel &= ~dst.channel;        // p3.3.50 Unset the desired channel bits. +              i->channel &= ~dst.channel;        // Unset the desired channel bits.                if(i->channel == 0)                // Only if there are no channel bits set, erase the route.                {                  //printf("erasing out route from midi port:%d\n", src.midiPort);                     outRoutes->erase(i);                }   -              break;                             // For safety, keep looking and remove any more found. -                                                  // No, must break, else crash. There should only be one route anyway... +              break;  // For safety, keep looking and remove any more found. +                      // No, must break, else crash. There should only be one route anyway...              }            }          } @@ -853,22 +627,21 @@ void removeRoute(Route src, Route dst)            RouteList* inRoutes = dst.track->inRoutes();            for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)             { -            //if (*i == src)  -            if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort)  // p3.3.50 Is there a route to the midi port? +            if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == src.midiPort)  // Is there a route to the midi port?              { -              i->channel &= ~src.channel;        // p3.3.50 Unset the desired channel bits. +              i->channel &= ~src.channel;        // Unset the desired channel bits.                if(i->channel == 0)                // Only if there are no channel bits set, erase the route.                  inRoutes->erase(i); -              break;                             // For safety, keep looking and remove any more found. -                                                  // No, must break, else crash. There should only be one route anyway... +              break;  // For safety, keep looking and remove any more found. +                      // No, must break, else crash. There should only be one route anyway...              }            }          }          else            printf("removeRoute: source is midi port:%d but destination track invalid\n", src.midiPort);        }       -      else if(dst.type == Route::MIDI_PORT_ROUTE)  // p3.3.49 +      else if(dst.type == Route::MIDI_PORT_ROUTE)          {          if(src.type != Route::TRACK_ROUTE)          { @@ -881,15 +654,14 @@ void removeRoute(Route src, Route dst)            RouteList* outRoutes = src.track->outRoutes();            for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)             { -            //if (*i == dst)  -            if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort)  // p3.3.50 Is there a route to the midi port? +            if (i->type == Route::MIDI_PORT_ROUTE && i->midiPort == dst.midiPort)  // Is there a route to the midi port?              { -              i->channel &= ~dst.channel;        // p3.3.50 Unset the desired channel bits. +              i->channel &= ~dst.channel;        // Unset the desired channel bits.                if(i->channel == 0)                // Only if there are no channel bits set, erase the route.                    outRoutes->erase(i); -              break;                             // For safety, keep looking and remove any more found. -                                                 // No, must break, else crash. There should only be one route anyway... +              break;  // For safety, keep looking and remove any more found. +                      // No, must break, else crash. There should only be one route anyway...              }            }          }   @@ -902,15 +674,14 @@ void removeRoute(Route src, Route dst)            RouteList* inRoutes = mp->inRoutes();            for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)             { -            //if (*i == src)  -            if (i->type == Route::TRACK_ROUTE && i->track == src.track)  // p3.3.50 Is there a route to the track? +            if (i->type == Route::TRACK_ROUTE && i->track == src.track)  // Is there a route to the track?              { -              i->channel &= ~src.channel;        // p3.3.50 Unset the desired channel bits. +              i->channel &= ~src.channel;        // Unset the desired channel bits.                if(i->channel == 0)                // Only if there are no channel bits set, erase the route.                  inRoutes->erase(i); -              break;                             // For safety, keep looking and remove any more found. -                                                 // No, must break, else crash. There should only be one route anyway... +              break;  // For safety, keep looking and remove any more found. +                      // No, must break, else crash. There should only be one route anyway...              }            }          }   @@ -919,87 +690,54 @@ void removeRoute(Route src, Route dst)        }        else         { -            if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)  // p3.3.49 +            if(src.type != Route::TRACK_ROUTE || dst.type != Route::TRACK_ROUTE)                {                fprintf(stderr, "removeRoute: source and destination are not tracks\n");                return;              } -            // Removed p3.3.49 -            /* -            //if((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) -            if(src.type == Route::MIDI_DEVICE_ROUTE) +            // Is the source an Aux Track or else does it have Aux Tracks routed to it? +            // Update the destination track's aux ref count, and all tracks it is routed to. +            if(src.isValid() && dst.isValid())              { -              if(src.isValid()) -              { -                RouteList* outRoutes = src.device->outRoutes(); -                for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -                { -                      if (*i == dst) { -                            outRoutes->erase(i); -                            break; -                            } -                } -              } +              if(src.track->auxRefCount()) +                //dst.track->updateAuxStates( -src.track->auxRefCount() ); +                src.track->updateAuxRoute( -src.track->auxRefCount(), dst.track );                else -                printf("removeRoute: source is midi but invalid\n"); -               -              if(dst.isValid()) +              if(src.track->type() == Track::AUDIO_AUX) +                //dst.track->updateAuxStates( -1 ); +                src.track->updateAuxRoute( -1, dst.track ); +            } +             +            if(src.isValid()) +            { +              RouteList* outRoutes = src.track->outRoutes(); +              for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)                 { -                RouteList* inRoutes = dst.track->inRoutes(); -                for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  -                { -                      if (*i == src) { -                            inRoutes->erase(i); -                            break; -                            } -                } +                    if (*i == dst) { +                          outRoutes->erase(i); +                          break; +                          }                } -              else -                printf("removeRoute: source is midi but destination invalid\n"); -            } +            }                else -            */ +              printf("removeRoute: source is track but invalid\n"); +            if(dst.isValid())              { -              if(src.isValid()) -              { -                RouteList* outRoutes = src.track->outRoutes(); -                for (iRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  -                { -                      if (*i == dst) { -                            outRoutes->erase(i); -                            break; -                            } -                } -              }   -              else -                printf("removeRoute: source is track but invalid\n"); +              RouteList* inRoutes; -              if(dst.isValid()) +              inRoutes = dst.track->inRoutes(); +              for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)                 { -                RouteList* inRoutes; -                 -                //if ((dst.type == Route::JACK_MIDI_ROUTE) || (dst.type == Route::ALSA_MIDI_ROUTE)) -                // Removed p3.3.49 -                /* -                if (dst.type == Route::MIDI_DEVICE_ROUTE) -                  inRoutes = dst.device->inRoutes(); -                else   -                */ -                 -                  inRoutes = dst.track->inRoutes(); -                for (iRoute i = inRoutes->begin(); i != inRoutes->end(); ++i)  -                { -                      if (*i == src) { -                            inRoutes->erase(i); -                            break; -                            } -                } -              }   -              else -                printf("removeRoute: source is track but destination invalid\n"); -            }       +                    if (*i == src) { +                          inRoutes->erase(i); +                          break; +                          } +              } +            }   +            else +              printf("removeRoute: source is track but destination invalid\n");        }  } @@ -1013,9 +751,19 @@ void removeRoute(Route src, Route dst)  //   So far it only works with MidiDevice <-> Jack.  //--------------------------------------------------------- -// p3.3.55  void removeAllRoutes(Route src, Route dst)  { +    // TODO: Is the source an Aux Track or else does it have Aux Tracks routed to it? +    // Update the destination track's aux ref count, and all tracks it is routed to. +    /* if(src.isValid() && dst.isValid()) +    { +      if(src.track->auxRefCount()) +        dst.track->updateAuxStates( -src.track->auxRefCount() ); +      else   +      if(src.track->type() == Track::TrackType::AUDIO_AUX)) +        dst.track->updateAuxStates( -1 ); +    }  */ +      if(src.isValid())        {        if(src.type == Route::MIDI_DEVICE_ROUTE) @@ -1052,22 +800,11 @@ static QString track2name(const Track* n)  QString Route::name() const  { -      // p3.3.38 Removed -      /* -      QString s; -      if ((type == TRACK_ROUTE) && (channel != -1)) { -//      if (channel != -1) { -            QString c; -            c.setNum(channel+1); -            s = c + ":"; -            } -      */ -              if(type == MIDI_DEVICE_ROUTE)         {          if(device)          { -          // p3.3.55 Removed for unified jack in/out devices, the actual port names are now different from device name. +          // For unified jack in/out devices, the actual port names are now different from device name.            // Like this:   device: "MyJackDevice1" ->  inport: "MyJackDevice1_in"  outport: "MyJackDevice1_out"            /*              if(device->deviceType() == MidiDevice::JACK_MIDI) @@ -1075,8 +812,7 @@ QString Route::name() const            else            */ -          //if(device->deviceType() == MidiDevice::ALSA_MIDI) -            return device->name(); +          return device->name();          }          return QWidget::tr("None");        } @@ -1084,16 +820,14 @@ QString Route::name() const        if(type == JACK_ROUTE)         {          if (!MusEGlobal::checkAudioDevice()) return ""; -        //return s + MusEGlobal::audioDevice->portName(jackPort);          return MusEGlobal::audioDevice->portName(jackPort);        }        else -      if(type == MIDI_PORT_ROUTE) // p3.3.49 +      if(type == MIDI_PORT_ROUTE)         {          return ROUTE_MIDIPORT_NAME_PREFIX + QString().setNum(midiPort);        }        else -        //return s + track2name(track);          return track2name(track);  } @@ -1106,7 +840,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)  {  // printf("name2route %s\n", rn.toLatin1().constData());    int channel = -1; -  //int channel = 0;    QString s(rn);    // Support old route style in med files. Obsolete.    if (rn[0].isNumber() && rn[1]==':')  @@ -1117,8 +850,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)    if(rtype == -1)    {   -    //if(dst)  -    //{        if(MusEGlobal::checkAudioDevice())        {          void* p = MusEGlobal::audioDevice->findPort(s.toLatin1().constData()); @@ -1149,7 +880,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)              return Route(*i, channel);        } -      // p3.3.49        if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)        {          bool ok = false; @@ -1160,8 +890,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)    }    else    { -    //if(dst)  -    //{        if(rtype == Route::TRACK_ROUTE)        {            TrackList* tl = MusEGlobal::song->tracks(); @@ -1178,8 +906,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)              AudioTrack* track = (AudioTrack*)*i;              if(track->name() == s)                return Route(track, channel); -              //return Route(track, channel, 1); -              //return Route(track, channel, track->channels());            }                }        } @@ -1191,7 +917,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)          for(iMidiDevice i = MusEGlobal::midiDevices.begin(); i != MusEGlobal::midiDevices.end(); ++i)           {            if((*i)->name() == s) -          //if (jmd->name() == rn)              return Route(*i, channel);            /* @@ -1224,7 +949,7 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)          }              }        else -      if(rtype == Route::MIDI_PORT_ROUTE) // p3.3.49 +      if(rtype == Route::MIDI_PORT_ROUTE)         {            if(s.left(ROUTE_MIDIPORT_NAME_PREFIX.length()) == ROUTE_MIDIPORT_NAME_PREFIX)          { @@ -1238,7 +963,6 @@ Route name2route(const QString& rn, bool /*dst*/, int rtype)    printf("  name2route: <%s> not found\n", rn.toLatin1().constData());    return Route((Track*) 0, channel); -  //return Route((Track*) 0, channel, 1);  }  //--------------------------------------------------------- @@ -1255,10 +979,6 @@ bool checkRoute(const QString& s, const QString& d)              return false;        if (src.type == Route::JACK_ROUTE)         { -            //if (dst.type != TRACK_ROUTE) { -            //      return false; -            //      } -                          if (dst.type == Route::TRACK_ROUTE)               {                if (dst.track->type() != Track::AUDIO_INPUT) { @@ -1274,12 +994,9 @@ bool checkRoute(const QString& s, const QString& d)                }              }              else -            //if (dst.type == Route::JACK_MIDI_ROUTE)               if (dst.type == Route::MIDI_DEVICE_ROUTE)               { -              //src.channel = dst.channel;                src.channel = -1; -              //dst.channel = -1;                RouteList* routes = dst.device->inRoutes();                for (ciRoute i = routes->begin(); i != routes->end(); ++i)                 { @@ -1293,10 +1010,6 @@ bool checkRoute(const QString& s, const QString& d)        }          else if (dst.type == Route::JACK_ROUTE)         { -            //if (src.type != TRACK_ROUTE) { -            //      return false; -            //      } -                          if (src.type == Route::TRACK_ROUTE)               {                if (src.track->type() != Track::AUDIO_OUTPUT) { @@ -1312,13 +1025,10 @@ bool checkRoute(const QString& s, const QString& d)                }              }              else -            //if (src.type == Route::JACK_MIDI_ROUTE)               if (src.type == Route::MIDI_DEVICE_ROUTE)               {                RouteList* routes = src.device->outRoutes(); -              //dst.channel = src.channel;                dst.channel = -1; -              //src.channel = -1;                for (ciRoute i = routes->begin(); i != routes->end(); ++i)                 {                      if (*i == dst) {   // route already there @@ -1329,7 +1039,7 @@ bool checkRoute(const QString& s, const QString& d)              else                return false;        }   -      else if (src.type == Route::MIDI_PORT_ROUTE) // p3.3.49 +      else if (src.type == Route::MIDI_PORT_ROUTE)         {              RouteList* outRoutes = MusEGlobal::midiPorts[src.midiPort].outRoutes();              for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  @@ -1339,13 +1049,11 @@ bool checkRoute(const QString& s, const QString& d)                          }              }        } -      //else if (dst.type == Route::MIDI_PORT_ROUTE) // p3.3.49 +      //else if (dst.type == Route::MIDI_PORT_ROUTE)         //{        //}        else         { -            //RouteList* outRoutes = ((src.type == Route::JACK_MIDI_ROUTE) || (src.type == Route::ALSA_MIDI_ROUTE)) ?  -            //                       src.device->outRoutes() : src.track->outRoutes();              RouteList* outRoutes = (src.type == Route::MIDI_DEVICE_ROUTE) ? src.device->outRoutes() : src.track->outRoutes();              for (ciRoute i = outRoutes->begin(); i != outRoutes->end(); ++i)  @@ -1366,7 +1074,7 @@ void Route::read(Xml& xml)  {        QString s;        int dtype = MidiDevice::ALSA_MIDI; -      int port = -1;                             // p3.3.49 +      int port = -1;                                     unsigned char rtype = Route::TRACK_ROUTE;          for (;;)  @@ -1397,7 +1105,7 @@ void Route::read(Xml& xml)                          if(tag == "name")                            s = xml.s2();                          else -                        if(tag == "mport") // p3.3.49 +                        if(tag == "mport")                           {                            port = xml.s2().toInt();                            rtype = Route::MIDI_PORT_ROUTE; @@ -1409,7 +1117,7 @@ void Route::read(Xml& xml)                          #ifdef ROUTE_DEBUG                          printf("Route::read(): tag end type:%d channel:%d name:%s\n", rtype, channel, s.toLatin1().constData());                          #endif -                        if(rtype == MIDI_PORT_ROUTE)  // p3.3.49 +                        if(rtype == MIDI_PORT_ROUTE)                            {                            if(port >= 0 && port < MIDI_PORTS)                            { @@ -1462,7 +1170,6 @@ void Route::read(Xml& xml)                                MidiDevice* md = *imd;                                if(md->name() == s && md->deviceType() == dtype)                                 { -                                // p3.3.45                                  // We found a device, but if it is not in use by the song (port is -1), ignore it.                                   // This prevents loading and propagation of bogus routes in the med file.                                  if(md->midiPort() == -1) @@ -1509,7 +1216,7 @@ void Song::readRoute(Xml& xml)                    case Xml::End:                          return;                    case Xml::TagStart: -                        // p3.3.38 2010/02/03 Support old routes in med files. Now obsolete! +                        // 2010/02/03 Support old routes in med files. Now obsolete!                          if (tag == "srcNode")                                src = xml.parse1();                          else if (tag == "dstNode") @@ -1545,7 +1252,7 @@ void Song::readRoute(Xml& xml)                          if(tag == "remch")                            remch = xml.s2().toInt();                          else -                        if(tag == "channelMask")           // p3.3.50 New channel mask for midi port-track routes. +                        if(tag == "channelMask")           // New channel mask for midi port-track routes.                            ch = xml.s2().toInt();                                         else                            printf("Song::readRoute(): unknown attribute:%s\n", tag.toLatin1().constData()); @@ -1564,17 +1271,17 @@ void Song::readRoute(Xml& xml)                            // Support new routes.                            if(sroute.isValid() && droute.isValid())                            {     -                            // p3.3.49 Support pre- 1.1-RC2 midi-device-to-track routes. Obsolete. Replaced with midi port routes. +                            // Support pre- 1.1-RC2 midi-device-to-track routes. Obsolete. Replaced with midi port routes.                              if(sroute.type == Route::MIDI_DEVICE_ROUTE && droute.type == Route::TRACK_ROUTE)                               {                                if(sroute.device->midiPort() >= 0 && sroute.device->midiPort() < MIDI_PORTS -                                 && ch >= 0 && ch < MIDI_CHANNELS)         // p3.3.50 +                                 && ch >= 0 && ch < MIDI_CHANNELS)                                         {                                  sroute.midiPort = sroute.device->midiPort();                                  sroute.device = 0;                                  sroute.type = Route::MIDI_PORT_ROUTE; -                                sroute.channel = 1 << ch;                  // p3.3.50  Convert to new bit-wise channel mask. +                                sroute.channel = 1 << ch;                  // Convert to new bit-wise channel mask.                                  droute.channel = sroute.channel;                                  addRoute(sroute, droute); @@ -1586,13 +1293,13 @@ void Song::readRoute(Xml& xml)                              else if(sroute.type == Route::TRACK_ROUTE && droute.type == Route::MIDI_DEVICE_ROUTE)                               {                                if(droute.device->midiPort() >= 0 && droute.device->midiPort() < MIDI_PORTS -                                 && ch >= 0 && ch < MIDI_CHANNELS)        // p3.3.50 +                                 && ch >= 0 && ch < MIDI_CHANNELS)                                        {                                  droute.midiPort = droute.device->midiPort();                                  droute.device = 0;                                  droute.type = Route::MIDI_PORT_ROUTE; -                                droute.channel = 1 << ch;                  // p3.3.50  Convert to new bit-wise channel mask. +                                droute.channel = 1 << ch;                  // Convert to new bit-wise channel mask.                                  sroute.channel = droute.channel;                                  addRoute(sroute, droute); @@ -1659,7 +1366,7 @@ void Route::dump() const            printf("Route dump: jack audio port <%s> channel %d\n", MusEGlobal::audioDevice->portName(jackPort).toLatin1().constData(), channel);        }        else  -      if (type == MIDI_PORT_ROUTE) // p3.3.49 +      if (type == MIDI_PORT_ROUTE)         {          printf("Route dump: midi port <%d> channel mask %d\n", midiPort, channel);        } @@ -1672,8 +1379,6 @@ void Route::dump() const            if(device->deviceType() == MidiDevice::JACK_MIDI)            {              if(MusEGlobal::checkAudioDevice()) -              //printf("jack midi port device <%s> ", MusEGlobal::audioDevice->portName(device->clientPort()).toLatin1().constData()); -            // p3.3.55              {                  printf("jack midi device <%s> ", device->name().toLatin1().constData());                if(device->inClientPort()) @@ -1730,36 +1435,16 @@ bool Route::operator==(const Route& a) const                {                      //if (!MusEGlobal::checkAudioDevice()) return false;                      //return MusEGlobal::audioDevice->portName(jackPort) == MusEGlobal::audioDevice->portName(a.jackPort); -                    // p3.3.55 Simplified. -                    return jackPort == a.jackPort; +                    return jackPort == a.jackPort;    // Simplified.                }                else  -              if (type == MIDI_PORT_ROUTE) // p3.3.49 +              if (type == MIDI_PORT_ROUTE)                 {                  return midiPort == a.midiPort;                }                else                 if (type == MIDI_DEVICE_ROUTE)                { -                // p3.3.55 Changed for unified jack in/out devices, the actual port names are now different from device name. -                // Like this:   device: "MyJackDevice1" ->  inport: "MyJackDevice1_in"  outport: "MyJackDevice1_out" -                /* -                if(device && a.device && device->deviceType() == a.device->deviceType()) -                { -                  if(device->deviceType() == MidiDevice::JACK_MIDI) -                  { -                    if (!MusEGlobal::checkAudioDevice()) return false; -                    return MusEGlobal::audioDevice->portName(device->clientPort()) == MusEGlobal::audioDevice->portName(a.device->clientPort()); -                  } -                  else -                  if(device->deviceType() == MidiDevice::ALSA_MIDI) -                    // TODO: OK ??  -                    return device->clientPort() == a.device->clientPort() && (channel == a.channel); -                  else -                  if(device->deviceType() == MidiDevice::SYNTH_MIDI) -                    return device->name() == a.device->name(); -                }     -                */                  return device == a.device;                }              }     @@ -1767,4 +1452,56 @@ bool Route::operator==(const Route& a) const        return false;  } +/* +//--------------------------------------------------------- +//   isCircularRoute +//   Recursive. +//   If dst is valid, start traversal from there, not from src. +//   Returns true if circular. +//--------------------------------------------------------- + +bool isCircularRoutePath(Track* src, Track* dst) +{ +  //if(isMidiTrack() || _type == AUDIO_AUX) +  //if(isMidiTrack()) +  //  return; +   +  bool rv = false; +   +  if(dst) +  {   +    src->setNodeTraversed(true); +    rv = isCircularRoutePath(dst, NULL); +    src->setNodeTraversed(false); +    //if(rv) +    //  fprintf(stderr, "  Circular route %s -> %s\n", src->name().toLatin1().constData(), dst->name().toLatin1().constData());  +    return rv; +  } +   +  if(src->nodeTraversed()) +    return true; +   +  src->setNodeTraversed(true); +   +  //printf("isCircularRoute %s\n", src->name().toLatin1().constData());  +   +  RouteList* orl = src->outRoutes(); +  for (iRoute i = orl->begin(); i != orl->end(); ++i)  +  { +    if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) +      continue; +    Track* t = (*i).track; +    //if(t->isMidiTrack()) +    //  continue; +    rv = isCircularRoutePath(src, NULL); +    if(rv) +      break;  +  } +   +  src->setNodeTraversed(false); +  return rv; +} +*/ + +  } // namespace MusECore diff --git a/muse2/muse/route.h b/muse2/muse/route.h index 36b00d47..587369bc 100644 --- a/muse2/muse/route.h +++ b/muse2/muse/route.h @@ -4,6 +4,7 @@  //  $Id: route.h,v 1.5.2.1 2008/05/21 00:28:52 terminator356 Exp $  //  //  (C) Copyright 2001 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -43,17 +44,15 @@ class Xml;  //---------------------------------------------------------  struct Route { -      enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2, MIDI_PORT_ROUTE=3 }; // p3.3.49 +      enum { TRACK_ROUTE=0, JACK_ROUTE=1, MIDI_DEVICE_ROUTE=2, MIDI_PORT_ROUTE=3 };         union { -            //AudioTrack* track;              Track* track; -            //MidiJackDevice* device;              MidiDevice* device;                    void* jackPort;              }; -      int midiPort;              // p3.3.49 Midi port number. Best not to put this in the union to avoid problems? +      int midiPort;              // Midi port number. Best not to put this in the union to avoid problems?        //snd_seq_addr_t alsaAdr; @@ -75,7 +74,7 @@ struct Route {        Route(void* t, int ch=-1);        Route(Track* t, int ch = -1, int chans = -1);        Route(MidiDevice* d, int ch);   -      Route(int port, int ch);         // p3.3.49 +      Route(int port, int ch);                 Route(const QString&, bool dst, int ch, int rtype = -1);        Route(); @@ -84,7 +83,7 @@ struct Route {        bool isValid() const {              return ((type == TRACK_ROUTE) && (track != 0)) || ((type == JACK_ROUTE) && (jackPort != 0)) ||                      ((type == MIDI_DEVICE_ROUTE) && (device != 0)) || -                   ((type == MIDI_PORT_ROUTE) && (midiPort >= 0) && (midiPort < MIDI_PORTS));   // p3.3.49 +                   ((type == MIDI_PORT_ROUTE) && (midiPort >= 0) && (midiPort < MIDI_PORTS));                 }        void read(Xml& xml);        void dump() const; @@ -106,6 +105,7 @@ extern void removeRoute(Route, Route);  extern void removeAllRoutes(Route, Route);  // p3.3.55  extern Route name2route(const QString&, bool dst, int rtype = -1);  extern bool checkRoute(const QString&, const QString&); +//extern bool isCircularRoutePath(Track* src, Track* dst);  // Recursive.  //---------------------------------------------------------  //   RouteMenuMap diff --git a/muse2/muse/shortcuts.cpp b/muse2/muse/shortcuts.cpp index 132eef97..cefb198e 100644 --- a/muse2/muse/shortcuts.cpp +++ b/muse2/muse/shortcuts.cpp @@ -66,7 +66,7 @@ void initShortCuts()        defShrt(SHRT_COPY,          Qt::CTRL + Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "Edit: Copy"), INVIS_SHRT, "copy");        defShrt(SHRT_COPY_RANGE,    Qt::CTRL + Qt::SHIFT + Qt::Key_C, QT_TRANSLATE_NOOP("shortcuts", "Edit: Copy in range"), GLOBAL_SHRT,    "copy_range");        defShrt(SHRT_UNDO,          Qt::CTRL + Qt::Key_Z, QT_TRANSLATE_NOOP("shortcuts", "Edit: Undo"), INVIS_SHRT, "undo"); -      defShrt(SHRT_REDO,          Qt::CTRL + Qt::Key_Y, QT_TRANSLATE_NOOP("shortcuts", "Edit: Redo"), INVIS_SHRT, "redo"); +      defShrt(SHRT_REDO,          Qt::CTRL + Qt::SHIFT + Qt::Key_Z, QT_TRANSLATE_NOOP("shortcuts", "Edit: Redo"), INVIS_SHRT, "redo");        defShrt(SHRT_CUT,           Qt::CTRL + Qt::Key_X, QT_TRANSLATE_NOOP("shortcuts", "Edit: Cut"), INVIS_SHRT, "cut");        defShrt(SHRT_PASTE,         Qt::CTRL + Qt::Key_V, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste"), INVIS_SHRT, "paste");        defShrt(SHRT_PASTE_DIALOG,  Qt::CTRL + Qt::SHIFT + Qt::Key_V, QT_TRANSLATE_NOOP("shortcuts", "Edit: Paste (with dialog)"), GLOBAL_SHRT, "paste_dialog"); diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp index 70314035..36be50a0 100644 --- a/muse2/muse/song.cpp +++ b/muse2/muse/song.cpp @@ -156,6 +156,7 @@ void Song::setSig(const AL::TimeSignature& sig)  Track* Song::addNewTrack(QAction* action, Track* insertAt)  { +printf("Song::addNewTrack\n");      int n = action->data().toInt();      // Ignore negative numbers since this slot could be called by a menu or list etc. passing -1.      if(n < 0) @@ -165,13 +166,20 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)      if(n >= MENU_ADD_SYNTH_ID_BASE)      {        n -= MENU_ADD_SYNTH_ID_BASE; +      int ntype = n / MENU_ADD_SYNTH_ID_BASE; +      if(ntype >= Synth::SYNTH_TYPE_END) +        return 0; + +      n %= MENU_ADD_SYNTH_ID_BASE;        if(n >= (int)MusEGlobal::synthis.size())          return 0; -      SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->name(), insertAt); +      //printf("Song::addNewTrack synth: type:%d idx:%d class:%s label:%s\n", ntype, n, MusEGlobal::synthis[n]->baseName().toLatin1().constData(), MusEGlobal::synthis[n]->name().toLatin1().constData());   +      SynthI* si = createSynthI(MusEGlobal::synthis[n]->baseName(), MusEGlobal::synthis[n]->name(), (Synth::Type)ntype, insertAt);        if(!si)          return 0; -       +      if (MusEGlobal::config.unhideTracks) SynthI::setVisible(true); +        // Add instance last in midi device list.        for (int i = 0; i < MIDI_PORTS; ++i)         { @@ -181,15 +189,19 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)          {            MusEGlobal::midiSeq->msgSetMidiDevice(port, si);            MusEGlobal::muse->changeConfig(true);     // save configuration file -          deselectTracks(); -          si->setSelected(true); -          update(); +          if (SynthI::visible()) { +            deselectTracks(); +            si->setSelected(true); +            update(); +          }            return si;          }        } -      deselectTracks(); -      si->setSelected(true); -      update(SC_SELECTION); +      if (SynthI::visible()) { +        deselectTracks(); +        si->setSelected(true); +        update(SC_SELECTION); +      }        return si;      }        // Normal track. @@ -200,10 +212,14 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)        if((Track::TrackType)n >= Track::AUDIO_SOFTSYNTH)          return 0; -      Track* t = addTrack((Track::TrackType)n, insertAt); -      deselectTracks(); -      t->setSelected(true); -      update(SC_SELECTION); +      Undo operations; +      Track* t = addTrack(operations, (Track::TrackType)n, insertAt); +      applyOperationGroup(operations); +      if (t->isVisible()) { +        deselectTracks(); +        t->setSelected(true); +        update(SC_SELECTION); +      }        return t;      }    }           @@ -216,53 +232,63 @@ Track* Song::addNewTrack(QAction* action, Track* insertAt)  //    If insertAt is valid, inserts before insertAt. Else at the end after all tracks.  //--------------------------------------------------------- -Track* Song::addTrack(Track::TrackType type, Track* insertAt) +Track* Song::addTrack(Undo& operations, Track::TrackType type, Track* insertAt)        { +  printf("Song::addTrack\n");        Track* track = 0;        int lastAuxIdx = _auxs.size();        switch(type) {              case Track::MIDI:                    track = new MidiTrack();                    track->setType(Track::MIDI); +                  if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true);                    break;              case Track::DRUM:                    track = new MidiTrack();                    track->setType(Track::DRUM);                    ((MidiTrack*)track)->setOutChannel(9); +                  if (MusEGlobal::config.unhideTracks) MidiTrack::setVisible(true);                    break;              case Track::WAVE:                    track = new MusECore::WaveTrack();                    ((AudioTrack*)track)->addAuxSend(lastAuxIdx); +                  if (MusEGlobal::config.unhideTracks) WaveTrack::setVisible(true);                    break;              case Track::AUDIO_OUTPUT:                    track = new AudioOutput(); +                  if (MusEGlobal::config.unhideTracks) AudioOutput::setVisible(true);                    break;              case Track::AUDIO_GROUP:                    track = new AudioGroup();                    ((AudioTrack*)track)->addAuxSend(lastAuxIdx); +                  if (MusEGlobal::config.unhideTracks) AudioGroup::setVisible(true);                    break;              case Track::AUDIO_AUX:                    track = new AudioAux(); +                  if (MusEGlobal::config.unhideTracks) AudioAux::setVisible(true);                    break;              case Track::AUDIO_INPUT:                    track = new AudioInput();                    ((AudioTrack*)track)->addAuxSend(lastAuxIdx); +                  if (MusEGlobal::config.unhideTracks) AudioInput::setVisible(true);                    break;              case Track::AUDIO_SOFTSYNTH:                    printf("not implemented: Song::addTrack(SOFTSYNTH)\n");                    // ((AudioTrack*)track)->addAuxSend(lastAuxIdx);                    break;              default: -                  printf("Song::addTrack() illegal type %d\n", type); -                  abort(); +                  printf("THIS SHOULD NEVER HAPPEN: Song::addTrack() illegal type %d. returning NULL.\n" +                         "save your work if you can and expect soon crashes!\n", type); +                  return NULL;              }        track->setDefaultName();        int idx = insertAt ? _tracks.index(insertAt) : -1; -      insertTrack1(track, idx); -      msgInsertTrack(track, idx, true); -      insertTrack3(track, idx); +      // insertTrack1(track, idx);         // this and the below are replaced +      // msgInsertTrack(track, idx, true); // by the UndoOp-operation +      // insertTrack3(track, idx); // does nothing +      operations.push_back(UndoOp(UndoOp::AddTrack, idx, track));        // Add default track <-> midiport routes.         if(track->isMidiTrack())  @@ -1928,7 +1954,7 @@ void Song::panic()  //    If clear_all is false, it will not touch things like midi ports.    //--------------------------------------------------------- -void Song::clear(bool signal, bool /*clear_all*/) +void Song::clear(bool signal, bool clear_all)        {        if(MusEGlobal::debugMsg)          printf("Song::clear\n"); @@ -1953,7 +1979,7 @@ void Song::clear(bool signal, bool /*clear_all*/)          // p3.3.50 Reset this.          MusEGlobal::midiPorts[i].setFoundInSongFile(false); -        //if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems... +        if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems...            // This will also close the device.            MusEGlobal::midiPorts[i].setMidiDevice(0);        } @@ -1972,7 +1998,7 @@ void Song::clear(bool signal, bool /*clear_all*/)            //if((*imd)->deviceType() == MidiDevice::JACK_MIDI)            if(dynamic_cast< MidiJackDevice* >(*imd))            { -            //if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems... +            if(clear_all)  // Allow not touching devices. p4.0.17  TESTING: Maybe some problems...              {                // Remove the device from the list.                MusEGlobal::midiDevices.erase(imd); @@ -2919,7 +2945,6 @@ void Song::insertTrack2(Track* track, int idx)                    break;              default:                    fprintf(stderr, "unknown track type %d\n", track->type()); -                  // abort();                    return;              } @@ -2936,7 +2961,7 @@ void Song::insertTrack2(Track* track, int idx)        for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) {              if ((*i)->isMidiTrack())                    continue; -            MusECore::WaveTrack* wt = (MusECore::WaveTrack*)*i; +            MusECore::AudioTrack* wt = (MusECore::AudioTrack*)*i;              if (wt->hasAuxSend()) {                    wt->addAuxSend(n);                    } @@ -2957,6 +2982,13 @@ void Song::insertTrack2(Track* track, int idx)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->outRoutes()->push_back(src); +                  // Is the source an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the Audio Output track's aux ref count.     p4.0.37 +                  if(r->track->auxRefCount()) +                    track->updateAuxRoute( r->track->auxRefCount(), NULL ); +                  else +                  if(r->track->type() == Track::AUDIO_AUX) +                    track->updateAuxRoute( 1, NULL );              }              }        else if (track->type() == Track::AUDIO_INPUT)  @@ -2970,6 +3002,13 @@ void Song::insertTrack2(Track* track, int idx)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->inRoutes()->push_back(src); +                  // Is this track an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the other track's aux ref count and all tracks it is connected to.     p4.0.37 +                  if(track->auxRefCount()) +                    r->track->updateAuxRoute( track->auxRefCount(), NULL ); +                  else +                  if(track->type() == Track::AUDIO_AUX) +                    r->track->updateAuxRoute( 1, NULL );              }              }        else if (track->isMidiTrack())          // p3.3.50 @@ -3000,6 +3039,13 @@ void Song::insertTrack2(Track* track, int idx)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->outRoutes()->push_back(src); +                  // Is the source an Aux Track or else does it have Aux Tracks routed to it? +                  // Update this track's aux ref count.     p4.0.37 +                  if(r->track->auxRefCount()) +                    track->updateAuxRoute( r->track->auxRefCount(), NULL ); +                  else +                  if(r->track->type() == Track::AUDIO_AUX) +                    track->updateAuxRoute( 1, NULL );              }              rl = track->outRoutes();              for (ciRoute r = rl->begin(); r != rl->end(); ++r) @@ -3010,6 +3056,13 @@ void Song::insertTrack2(Track* track, int idx)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->inRoutes()->push_back(src); +                  // Is this track an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the other track's aux ref count and all tracks it is connected to.     p4.0.37 +                  if(track->auxRefCount()) +                    r->track->updateAuxRoute( track->auxRefCount(), NULL ); +                  else +                  if(track->type() == Track::AUDIO_AUX) +                    r->track->updateAuxRoute( 1, NULL );              }              } @@ -3022,18 +3075,9 @@ void Song::insertTrack2(Track* track, int idx)  //    non realtime part of insertTrack  //--------------------------------------------------------- +// empty. gets executed after the realtime part  void Song::insertTrack3(Track* /*track*/, int /*idx*/)//prevent compiler warning: unused parameter  { -      //printf("Song::insertTrack3\n"); -       -      /* -      switch(track->type()) { -            case Track::AUDIO_SOFTSYNTH: -                  break; -            default: -                  break; -            } -      */  }  //--------------------------------------------------------- @@ -3153,6 +3197,13 @@ void Song::removeTrack2(Track* track)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->outRoutes()->removeRoute(src); +                  // Is the source an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the Audio Output track's aux ref count.     p4.0.37 +                  if(r->track->auxRefCount()) +                    track->updateAuxRoute( -r->track->auxRefCount(), NULL ); +                  else +                  if(r->track->type() == Track::AUDIO_AUX) +                    track->updateAuxRoute( -1, NULL );              }              }        else if (track->type() == Track::AUDIO_INPUT)  @@ -3167,6 +3218,13 @@ void Song::removeTrack2(Track* track)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->inRoutes()->removeRoute(src); +                  // Is this track an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the other track's aux ref count and all tracks it is connected to.     p4.0.37 +                  if(track->auxRefCount()) +                    r->track->updateAuxRoute( -track->auxRefCount(), NULL ); +                  else +                  if(track->type() == Track::AUDIO_AUX) +                    r->track->updateAuxRoute( -1, NULL );              }              }        else if (track->isMidiTrack())          // p3.3.50 @@ -3198,6 +3256,13 @@ void Song::removeTrack2(Track* track)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->outRoutes()->removeRoute(src); +                  // Is the source an Aux Track or else does it have Aux Tracks routed to it? +                  // Update this track's aux ref count.     p4.0.37 +                  if(r->track->auxRefCount()) +                    track->updateAuxRoute( -r->track->auxRefCount(), NULL ); +                  else +                  if(r->track->type() == Track::AUDIO_AUX) +                    track->updateAuxRoute( -1, NULL );              }              rl = track->outRoutes();              for (ciRoute r = rl->begin(); r != rl->end(); ++r) @@ -3209,6 +3274,13 @@ void Song::removeTrack2(Track* track)                    Route src(track, r->channel, r->channels);                    src.remoteChannel = r->remoteChannel;                    r->track->inRoutes()->removeRoute(src); +                  // Is this track an Aux Track or else does it have Aux Tracks routed to it? +                  // Update the other track's aux ref count and all tracks it is connected to.     p4.0.37 +                  if(track->auxRefCount()) +                    r->track->updateAuxRoute( -track->auxRefCount(), NULL ); +                  else +                  if(track->type() == Track::AUDIO_AUX) +                    r->track->updateAuxRoute( -1, NULL );              }              } @@ -3219,21 +3291,10 @@ void Song::removeTrack2(Track* track)  //    non realtime part of removeTrack  //--------------------------------------------------------- +//empty. gets executed after the realtime part  void Song::removeTrack3(Track* /*track*/)//prevent of compiler warning: unused parameter -      { -      /* -      switch(track->type()) { -            case Track::AUDIO_SOFTSYNTH: -                  { -                  SynthI* s = (SynthI*) track; -                  s->deactivate3(); -                  } -                  break; -            default: -                  break; -            } -      */ -      } +{ +}  //---------------------------------------------------------  //   executeScript diff --git a/muse2/muse/song.h b/muse2/muse/song.h index 7bbd831d..2c07396c 100644 --- a/muse2/muse/song.h +++ b/muse2/muse/song.h @@ -37,6 +37,7 @@  #include "al/sig.h"  #include "undo.h"  #include "track.h" +#include "synth.h"  class QAction;  class QFont; @@ -362,7 +363,7 @@ class Song : public QObject {        //   Configuration        //----------------------------------------- -      SynthI* createSynthI(const QString& sclass, const QString& label = QString(), Track* insertAt = 0); +      SynthI* createSynthI(const QString& sclass, const QString& label = QString(), Synth::Type type = Synth::SYNTH_TYPE_END, Track* insertAt = 0);        void rescanAlsaPorts(); @@ -410,7 +411,7 @@ class Song : public QObject {        void setQuantize(bool val);        void panic();        void seqSignal(int fd); -      Track* addTrack(Track::TrackType type, Track* insertAt = 0); +      Track* addTrack(Undo& operations, Track::TrackType type, Track* insertAt = 0);        Track* addNewTrack(QAction* action, Track* insertAt = 0);        QString getScriptPath(int id, bool delivered);        void populateScriptMenu(QMenu* menuPlugins, QObject* receiver); diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp index 9adfd406..9a3c11f5 100644 --- a/muse2/muse/songfile.cpp +++ b/muse2/muse/songfile.cpp @@ -1325,13 +1325,19 @@ void MusE::readToplevels(MusECore::Xml& xml)                                }                          else if (tag == "marker") {                                showMarker(true); -                              if (toplevels.back()->type()==MusEGui::TopWin::MARKER) -                                toplevels.back()->readStatus(xml); +                              TopWin* tw = toplevels.findType(TopWin::MARKER); +                              if(!tw) +                                xml.skip("marker"); +                              else +                                tw->readStatus(xml);                                }                          else if (tag == "arrangerview") {                                showArranger(true); -                              if (toplevels.back()->type()==MusEGui::TopWin::ARRANGER) -                                toplevels.back()->readStatus(xml); +                              TopWin* tw = toplevels.findType(TopWin::ARRANGER); +                              if(!tw) +                                xml.skip("arrangerview"); +                              else +                                tw->readStatus(xml);                                }                          else if (tag == "waveedit") {                                if(!pl->empty()) @@ -1343,8 +1349,11 @@ void MusE::readToplevels(MusECore::Xml& xml)                                }                          else if (tag == "cliplist") {                                startClipList(true); -                              if (toplevels.back()->type()==MusEGui::TopWin::CLIPLIST) -                                toplevels.back()->readStatus(xml); +                              TopWin* tw = toplevels.findType(TopWin::CLIPLIST); +                              if(!tw) +                                xml.skip("cliplist"); +                              else +                                tw->readStatus(xml);                                }                          else                                xml.unknown("MusE"); @@ -1506,9 +1515,34 @@ void MusE::read(MusECore::Xml& xml, bool skipConfig, bool isTemplate)                          else if (tag == "configuration")                                if (skipConfig)                                      //xml.skip(tag); -                                    readConfiguration(xml,true /* only read sequencer settings */, false /* do NOT read global settings */); +                                    readConfiguration(xml,true /* only read sequencer settings */, false /* do NOT read global settings, see below */); +                                    // see even more below!                                else -                                    readConfiguration(xml, false, false /* do NOT read global settings */); +                                    readConfiguration(xml, false, false /* do NOT read global settings, see below */); +                        /* Explanation for why "do NOT read global settings": +                         * if you would use true here, then muse would overwrite certain global config stuff +                         * by the settings stored in the song. but you don't want this. imagine that you +                         * send a friend a .med file. your friend opens it and baaam, his configuration is +                         * garbled. why? well, because these readConfigurations here would have overwritten +                         * parts (but not all) of his global config (like MDI/SDI, toolbar states etc.) +                         * with the data stored in the song. (it IS stored there. dunny why, i find it pretty +                         * senseless.) +                         *  +                         * If you've a problem which seems to be solved by replacing "false" with "true", i've +                         * a better solution for you: go into conf.cpp, in void readConfiguration(Xml& xml, bool readOnlySequencer, bool doReadGlobalConfig) +                         * (around line 525), look for a comment like this: +                         * "Global and/or per-song config stuff ends here" (alternatively just search for +                         * "----"). Your problem is probably that some non-global setting should be loaded but +                         * is not. Fix it by either placing the else if (foo)... clause responsible for that +                         * setting to be loaded into the first part, that is, before "else if (!doReadGlobalConfig)" +                         * or (if the settings actually IS global and not per-song), ensure that the routine +                         * which writes the global (and not the song-)configuration really writes that setting. +                         * (it might happen that it formerly worked because it was written to the song instead +                         *  of the global config by mistake, and now isn't loaded anymore. write it to the +                         *  correct location.) +                         *  +                         *                                                                                -- flo93 +                         */                          else if (tag == "song")                          {                                MusEGlobal::song->read(xml, isTemplate); diff --git a/muse2/muse/structure.cpp b/muse2/muse/structure.cpp index 90d02908..70b19540 100644 --- a/muse2/muse/structure.cpp +++ b/muse2/muse/structure.cpp @@ -137,7 +137,7 @@ void adjustGlobalLists(Undo& operations, int startPos, int diff)  //    - cut master track  //--------------------------------------------------------- -void globalCut() +void globalCut(bool onlySelectedTracks)        {        int lpos = MusEGlobal::song->lpos();        int rpos = MusEGlobal::song->rpos(); @@ -146,17 +146,11 @@ void globalCut()        Undo operations;        TrackList* tracks = MusEGlobal::song->tracks(); -      bool at_least_one_selected=false; -       -      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) -            if ( (*it)->selected() ) { -                  at_least_one_selected=true; -                  break; -                  }        for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { -            MidiTrack* track = dynamic_cast<MidiTrack*>(*it); -            if (track == 0 || (at_least_one_selected && !track->selected())) +            //MidiTrack* track = dynamic_cast<MidiTrack*>(*it); +            Track* track = *it; +            if (track == 0 || (onlySelectedTracks && !track->selected()))                    continue;              PartList* pl = track->parts();              for (iPart p = pl->begin(); p != pl->end(); ++p) { @@ -169,63 +163,61 @@ void globalCut()                          operations.push_back(UndoOp(UndoOp::DeletePart,part));                          }                    else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) { -                        // remove part tail -                        int len = lpos - t; -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); -                        nPart->setLenTick(len); -                        // -                        // cut Events in nPart -                        EventList* el = nPart->events(); -                        for (iEvent ie = el->lower_bound(len); ie != el->end(); ++ie) -                              operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, nPart, false, false)); - -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); -                        } +                      // remove part tail +                      int len = lpos - t; +                      Part *nPart; +                      if (track->isMidiTrack()) +                        nPart = new MidiPart(*(MidiPart*)part); +                      else +                        nPart = new WavePart(*(WavePart*)part); + +                      nPart->setLenTick(len); +                      // +                      // cut Events in nPart +                      EventList* el = nPart->events(); +                      for (iEvent ie = el->lower_bound(len); ie != el->end(); ++ie) +                            operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, nPart, false, false)); + +                      operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); +                  }                    else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) {                          //----------------------                          // remove part middle                          //---------------------- +                        Part* p1; +                        Part* p2; +                        Part* p3; +                        track->splitPart(part, lpos, p1, p2); +                        delete p2; +                        track->splitPart(part, rpos, p2, p3); +                        delete p2; +                        p3->setTick(lpos); +                        p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ +                        p3->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); -                        EventList* el = nPart->events(); -                        iEvent is = el->lower_bound(lpos-t); -                        iEvent ie = el->lower_bound(rpos-t); //lower bound, because we do NOT want to erase the events at rpos-t -                        for (iEvent i = is; i != ie; ++i) -                              operations.push_back(UndoOp(UndoOp::DeleteEvent,i->second, nPart, false, false)); - -                        for (iEvent i = el->lower_bound(rpos-t); i != el->end(); ++i) { -                              Event event = i->second; -                              Event nEvent = event.clone(); -                              nEvent.setTick(nEvent.tick() - (rpos-lpos)); -                              // Indicate no undo, and do not do port controller values and clone parts. -                              operations.push_back(UndoOp(UndoOp::ModifyEvent,nEvent, event, nPart, false, false)); -                              } -                        nPart->setLenTick(l - (rpos-lpos));                          // Indicate no undo, and do port controller values and clone parts. -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); +                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, true)); +                        operations.push_back(UndoOp(UndoOp::AddPart,p3));                          }                    else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) {                          // remove part head -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); -                        EventList* el = nPart->events(); -                        iEvent i_end = el->lower_bound(rpos-t); //lower bound, because we do NOT want to erase the events at rpos-t -                        for (iEvent it = el->begin(); it!=i_end; it++) -                              operations.push_back(UndoOp(UndoOp::DeleteEvent,it->second, nPart, false, false)); -                         -                        for (iEvent it = el->lower_bound(rpos-t); it!=el->end(); it++) { -                              Event event = it->second; -                              Event nEvent = event.clone(); -                              nEvent.setTick(nEvent.tick() - (rpos-t)); -                              // Indicate no undo, and do not do port controller values and clone parts. -                              operations.push_back(UndoOp(UndoOp::ModifyEvent,nEvent, event, nPart, false, false)); -                              } -                         -                        nPart->setLenTick(l - (rpos-t)); -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, nPart, true, true)); +                        Part* p1; +                        Part* p2; +                        track->splitPart(part, rpos, p1, p2); +                        delete p1; +                        p2->setTick(lpos); +                        p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ +                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, p2, true, true));                          }                    else if (t >= rpos) { -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); +                        // move part to the left +                        Part *nPart; +                        if (track->isMidiTrack()) +                          nPart = new MidiPart(*(MidiPart*)part); +                        else +                          nPart = new WavePart(*(WavePart*)part); +                        //MidiPart* nPart = new MidiPart(*(MidiPart*)part);                          int nt = part->tick();                          nPart->setTick(nt - (rpos -lpos));                          // Indicate no undo, and do port controller values but not clone parts. @@ -246,33 +238,24 @@ void globalCut()  //    - insert in master track  //--------------------------------------------------------- -void globalInsert() -      { -      Undo operations=movePartsTotheRight(MusEGlobal::song->lpos(), MusEGlobal::song->rpos()-MusEGlobal::song->lpos(), true); +void globalInsert(bool onlySelectedTracks) +{ +      Undo operations=movePartsTotheRight(MusEGlobal::song->lpos(), MusEGlobal::song->rpos()-MusEGlobal::song->lpos(), onlySelectedTracks);        MusEGlobal::song->applyOperationGroup(operations); -      } - +}  Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selected, set<Track*>* tracklist) -      { +{        if (moveTicks<=0)              return Undo();        Undo operations;        TrackList* tracks = MusEGlobal::song->tracks(); -      bool at_least_one_selected=false; -       -      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) -            if ( (*it)->selected() ) { -                  at_least_one_selected=true; -                  break; -                  } -              for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { -            MidiTrack* track = dynamic_cast<MidiTrack*>(*it); +            Track* track = *it;              if ( (track == 0) || -                 (only_selected && at_least_one_selected && !track->selected()) || +                 (only_selected && !track->selected()) ||                   (tracklist && tracklist->find(track)==tracklist->end()) )                    continue;              PartList* pl = track->parts(); @@ -283,23 +266,23 @@ Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selec                    if (t + l <= startTicks)                          continue;                    if (startTicks > t && startTicks < (t+l)) { -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); -                        nPart->setLenTick(l + moveTicks); -                        EventList* el = nPart->events(); - -                        for (riEvent i = el->rbegin(); i!=el->rend(); ++i) -                        { -                              if (i->first < startTicks-t) -                                    break; -                              Event event  = i->second; -                              Event nEvent = i->second.clone(); -                              nEvent.setTick(nEvent.tick() + moveTicks); -                              operations.push_back(UndoOp(UndoOp::ModifyEvent, nEvent, event, nPart, false, false)); -                              } -                        operations.push_back(UndoOp(UndoOp::ModifyPart, part, nPart, true, true)); +                        // split part to insert new space +                        Part* p1; +                        Part* p2; +                        track->splitPart(part, startTicks, p1, p2); +                        p2->setTick(startTicks+moveTicks); +                        p2->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ +                        p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it so we must decrement it first :/ + +                        operations.push_back(UndoOp(UndoOp::ModifyPart, part, p1, true, true)); +                        operations.push_back(UndoOp(UndoOp::AddPart, p2));                          }                    else if (t >= startTicks) { -                        MidiPart* nPart = new MidiPart(*(MidiPart*)part); +                        Part *nPart; +                        if (track->isMidiTrack()) +                          nPart = new MidiPart(*(MidiPart*)part); +                        else +                          nPart = new WavePart(*(WavePart*)part);                          nPart->setTick(t + moveTicks);                          operations.push_back(UndoOp(UndoOp::ModifyPart, part, nPart, true, false));                          } @@ -317,47 +300,50 @@ Undo movePartsTotheRight(unsigned int startTicks, int moveTicks, bool only_selec  //    - split all parts at the song position pointer  //--------------------------------------------------------- -void globalSplit() -      { -      int pos = MusEGlobal::song->cpos(); -      Undo operations; -      TrackList* tracks = MusEGlobal::song->tracks(); -      bool at_least_one_selected=false; -       -      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) -            if ( (*it)->selected() ) { -                  at_least_one_selected=true; -                  break; -                  } -       - -      for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { -            Track* track = *it; -            if (track == 0 || (at_least_one_selected && !track->selected())) -                  continue; - -            PartList* pl = track->parts(); -            for (iPart p = pl->begin(); p != pl->end(); ++p) { -                  Part* part = p->second; -                  int p1 = part->tick(); -                  int l0 = part->lenTick(); -                  if (pos > p1 && pos < (p1+l0)) { -                        Part* p1; -                        Part* p2; -                        track->splitPart(part, pos, p1, p2); +void globalSplit(bool onlySelectedTracks) +{ +    Undo operations=partSplitter(MusEGlobal::song->cpos(), onlySelectedTracks); +    MusEGlobal::song->applyOperationGroup(operations); +} -                        p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it -                        p2->events()->incARef(-1); // so we must decrement it first :/ +Undo partSplitter(unsigned int pos, bool onlySelectedTracks) +{ +    Undo operations; +    TrackList* tracks = MusEGlobal::song->tracks(); + +    for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { +        Track* track = *it; +        if (track == 0 || (onlySelectedTracks && !track->selected())) +              continue; + +        PartList* pl = track->parts(); +        for (iPart p = pl->begin(); p != pl->end(); ++p) { +              Part* part = p->second; +              unsigned int p1 = part->tick(); +              unsigned int l0 = part->lenTick(); +              if (pos > p1 && pos < (p1+l0)) { +                    Part* p1; +                    Part* p2; +                    track->splitPart(part, pos, p1, p2); + +                    p1->events()->incARef(-1); // the later MusEGlobal::song->applyOperationGroup() will increment it +                    p2->events()->incARef(-1); // so we must decrement it first :/ + +                    //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ModifyPart +                    MusEGlobal::song->informAboutNewParts(part, p2); +                    operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, false)); +                    operations.push_back(UndoOp(UndoOp::AddPart,p2)); +                    if (MusEGlobal::debugMsg) +                    { +                          printf("in partSplitter: part1 %d\n",p1->events()->refCount()); +                          printf("in partSplitter: part2 %d\n",p2->events()->refCount()); +                          } +                    break; +                    } +              } +        } +    return operations; +} -                        //MusEGlobal::song->informAboutNewParts(part, p1); // is unneccessary because of ModifyPart -                        MusEGlobal::song->informAboutNewParts(part, p2); -                        operations.push_back(UndoOp(UndoOp::ModifyPart,part, p1, true, false)); -                        operations.push_back(UndoOp(UndoOp::AddPart,p2)); -                        break; -                        } -                  } -            } -      MusEGlobal::song->applyOperationGroup(operations); -      }  } // namespace MusECore diff --git a/muse2/muse/structure.h b/muse2/muse/structure.h index b92c4e14..3a359dc0 100644 --- a/muse2/muse/structure.h +++ b/muse2/muse/structure.h @@ -28,10 +28,11 @@  namespace MusECore {  Undo movePartsTotheRight(unsigned int startTick, int moveTick, bool only_selected=false, std::set<Track*>* tracklist=NULL); +Undo partSplitter(unsigned int tick, bool onlySelectedTracks=false);  void adjustGlobalLists(Undo& operations, int startPos, int diff); -void globalCut(); -void globalInsert(); -void globalSplit(); +void globalCut(bool onlySelectedTracks=false); +void globalInsert(bool onlySelectedTracks=false); +void globalSplit(bool onlySelectedTracks=false);  }  #endif diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index 93067835..7ab18bda 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -32,6 +32,7 @@  #include <dlfcn.h>  #include <QDir> +#include <QString>  //#include <QMenu>  #include "app.h" @@ -62,6 +63,19 @@ namespace MusECore {  extern void connectNodes(AudioTrack*, AudioTrack*);  bool SynthI::_isVisible=false; +const char* synthTypes[] = { "METRONOME", "MESS", "DSSI", "VST", "UNKNOWN" }; +QString synthType2String(Synth::Type type) { return QString(synthTypes[type]); }  + +Synth::Type string2SynthType(const QString& type)  +{  +  for(int i = 0; i < Synth::SYNTH_TYPE_END; ++i) +  {   +    if(synthType2String((Synth::Type)i) == type) +      return (Synth::Type)i;  +  }   +  return Synth::SYNTH_TYPE_END; +}  +  /*  //---------------------------------------------------------  //   description @@ -145,19 +159,17 @@ void MessSynthIF::setNativeGeometry(int x, int y, int w, int h)  //    search for synthesizer base class  //--------------------------------------------------------- -//static Synth* findSynth(const QString& sclass) -static Synth* findSynth(const QString& sclass, const QString& label) +static Synth* findSynth(const QString& sclass, const QString& label, Synth::Type type = Synth::SYNTH_TYPE_END)        {        for (std::vector<Synth*>::iterator i = MusEGlobal::synthis.begin();           i != MusEGlobal::synthis.end(); ++i)            { -            //if ((*i)->baseName() == sclass) -            //if ((*i)->name() == sclass) -            if ( ((*i)->baseName() == sclass) && (label.isEmpty() || ((*i)->name() == label)) ) -                   -                  return *i; +            if( ((*i)->baseName() == sclass) &&  +                (label.isEmpty() || ((*i)->name() == label)) &&  +                (type == Synth::SYNTH_TYPE_END || type == (*i)->synthType()) ) +              return *i;           } -      printf("synthi class:%s label:%s not found\n", sclass.toLatin1().constData(), label.toLatin1().constData()); +      printf("synthi type:%d class:%s label:%s not found\n", type, sclass.toLatin1().constData(), label.toLatin1().constData());        return 0;        } @@ -166,10 +178,9 @@ static Synth* findSynth(const QString& sclass, const QString& label)  //    create a synthesizer instance of class "label"  //--------------------------------------------------------- -static SynthI* createSynthInstance(const QString& sclass, const QString& label) +static SynthI* createSynthInstance(const QString& sclass, const QString& label, Synth::Type type = Synth::SYNTH_TYPE_END)        { -      //Synth* s = findSynth(sclass); -      Synth* s = findSynth(sclass, label); +      Synth* s = findSynth(sclass, label, type);        SynthI* si = 0;        if (s) {              si = new SynthI(); @@ -652,13 +663,11 @@ void initMidiSynth()  //    If insertAt is valid, inserts before insertAt. Else at the end after all tracks.  //--------------------------------------------------------- -SynthI* Song::createSynthI(const QString& sclass, const QString& label, Track* insertAt) +SynthI* Song::createSynthI(const QString& sclass, const QString& label, Synth::Type type, Track* insertAt)        {        //printf("Song::createSynthI calling ::createSynthI class:%s\n", sclass.toLatin1().constData()); -      //SynthI* si = ::createSynthI(sclass); -      //SynthI* si = ::createSynthI(sclass, label); -      SynthI* si = createSynthInstance(sclass, label); +      SynthI* si = createSynthInstance(sclass, label, type);        if(!si)          return 0;        //printf("Song::createSynthI created SynthI. Before insertTrack1...\n"); @@ -705,6 +714,9 @@ void SynthI::write(int level, Xml& xml) const        {        xml.tag(level++, "SynthI");        AudioTrack::writeProperties(level, xml); +      //xml.intTag(level, "synthType", synth()->synthType()); +      xml.strTag(level, "synthType", synthType2String(synth()->synthType())); +        xml.strTag(level, "class", synth()->baseName());        // To support plugins like dssi-vst where all the baseNames are the same 'dssi-vst' and the label is the name of the dll file. @@ -823,7 +835,8 @@ void SynthI::read(Xml& xml)        {        QString sclass;        QString label; -       +      Synth::Type type = Synth::SYNTH_TYPE_END; +        int port = -1;        bool startgui = false;        bool startngui = false; @@ -837,7 +850,10 @@ void SynthI::read(Xml& xml)                    case Xml::End:                          return;                    case Xml::TagStart: -                        if (tag == "class") +                        if (tag == "synthType") +                              //type = xml.parseInt(); +                              type = string2SynthType(xml.parse1()); +                        else if (tag == "class")                                sclass = xml.parse1();                          else if (tag == "label")                                label  = xml.parse1(); @@ -866,8 +882,15 @@ void SynthI::read(Xml& xml)                          break;                    case Xml::TagEnd:                          if (tag == "SynthI") { -                              //Synth* s = findSynth(sclass); -                              Synth* s = findSynth(sclass, label); +                               +                              // NOTICE: This is a hack to quietly change songs to use the new 'fluid_synth' name instead of 'fluidsynth'. +                              //         Recent linker changes required the name change in fluidsynth's cmakelists. Nov 8, 2011 By Tim. +                              if(sclass == QString("fluidsynth") &&  +                                 (type == Synth::SYNTH_TYPE_END || type == Synth::MESS_SYNTH) && +                                 (label.isEmpty() || label == QString("FluidSynth")) ) +                                sclass = QString("fluid_synth"); +                               +                              Synth* s = findSynth(sclass, label, type);                                if (s == 0)                                      return;                                if (initInstance(s, name())) diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h index c5b63424..497395c0 100644 --- a/muse2/muse/synth.h +++ b/muse2/muse/synth.h @@ -72,6 +72,8 @@ class Synth {        QString _version;     public: +      enum Type { METRO_SYNTH=0, MESS_SYNTH, DSSI_SYNTH, VST_SYNTH, SYNTH_TYPE_END }; +        //Synth(const QFileInfo& fi);        //Synth(const QFileInfo& fi, QString label);        Synth(const QFileInfo& fi, QString label, QString descr, QString maker, QString ver); @@ -80,6 +82,7 @@ class Synth {        //virtual const char* description() const { return ""; }        //virtual const char* version() const { return ""; } +      virtual Type synthType() const = 0;        int instances() const                            { return _instances; }        virtual void incInstances(int val)               { _instances += val; }        QString completeBaseName()             /*const*/ { return info.completeBaseName(); } // ddskrjo @@ -117,6 +120,8 @@ class MessSynth : public Synth {        //virtual const char* description() const;        //virtual const char* version() const; +      virtual Type synthType() const { return MESS_SYNTH; } +        //virtual void* instantiate();        virtual void* instantiate(const QString&); @@ -363,6 +368,9 @@ class MessSynthIF : public SynthIF {        virtual int getControllerInfo(int id, const char** name, int* ctrl, int* min, int* max, int* initval);        }; +extern QString synthType2String(Synth::Type); +extern Synth::Type string2SynthType(const QString&);  +        } // namespace MusECore  namespace MusEGlobal { diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp index 1edc0b12..6d3721ea 100644 --- a/muse2/muse/ticksynth.cpp +++ b/muse2/muse/ticksynth.cpp @@ -49,6 +49,7 @@ class MetronomeSynth : public Synth {        //MetronomeSynth(const QFileInfo& fi) : Synth(fi, QString("Metronome")) {}        MetronomeSynth(const QFileInfo& fi) : Synth(fi, QString("Metronome"), QString("Metronome"), QString(), QString()) {}        virtual ~MetronomeSynth() {} +      virtual Type synthType() const { return METRO_SYNTH; }        virtual void incInstances(int) {}        virtual void* instantiate(); diff --git a/muse2/muse/track.cpp b/muse2/muse/track.cpp index 2091d03e..e9aa0cf6 100644 --- a/muse2/muse/track.cpp +++ b/muse2/muse/track.cpp @@ -4,6 +4,7 @@  //  $Id: track.cpp,v 1.34.2.11 2009/11/30 05:05:49 terminator356 Exp $  //  //  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -36,10 +37,12 @@  namespace MusECore {  //bool Track::_isVisible=true; -unsigned int Track::_soloRefCnt = 0; +unsigned int Track::_soloRefCnt  = 0;  Track* Track::_tmpSoloChainTrack = 0;  bool Track::_tmpSoloChainDoIns   = false;  bool Track::_tmpSoloChainNoDec   = false; +//bool Track::_tmpIsAuxProcessing  = false;  +//int Track::_tmpIsAuxProcRefCount = 0;   const char* Track::_cname[] = {        "Midi", "Drum", "Wave", "AudioOut", "AudioIn", "AudioGroup",  @@ -199,6 +202,8 @@ int Track::y() const  void Track::init()        { +      _auxRouteCount = 0;   +      _nodeTraversed = false;        _activity      = 0;        _lastActivity  = 0;        _recordFlag    = false; @@ -233,6 +238,8 @@ Track::Track(Track::TrackType t)  //Track::Track(const Track& t)  Track::Track(const Track& t, bool cloneParts)        { +      _auxRouteCount = t._auxRouteCount; +      _nodeTraversed = t._nodeTraversed;        _activity     = t._activity;        _lastActivity = t._lastActivity;        _recordFlag   = t._recordFlag; @@ -298,6 +305,8 @@ Track::~Track()  Track& Track::operator=(const Track& t)   { +      _auxRouteCount = t._auxRouteCount; +      _nodeTraversed = t._nodeTraversed;        _activity     = t._activity;        _lastActivity = t._lastActivity;        _recordFlag   = t._recordFlag; @@ -414,6 +423,107 @@ void Track::dump() const           _name.toLatin1().constData(), _type, _parts.size(), _selected);        } +//--------------------------------------------------------- +//   updateAuxRoute +//   Internal use. Update all the Aux ref counts of tracks dst is connected to. +//   If dst is valid, start traversal from there, not from this track. +//--------------------------------------------------------- + +void Track::updateAuxRoute(int refInc, Track* dst) +{ +  //if(isMidiTrack() || _type == AUDIO_AUX) +  if(isMidiTrack()) +    return; +   +  //printf("Track::updateAuxRoute %s _auxRouteCount:%d refInc:%d\n", name().toLatin1().constData(), _auxRouteCount, refInc);  + +  if(dst) +  {   +    _nodeTraversed = true; +    dst->updateAuxRoute(refInc, NULL); +    _nodeTraversed = false; +    return; +  }   +   +  if(_type == AUDIO_AUX) +    return; +   +  if(_nodeTraversed) +  { +    fprintf(stderr, "Track::updateAuxRoute %s _auxRouteCount:%d refInc:%d :\n", name().toLatin1().constData(), _auxRouteCount, refInc);  +    if(refInc >= 0) +      fprintf(stderr, "  MusE Warning: Please check your routes: Circular path found!\n");  +    else +      fprintf(stderr, "  MusE: Circular path removed.\n");  +    return; +  } +   +  _nodeTraversed = true; +   +  _auxRouteCount += refInc; +  if(_auxRouteCount < 0) +  { +    fprintf(stderr, "Track::updateAuxRoute Ref underflow! %s _auxRouteCount:%d refInc:%d\n", name().toLatin1().constData(), _auxRouteCount, refInc);  +    //_auxRouteCount = 0;     +  } +   +  for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i)  +  { +    if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) +      continue; +    Track* t = (*i).track; +    //if(t->isMidiTrack()) +    //  continue; +    t->updateAuxRoute(refInc, NULL); +  } +   +  _nodeTraversed = false; +} + +//--------------------------------------------------------- +//   isCircularRoute +//   If dst is valid, start traversal from there, not from this track. +//   Returns true if circular. +//--------------------------------------------------------- + +bool Track::isCircularRoute(Track* dst) +{ +  //if(isMidiTrack() || _type == AUDIO_AUX) +  //if(isMidiTrack()) +  //  return; +   +  bool rv = false; +   +  if(dst) +  {   +    _nodeTraversed = true; +    rv = dst->isCircularRoute(NULL); +    _nodeTraversed = false; +    //if(rv) +    //  fprintf(stderr, "  Circular route %s -> %s\n", name().toLatin1().constData(), dst->name().toLatin1().constData());  +    return rv; +  } +   +  if(_nodeTraversed) +    return true; +   +  _nodeTraversed = true; +   +  for (iRoute i = _outRoutes.begin(); i != _outRoutes.end(); ++i)  +  { +    if( !(*i).isValid() || (*i).type != Route::TRACK_ROUTE ) +      continue; +    Track* t = (*i).track; +    //if(t->isMidiTrack()) +    //  continue; +    rv = t->isCircularRoute(NULL); +    if(rv) +      break;  +  } +   +  _nodeTraversed = false; +  return rv; +}  //---------------------------------------------------------  //   MidiTrack @@ -462,7 +572,6 @@ void MidiTrack::init()        {        _outPort       = 0;        _outChannel    = 0; -      // Changed by Tim. p3.3.8        //_inPortMask    = 0xffff;        ///_inPortMask    = 0xffffffff; @@ -537,7 +646,7 @@ void MidiTrack::setOutPortAndChannelAndUpdate(int port, int ch)  //---------------------------------------------------------  //   setInPortAndChannelMask  //   For old song files with port mask (max 32 ports) and channel mask (16 channels),  -//    before midi routing was added (the iR button). p3.3.48 +//    before midi routing was added (the iR button).   //---------------------------------------------------------  void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask)  @@ -550,7 +659,7 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask)    for(int port = 0; port < 32; ++port)  // 32 is the old maximum number of ports.    { -    // p3.3.50 If the port was not used in the song file to begin with, just ignore it. +    // If the port was not used in the song file to begin with, just ignore it.      // This saves from having all of the first 32 ports' channels connected.      if(!MusEGlobal::midiPorts[port].foundInSongFile())        continue; @@ -558,34 +667,18 @@ void MidiTrack::setInPortAndChannelMask(unsigned int portmask, int chanmask)      //if(!(portmask & (1 << port)))      //  continue; -    // p3.3.50 Removed. Allow to connect to port with no device so user can change device later. +    // Removed. Allow to connect to port with no device so user can change device later.      //MidiPort* mp = &MusEGlobal::midiPorts[port];      //MidiDevice* md = mp->device();      //if(!md)      //  continue; -    //for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  // p3.3.50 Removed. -    //{ -      //if(!(chanmask & (1 << ch))) -      //  continue; -     -      //Route aRoute(md, ch); -      //Route bRoute(this, ch); -      Route aRoute(port, chanmask);     // p3.3.50 +      Route aRoute(port, chanmask);             Route bRoute(this, chanmask); -      // p3.3.50 Removed. -      //iRoute iir = rl->begin(); -      //for(; iir != rl->end(); ++iir)  -      //{ -        //if(*iir == aRoute) -      //  if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == port)      // p3.3.50 -      //    break; -      //} -              // Route wanted?        //if((portmask & (1 << port)) && (chanmask & (1 << ch))) -      if(portmask & (1 << port))                                          // p3.3.50 +      if(portmask & (1 << port))                                                  {          // Route already exists?          //if(iir != rl->end())  @@ -818,11 +911,11 @@ void MidiTrack::read(Xml& xml)                                //setInPortMask(xml.parseInt());                                ///setInPortMask(xml.parseUInt());                                //xml.skip(tag);                      // Obsolete.  -                              portmask = xml.parseUInt();           // p3.3.48: Support old files. +                              portmask = xml.parseUInt();           // Support old files.                          else if (tag == "inchannelMap")                                ///setInChannelMask(xml.parseInt());                                //xml.skip(tag);                      // Obsolete. -                              chanmask = xml.parseInt();            // p3.3.48: Support old files. +                              chanmask = xml.parseInt();            // Support old files.                          else if (tag == "locked")                                _locked = xml.parseInt();                          else if (tag == "echo") @@ -843,7 +936,7 @@ void MidiTrack::read(Xml& xml)                    case Xml::TagEnd:                          if (tag == "miditrack" || tag == "drumtrack")                           { -                          setInPortAndChannelMask(portmask, chanmask); // p3.3.48: Support old files. +                          setInPortAndChannelMask(portmask, chanmask); // Support old files.                            return;                          }                    default: @@ -972,7 +1065,7 @@ void Track::writeRouting(int level, Xml& xml) const              xml.tag(level++, s.toAscii().constData()); -            // p3.3.38 New routing scheme. +            // New routing scheme.              s = "source";              if(r->type != Route::TRACK_ROUTE)                s += QString(" type=\"%1\"").arg(r->type); @@ -994,10 +1087,10 @@ void Track::writeRouting(int level, Xml& xml) const          if(r->type == Route::TRACK_ROUTE && r->track && r->track->type() == Track::AUDIO_INPUT)             continue; -        if(r->midiPort != -1 || !r->name().isEmpty()) // p3.3.49 +        if(r->midiPort != -1 || !r->name().isEmpty())           {            s = "Route"; -          if(r->type == Route::MIDI_PORT_ROUTE)  // p3.3.50 +          if(r->type == Route::MIDI_PORT_ROUTE)              {              if(r->channel != -1 && r->channel != 0)                s += QString(" channelMask=\"%1\"").arg(r->channel);  // Use new channel mask. @@ -1019,14 +1112,14 @@ void Track::writeRouting(int level, Xml& xml) const            s = "dest"; -          //if(r->type == Route::MIDI_DEVICE_ROUTE)                                      // p3.3.49 Obsolete since 1.1-RC2     +          //if(r->type == Route::MIDI_DEVICE_ROUTE)                                      // Obsolete since 1.1-RC2                //  s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType());  //            //if(r->type != Route::TRACK_ROUTE)                                            //            if(r->type != Route::TRACK_ROUTE && r->type != Route::MIDI_PORT_ROUTE)              s += QString(" type=\"%1\"").arg(r->type);            //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name()); -          if(r->type == Route::MIDI_PORT_ROUTE)                                          // p3.3.49  +          if(r->type == Route::MIDI_PORT_ROUTE)                                                        s += QString(" mport=\"%1\"/").arg(r->midiPort);            else                s += QString(" name=\"%1\"/").arg(Xml::xmlString(r->name())); diff --git a/muse2/muse/track.h b/muse2/muse/track.h index 25a846ac..04cf71c2 100644 --- a/muse2/muse/track.h +++ b/muse2/muse/track.h @@ -4,6 +4,7 @@  //  $Id: track.h,v 1.39.2.17 2009/12/20 05:00:35 terminator356 Exp $  //  //  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -70,9 +71,10 @@ class Track {        static bool _tmpSoloChainDoIns;        static bool _tmpSoloChainNoDec; -      // p3.3.38        RouteList _inRoutes;        RouteList _outRoutes; +      bool _nodeTraversed;   // Internal anti circular route traversal flag. +      int _auxRouteCount;    // Number of aux paths feeding this track.        QString _name;        bool _recordFlag; @@ -89,8 +91,6 @@ class Track {        int _activity;        int _lastActivity; -      //int _meter[MAX_CHANNELS]; -      //int _peak[MAX_CHANNELS];        double _meter[MAX_CHANNELS];        double _peak[MAX_CHANNELS]; @@ -147,7 +147,10 @@ class Track {        bool noInRoute() const   { return _inRoutes.empty();  }        bool noOutRoute() const  { return _outRoutes.empty(); }        void writeRouting(int, Xml&) const; - +      bool isCircularRoute(Track* dst);    +      int auxRefCount() const { return _auxRouteCount; }  // Number of Aux Tracks with routing paths to this track.  +      void updateAuxRoute(int refInc, Track* dst);  // Internal use.  +              PartList* parts()               { return &_parts; }        const PartList* cparts() const  { return &_parts; }        Part* findPart(unsigned tick); @@ -168,20 +171,21 @@ class Track {        virtual void setMute(bool val);        virtual void setOff(bool val); -      virtual void updateSoloStates(bool noDec) = 0; -      virtual void updateInternalSoloStates(); -      void updateSoloState();        void setInternalSolo(unsigned int val); -      static void clearSoloRefCounts();        virtual void setSolo(bool val) = 0;        virtual bool isMute() const = 0; -              unsigned int internalSolo() const  { return _internalSolo; }        bool soloMode() const              { return _soloRefCnt; }        bool solo() const                  { return _solo;         }        bool mute() const                  { return _mute;         }        bool off() const                   { return _off;          }        bool recordFlag() const            { return _recordFlag;   } +      // +      // Internal use... +      static void clearSoloRefCounts(); +      void updateSoloState(); +      virtual void updateSoloStates(bool noDec) = 0;   +      virtual void updateInternalSoloStates();                int activity()                     { return _activity;     }        void setActivity(int v)            { _activity = v;        } @@ -190,8 +194,6 @@ class Track {        void addActivity(int v)            { _activity += v;       }        void resetPeaks();        static void resetAllMeter(); -      //int meter(int ch) const  { return _meter[ch]; } -      //int peak(int ch) const   { return _peak[ch]; }        double meter(int ch) const  { return _meter[ch]; }        double peak(int ch) const   { return _peak[ch]; }        void resetMeter(); @@ -220,9 +222,9 @@ class MidiTrack : public Track {        int _outPort;        int _outChannel;        //int _inPortMask;         -      ///unsigned int _inPortMask; // bitmask of accepted record ports -      ///int _inChannelMask;     // bitmask of accepted record channels -      bool _recEcho;          // For midi (and audio). Whether to echo incoming record events to output device. +      //unsigned int _inPortMask; // bitmask of accepted record ports +      //int _inChannelMask;       // bitmask of accepted record channels +      bool _recEcho;              // For midi (and audio). Whether to echo incoming record events to output device.        EventList* _events;     // tmp Events during midi import        MPEventList* _mpevents; // tmp Events druring recording @@ -270,17 +272,17 @@ class MidiTrack : public Track {        void setOutPortAndChannelAndUpdate(int /*port*/, int /*chan*/);        //void setInPortMask(int i)       { _inPortMask = i; } -      ///void setInPortMask(unsigned int i) { _inPortMask = i; }  // Obsolete -      ///void setInChannelMask(int i)    { _inChannelMask = i; }  // +      //void setInPortMask(unsigned int i) { _inPortMask = i; }  // Obsolete +      //void setInChannelMask(int i)    { _inChannelMask = i; }  //        // Backward compatibility: For reading old songs.        void setInPortAndChannelMask(unsigned int /*portmask*/, int /*chanmask*/);         void setRecEcho(bool b)         { _recEcho = b; }        int outPort() const             { return _outPort;     }        //int inPortMask() const          { return _inPortMask;  } -      ///unsigned int inPortMask() const { return _inPortMask;  } +      //unsigned int inPortMask() const { return _inPortMask;  }        int outChannel() const          { return _outChannel;  } -      ///int inChannelMask() const       { return _inChannelMask; } +      //int inChannelMask() const       { return _inChannelMask; }        bool recEcho() const            { return _recEcho; }        virtual bool isMute() const; @@ -298,14 +300,10 @@ class MidiTrack : public Track {        clefTypes getClef() { return clefType; }        }; -} // namespace MusECore - -namespace MusECore { -  //---------------------------------------------------------  //   AudioTrack  //    this track can hold audio automation data and can -//    hold tracktypes AUDIO, AUDIO_MASTER, AUDIO_GROUP, +//    hold tracktypes WAVE, AUDIO_GROUP, AUDIO_OUTPUT,  //    AUDIO_INPUT, AUDIO_SOFTSYNTH, AUDIO_AUX  //--------------------------------------------------------- @@ -313,25 +311,19 @@ class AudioTrack : public Track {        //friend class MidiTrack;        //static unsigned int _soloRefCnt; -      bool _haveData; +      bool _haveData; // Whether we have data from a previous process call during current cycle.        CtrlListList _controller;        CtrlRecList _recEvents;     // recorded automation events        bool _prefader;               // prefader metering        std::vector<double> _auxSend; -      Pipeline* _efxPipe; - -      AutomationType _automationType; - -      //RouteList _inRoutes; -      //RouteList _outRoutes; -       -      bool _sendMetronome; -              //void readRecfile(Xml& xml);        void readAuxSend(Xml& xml); - +       +      bool _sendMetronome; +      AutomationType _automationType; +      Pipeline* _efxPipe;     protected:        float** outBuffers; @@ -344,7 +336,7 @@ class AudioTrack : public Track {        SndFile* _recFile;        Fifo fifo;                    // fifo -> _recFile        bool _processed; - +           public:        AudioTrack(TrackType t);        //AudioTrack(TrackType t, int num_out_bufs = MAX_CHANNELS);  @@ -424,12 +416,6 @@ class AudioTrack : public Track {        void readVolume(Xml& xml);        //void writeRouting(int, Xml&) const; -      // routing -      //RouteList* inRoutes()    { return &_inRoutes; } -      //RouteList* outRoutes()   { return &_outRoutes; } -      //bool noInRoute() const   { return _inRoutes.empty();  } -      //bool noOutRoute() const  { return _outRoutes.empty(); } -        virtual void preProcessAlways() { _processed = false; }        virtual void  addData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/);        virtual void copyData(unsigned /*samplePos*/, int /*channels*/, int /*srcStartChan*/, int /*srcChannels*/, unsigned /*frames*/, float** /*buffer*/); diff --git a/muse2/muse/undo.cpp b/muse2/muse/undo.cpp index eb554495..8587b108 100644 --- a/muse2/muse/undo.cpp +++ b/muse2/muse/undo.cpp @@ -50,8 +50,11 @@ const char* UndoOp::typeName()              "AddTrack", "DeleteTrack", "ModifyTrack",              "AddPart",  "DeletePart",  "ModifyPart",              "AddEvent", "DeleteEvent", "ModifyEvent", -            "AddTempo", "DeleteTempo", "AddSig", "DeleteSig", -            "SwapTrack", "ModifyClip" +            "AddTempo", "DeleteTempo", +            "AddSig", "DeleteSig", +            "AddKey", "DeleteKey", +            "SwapTrack", "ModifyClip", "ModifyMarker", +            "ModifySongLen", "DoNothing"              };        return name[type];        } @@ -95,6 +98,7 @@ void UndoOp::dump()              case ModifyMarker:              case AddKey:              case DeleteKey: +            case ModifySongLen:              case DoNothing:                    break;              } @@ -530,6 +534,10 @@ void Song::doUndo2()                          MusEGlobal::keymap.addKey(i->a, (key_enum)i->b);                          updateFlags |= SC_KEY;                          break; +                  case UndoOp::ModifySongLen: +                        _len=i->b; +                        updateFlags = -1; // set all flags +                        break;                    case UndoOp::ModifyClip:                    case UndoOp::ModifyMarker:                    case UndoOp::DoNothing: @@ -767,6 +775,10 @@ void Song::doRedo2()                          MusEGlobal::keymap.delKey(i->a);                          updateFlags |= SC_KEY;                          break; +                  case UndoOp::ModifySongLen: +                        _len=i->a; +                        updateFlags = -1; // set all flags +                        break;                    case UndoOp::ModifyClip:                    case UndoOp::ModifyMarker:                    case UndoOp::DoNothing: diff --git a/muse2/muse/undo.h b/muse2/muse/undo.h index 19c252bf..af55a307 100644 --- a/muse2/muse/undo.h +++ b/muse2/muse/undo.h @@ -54,6 +54,7 @@ struct UndoOp {              SwapTrack,              ModifyClip,              ModifyMarker, +            ModifySongLen, // a = new len, b = old len              DoNothing              };        UndoType type; diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h index b57b598d..b41e7137 100644 --- a/muse2/muse/vst.h +++ b/muse2/muse/vst.h @@ -50,6 +50,7 @@ class VstSynth : public Synth {              }        virtual ~VstSynth() {} +      virtual Type synthType() const { return VST_SYNTH; }        virtual void incInstances(int val);        virtual void* instantiate();        //virtual SynthIF* createSIF() const; diff --git a/muse2/muse/wave.cpp b/muse2/muse/wave.cpp index 06759441..f22f6f97 100644 --- a/muse2/muse/wave.cpp +++ b/muse2/muse/wave.cpp @@ -105,7 +105,7 @@ SndFile::~SndFile()  bool SndFile::openRead()        {        if (openFlag) { -            printf("SndFile:: alread open\n"); +            printf("SndFile:: already open\n");              return false;              }        QString p = path(); @@ -468,7 +468,7 @@ size_t SndFile::readWithHeap(int srcChannels, float** dst, size_t n, bool overwr        {        float *buffer = new float[n * sfinfo.channels];        int rn = readInternal(srcChannels,dst,n,overwrite, buffer); -      delete buffer; +      delete[] buffer;        return rn;        } @@ -588,11 +588,11 @@ size_t SndFile::write(int srcChannels, float** src, size_t n)        else {              printf("SndFile:write channel mismatch %d -> %d\n",                 srcChannels, dstChannels); -            delete buffer; +            delete[] buffer;              return 0;              }        int nbr = sf_writef_float(sf, buffer, n) ; -      delete buffer; +      delete[] buffer;        return nbr;        } @@ -1120,6 +1120,22 @@ SndFileR::~SndFileR()                  }        } +void SndFileList::clearDelete() +{ +      // ~SndFile searches itself on the list (and will find for +      // sure) and deletes the entry on its own. +      while (!empty())  +            delete *begin(); + +      /* this is wrong, because ~SndFile deletes itself from the +       * list, causing the iterator to be invalidated -> fail. +      for (SndFileList::iterator i = begin(); i != end(); ++i) +            delete *i; +      clear(); +      */ +} + +  } // namespace MusECore  namespace MusEGui { diff --git a/muse2/muse/wave.h b/muse2/muse/wave.h index 58e0ab87..535df939 100644 --- a/muse2/muse/wave.h +++ b/muse2/muse/wave.h @@ -182,11 +182,7 @@ class SndFileR {  class SndFileList : public std::list<SndFile*> {     public:        SndFile* search(const QString& name); -      void clearDelete() { -            for (SndFileList::iterator i = begin(); i != end(); ++i) -                  delete *i; -            clear(); -            } +      void clearDelete();        };  typedef SndFileList::iterator iSndFile; diff --git a/muse2/muse/waveedit/waveedit.cpp b/muse2/muse/waveedit/waveedit.cpp index 537d8529..1c1115b1 100644 --- a/muse2/muse/waveedit/waveedit.cpp +++ b/muse2/muse/waveedit/waveedit.cpp @@ -289,6 +289,7 @@ WaveEdit::WaveEdit(MusECore::PartList* pl)        }        initTopwinState(); +      MusEGlobal::muse->topwinMenuInited(this);        }  void WaveEdit::initShortcuts() diff --git a/muse2/muse/wavetrack.cpp b/muse2/muse/wavetrack.cpp index 9edeffb6..0d699cbe 100644 --- a/muse2/muse/wavetrack.cpp +++ b/muse2/muse/wavetrack.cpp @@ -229,8 +229,8 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float*              ciRoute i = irl->begin();              if(i->track->isMidiTrack())              { -              if(MusEGlobal::debugMsg) -                printf("WaveTrack::getData: Error: First route is a midi track route!\n"); +              //if(MusEGlobal::debugMsg) +              //  printf("WaveTrack::getData: Error: First route is a midi track route!\n");                return false;              }              // p3.3.38 @@ -246,8 +246,8 @@ bool WaveTrack::getData(unsigned framePos, int channels, unsigned nframe, float*              {                if(i->track->isMidiTrack())                { -                if(MusEGlobal::debugMsg) -                  printf("WaveTrack::getData: Error: Route is a midi track route!\n"); +                //if(MusEGlobal::debugMsg) +                //  printf("WaveTrack::getData: Error: Route is a midi track route!\n");                  //return false;                  continue;                } diff --git a/muse2/muse/widgets/citem.h b/muse2/muse/widgets/citem.h index 1777eb23..199d18b0 100644 --- a/muse2/muse/widgets/citem.h +++ b/muse2/muse/widgets/citem.h @@ -90,7 +90,7 @@ class CItem {        };  typedef std::multimap<int, CItem*, std::less<int> >::iterator iCItem; -//typedef std::multimap<int, CItem*, std::less<int> >::const_iterator ciCItem; +typedef std::multimap<int, CItem*, std::less<int> >::const_iterator ciCItem;  typedef std::multimap<int, CItem*, std::less<int> >::const_reverse_iterator rciCItem;  //--------------------------------------------------------- diff --git a/muse2/muse/widgets/filedialog.cpp b/muse2/muse/widgets/filedialog.cpp index 68f2718f..7f2c1681 100644 --- a/muse2/muse/widgets/filedialog.cpp +++ b/muse2/muse/widgets/filedialog.cpp @@ -123,11 +123,13 @@ void MFileDialog::userToggled(bool flag)              if (lastUserDir.isEmpty()) { -                  lastUserDir = MusEGlobal::museUser + QString("/") + baseDir; // Initialize if first time +                  //lastUserDir = MusEGlobal::museUser + QString("/") + baseDir; // Initialize if first time +                  lastUserDir = MusEGlobal::configPath + QString("/") + baseDir; // Initialize if first time    // p4.0.39                    }              if (testDirCreate(this, lastUserDir)) -                  setDirectory(MusEGlobal::museUser); +                  //setDirectory(MusEGlobal::museUser); +                  setDirectory(MusEGlobal::configPath);  // p4.0.39              else                    setDirectory(lastUserDir); @@ -270,34 +272,6 @@ void MFileDialog::directoryChanged(const QString&)              }        } - -//--------------------------------------------------------- -//   getFilterExtension -//--------------------------------------------------------- - -QString getFilterExtension(const QString &filter) -{ -  // -  // Return the first extension found. Must contain at least one * character. -  // -   -  int pos = filter.indexOf('*'); -  if(pos == -1) -    return QString();  -   -  QString filt; -  int len = filter.length(); -  ++pos; -  for( ; pos < len; ++pos) -  { -    QChar c = filter[pos]; -    if((c == ')') || (c == ';') || (c == ',') || (c == ' ')) -      break;  -    filt += filter[pos]; -  } -  return filt; -} -  //---------------------------------------------------------  //   getOpenFileName  //--------------------------------------------------------- @@ -509,10 +483,12 @@ FILE* fileOpen(QWidget* parent, QString name, const QString& ext,        FILE* fp = 0;        if (popenFlag) {              if (strcmp(mode, "r") == 0) -                  zip += QString(" -d < "); +                  //zip += QString(" -d < "); +                  zip += QString(" -d < \"");    // p4.0.40              else -                  zip += QString(" > "); -            zip += name; +                  zip += QString(" > \""); +            //zip += name; +            zip = zip + name + QString("\"");    // p4.0.40              fp  = popen(zip.toAscii().data(), mode);              }        else { diff --git a/muse2/muse/widgets/filedialog.h b/muse2/muse/widgets/filedialog.h index b731b65a..b4e21e2c 100644 --- a/muse2/muse/widgets/filedialog.h +++ b/muse2/muse/widgets/filedialog.h @@ -3,6 +3,7 @@  //  Linux Music Editor  //    $Id: filedialog.h,v 1.2.2.2 2008/01/19 13:33:46 wschweer Exp $  //  (C) Copyright 2000 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License diff --git a/muse2/muse/widgets/genset.cpp b/muse2/muse/widgets/genset.cpp index d7642b3b..ec2c8637 100644 --- a/muse2/muse/widgets/genset.cpp +++ b/muse2/muse/widgets/genset.cpp @@ -4,6 +4,7 @@  //  $Id: genset.cpp,v 1.7.2.8 2009/12/01 03:52:40 terminator356 Exp $  //  //  (C) Copyright 2001-2004 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -24,8 +25,10 @@  #include <stdio.h>  #include <QFileDialog> +#include <QFileInfo>  #include <QRect>  #include <QShowEvent> +#include <QString>  #include "genset.h"  #include "app.h" @@ -33,6 +36,7 @@  #include "midiseq.h"  #include "globals.h"  #include "icons.h" +#include "helper.h"  namespace MusEGui { @@ -93,12 +97,6 @@ GlobalSettingsConfig::GlobalSettingsConfig(QWidget* parent)                    }              } -      userInstrumentsPath->setText(MusEGlobal::config.userInstrumentsDir); -      selectInstrumentsDirButton->setIcon(*openIcon); -      defaultInstrumentsDirButton->setIcon(*undoIcon); -      connect(selectInstrumentsDirButton, SIGNAL(clicked()), SLOT(selectInstrumentsPath())); -      connect(defaultInstrumentsDirButton, SIGNAL(clicked()), SLOT(defaultInstrumentsPath())); -        guiRefreshSelect->setValue(MusEGlobal::config.guiRefresh);        minSliderSelect->setValue(int(MusEGlobal::config.minSlider));        minMeterSelect->setValue(MusEGlobal::config.minMeter); @@ -119,6 +117,9 @@ GlobalSettingsConfig::GlobalSettingsConfig(QWidget* parent)  Period affects midi playback resolution.   Shorter periods are desirable.</string>              </property>                       */ + +      projDirEntry->setText(MusEGlobal::config.projectBaseFolder); +      projDirOpenToolButton->setIcon(*openIcon);        startSongEntry->setText(MusEGlobal::config.startSong);        startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); @@ -171,9 +172,14 @@ Shorter periods are desirable.</string>        popsDefStayOpenCheckBox->setChecked(MusEGlobal::config.popupsDefaultStayOpen);        lmbDecreasesCheckBox->setChecked(MusEGlobal::config.leftMouseButtonCanDecrease);        rangeMarkerWithoutMMBCheckBox->setChecked(MusEGlobal::config.rangeMarkerWithoutMMB); -       + +      addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); +      unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); +        //updateSettings();    // TESTING +      connect(projDirOpenToolButton, SIGNAL(clicked()), SLOT(browseProjDir())); +        connect(applyButton, SIGNAL(clicked()), SLOT(apply()));        connect(okButton, SIGNAL(clicked()), SLOT(ok()));        connect(cancelButton, SIGNAL(clicked()), SLOT(cancel())); @@ -258,6 +264,8 @@ void GlobalSettingsConfig::updateSettings()        //dummyAudioRealRate->setText(dad ? QString().setNum(sampleRate) : "---");        //dummyAudioRealRate->setText(QString().setNum(sampleRate));   // Not used any more. p4.0.20  +      projDirEntry->setText(MusEGlobal::config.projectBaseFolder); +        startSongEntry->setText(MusEGlobal::config.startSong);        startSongGroup->button(MusEGlobal::config.startMode)->setChecked(true); @@ -310,6 +318,9 @@ void GlobalSettingsConfig::updateSettings()        lmbDecreasesCheckBox->setChecked(MusEGlobal::config.leftMouseButtonCanDecrease);        rangeMarkerWithoutMMBCheckBox->setChecked(MusEGlobal::config.rangeMarkerWithoutMMB); +      addHiddenCheckBox->setChecked(MusEGlobal::config.addHiddenTracks); +      unhideTracksCheckBox->setChecked(MusEGlobal::config.unhideTracks); +        updateMdiSettings();  } @@ -350,7 +361,9 @@ void GlobalSettingsConfig::apply()        MusEGlobal::config.useOutputLimiter = outputLimiterCheckBox->isChecked();        MusEGlobal::config.vstInPlace  = vstInPlaceCheckBox->isChecked();        MusEGlobal::config.rtcTicks    = rtcResolutions[rtcticks]; -      MusEGlobal::config.userInstrumentsDir = userInstrumentsPath->text(); +       +      MusEGlobal::config.projectBaseFolder = projDirEntry->text(); +              MusEGlobal::config.startSong   = startSongEntry->text();        MusEGlobal::config.startMode   = startSongGroup->checkedId();        int das = dummyAudioSize->currentIndex(); @@ -408,6 +421,9 @@ void GlobalSettingsConfig::apply()        MusEGlobal::config.leftMouseButtonCanDecrease = lmbDecreasesCheckBox->isChecked();        MusEGlobal::config.rangeMarkerWithoutMMB = rangeMarkerWithoutMMBCheckBox->isChecked(); +      MusEGlobal::config.addHiddenTracks = addHiddenCheckBox->isChecked(); +      MusEGlobal::config.unhideTracks = unhideTracksCheckBox->isChecked(); +        //MusEGlobal::muse->showMixer(MusEGlobal::config.mixerVisible);        MusEGlobal::muse->showMixer1(MusEGlobal::config.mixer1Visible);        MusEGlobal::muse->showMixer2(MusEGlobal::config.mixer2Visible); @@ -442,8 +458,6 @@ void GlobalSettingsConfig::apply()        MusEGlobal::muse->resize(MusEGlobal::config.geometryMain.size());        MusEGlobal::muse->move(MusEGlobal::config.geometryMain.topLeft()); -      MusEGlobal::museUserInstruments = MusEGlobal::config.userInstrumentsDir; -        MusEGlobal::muse->setHeartBeat();        // set guiRefresh        MusEGlobal::midiSeq->msgSetRtc();        // set midi tick rate @@ -546,21 +560,6 @@ void GlobalSettingsConfig::transportCurrent()        transportY->setValue(r.y());        } -void GlobalSettingsConfig::selectInstrumentsPath() -      { -      QString dir = QFileDialog::getExistingDirectory(this,  -                                                      tr("Selects instruments directory"),  -                                                      MusEGlobal::config.userInstrumentsDir); -      userInstrumentsPath->setText(dir); -      } - -void GlobalSettingsConfig::defaultInstrumentsPath() -      { -      QString dir = MusEGlobal::configPath + "/instruments"; -      userInstrumentsPath->setText(dir); -      } - -  void GlobalSettingsConfig::traditionalPreset()  {    for (std::list<MdiSettings*>::iterator it = mdisettings.begin(); it!=mdisettings.end(); it++) @@ -598,5 +597,12 @@ void GlobalSettingsConfig::borlandPreset()    updateMdiSettings();  } +void GlobalSettingsConfig::browseProjDir() +{ +  QString dir = MusEGui::browseProjectFolder(this); +  if(!dir.isEmpty()) +    projDirEntry->setText(dir); +} +  } // namespace MusEGui diff --git a/muse2/muse/widgets/genset.h b/muse2/muse/widgets/genset.h index 0e1697ee..b076a27f 100644 --- a/muse2/muse/widgets/genset.h +++ b/muse2/muse/widgets/genset.h @@ -4,6 +4,7 @@  //  $Id: genset.h,v 1.3 2004/01/25 09:55:17 wschweer Exp $  //  //  (C) Copyright 2001 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -53,8 +54,7 @@ class GlobalSettingsConfig : public QDialog, public Ui::GlobalSettingsDialogBase        void bigtimeCurrent();        void mainCurrent();        void transportCurrent(); -      void selectInstrumentsPath(); -      void defaultInstrumentsPath(); +      void browseProjDir();        void traditionalPreset();        void mdiPreset();        void borlandPreset(); diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui index ba26cf38..124ee72a 100644 --- a/muse2/muse/widgets/gensetbase.ui +++ b/muse2/muse/widgets/gensetbase.ui @@ -30,7 +30,36 @@         <string>Application</string>        </attribute>        <layout class="QGridLayout"> -       <item row="1" column="0"> +       <item row="0" column="0"> +        <widget class="QGroupBox" name="projDirGroupBox"> +         <property name="title"> +          <string>Project directory</string> +         </property> +         <layout class="QHBoxLayout" name="qhboxProjDir"> +          <item> +           <widget class="QLabel" name="textLabel_ProjDir"> +            <property name="text"> +             <string>Projects:</string> +            </property> +            <property name="wordWrap"> +             <bool>false</bool> +            </property> +           </widget> +          </item> +          <item> +           <widget class="QLineEdit" name="projDirEntry"/> +          </item> +          <item> +           <widget class="QToolButton" name="projDirOpenToolButton"> +            <property name="text"> +             <string>...</string> +            </property> +           </widget> +          </item> +         </layout> +        </widget> +       </item> +       <item row="2" column="0">          <widget class="QGroupBox" name="groupBox4">           <property name="sizePolicy">            <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> @@ -413,14 +442,14 @@           </layout>          </widget>         </item> -       <item row="0" column="0"> +       <item row="1" column="0">          <widget class="QGroupBox" name="groupBox3">           <property name="title">            <string>Start Muse</string>           </property>           <layout class="QGridLayout">            <item row="0" column="0"> -           <layout class="QGridLayout"> +           <layout class="QGridLayout" name="gridLayout11">              <item row="1" column="0">               <spacer name="spacer7_2">                <property name="orientation"> @@ -438,7 +467,7 @@               </spacer>              </item>              <item row="2" column="0" colspan="2"> -             <layout class="QHBoxLayout"> +             <layout class="QHBoxLayout" name="qhboxStartSong">                <item>                 <widget class="QLabel" name="textLabel1_2">                  <property name="text"> @@ -811,9 +840,9 @@ Adjusts responsiveness of audio controls and             <number>2</number>            </property>            <item row="0" column="0"> -           <layout class="QGridLayout"> +           <layout class="QGridLayout" name="gridLayoutwaveEditor">              <item row="0" column="0"> -             <layout class="QHBoxLayout"> +             <layout class="QHBoxLayout" name="qhboxLayoutWaveEditor">                <item>                 <widget class="QLabel" name="textLabel2_2">                  <property name="sizePolicy"> @@ -1179,31 +1208,7 @@ Adjusts responsiveness of audio controls and              </item>             </widget>            </item> -          <item row="3" column="0"> -           <widget class="QLabel" name="TextLabel3_4"> -            <property name="text"> -             <string>Instruments Directory</string> -            </property> -           </widget> -          </item>            <item row="3" column="1"> -           <widget class="QLineEdit" name="userInstrumentsPath"/> -          </item> -          <item row="3" column="2"> -           <widget class="QPushButton" name="selectInstrumentsDirButton"> -            <property name="text"> -             <string/> -            </property> -           </widget> -          </item> -          <item row="3" column="3"> -           <widget class="QPushButton" name="defaultInstrumentsDirButton"> -            <property name="text"> -             <string/> -            </property> -           </widget> -          </item> -          <item row="4" column="1">             <spacer name="verticalSpacer_3">              <property name="orientation">               <enum>Qt::Vertical</enum> @@ -1223,7 +1228,7 @@ Adjusts responsiveness of audio controls and       </widget>       <widget class="QWidget" name="tab3">        <attribute name="title"> -       <string>GUI</string> +       <string>GUI Behaviour</string>        </attribute>        <layout class="QVBoxLayout" name="verticalLayout_3">         <property name="spacing"> @@ -1406,10 +1411,58 @@ left button behave like the middle button in such areas.</string>              </property>             </widget>            </item> +          <item row="9" column="0"> +           <spacer name="verticalSpacer_2"> +            <property name="orientation"> +             <enum>Qt::Vertical</enum> +            </property> +            <property name="sizeHint" stdset="0"> +             <size> +              <width>20</width> +              <height>40</height> +             </size> +            </property> +           </spacer> +          </item> +          <item row="7" column="1"> +           <widget class="QCheckBox" name="addHiddenCheckBox"> +            <property name="text"> +             <string/> +            </property> +           </widget> +          </item> +          <item row="7" column="0"> +           <widget class="QLabel" name="label_4"> +            <property name="text"> +             <string>Allow adding hidden tracks in track list menu</string> +            </property> +           </widget> +          </item> +          <item row="8" column="0"> +           <widget class="QLabel" name="label_5"> +            <property name="text"> +             <string>Unhide tracks when adding hidden tracks</string> +            </property> +           </widget> +          </item> +          <item row="8" column="1"> +           <widget class="QCheckBox" name="unhideTracksCheckBox"> +            <property name="text"> +             <string/> +            </property> +           </widget> +          </item>           </layout>          </widget>         </item> -       <item> +      </layout> +     </widget> +     <widget class="QWidget" name="tab_2"> +      <attribute name="title"> +       <string>GUI Style</string> +      </attribute> +      <layout class="QGridLayout" name="gridLayoutTab2"> +       <item row="0" column="0">          <widget class="QGroupBox" name="groupBox_2">           <property name="title">            <string>MDI-subwindowness and sharing menus</string> @@ -1460,8 +1513,8 @@ left button behave like the middle button in such areas.</string>                <rect>                 <x>0</x>                 <y>0</y> -               <width>482</width> -               <height>143</height> +               <width>512</width> +               <height>378</height>                </rect>               </property>               <layout class="QHBoxLayout" name="horizontalLayout_3"> diff --git a/muse2/muse/widgets/header.cpp b/muse2/muse/widgets/header.cpp index 2c1057c3..968e7f73 100644 --- a/muse2/muse/widgets/header.cpp +++ b/muse2/muse/widgets/header.cpp @@ -51,7 +51,7 @@ void Header::readStatus(MusECore::Xml& xml)                            for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {                                  int logialIdx=abs((*it).toInt());                                  bool isHidden = (*it).toInt() < 0 ? true:false; -                                int section = visualIndex(logialIdx); +                                int section = visualIndex(logialIdx - (isHidden? 1:0));                                  moveSection(section, index);                                  if (isHidden)                                    hideSection(logialIdx-1); @@ -65,7 +65,7 @@ void Header::readStatus(MusECore::Xml& xml)                                bool foundIt=false;                                for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {                                  int id=((*it).toInt()); -                                if ( id == i || i ==1-id ) +                                if ( id == i || i == -1 - id )                                      foundIt=true;                                }                                if (foundIt == false) { @@ -97,7 +97,7 @@ void Header::writeStatus(int level, MusECore::Xml& xml) const        //xml.nput(level, "<%s> ", name());        xml.nput(level, "<%s> ", MusECore::Xml::xmlString(objectName()).toLatin1().constData());        int n = count(); -      for (int i = n; i >= 0; --i) { +      for (int i = n-1; i >= 0; --i) {              if (isSectionHidden(logicalIndex(i)))                xml.nput("%d ", -logicalIndex(i)-1); // hidden is stored as negative value starting from -1              else diff --git a/muse2/muse/widgets/knob.cpp b/muse2/muse/widgets/knob.cpp index 920d2028..269f65cf 100644 --- a/muse2/muse/widgets/knob.cpp +++ b/muse2/muse/widgets/knob.cpp @@ -323,6 +323,30 @@ void Knob::rangeChange()      repaint();  } +void Knob::mousePressEvent(QMouseEvent *e) +{ +  if (e->button() == Qt::MidButton || e->modifiers() & Qt::ControlModifier) { +    int xpos = e->x() - width() /2; +    double v = float(e->y()) / height() * 1.2; + +    double halfRange = (maxValue() - minValue())/2; +    double midValue = minValue() + halfRange; +    // apply to range +    if (xpos < 0) { // left values +     v = -v; +    } +    setValue(v * halfRange + midValue); +    SliderBase::valueChange(); +     +    // fake a left-click to make the knob still "stick" to +    // the mouse. +    QMouseEvent temp(e->type(), e->pos(), Qt::LeftButton, e->buttons(), e->modifiers()); +    SliderBase::mousePressEvent(&temp); +    return; +  } +  SliderBase::mousePressEvent(e); +} +  //---------------------------------------------------------  //   resizeEvent  //--------------------------------------------------------- diff --git a/muse2/muse/widgets/knob.h b/muse2/muse/widgets/knob.h index 483fafa6..bd8621a1 100644 --- a/muse2/muse/widgets/knob.h +++ b/muse2/muse/widgets/knob.h @@ -80,6 +80,7 @@ class Knob : public SliderBase, public ScaleIf        virtual void paintEvent(QPaintEvent *);        virtual void resizeEvent(QResizeEvent *e); +      virtual void mousePressEvent(QMouseEvent *e);        double getValue(const QPoint &p);        void getScrollMode( QPoint &p, const Qt::MouseButton &button, int &scrollMode, int &direction );        void scaleChange()             { repaint(); } diff --git a/muse2/muse/widgets/meter.cpp b/muse2/muse/widgets/meter.cpp index 5c79ffb2..d9ca8e20 100644 --- a/muse2/muse/widgets/meter.cpp +++ b/muse2/muse/widgets/meter.cpp @@ -229,6 +229,8 @@ void Meter::setRange(double min, double max)  void Meter::paintEvent(QPaintEvent* ev)        { +      // For some reason upon resizing we get double calls here and in resizeEvent. +        QPainter p(this);        p.setRenderHint(QPainter::Antialiasing);   @@ -534,8 +536,11 @@ void Meter::drawVU(QPainter& p, const QRect& rect, const QPainterPath& drawPath,  void Meter::resizeEvent(QResizeEvent* ev)      {   -      QFrame::resizeEvent(ev); +      // For some reason upon resizing we get double calls here and in paintEvent. +      //printf("Meter::resizeEvent w:%d h:%d\n", ev->size().width(), ev->size().height());          cur_yv = -1;  // Force re-initialization. +      QFrame::resizeEvent(ev); +      update();      }  //--------------------------------------------------------- diff --git a/muse2/muse/widgets/midisync.ui b/muse2/muse/widgets/midisync.ui index 8fc6248a..81d7451e 100644 --- a/muse2/muse/widgets/midisync.ui +++ b/muse2/muse/widgets/midisync.ui @@ -388,6 +388,19 @@ Enabled inputs in the list will          </column>         </widget>        </item> +      <item row="5" column="0"> +        <widget class="QLabel" name="toBeDoneLabel"> +        <property name="text"> +          <string>Note: Sync delay and MTC sync currently not fully implemeted</string> +        </property> +        <property name="alignment"> +          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> +        </property> +        <property name="wordWrap"> +          <bool>false</bool> +        </property> +        </widget> +      </item>       </layout>      </widget>     </item> diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index b5460447..19e9729a 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -574,7 +574,8 @@ void MidiTrackInfo::setLabelText()          //gradient.setColorAt(0, c.darker());          //gradient.setColorAt(0, c);          //gradient.setColorAt(1, c.darker()); -        gradient.setColorAt(0, c.lighter()); +        gradient.setColorAt(0, c); +        gradient.setColorAt(0.5, c.lighter());          gradient.setColorAt(1, c);          //palette.setBrush(QPalette::Button, gradient);          //palette.setBrush(QPalette::Window, gradient); @@ -635,14 +636,17 @@ void MidiTrackInfo::iOutputPortChanged(int index)        {        if(!selected)          return; +      int port_num = iOutput->itemData(index).toInt(); +      if(port_num < 0 || port_num >= MIDI_PORTS) +        return;        MusECore::MidiTrack* track = (MusECore::MidiTrack*)selected; -      if (index == track->outPort()) +      if (port_num == track->outPort())              return;        // Changed by T356. -      //track->setOutPort(index); +      //track->setOutPort(port_num);        MusEGlobal::audio->msgIdle(true); -      //audio->msgSetTrackOutPort(track, index); -      track->setOutPortAndUpdate(index); +      //audio->msgSetTrackOutPort(track, port_num); +      track->setOutPortAndUpdate(port_num);        MusEGlobal::audio->msgIdle(false);        //MusEGlobal::song->update(SC_MIDI_TRACK_PROP);   @@ -1081,11 +1085,9 @@ void MidiTrackInfo::instrPopup()        //QMenu* pup = new QMenu;        PopupMenu* pup = new PopupMenu(true); -      //instr->populatePatchPopup(pop, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); -      populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); +      instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); +      //populatePatchPopup(instr, pup, channel, MusEGlobal::song->mtype(), track->type() == MusECore::Track::DRUM); -      //if(pop->actions().count() == 0) -      //  return;        if(pup->actions().count() == 0)        {          delete pup; @@ -1095,7 +1097,6 @@ void MidiTrackInfo::instrPopup()        connect(pup, SIGNAL(triggered(QAction*)), SLOT(instrPopupActivated(QAction*)));        //connect(pup, SIGNAL(hovered(QAction*)), SLOT(instrPopupActivated(QAction*))); -      //QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5)));        QAction *act = pup->exec(iPatch->mapToGlobal(QPoint(10,5)));        if(act)         { @@ -1346,12 +1347,20 @@ void MidiTrackInfo::updateTrackInfo(int flags)          //iInput->clear();          iOutput->clear(); +        int item_idx = 0;          for (int i = 0; i < MIDI_PORTS; ++i) { +              MusECore::MidiDevice* md = MusEGlobal::midiPorts[i].device();  +              if(!md)  // In the case of this combo box, don't bother listing empty ports.             p4.0.41 +                continue; +              //if(!(md->rwFlags() & 1 || md->isSynti()) && (i != outPort))   +              if(!(md->rwFlags() & 1) && (i != outPort))   // Only writeable ports, or current one.    p4.0.41 +                continue;                QString name;                name.sprintf("%d:%s", i+1, MusEGlobal::midiPorts[i].portname().toLatin1().constData()); -              iOutput->insertItem(i, name); +              iOutput->insertItem(item_idx, name, i);                if (i == outPort) -                    iOutput->setCurrentIndex(i); +                    iOutput->setCurrentIndex(item_idx); +              item_idx++;                }          iOutput->blockSignals(false); diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp index 4068da57..f707fb7c 100644 --- a/muse2/muse/widgets/musewidgetsplug.cpp +++ b/muse2/muse/widgets/musewidgetsplug.cpp @@ -157,7 +157,8 @@ MusEGlobal::GlobalConfigValues config = {        -60.0,                        // double minSlider;        false,                        // use Jack freewheel        20,                           // int guiRefresh; -      QString(""),                  // helpBrowser +      QString(""),                  // userInstrumentsDir  // Obsolete. Must keep for compatibility. +      //QString(""),                // helpBrowser  // Obsolete        true,                         // extendedMidi        384,                          // division for smf export        QString(""),                  // copyright string for smf export diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index af546ec3..af870975 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -341,21 +341,38 @@ void PopupMenu::popHovered(QAction* action)  void PopupMenu::mouseReleaseEvent(QMouseEvent *e)  { -    #ifdef POPUP_MENU_DISABLE_STAY_OPEN     +    QAction* action = actionAt(e->pos()); +    if (!(action && action == activeAction() && !action->isSeparator() && action->isEnabled())) +      action=NULL; + +    #ifdef POPUP_MENU_DISABLE_STAY_OPEN +    if (action && action->menu() != NULL  &&  action->isCheckable()) +      action->activate(QAction::Trigger); +      QMenu::mouseReleaseEvent(e); +     +    if (action && action->menu() != NULL  &&  action->isCheckable()) +      close(); +            return;      #else      // Check for Ctrl to stay open.      if(!_stayOpen || (!MusEGlobal::config.popupsDefaultStayOpen && (e->modifiers() & Qt::ControlModifier) == 0))        { +      if (action && action->menu() != NULL  &&  action->isCheckable()) +        action->activate(QAction::Trigger); +        QMenu::mouseReleaseEvent(e); + +      if (action && action->menu() != NULL  &&  action->isCheckable()) +        close(); +        return;      }        //printf("PopupMenu::mouseReleaseEvent\n");   -    QAction *action = actionAt(e->pos()); -    if (action && action == activeAction() && !action->isSeparator() && action->isEnabled())  +    if (action)         action->activate(QAction::Trigger);      else         QMenu::mouseReleaseEvent(e); diff --git a/muse2/muse/widgets/poslabel.cpp b/muse2/muse/widgets/poslabel.cpp index 6cdcb27e..b893c58d 100644 --- a/muse2/muse/widgets/poslabel.cpp +++ b/muse2/muse/widgets/poslabel.cpp @@ -138,7 +138,11 @@ void PosLabel::setTickValue(unsigned val)        if (val == _tickValue)              return;        if (val >= MAX_TICK) -            abort(); +      { +            printf("THIS SHOULD NEVER HAPPEN: val=%u > MAX_TICK=%u in PosLabel::setTickValue()!\n",val, MAX_TICK); +            val=MAX_TICK-1; +      } +              _tickValue = val;        updateValue();        } diff --git a/muse2/muse/widgets/projectcreate.ui b/muse2/muse/widgets/projectcreate.ui index 406c83d6..d03f093c 100644 --- a/muse2/muse/widgets/projectcreate.ui +++ b/muse2/muse/widgets/projectcreate.ui @@ -17,28 +17,94 @@     <item>      <layout class="QVBoxLayout" name="verticalLayout">       <item> -      <widget class="QLabel" name="label_2"> -       <property name="text"> -        <string>Project Name:</string> +      <layout class="QHBoxLayout" name="horizontalLayout_8"> +       <item> +        <widget class="QLabel" name="label_5"> +         <property name="text"> +          <string>Projects folder:</string> +         </property> +        </widget> +       </item> +       <item> +        <widget class="QLineEdit" name="projDirLineEdit"> +         <property name="readOnly"> +          <bool>true</bool> +         </property> +        </widget> +       </item> +       <item> +        <widget class="QToolButton" name="projDirToolButton"> +         <property name="text"> +          <string>...</string> +         </property> +        </widget> +       </item> +      </layout> +     </item> +     <item> +      <widget class="Line" name="line"> +       <property name="orientation"> +        <enum>Qt::Horizontal</enum>         </property>        </widget>       </item>       <item>        <layout class="QHBoxLayout" name="horizontalLayout_3">         <item> +        <widget class="QLabel" name="label_2"> +         <property name="text"> +          <string>Project Name:</string> +         </property> +        </widget> +       </item> +       <item>          <widget class="QLineEdit" name="projectNameEdit"/>         </item>         <item> +        <widget class="QCheckBox" name="templateCheckBox"> +         <property name="text"> +          <string>Project is a Template</string> +         </property> +        </widget> +       </item> +       <item>          <spacer name="horizontalSpacer">           <property name="orientation">            <enum>Qt::Horizontal</enum>           </property>           <property name="sizeType"> -          <enum>QSizePolicy::Fixed</enum> +          <enum>QSizePolicy::Minimum</enum> +         </property> +         <property name="sizeHint" stdset="0"> +          <size> +           <width>60</width> +           <height>20</height> +          </size> +         </property> +        </spacer> +       </item> +      </layout> +     </item> +     <item> +      <layout class="QHBoxLayout" name="horizontalLayout_5"> +       <item> +        <widget class="QLabel" name="label_4"> +         <property name="text"> +          <string>Project song file type:</string> +         </property> +        </widget> +       </item> +       <item> +        <widget class="QComboBox" name="projectFileTypeCB"/> +       </item> +       <item> +        <spacer name="horizontalSpacer_3"> +         <property name="orientation"> +          <enum>Qt::Horizontal</enum>           </property>           <property name="sizeHint" stdset="0">            <size> -           <width>75</width> +           <width>40</width>             <height>20</height>            </size>           </property> @@ -87,9 +153,16 @@          </widget>         </item>         <item> -        <widget class="QPushButton" name="browseDirButton"> +        <widget class="QToolButton" name="browseDirButton"> +         <property name="text"> +          <string>...</string> +         </property> +        </widget> +       </item> +       <item> +        <widget class="QToolButton" name="restorePathButton">           <property name="text"> -          <string>Browse</string> +          <string>...</string>           </property>          </widget>         </item> @@ -123,6 +196,18 @@     </item>    </layout>   </widget> + <tabstops> +  <tabstop>projectNameEdit</tabstop> +  <tabstop>templateCheckBox</tabstop> +  <tabstop>projectFileTypeCB</tabstop> +  <tabstop>createFolderCheckbox</tabstop> +  <tabstop>storageDirEdit</tabstop> +  <tabstop>browseDirButton</tabstop> +  <tabstop>commentEdit</tabstop> +  <tabstop>buttonBox</tabstop> +  <tabstop>projDirLineEdit</tabstop> +  <tabstop>projDirToolButton</tabstop> + </tabstops>   <resources/>   <connections>    <connection> diff --git a/muse2/muse/widgets/projectcreateimpl.cpp b/muse2/muse/widgets/projectcreateimpl.cpp index 31973101..665d725e 100644 --- a/muse2/muse/widgets/projectcreateimpl.cpp +++ b/muse2/muse/widgets/projectcreateimpl.cpp @@ -4,6 +4,7 @@  //  $Id: ./muse/widgets/projectcreateimpl.cpp $  //  //  Copyright (C) 1999-2011 by Werner Schweer and others +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -21,12 +22,16 @@  //  //=========================================================  #include <stdio.h> -#include <qfiledialog.h> -#include <qdir.h> +#include <QFileDialog> +#include <QDir> +#include <QStringList> +  #include "projectcreateimpl.h"  #include "gconfig.h"  #include "globals.h"  #include "app.h" +#include "helper.h" +#include "icons.h"  namespace MusEGui { @@ -35,10 +40,51 @@ ProjectCreateImpl::ProjectCreateImpl(QWidget *parent) :  {    setupUi(this); -  createFolderCheckbox->setChecked(MusEGlobal::config.projectStoreInFolder); +  //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath);   +  directoryPath = MusEGlobal::config.projectBaseFolder; + +  QStringList filters = localizedStringListFromCharArray(MusEGlobal::project_create_file_save_pattern, "file_patterns"); +  projectFileTypeCB->addItems(filters); + +  QString proj_title = MusEGlobal::muse->projectTitle(); +  QString proj_path  = MusEGlobal::muse->projectPath(); +  QString proj_ext   = MusEGlobal::muse->projectExtension(); +   +  projectNameEdit->setText(proj_title);  + +  bool is_template = proj_path.startsWith(MusEGlobal::configPath + "/templates"); +   +  templateCheckBox->setChecked(is_template); +   +  projDirPath = proj_path; +     +  int type_idx = 0; +  if(!proj_ext.isEmpty()) +  {   +    // FIXME Imperfect. Trying to avoid adding yet another series of character strings.   p4.0.40 +    type_idx = projectFileTypeCB->findText(proj_ext, Qt::MatchContains | Qt::MatchCaseSensitive); +    if(type_idx == -1) +      type_idx = 0; +  }   +  projectFileTypeCB->setCurrentIndex(type_idx); +   +  projDirToolButton->setIcon(*openIcon); +  browseDirButton->setIcon(*openIcon); +  restorePathButton->setIcon(*undoIcon); + +  restorePathButton->setEnabled(false);  // Disabled at first. +   +  //createFolderCheckbox->setChecked(MusEGlobal::config.projectStoreInFolder && is_new); // Suggest no folder if not new. +   +  connect(templateCheckBox,SIGNAL(clicked()), this, SLOT(templateButtonChanged())); +  //connect(templateCheckBox,SIGNAL(clicked()), this, SLOT(updateDirectoryPath())); +  connect(projDirToolButton,SIGNAL(clicked()), this, SLOT(browseProjDir())); +  connect(restorePathButton,SIGNAL(clicked()), this, SLOT(restorePath()));    connect(browseDirButton,SIGNAL(clicked()), this, SLOT(selectDirectory())); -  connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateDirectoryPath())); -  connect(createFolderCheckbox,SIGNAL(clicked()), this, SLOT(updateDirectoryPath())); +  //connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateDirectoryPath())); +  connect(projectNameEdit,SIGNAL(textChanged(QString)), this, SLOT(updateProjectName())); +  connect(createFolderCheckbox,SIGNAL(clicked()), this, SLOT(createProjFolderChanged())); +  connect(projectFileTypeCB,SIGNAL(currentIndexChanged(int)), this, SLOT(updateDirectoryPath()));    connect(buttonBox, SIGNAL(accepted()), this, SLOT(ok()));  #if QT_VERSION >= 0x040700    projectNameEdit->setPlaceholderText("<Project Name>"); @@ -46,52 +92,155 @@ ProjectCreateImpl::ProjectCreateImpl(QWidget *parent) :    //        as of Qt-4.7.1    //commentEdit->setPlaceholderText("<Add information about project here>");  #endif -  directoryPath = MusEGlobal::config.projectBaseFolder;    updateDirectoryPath();    show();  }  void ProjectCreateImpl::selectDirectory()  { -  QFileDialog qfd; -  qfd.selectFile(directoryPath); -  qfd.setFileMode(QFileDialog::DirectoryOnly); -  if (qfd.exec() == QDialog::Rejected) { -    return; -  } -  directoryPath=qfd.selectedFiles().first(); +  QString dpath = templateCheckBox->isChecked() ?  +                   (overrideTemplDirPath.isEmpty()    ? (MusEGlobal::configPath + QString("/templates")) : overrideTemplDirPath) : +                   (overrideDirPath.isEmpty() ? directoryPath : overrideDirPath); +   +  QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), dpath); +  if(dir.isEmpty()) +     return; +   +  (templateCheckBox->isChecked() ? overrideTemplDirPath : overrideDirPath) = dir; +  restorePathButton->setEnabled(true);     updateDirectoryPath();  } -void ProjectCreateImpl::updateDirectoryPath() +void ProjectCreateImpl::updateProjectName()  { +  QString curExt = projectFileTypeCB->currentText();   +  if(curExt.isEmpty()) +    curExt = ".med"; +  else +  {   +    curExt = MusEGui::getFilterExtension(curExt); +    // Do we have a valid extension? +    if(curExt.isEmpty()) +      curExt = ".med"; +  } +      QString name = "";    if (createFolderCheckbox->isChecked()) {      if (!projectNameEdit->text().isEmpty()) -      name = projectNameEdit->text() + "/" + projectNameEdit->text() + ".med"; +      //name = projectNameEdit->text() + "/" + projectNameEdit->text() + ".med"; +      name = projectNameEdit->text() + "/" + projectNameEdit->text() + curExt;      //storageDirEdit->setText(directoryPath + name );    }  else {      if (!projectNameEdit->text().isEmpty()) -      name = projectNameEdit->text() + ".med"; +      //name = projectNameEdit->text() + ".med"; +      name = projectNameEdit->text() + curExt;      //storageDirEdit->setText(directoryPath +"/" + name);    } -  storageDirEdit->setText(directoryPath +"/" + name );    // Tim +   +  bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath);   + +  QString dpath = templateCheckBox->isChecked() ?  +                   (overrideTemplDirPath.isEmpty()    ? (MusEGlobal::configPath + QString("/templates")) : overrideTemplDirPath) : +                   (overrideDirPath.isEmpty() ? (is_new ? directoryPath : projDirPath) : overrideDirPath); +   +  QDir proj_dir(dpath); +  //if(is_project && MusEGlobal::config.projectStoreInFolder) +  bool is_project = dpath.startsWith(MusEGlobal::config.projectBaseFolder); +  //bool is_template = dpath.startsWith(MusEGlobal::configPath + "/templates") && templateCheckBox->isChecked(); +  //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath) && MusEGlobal::config.projectStoreInFolder;   +  //bool is_new = (MusEGlobal::museProject == MusEGlobal::museProjectInitPath) &&  +                MusEGlobal::config.projectStoreInFolder &&  +                (templateCheckBox->isChecked() ? overrideTemplDirPath.isEmpty() : overrideDirPath.isEmpty());   +  //bool is_template = is_new && dpath.startsWith(MusEGlobal::configPath + "/templates") && templateCheckBox->isChecked(); +  if(!is_new && createFolderCheckbox->isChecked() && !templateCheckBox->isChecked() &&  +     (templateCheckBox->isChecked() ? overrideTemplDirPath.isEmpty() : overrideDirPath.isEmpty())) +    proj_dir.cdUp(); +  dpath = proj_dir.absolutePath(); +   +  //if(!initProjPath.isEmpty()) +  //{   +  //  initProjPath.clear(); +  //} +   +  storageDirEdit->blockSignals(true); +  storageDirEdit->setText(dpath + "/" + name );     +  storageDirEdit->blockSignals(false); +   +  projDirLineEdit->setEnabled(!templateCheckBox->isChecked() && is_project); +} + +void ProjectCreateImpl::updateDirectoryPath() +{ +  updateProjectName(); + +  projDirLineEdit->blockSignals(true); +  projDirLineEdit->setText(MusEGlobal::config.projectBaseFolder); +  projDirLineEdit->blockSignals(false);  } -QString ProjectCreateImpl::getProjectPath() +QString ProjectCreateImpl::getProjectPath() const  {     return storageDirEdit->text();  } -QString ProjectCreateImpl::getSongInfo() + +QString ProjectCreateImpl::getSongInfo() const  {     return commentEdit->toPlainText();  } +  void ProjectCreateImpl::ok()  {    MusEGlobal::config.projectStoreInFolder = createFolderCheckbox->isChecked(); -  MusEGlobal::config.projectBaseFolder = directoryPath; -  MusEGlobal::muse->changeConfig(true); +  //MusEGlobal::config.projectBaseFolder = directoryPath; +  //MusEGlobal::muse->changeConfig(true);    emit accept();  } +void ProjectCreateImpl::createProjFolderChanged() +{ +  //MusEGlobal::config.projectStoreInFolder = createFolderCheckbox->isChecked(); +  //MusEGlobal::muse->changeConfig(true);  // Save to config file. +  updateDirectoryPath(); +} + +void ProjectCreateImpl::browseProjDir() +{ +  QString dir = MusEGui::browseProjectFolder(this); +  if(!dir.isEmpty()) +  {   +    directoryPath = dir; +    MusEGlobal::config.projectBaseFolder = dir; +    MusEGlobal::muse->changeConfig(true);  // Save to config file. +    updateDirectoryPath(); +  }   +} + +void ProjectCreateImpl::templateButtonChanged() +{ +  restorePathButton->setEnabled(templateCheckBox->isChecked() ? !overrideTemplDirPath.isEmpty() : !overrideDirPath.isEmpty());  +  updateDirectoryPath(); +} + +void ProjectCreateImpl::restorePath()   +{ +  if(templateCheckBox->isChecked()) +    overrideTemplDirPath.clear(); +  else +    overrideDirPath.clear(); +  restorePathButton->setEnabled(templateCheckBox->isChecked() ? !overrideTemplDirPath.isEmpty() : !overrideDirPath.isEmpty());  +  updateDirectoryPath(); +} + +/* +bool ProjectCreateImpl::getProjectIsTemplate() const +{ +  return templateCheckBox->isChecked(); +} + +QString ProjectCreateImpl::getTemplatePath() const +{ +   return templDirPath; +} +*/ +  } //namespace MusEGui diff --git a/muse2/muse/widgets/projectcreateimpl.h b/muse2/muse/widgets/projectcreateimpl.h index 258b0921..f08cb1bc 100644 --- a/muse2/muse/widgets/projectcreateimpl.h +++ b/muse2/muse/widgets/projectcreateimpl.h @@ -4,6 +4,7 @@  //  $Id: ./muse/widgets/projectcreateimpl.h $  //  //  Copyright (C) 1999-2011 by Werner Schweer and others +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -33,18 +34,28 @@ class ProjectCreateImpl : public QDialog, Ui::ProjectCreate      Q_OBJECT      QString directoryPath; +    QString overrideDirPath; +    QString overrideTemplDirPath; +    QString projDirPath; +      public:      explicit ProjectCreateImpl(QWidget *parent = 0); -    QString getProjectPath(); -    QString getSongInfo(); +    QString getProjectPath() const; +    QString getSongInfo() const; +    //bool getProjectIsTemplate() const; +    //QString getTemplatePath() const;  signals: -public slots: +protected slots: +    void updateProjectName();      void updateDirectoryPath();      void selectDirectory();      void ok(); - +    void createProjFolderChanged(); +    void browseProjDir(); +    void templateButtonChanged(); +    void restorePath();  };  } // namespace MusEGui diff --git a/muse2/muse/widgets/routepopup.cpp b/muse2/muse/widgets/routepopup.cpp index 80ae98bd..0f1f8264 100644 --- a/muse2/muse/widgets/routepopup.cpp +++ b/muse2/muse/widgets/routepopup.cpp @@ -43,10 +43,10 @@ namespace MusEGui {  int RoutePopupMenu::addMenuItem(MusECore::AudioTrack* track, MusECore::Track* route_track, PopupMenu* lb, int id, int channel, int channels, bool isOutput)  {    // totalInChannels is only used by syntis. -  int toch = ((MusECore::AudioTrack*)track)->totalOutChannels(); +  //int toch = ((MusECore::AudioTrack*)track)->totalOutChannels();    // If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user. -  if(track->channels() == 1) -    toch = 1; +  //if(track->channels() == 1) +  //  toch = 1;    // Don't add the last stray mono route if the track is stereo.    //if(route_track->channels() > 1 && (channel+1 == chans)) @@ -95,6 +95,13 @@ int RoutePopupMenu::addMenuItem(MusECore::AudioTrack* track, MusECore::Track* ro        }      }      } +   +  if(!act->isChecked())  // If circular route exists, allow user to break it, otherwise forbidden. +  { +    if( (isOutput ? track : route_track)->isCircularRoute(isOutput ? route_track : track) )  +      act->setEnabled(false); +  } +    return ++id;        } @@ -259,6 +266,13 @@ int RoutePopupMenu::addSyntiPorts(MusECore::AudioTrack* t, PopupMenu* lb, int id                      }                    }                  }   + +                if(!act->isChecked())  // If circular route exists, allow user to break it, otherwise forbidden. +                { +                  if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) )  +                    act->setEnabled(false); +                } +                  ++id;                } @@ -520,6 +534,13 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l                      }                    }                  } +                 +                if(!act->isChecked())  // If circular route exists, allow user to break it, otherwise forbidden. +                { +                  if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) )  +                    act->setEnabled(false); +                } +                  ++id;                } @@ -573,6 +594,13 @@ int RoutePopupMenu::nonSyntiTrackAddSyntis(MusECore::AudioTrack* t, PopupMenu* l                        }                      }                      } +                   +                  if(!act->isChecked())  // If circular route exists, allow user to break it, otherwise forbidden. +                  { +                    if( (isOutput ? t : track)->isCircularRoute(isOutput ? track : t) )  +                      act->setEnabled(false); +                  } +                    ++id;                  }                } @@ -1062,9 +1090,8 @@ void RoutePopupMenu::prepare()        for( ; pi < MIDI_PORTS; ++pi)        {          MusECore::MidiDevice* md = MusEGlobal::midiPorts[pi].device(); -        //if(md && !md->isSynti() && (md->rwFlags() & 2)) -        //if(md && (md->rwFlags() & 2))   // p4.0.27 -        if(md && (md->rwFlags() & 2 || md->isSynti()) )  // p4.0.27 +        if(md && !md->isSynti() && (md->rwFlags() & 2)) +        //if(md && (md->rwFlags() & 2 || md->isSynti()) )  // p4.0.27 Reverted p4.0.35             break;        }        if(pi == MIDI_PORTS) @@ -1091,12 +1118,9 @@ void RoutePopupMenu::prepare()          //  continue;          // Do not list synth devices! -        ///if(md && md->isSynti()) -        ///  continue; -        ///if(md && !(md->rwFlags() & 2)) -        ///  continue; -        // p4.0.27 Go ahead. Synths esp MESS send out stuff.  -        if( md && !(md->rwFlags() & 2) && !md->isSynti() ) +        if( md && (!(md->rwFlags() & 2) || md->isSynti()) ) +        // p4.0.27 Go ahead. Synths esp MESS send out stuff. Reverted p4.0.35  +        //if( md && !(md->rwFlags() & 2) && !md->isSynti() )            continue;          //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i); diff --git a/muse2/muse/widgets/synthconfigbase.ui b/muse2/muse/widgets/synthconfigbase.ui index 97f0beaa..500241a8 100644 --- a/muse2/muse/widgets/synthconfigbase.ui +++ b/muse2/muse/widgets/synthconfigbase.ui @@ -6,12 +6,12 @@     <rect>      <x>0</x>      <y>0</y> -    <width>630</width> +    <width>810</width>      <height>492</height>     </rect>    </property>    <property name="windowTitle"> -   <string>MusE: Synth Configuration</string> +   <string>Midi Port and Soft Synth Configuration</string>    </property>    <layout class="QGridLayout">     <item row="1" column="1"> @@ -32,6 +32,11 @@          </column>          <column>           <property name="text"> +          <string>Type</string> +         </property> +        </column> +        <column> +         <property name="text">            <string>Midi Port</string>           </property>          </column> @@ -137,6 +142,11 @@          </column>          <column>           <property name="text"> +          <string>Type</string> +         </property> +        </column> +        <column> +         <property name="text">            <string>Inst</string>           </property>          </column> diff --git a/muse2/muse/widgets/utils.cpp b/muse2/muse/widgets/utils.cpp index 708bef07..1641b267 100644 --- a/muse2/muse/widgets/utils.cpp +++ b/muse2/muse/widgets/utils.cpp @@ -528,7 +528,8 @@ int get_paste_len()                                      if (p->endTick() > end_tick)                                            end_tick=p->endTick(); - +                                     +                                    unchainClone(p);                                      delete p;                                      }                                } diff --git a/muse2/muse/widgets/visibletracks.cpp b/muse2/muse/widgets/visibletracks.cpp index f8ce06bf..4976ecf9 100644 --- a/muse2/muse/widgets/visibletracks.cpp +++ b/muse2/muse/widgets/visibletracks.cpp @@ -29,6 +29,7 @@  #include "action.h"  #include "track.h"  #include "synth.h" +#include "app.h"  namespace MusEGui { @@ -130,6 +131,7 @@ void VisibleTracks::visibilityChanged(QAction* action)        default:              break;        } +      MusEGlobal::muse->changeConfig(true);    // save settings        emit visibilityChanged();  } diff --git a/muse2/muse/widgets/visibletracks.h b/muse2/muse/widgets/visibletracks.h index d56c9ce7..bf49c068 100644 --- a/muse2/muse/widgets/visibletracks.h +++ b/muse2/muse/widgets/visibletracks.h @@ -52,13 +52,14 @@ class VisibleTracks : public QToolBar {     private slots:        void visibilityChanged(QAction* action); +   public slots: +      void updateVisibleTracksButtons();     signals:        void visibilityChanged();     public:        VisibleTracks(QWidget* /*parent*/, const char* name = 0);  // Needs a parent ! -      void updateVisibleTracksButtons();        ~VisibleTracks();        }; diff --git a/muse2/muse/xml.cpp b/muse2/muse/xml.cpp index 139437c1..45bed368 100644 --- a/muse2/muse/xml.cpp +++ b/muse2/muse/xml.cpp @@ -4,6 +4,7 @@  //  $Id: xml.cpp,v 1.17.2.6 2009/12/07 20:48:45 spamatica Exp $  //  //  (C) Copyright 2000 Werner Schweer (ws@seh.de) +//  (C) Copyright 2011 Tim E. Real (terminator356 on sourceforge)  //  //  This program is free software; you can redistribute it and/or  //  modify it under the terms of the GNU General Public License @@ -24,6 +25,7 @@  #include <stdio.h>  #include <stdarg.h> +#include <QByteArray>  #include <QString>  #include <QColor>  #include <QWidget> @@ -112,9 +114,12 @@ void Xml::nextc()  void Xml::token(int cc)        { -      char buffer[512]; +      //char buffer[512]; +      QByteArray buffer; +        int i = 0; -      for (; i < 511;) { +      //for (; i < 511;) { +      for (; i < 9999999;) {   // Stop at a reasonably large amount 10 million.              if (c == ' ' || c == '\t' || c == cc || c == '\n' || c == EOF)                    break;              buffer[i++] = c; @@ -131,12 +136,16 @@ void Xml::token(int cc)  void Xml::stoken()        { -      char buffer[1024*4]; +      //char buffer[1024*4]; +      QByteArray buffer; +              int i = 0;        buffer[i] = c;        ++i;        next(); -      for (;i < 1024*4-1;) { + +      //for (;i < 1024*4-1;) { +      for (;i < 10000000*4-1;) {  // Stop at a reasonably large amount 10 million.              if (c == '"') {                    buffer[i++] = c;                    next(); @@ -207,8 +216,10 @@ QString Xml::strip(const QString& s)  Xml::Token Xml::parse()        { -      char buffer[1024*1024];   // increase buffer -rj -      char* p; +      //char buffer[1024*1024];   // increase buffer -rj +      //char* p; +      QByteArray buffer; +      int idx = 0;   again:        bool endFlag = false; @@ -262,15 +273,23 @@ Xml::Token Xml::parse()                    }              if (c == '?') {                    next(); -                  p = buffer; +                  //p = buffer; +                  //p = buffer.data(); +                  idx = 0;                    for (;;) {                          if (c == '?' || c == EOF || c == '>')                                break; -                        *p++ = c; +                         +                        //*p++ = c; +                        buffer[idx++] = c; +                                                  // TODO: check overflow                          next();                          } -                  *p = 0; +                   +                  //*p = 0; +                  buffer[idx] = 0; +                                      _s1 = QString(buffer);                    if (c == EOF) {                          fprintf(stderr, "XML: unexpected EOF\n"); @@ -298,15 +317,23 @@ Xml::Token Xml::parse()                          }                    goto again;                    } -            p = buffer; +            //p = buffer; +            //p = buffer.data(); +            idx = 0;              for (;;) {                    if (c == '/' || c == ' ' || c == '\t' || c == '>' || c == '\n' || c == EOF)                          break;                    // TODO: check overflow -                  *p++ = c; +                   +                  //*p++ = c; +                  buffer[idx++] = c; +                                      next();                    } -            *p = 0; +             +            //*p = 0; +            buffer[idx] = 0; +                          _s1 = QString(buffer);              // skip white space:              while (c == ' ' || c == '\t' || c == '\n') @@ -355,26 +382,43 @@ Xml::Token Xml::parse()                    fprintf(stderr, "XML: level = 0\n");                    goto error;                    } -            p = buffer; +            //p = buffer; +            //p = buffer.data(); +            idx = 0;              for (;;) {                    if (c == EOF || c == '<')                          break;                    if (c == '&') {                          next();                          if (c == '<') {         // be tolerant with old muse files -                              *p++ = '&'; +                               +                              //*p++ = '&'; +                              buffer[idx++] = '&'; +                                                              continue;                                } -                        char name[32]; -                        char* dp = name; -                        *dp++ = c; -                        for (; dp-name < 31;) { +                               +                        //char name[32]; +                        //char* dp = name; +                        QByteArray name; +                        int name_idx = 0; +                         +                        //*dp++ = c; +                        name[name_idx++] = c; +                         +                        //for (; dp-name < 31;) { +                        for (; name_idx < 9999999;) {   // Stop at a reasonably large amount 10 million.                                next();                                if (c == ';')                                      break; -                              *dp++ = c; +                               +                              //*dp++ = c; +                              name[name_idx++] = c;                                } -                        *dp = 0; +                               +                        //*dp = 0; +                        name[name_idx] = 0; +                                                  if (strcmp(name, "lt") == 0)                                c = '<';                          else if (strcmp(name, "gt") == 0) @@ -388,10 +432,16 @@ Xml::Token Xml::parse()                          else                                c = '?';                          } -                  *p++ = c; +                         +                  //*p++ = c; +                  buffer[idx++] = c; +                                      next();                    } -            *p = 0; +                   +            //*p = 0; +            buffer[idx] = 0; +                          _s1 = QString(buffer);              if (c == '<') | 
