diff options
| author | Tim E. Real <termtech@rogers.com> | 2010-01-21 23:21:47 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2010-01-21 23:21:47 +0000 | 
| commit | 6ba5244898afe623cbd219539c796e286429a24b (patch) | |
| tree | 8697844767a5098ecf340867c9f4a7be7b8aee03 | |
| parent | d65bd2bca695098fb038d9f3611d775bf66a3581 (diff) | |
See ChangeLog
| -rw-r--r-- | muse/ChangeLog | 19 | ||||
| -rw-r--r-- | muse/muse/arranger/pcanvas.cpp | 3 | ||||
| -rw-r--r-- | muse/muse/audio.cpp | 23 | ||||
| -rw-r--r-- | muse/muse/globals.cpp | 167 | ||||
| -rw-r--r-- | muse/muse/globals.h | 35 | ||||
| -rw-r--r-- | muse/muse/icons.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/master/lmaster.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/master/masteredit.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/midi.cpp | 115 | ||||
| -rw-r--r-- | muse/muse/midiedit/drumedit.cpp | 19 | ||||
| -rw-r--r-- | muse/muse/midiedit/pianoroll.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/midiseq.cpp | 9 | ||||
| -rw-r--r-- | muse/muse/mixer/amixer.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/mixer/rack.cpp | 43 | ||||
| -rw-r--r-- | muse/muse/plugin.cpp | 15 | ||||
| -rw-r--r-- | muse/muse/song.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/sync.cpp | 22 | ||||
| -rw-r--r-- | muse/muse/transport.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/wave.cpp | 7 | ||||
| -rw-r--r-- | muse/muse/waveedit/waveedit.cpp | 1 | ||||
| -rw-r--r-- | muse/muse/widgets/filedialog.cpp | 109 | ||||
| -rw-r--r-- | muse/muse/widgets/filedialog.h | 15 | 
22 files changed, 490 insertions, 119 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog index 3bcfdc8c..4b5376ca 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,22 @@ +21.01.2010 +      * Fixed: First tests: External midi sync in works now! Should be rock solid no matter what is thrown at it. (T356) +        - All changes are labeled "p3.3.25" +        - Switched to a 'direct drive' method instead of 'calculation of tempo' method. +          Drift between source of master and slave is non-existant since the incoming midi clocks  +           drive the midi engine directly. This is at the expense of exact 64th note resolution. +          At MusE's fixed 24 midi clocks per quarternote, triplet 32nd notes are resolved (32nd note divided by three). +          MusE's default 'division' (ticks per quarternote) is 384. 384/24 gives a division of 16 MusE 'ticks' per midi clock. +        - Normally when using the tempo map (external sync is off), device play event times are in frames, +           because the tempo map provides for that kind of sub-tick frame resolution. +          But now, during external sync, device play event times are in ticks, not frames.  +          Hence the compromise between exactness of note times, and master/slave drift. +        - Tested heavily with a Roland TR-505 which has a variable 'analog' tempo knob.   +          Combined that with a complete midi song, and other test 'tick' tracks driving external synth KB, +           was rock solid going 'absolutely nuts' with the tempo knob up to 260BPM, surprisingly good resolution. +        - TODO: Check safety of 'midiExtSyncTicks = 0' inside audio thread while midi thread is counting it up. +          Also fix seek operations and check for any more place needing these 'tick'frame' alterations. +      * Changed: Some more changes for compressed files operations. (T356) +        - More to be done, but tests OK so far.      19.01.2010        * Fixed: Saving/loading compressed .gz/.bz2 MusE .med files, + loading compressed .mid/.kar files (save broken, off for now). (T356)          - Changed filedialog.cpp:getSaveFileName() and MusE::loadProjectFile1. diff --git a/muse/muse/arranger/pcanvas.cpp b/muse/muse/arranger/pcanvas.cpp index 38ddfa77..5a702713 100644 --- a/muse/muse/arranger/pcanvas.cpp +++ b/muse/muse/arranger/pcanvas.cpp @@ -861,7 +861,8 @@ void PartCanvas::itemPopup(CItem* item, int n, const QPoint& pt)                    {                    const Part* part = item->part();                    bool popenFlag = false; -                  QString fn = getSaveFileName(QString(""), part_file_pattern, this, tr("MusE: save part")); +                  //QString fn = getSaveFileName(QString(""), part_file_pattern, this, tr("MusE: save part")); +                  QString fn = getSaveFileName(QString(""), part_file_save_pattern, this, tr("MusE: save part"));                    if (!fn.isEmpty()) {                          FILE* fp = fileOpen(this, fn, ".mpt", "w", popenFlag, false, false);                          if (fp) { diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index dab1be16..aa5cebdd 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -35,6 +35,10 @@ extern double curTime();  Audio* audio;  AudioDevice* audioDevice;   // current audio device in use +// p3.3.25 +extern unsigned int midiExtSyncTicks; + +  static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 };  static const unsigned char mmcStopMsg[] =         { 0x7f, 0x7f, 0x06, 0x01 }; @@ -464,10 +468,23 @@ void Audio::process(unsigned frames)  // printf("  process: seek to %d, end %d\n", _loopFrame, loop.frame());                          }                    } -            Pos ppp(_pos); -            ppp += frames; -            nextTickPos = ppp.tick(); +             +             +            // P3.3.25 +            if(extSyncFlag.value()) +            { +              nextTickPos = curTickPos + midiExtSyncTicks; +              // Probably not good - interfere with midi thread. +              midiExtSyncTicks = 0;              } +            else +            { +               +              Pos ppp(_pos); +              ppp += frames; +              nextTickPos = ppp.tick(); +            } +          }        //        // resync with audio interface        // diff --git a/muse/muse/globals.cpp b/muse/muse/globals.cpp index 12a5f862..9c48826f 100644 --- a/muse/muse/globals.cpp +++ b/muse/muse/globals.cpp @@ -92,13 +92,21 @@ bool loadDSSI = true;  bool usePythonBridge = false;  bool useLASH = true; +/*  const char* midi_file_pattern[] = { -      "Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2)", -      "Midi (*.mid *.MID *.mid.gz *.mid.bz2)", -      "Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2)", -      "All Files (*)", +      QT_TR_NOOP("Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2)"), +      QT_TR_NOOP("Midi (*.mid *.MID *.mid.gz *.mid.bz2)"), +      QT_TR_NOOP("Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2)"), +      QT_TR_NOOP("All Files (*)"),        0        }; +*/       +const QStringList midi_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Midi/Kar (*.mid *.MID *.kar *.KAR *.mid.gz *.mid.bz2);;") + +      QString("Midi (*.mid *.MID *.mid.gz *.mid.bz2);;") + +      QString("Karaoke (*.kar *.KAR *.kar.gz *.kar.bz2);;") + +      QString("All Files (*)")) );  //FIXME: By T356 01/19/2010  // If saving as a compressed file (gz or bz2), @@ -116,37 +124,78 @@ const char* midi_file_save_pattern[] = {        "All Files (*)",        0        }; +QStringList midi_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Midi (*.mid);;") + +      QString("gzip compressed Midi (*.mid.gz);;") + +      QString("bzip2 compressed Midi (*.mid.bz2);;") + +      QString("Karaoke (*.kar);;") + +      QString("gzip compressed karaoke (*.kar.gz);;") + +      QString("bzip2 compressed karaoke (*.kar.bz2);;") + +      QString("All Files (*)")) );  */ +/*  const char* midi_file_save_pattern[] = { -      "Midi (*.mid)", -      "Karaoke (*.kar)", -      "All Files (*)", +      QT_TR_NOOP("Midi (*.mid)"), +      QT_TR_NOOP("Karaoke (*.kar)"), +      QT_TR_NOOP("All Files (*)"),        0        }; +*/ +const QStringList midi_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Midi (*.mid);;") + +      QString("Karaoke (*.kar);;") + +      QString("All Files (*)")) ); +/*  const char* med_file_pattern[] = { -      "med Files (*.med *.med.gz *.med.bz2)", -      "gzip compressed med Files (*.med.gz)", -      "bzip2 compressed med Files (*.med.bz2)", -      "Uncompressed med Files (*.med)", -      "All Files (*)", +      QT_TR_NOOP("med Files (*.med *.med.gz *.med.bz2)"), +      QT_TR_NOOP("Uncompressed med Files (*.med)"), +      QT_TR_NOOP("gzip compressed med Files (*.med.gz)"), +      QT_TR_NOOP("bzip2 compressed med Files (*.med.bz2)"), +      QT_TR_NOOP("All Files (*)"),        0        };  const char* med_file_save_pattern[] = { -      "med Files (*.med)", -      "gzip compressed med Files (*.med.gz)", -      "bzip2 compressed med Files (*.med.bz2)", -      "All Files (*)", +      QT_TR_NOOP("Uncompressed med Files (*.med)"), +      QT_TR_NOOP("gzip compressed med Files (*.med.gz)"), +      QT_TR_NOOP("bzip2 compressed med Files (*.med.bz2)"), +      QT_TR_NOOP("All Files (*)"),        0        }; +*/       +const QStringList med_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("med Files (*.med *.med.gz *.med.bz2);;") + +      QString("Uncompressed med Files (*.med);;") + +      QString("gzip compressed med Files (*.med.gz);;") + +      QString("bzip2 compressed med Files (*.med.bz2);;") + +      QString("All Files (*)")) ); +const QStringList med_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Uncompressed med Files (*.med);;") + +      QString("gzip compressed med Files (*.med.gz);;") + +      QString("bzip2 compressed med Files (*.med.bz2);;") + +      QString("All Files (*)")) ); + +/*  const char* image_file_pattern[] = { -      "(*.jpg *.gif *.png)", -      "(*.jpg)", -      "(*.gif)", -      "(*.png)", -      "All Files (*)", +      QT_TR_NOOP("(*.jpg *.gif *.png)"), +      QT_TR_NOOP("(*.jpg)"), +      QT_TR_NOOP("(*.gif)"), +      QT_TR_NOOP("(*.png)"), +      QT_TR_NOOP("All Files (*)"),        0        }; +*/       +const QStringList image_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("(*.jpg *.gif *.png);;") + +      QString("(*.jpg);;") + +      QString("(*.gif);;") + +      QString("(*.png);;") + +      QString("All Files (*)")) );  // Not used.  /* @@ -157,17 +206,85 @@ const char* ctrl_file_pattern[] = {        };  */ +/*  const char* part_file_pattern[] = { -      "part Files (*.mpt)", -      "All Files (*)", +      //QT_TR_NOOP("part Files (*.mpt)"), +      QT_TR_NOOP("part Files (*.mpt *.mpt.gz *.mpt.bz2)"), +      QT_TR_NOOP("All Files (*)"), +      0 +      }; +const char* part_file_save_pattern[] = { +      QT_TR_NOOP("part Files (*.mpt)"), +      QT_TR_NOOP("gzip compressed part Files (*.mpt.gz)"), +      QT_TR_NOOP("bzip2 compressed part Files (*.mpt.bz2)"), +      QT_TR_NOOP("All Files (*)"),        0        }; +*/ +const QStringList part_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("part Files (*.mpt *.mpt.gz *.mpt.bz2);;") + +      QString("All Files (*)")) ); + +const QStringList part_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("part Files (*.mpt);;") + +      QString("gzip compressed part Files (*.mpt.gz);;") + +      QString("bzip2 compressed part Files (*.mpt.bz2);;") + +      QString("All Files (*)")) ); +/*  const char* plug_file_pattern[] = { -      "part Files (*.pre)", -      "All Files (*)", +      QT_TR_NOOP("part Files (*.pre)"), +      QT_TR_NOOP("All Files (*)"), +      0 +      }; +*/ +/* +const char* preset_file_pattern[] = { +      QT_TR_NOOP("Presets (*.pre *.pre.gz *.pre.bz2)"), +      QT_TR_NOOP("All Files (*)"),        0        }; + +const char* preset_file_save_pattern[] = { +      QT_TR_NOOP("Presets (*.pre)"), +      QT_TR_NOOP("gzip compressed presets (*.pre.gz)"), +      QT_TR_NOOP("bzip2 compressed presets (*.pre.bz2)"), +      QT_TR_NOOP("All Files (*)"), +      0 +      }; +*/ +const QStringList preset_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Presets (*.pre *.pre.gz *.pre.bz2);;") + +      QString("All Files (*)")) ); + +const QStringList preset_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Presets (*.pre);;") + +      QString("gzip compressed presets (*.pre.gz);;") + +      QString("bzip2 compressed presets (*.pre.bz2);;") + +      QString("All Files (*)")) ); + +const QStringList drum_map_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Presets (*.map *.map.gz *.map.bz2);;") + +      QString("All Files (*)")) ); +const QStringList drum_map_file_save_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Presets (*.map);;") + +      QString("gzip compressed presets (*.map.gz);;") + +      QString("bzip2 compressed presets (*.map.bz2);;") + +      QString("All Files (*)")) ); + +const QStringList audio_file_pattern =   +      QStringList::split(";;", QT_TR_NOOP( +      QString("Wave/Binary (*.wav *.ogg *.bin);;") + +      QString("Wave (*.wav *.ogg);;") + +      QString("Binary (*.bin);;") + +      QString("All Files (*)")) ); +  Qt::ButtonState globalKeyState;  // Midi Filter Parameter diff --git a/muse/muse/globals.h b/muse/muse/globals.h index fb4e42b1..771769a2 100644 --- a/muse/muse/globals.h +++ b/muse/muse/globals.h @@ -10,15 +10,21 @@  #define GLOBALS_H  #include <sys/types.h> -#include <qstring.h> -#include <qfont.h> +//#include <qstring.h> +//#include <qfont.h>  #include <qnamespace.h> -#include <qaction.h> +//#include <qaction.h>  #include "value.h"  #include "mtc.h"  #include <unistd.h> +class QString; +class QFont; +class QAction; +class QActionGroup; +class QStringList; +  extern const float denormalBias;  extern int recFileNumber; @@ -66,14 +72,33 @@ extern bool realTimeScheduling;  extern int realTimePriority;  extern int midiRTPrioOverride; +/*  extern const char* midi_file_pattern[];  //!< File name pattern for midi files  extern const char* midi_file_save_pattern[];  //!< File name pattern for saving midi files  extern const char* med_file_pattern[];   //!< File name pattern for muse project files  extern const char* med_file_save_pattern[];   //!< File name pattern for saving muse project files  extern const char* image_file_pattern[]; //!< File name pattern for image files (gfx) -extern const char* ctrl_file_pattern[];  //!< File name pattern for controller-files +//extern const char* ctrl_file_pattern[];  //!< File name pattern for controller-files  extern const char* part_file_pattern[];  //!< File name pattern for part files -extern const char* plug_file_pattern[];  //!< File name pattern for plugin files +extern const char* part_file_save_pattern[];  //!< File name pattern for saving part files +//extern const char* plug_file_pattern[];  //!< File name pattern for plugin files +extern const char* preset_file_pattern[];  //!< File name pattern for plugin files +extern const char* preset_file_save_pattern[];  //!< File name pattern for saving plugin files +*/ + +extern const QStringList midi_file_pattern; +extern const QStringList midi_file_save_pattern; +extern const QStringList med_file_pattern; +extern const QStringList med_file_save_pattern; +extern const QStringList image_file_pattern; +//extern const QStringList ctrl_file_pattern; +extern const QStringList part_file_pattern; +extern const QStringList part_file_save_pattern; +extern const QStringList preset_file_pattern; +extern const QStringList preset_file_save_pattern; +extern const QStringList drum_map_file_pattern; +extern const QStringList drum_map_file_save_pattern; +extern const QStringList audio_file_pattern;  extern Qt::ButtonState globalKeyState; diff --git a/muse/muse/icons.cpp b/muse/muse/icons.cpp index ca2e8567..9ff757b9 100644 --- a/muse/muse/icons.cpp +++ b/muse/muse/icons.cpp @@ -8,6 +8,7 @@  #include "globals.h"  #include <qpixmap.h> +#include <qiconset.h>  #include "xpm/track_comment.xpm"  #include "xpm/audio_bounce_to_file.xpm" diff --git a/muse/muse/master/lmaster.cpp b/muse/muse/master/lmaster.cpp index aa1ce007..f0a2704f 100644 --- a/muse/muse/master/lmaster.cpp +++ b/muse/muse/master/lmaster.cpp @@ -26,6 +26,7 @@  #include <qmessagebox.h>  #include <qstyle.h>  #include <qaccel.h> +#include <qaction.h>  #define LMASTER_BEAT_COL 0  #define LMASTER_TIME_COL 1 diff --git a/muse/muse/master/masteredit.cpp b/muse/muse/master/masteredit.cpp index 76a72805..4179a3e4 100644 --- a/muse/muse/master/masteredit.cpp +++ b/muse/muse/master/masteredit.cpp @@ -39,6 +39,7 @@  #include <qheader.h>  #include <qpopupmenu.h>  #include <qmenubar.h> +#include <qaction.h>  int MasterEdit::_rasterInit = 0; diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index a1fc3ea0..60b63179 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -812,14 +812,30 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)                                if (port == defaultPort) {                                      //printf("Adding event normally: frame=%d port=%d channel=%d pitch=%d velo=%d\n",frame, port, channel, pitch, velo); -                                    playEvents->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); +                                     +                                    // P3.3.25 +                                    // If syncing to external midi sync, we cannot use the tempo map. +                                    // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. +                                    if(extSyncFlag.value()) +                                      playEvents->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo)); +                                    else +                                     +                                      playEvents->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); +                                                                            stuckNotes->add(MidiPlayEvent(tick + len, port, channel,                                         veloOff ? 0x80 : 0x90, pitch, veloOff));                                      }                                else { //Handle events to different port than standard.                                      MidiDevice* mdAlt = midiPorts[port].device();                                      if (mdAlt) { -                                        mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); +                                         +                                        // P3.3.25 +                                        if(extSyncFlag.value()) +                                          mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo)); +                                        else   +                                           +                                          mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); +                                                                                    mdAlt->stuckNotes()->add(MidiPlayEvent(tick + len, port, channel,                                            veloOff ? 0x80 : 0x90, pitch, veloOff));                                        } @@ -850,20 +866,40 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)                                      MidiDevice* mdAlt = midiPorts[port].device();                                      if(mdAlt)                                       { -                                      //playEvents->add(MidiPlayEvent(frame, port, channel, ev)); -                                      mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel,  +                                      // P3.3.25 +                                      // If syncing to external midi sync, we cannot use the tempo map. +                                      // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. +                                      if(extSyncFlag.value()) +                                        mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel,  +                                                                             ME_CONTROLLER, ctl | pitch, ev.dataB())); +                                      else +                                                                              +                                        //playEvents->add(MidiPlayEvent(frame, port, channel, ev)); +                                        mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel,                                                                                ME_CONTROLLER, ctl | pitch, ev.dataB())); +                                                                                                                   }                                        break;                                    }                                    } -                                playEvents->add(MidiPlayEvent(frame, port, channel, ev)); +                                // P3.3.25 +                                if(extSyncFlag.value()) +                                  playEvents->add(MidiPlayEvent(tick, port, channel, ev)); +                                else   +                                 +                                  playEvents->add(MidiPlayEvent(frame, port, channel, ev));                                }                                     break;                          default: -                              playEvents->add(MidiPlayEvent(frame, port, channel, ev)); +                              // P3.3.25 +                              if(extSyncFlag.value()) +                                playEvents->add(MidiPlayEvent(tick, port, channel, ev)); +                              else +                                 +                                playEvents->add(MidiPlayEvent(frame, port, channel, ev)); +                                                                break;                          }                    } @@ -909,6 +945,9 @@ void Audio::processMidi()        iMPEvent nextPlayEvent  = metronome->nextPlayEvent();        playEvents->erase(playEvents->begin(), nextPlayEvent); +      // P3.3.25 +      bool extsync = extSyncFlag.value(); +              for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t)         {              MidiTrack* track = *t; @@ -1046,7 +1085,13 @@ void Audio::processMidi()                                  }                                } -                              unsigned time = event.time() + segmentSize*(segmentCount-1); +                              // p3.3.25  +                              // MusE uses a fixed clocks per quarternote of 24.  +                              // At standard 384 ticks per quarternote for example,  +                              // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks'). +                              // That is what we'll use if syncing externally. +                              //unsigned time = event.time() + segmentSize*(segmentCount-1); +                              unsigned time = event.time() + (extsync ? config.division/24 : segmentSize*(segmentCount-1));                                event.setTime(time);                                // dont't echo controller changes back to software @@ -1076,8 +1121,14 @@ void Audio::processMidi()                                    track->setActivity(event.dataB());                                } -                              time = tempomap.frame2tick(event.time()); -                              event.setTime(time);  // set tick time +                              // p3.3.25 +                              // If syncing externally the event time is already in units of ticks, set above. +                              if(!extsync) +                              { +                                 +                                time = tempomap.frame2tick(event.time()); +                                event.setTime(time);  // set tick time +                              }                                  // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)                                if (recording)  @@ -1160,8 +1211,22 @@ void Audio::processMidi()                    if (k->time() >= nextTickPos)                          break;                    MidiPlayEvent ev(*k); -                  int frame = tempomap.tick2frame(k->time()) + frameOffset; -                  ev.setTime(frame); +                   +                  // P3.3.25 +                  //int frame = tempomap.tick2frame(k->time()) + frameOffset; +                  if(extsync) +                  { +                    ev.setTime(k->time()); +                  } +                  else +                  { +                    int frame = tempomap.tick2frame(k->time()) + frameOffset; +                    ev.setTime(frame); +                  }   +                   +                  // P3.3.25 +                  //ev.setTime(frame); +                                      playEvents->add(ev);                    }              stuckNotes->erase(stuckNotes->begin(), k); @@ -1193,12 +1258,21 @@ void Audio::processMidi()                    else if (state == PRECOUNT) {                          isMeasure = (clickno % clicksMeasure) == 0;                          } -                  int frame = tempomap.tick2frame(midiClick) + frameOffset; -                  MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, +                  // P3.3.25 +                  //int frame = tempomap.tick2frame(midiClick) + frameOffset; +                  int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset; +                   +                  // P3.3.25 +                  //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, +                  MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,                       beatClickNote, beatClickVelo); +                                         if (md) { -                        MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, +                        // P3.3.25 +                        //MidiPlayEvent ev(frame, clickPort, clickChan, ME_NOTEON, +                        MidiPlayEvent ev(evtime, clickPort, clickChan, ME_NOTEON,                             beatClickNote, beatClickVelo); +                                                  if (isMeasure) {                                ev.setA(measureClickNote);                                ev.setB(measureClickVelo); @@ -1206,14 +1280,23 @@ void Audio::processMidi()                          playEvents->add(ev);                          }                    if (audioClickFlag) { -                        MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0); +                        // P3.3.25 +                        //MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0); +                        MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0); +                                                  ev1.setA(isMeasure ? 0 : 1);                          metronome->playEvents()->add(ev1);                          }                    if (md) {                          ev.setB(0); -                        frame = tempomap.tick2frame(midiClick+20) + frameOffset; +                        // P3.3.25 +                        // Removed. Why was this here? +                        //frame = tempomap.tick2frame(midiClick+20) + frameOffset; +                        // +                        // Does it mean this should be changed too?  +                        // No, stuck notes are in units of ticks, not frames like (normal, non-external) play events...                          ev.setTime(midiClick+10); +                                                  if (md)                                stuckNotes->add(ev);                          } diff --git a/muse/muse/midiedit/drumedit.cpp b/muse/muse/midiedit/drumedit.cpp index 2544495b..c6204cfd 100644 --- a/muse/muse/midiedit/drumedit.cpp +++ b/muse/muse/midiedit/drumedit.cpp @@ -22,6 +22,7 @@  #include <qapplication.h>  #include <qclipboard.h>  #include <qmessagebox.h> +#include <qaction.h>  #include "drumedit.h"  #include "mtscale.h" @@ -43,11 +44,21 @@  #include "audio.h"  #include "gconfig.h" +/*  static const char* map_file_pattern[] = { -      "presets (*.map *.map.gz *.map.bz2)", +      "Presets (*.map *.map.gz *.map.bz2)",        "All Files (*)",        0        }; +static const char* map_file_save_pattern[] = { +      "Presets (*.map)", +      "gzip compressed presets (*.map.gz)", +      "bzip2 compressed presets (*.map.bz2)", +      "All Files (*)", +      0 +      }; +*/       +  int DrumEdit::_quantInit = 96;  int DrumEdit::_rasterInit = 96;  int DrumEdit::_widthInit = 600; @@ -696,7 +707,8 @@ void DrumEdit::writeConfiguration(int level, Xml& xml)  void DrumEdit::load()        { -      QString fn = getOpenFileName("drummaps", map_file_pattern, +      //QString fn = getOpenFileName("drummaps", map_file_pattern, +      QString fn = getOpenFileName("drummaps", drum_map_file_pattern,           this, tr("Muse: Load Drum Map"), 0);        if (fn.isEmpty())              return; @@ -748,7 +760,8 @@ ende:  void DrumEdit::save()        { -      QString fn = getSaveFileName(QString("drummaps"), map_file_pattern, +      //QString fn = getSaveFileName(QString("drummaps"), map_file_pattern, +      QString fn = getSaveFileName(QString("drummaps"), drum_map_file_save_pattern,          this, tr("MusE: Store Drum Map"));        if (fn.isEmpty())              return; diff --git a/muse/muse/midiedit/pianoroll.cpp b/muse/muse/midiedit/pianoroll.cpp index 0a5a3aea..e02619c9 100644 --- a/muse/muse/midiedit/pianoroll.cpp +++ b/muse/muse/midiedit/pianoroll.cpp @@ -19,6 +19,7 @@  #include <qapplication.h>  #include <qclipboard.h>  #include <qdir.h> +#include <qaction.h>  #include <stdio.h> diff --git a/muse/muse/midiseq.cpp b/muse/muse/midiseq.cpp index 89b88804..f3dfe870 100644 --- a/muse/muse/midiseq.cpp +++ b/muse/muse/midiseq.cpp @@ -665,6 +665,9 @@ void MidiSeq::processTimerTick()              // printf("Midi Time Code Sync generation not impl.\n");  //            } +      // P3.3.25 +      int tickpos = audio->tickPos(); +      bool extsync = extSyncFlag.value();        //        // play all events upto curFrame        // @@ -679,7 +682,11 @@ void MidiSeq::processTimerTick()                    continue;              iMPEvent i = md->nextPlayEvent();              for (; i != el->end(); ++i) { -                  if (i->time() > curFrame) { +                  // P3.3.25 +                  // If syncing to external midi sync, we cannot use the tempo map. +                  // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. +                  //if (i->time() > curFrame) { +                  if (i->time() > (extsync ? tickpos : curFrame)) {                          //printf("  curT %d  frame %d\n", i->time(), curFrame);                          break; // skip this event                          } diff --git a/muse/muse/mixer/amixer.cpp b/muse/muse/mixer/amixer.cpp index 18361376..da51f8f6 100644 --- a/muse/muse/mixer/amixer.cpp +++ b/muse/muse/mixer/amixer.cpp @@ -11,6 +11,7 @@  #include <qapplication.h>  #include <qmenubar.h> +#include <qaction.h>  #include "app.h"  #include "amixer.h" diff --git a/muse/muse/mixer/rack.cpp b/muse/muse/mixer/rack.cpp index 4da36afe..57fc4b78 100644 --- a/muse/muse/mixer/rack.cpp +++ b/muse/muse/mixer/rack.cpp @@ -269,12 +269,16 @@ void EffectRack::doubleClicked(QListBoxItem* it)  void EffectRack::savePreset(int idx)        { -      QString name = getSaveFileName(QString(""), plug_file_pattern, this, +      //QString name = getSaveFileName(QString(""), plug_file_pattern, this, +      QString name = getSaveFileName(QString(""), preset_file_save_pattern, this,           tr("MusE: Save Preset")); -      FILE* presetFp = fopen(name.ascii(),"w+"); +       +      //FILE* presetFp = fopen(name.ascii(),"w+"); +      bool popenFlag; +      FILE* presetFp = fileOpen(this, name, QString(".pre"), "w", popenFlag, false, true);        if (presetFp == 0) { -            fprintf(stderr, "EffectRack::savePreset() fopen failed: %s\n", -               strerror(errno)); +            //fprintf(stderr, "EffectRack::savePreset() fopen failed: %s\n", +            //   strerror(errno));              return;              }        Xml xml(presetFp); @@ -288,16 +292,28 @@ void EffectRack::savePreset(int idx)                  }              else {                  printf("no plugin!\n"); -                fclose(presetFp); +                //fclose(presetFp); +                if (popenFlag) +                      pclose(presetFp); +                else +                      fclose(presetFp);                  return;                  }              }        else {            printf("no pipe!\n"); -          fclose(presetFp); +          //fclose(presetFp); +          if (popenFlag) +                pclose(presetFp); +          else +                fclose(presetFp);            return;            } -      fclose(presetFp); +      //fclose(presetFp); +      if (popenFlag) +            pclose(presetFp); +      else +            fclose(presetFp);        }  void EffectRack::startDrag(int idx) @@ -377,17 +393,26 @@ void EffectRack::dropEvent(QDropEvent *event)              if(QTextDrag::decode(event, text))                  {                  text = text.stripWhiteSpace(); -                if (text.endsWith(".pre", false)) +                // Changed by T356. +                //if (text.endsWith(".pre", false)) +                if (text.endsWith(".pre", false) || text.endsWith(".pre.gz", false) || text.endsWith(".pre.bz2", false))                      {                      QUrl url(text);                      QString newPath = url.path(); -                    bool popenFlag = false; +                    //bool popenFlag = false; +                    bool popenFlag;                      FILE* fp = fileOpen(this, newPath, ".pre", "r", popenFlag, false, false);                      if (fp) {                          Xml xml(fp);                          initPlugin(xml, idx); +                         +                        // Added by T356. +                        if (popenFlag) +                              pclose(fp); +                        else +                              fclose(fp);                          }                      }                  else if (event->provides("text/x-muse-plugin")) diff --git a/muse/muse/plugin.cpp b/muse/muse/plugin.cpp index ad9a7ce9..bed29859 100644 --- a/muse/muse/plugin.cpp +++ b/muse/muse/plugin.cpp @@ -53,11 +53,21 @@  PluginList plugins; +/*  static const char* preset_file_pattern[] = { -      QT_TR_NOOP("presets (*.pre *.pre.gz *.pre.bz2)"), +      QT_TR_NOOP("Presets (*.pre *.pre.gz *.pre.bz2)"), +      QT_TR_NOOP("All Files (*)"), +      0 +      }; + +static const char* preset_file_save_pattern[] = { +      QT_TR_NOOP("Presets (*.pre)"), +      QT_TR_NOOP("gzip compressed presets (*.pre.gz)"), +      QT_TR_NOOP("bzip2 compressed presets (*.pre.bz2)"),        QT_TR_NOOP("All Files (*)"),        0        }; +*/  int PluginDialog::selectedPlugType = 0;  QStringList PluginDialog::sortItems = QStringList(); @@ -2383,7 +2393,8 @@ void PluginGui::save()        s += plugin->plugin()->label();        s += "/"; -      QString fn = getSaveFileName(s, preset_file_pattern, this, +      //QString fn = getSaveFileName(s, preset_file_pattern, this, +      QString fn = getSaveFileName(s, preset_file_save_pattern, this,          tr("MusE: save preset"));        if (fn.isEmpty())              return; diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index 6bd5f9b8..9d0c6ee5 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -13,6 +13,7 @@  #include <qmessagebox.h>  #include <qpopupmenu.h>  #include <qdir.h> +#include <qaction.h>  #include "app.h"  #include "song.h" diff --git a/muse/muse/sync.cpp b/muse/muse/sync.cpp index fe3dcfee..1d032cdd 100644 --- a/muse/muse/sync.cpp +++ b/muse/muse/sync.cpp @@ -48,6 +48,9 @@ static bool mtcSync;    // receive complete mtc frame?  // static bool mcStart = false;  // static int mcStartTick; +// p3.3.25 +unsigned int midiExtSyncTicks = 0; +  //---------------------------------------------------------  //  MidiSyncInfo  //--------------------------------------------------------- @@ -650,6 +653,14 @@ void MidiSeq::realtimeSystemInput(int port, int c)                      if(p != port && midiPorts[p].syncInfo().MCOut())                        midiPorts[p].sendClock(); +                  // p3.3.25 +                  if(audio->isPlaying()) +                  { +                    int div = config.division/24; +                    midiExtSyncTicks += div; +                  } +                   +                  /*                    double mclock0 = curTime();                    // Difference in time last 2 rounds:                    double tdiff0   = mclock0 - mclock1; @@ -675,7 +686,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          }                    // Compare w audio if playing: -                  if (playStateExt == true /* audio->isPlaying() */ /*state == PLAY*/) { +                  if (playStateExt == true ) {  //audio->isPlaying()  state == PLAY                          //BEGIN standard setup:                          recTick  += config.division / 24; // The one we're syncing to                          int tempo = tempomap.tempo(0); @@ -697,13 +708,15 @@ void MidiSeq::realtimeSystemInput(int port, int c)                                        songtick, recTick, tickdiff, song_beat, sync_beat, scale, curFrame);                                } -                        if ((mclock2 !=0.0) && (tdiff1 > 0.0) /*&& fabs(tickdiff) > 0.5*/ && lastTempo != 0) { +                        //if ((mclock2 !=0.0) && (tdiff1 > 0.0) && fabs(tickdiff) > 0.5 && lastTempo != 0) { +                        if ((mclock2 !=0.0) && (tdiff1 > 0.0) && lastTempo != 0) {                                // Interpolate:                                double tickdiff1 = songtick1 - recTick1;                                double tickdiff2 = songtick2 - recTick2; -                              double newtickdiff = (tickdiff1+tickdiff2)/250; /*tickdiff/5.0  + +                              double newtickdiff = (tickdiff1+tickdiff2)/250;  +                                                   //tickdiff/5.0  +                                                     tickdiff1/16.0 + -                                                   tickdiff2/24.0;*/  //5 mins 30 secs on 116BPM, -p 512 jackd +                                                   tickdiff2/24.0;  //5 mins 30 secs on 116BPM, -p 512 jackd                                if (newtickdiff != 0.0) {                                      int newTempo = tempomap.tempo(0); @@ -757,6 +770,7 @@ void MidiSeq::realtimeSystemInput(int port, int c)                          }                    mclock2 = mclock1;                    mclock1 = mclock0; +                  */                    }                    break;              case 0xf9:  // midi tick  (every 10 msec) diff --git a/muse/muse/transport.cpp b/muse/muse/transport.cpp index cb290044..7444765e 100644 --- a/muse/muse/transport.cpp +++ b/muse/muse/transport.cpp @@ -16,6 +16,7 @@  #include <qlayout.h>  #include <qtoolbutton.h>  #include <qcombobox.h> +#include <qaction.h>  #include "song.h"  #include "transport.h" diff --git a/muse/muse/wave.cpp b/muse/muse/wave.cpp index ac26d5e9..fab1a9cd 100644 --- a/muse/muse/wave.cpp +++ b/muse/muse/wave.cpp @@ -29,6 +29,7 @@  //#define WAVE_DEBUG  //#define WAVE_DEBUG_PRC +/*  const char* audioFilePattern[] = {        "Wave/Binary (*.wav *.ogg *.bin)",        "Wave (*.wav *.ogg)", @@ -36,6 +37,7 @@ const char* audioFilePattern[] = {        "All Files (*)",        0        }; +*/  const int cacheMag = 128;  // ClipList* waveClips; @@ -786,8 +788,9 @@ void MusE::importWave()                "a wave track"));              return;              } -      QString fn = getOpenFileName(lastWavePath, audioFilePattern, this, -         tr("Import Wave File"), 0); +      //QString fn = getOpenFileName(lastWavePath, audioFilePattern, this, +      QString fn = getOpenFileName(lastWavePath, audio_file_pattern, this, +         tr("Import Wave File"), 0);                                            if (!fn.isEmpty()) {              lastWavePath = fn;              importWaveToTrack(fn); diff --git a/muse/muse/waveedit/waveedit.cpp b/muse/muse/waveedit/waveedit.cpp index 527c3dbf..a7b4c511 100644 --- a/muse/muse/waveedit/waveedit.cpp +++ b/muse/muse/waveedit/waveedit.cpp @@ -37,6 +37,7 @@  #include <qheader.h>  #include <qpopupmenu.h>  #include <qmenubar.h> +#include <qaction.h>  extern QColor readColor(Xml& xml); diff --git a/muse/muse/widgets/filedialog.cpp b/muse/muse/widgets/filedialog.cpp index ba599a3c..90120654 100644 --- a/muse/muse/widgets/filedialog.cpp +++ b/muse/muse/widgets/filedialog.cpp @@ -263,11 +263,39 @@ void ContentsPreview::previewUrl(const QUrl& url)        }  //--------------------------------------------------------- +//   getFilterExtension +//--------------------------------------------------------- + +QString getFilterExtension(const QString &filter) +{ +  // +  // Return the first extension found. Must contain at least one * character. +  // +   +  int pos = filter.find('*'); +  if(pos == -1) +    return QString();  +   +  QString filt; +  int len = filter.length(); +  ++pos; +  for( ; pos < len; ++pos) +  { +    QChar c = filter[pos]; +    if((c == ')') || (c == ';') || (c == ',') || (c == ' ')) +      break;  +    filt += filter[pos]; +  } +  return filt; +} + +//---------------------------------------------------------  //   getOpenFileName  //---------------------------------------------------------  QString getOpenFileName(const QString &startWith, -   const char** filters, QWidget* parent, const QString& name, bool* all) +   //const char** filters, QWidget* parent, const QString& name, bool* all) +   const QStringList& filters, QWidget* parent, const QString& name, bool* all)        {        QString initialSelection;        MFileDialog *dlg = new MFileDialog(startWith, QString::null, parent, false); @@ -294,7 +322,8 @@ QString getOpenFileName(const QString &startWith,  //---------------------------------------------------------  QString getSaveFileName(const QString &startWith, -   const char** filters, QWidget* parent, const QString& name) +   //const char** filters, QWidget* parent, const QString& name) +   const QStringList& filters, QWidget* parent, const QString& name)        {        MFileDialog *dlg = new MFileDialog(startWith, QString::null, parent, true);        dlg->setFilters(filters); @@ -307,47 +336,39 @@ QString getSaveFileName(const QString &startWith,        // Added by T356.        QString filt = dlg->selectedFilter(); -      int p2 = filt.findRev(')'); -      if(p2 != -1) +      filt = getFilterExtension(filt); +      // Do we have a valid extension? +      if(!filt.isEmpty())        { -        int p1 = filt.findRev('*', p2); -        if(p1 != -1) +        // If the rightmost characters of the filename do not already contain +        //  the extension, add the extension to the filename. +        //if(result.right(filt.length()) != filt) +        if(!result.endsWith(filt)) +          result += filt; +      } +      else +      { +        // No valid extension, or just * was given. Although it would be nice to allow no extension +        //  or any desired extension by commenting this section out, it's probably not a good idea to do so. +        // +        // NOTE: Most calls to this routine getSaveFileName() are followed by fileOpen(), +        //  which can tack on its own extension, but only if the *complete* extension is blank.  +        // So there is some overlap going on. Enabling this actually stops that action,  +        //  but only if there are no errors in the list of filters. fileOpen() will act as a 'catchall'. +        // +        // Force the filter list to the first one (the preferred one), and then get the filter. +        dlg->setSelectedFilter(0); +        filt = dlg->selectedFilter(); +        filt = getFilterExtension(filt); +             +        // Do we have a valid extension? +        if(!filt.isEmpty())          { -          filt = filt.mid(p1 + 1, p2 - p1 - 1); -          // Do we have a valid extension? -          if(!filt.isEmpty()) -          { -            // If the rightmost characters of the filename do not already contain -            //  the extension, add the extension to the filename. -            if(result.right(filt.length()) != filt) -              result += filt; -          } -          else -          { -            // Works, but no, we want to allow saving as any name without an extension... -            /* -            // Force the filter list to the first one (the preferred one), and then get the filter. -            dlg->setSelectedFilter(0); -            filt = dlg->selectedFilter(); -            p2 = filt.findRev(')'); -            if(p2 != -1) -            { -              p1 = filt.findRev('*', p2); -              if(p1 != -1) -              { -                filt = filt.mid(p1 + 1, p2 - p1 - 1); -                // Do we have a valid extension? -                if(!filt.isEmpty()) -                { -                  // If the rightmost characters of the filename do not already contain -                  //  the extension, add the extension to the filename. -                  if(result.right(filt.length()) != filt) -                    result += filt; -                } -              } -            } -            */ -          } +          // If the rightmost characters of the filename do not already contain +          //  the extension, add the extension to the filename. +          //if(result.right(filt.length()) != filt) +          if(!result.endsWith(filt)) +            result += filt;          }        } @@ -360,7 +381,8 @@ QString getSaveFileName(const QString &startWith,  //---------------------------------------------------------  QString getImageFileName(const QString& startWith, -   const char** filters, QWidget* parent, const QString& name) +   //const char** filters, QWidget* parent, const QString& name) +   const QStringList& filters, QWidget* parent, const QString& name)        {        QString initialSelection;  	QString* workingDirectory = new QString(QDir::currentDirPath()); @@ -491,7 +513,8 @@ MFile::~MFile()  //   open  //--------------------------------------------------------- -FILE* MFile::open(const char* mode, const char** pattern, +//FILE* MFile::open(const char* mode, const char** pattern, +FILE* MFile::open(const char* mode, const QStringList& pattern,     QWidget* parent, bool noError, bool warnIfOverwrite, const QString& caption)        {        QString name; diff --git a/muse/muse/widgets/filedialog.h b/muse/muse/widgets/filedialog.h index ca668a80..bff9e9d5 100644 --- a/muse/muse/widgets/filedialog.h +++ b/muse/muse/widgets/filedialog.h @@ -8,6 +8,7 @@  #include <qfiledialog.h>  class FileDialogButtons; +class QStringList;  //---------------------------------------------------------  //   MFileDialog @@ -53,12 +54,15 @@ class ContentsPreview : public QWidget, public QFilePreview {        ~ContentsPreview();        }; -QString getSaveFileName(const QString& startWidth, const char** filter, +//QString getSaveFileName(const QString& startWidth, const char** filter, +QString getSaveFileName(const QString& startWidth, const QStringList& filters,           QWidget* parent, const QString& name); -QString getOpenFileName(const QString& startWidth, const char** filter, +//QString getOpenFileName(const QString& startWidth, const char** filter, +QString getOpenFileName(const QString& startWidth, const QStringList& filters,           QWidget* parent, const QString& name, bool* openAll); -QString getImageFileName(const QString& startWith, -   const char** filters, QWidget* parent, const QString& name); +//QString getImageFileName(const QString& startWith, const char** filters,  +QString getImageFileName(const QString& startWith, const QStringList& filters,  +         QWidget* parent, const QString& name);  FILE* fileOpen(QWidget*, QString, const QString&,     const char*, bool&, bool = false, bool = false); @@ -78,7 +82,8 @@ class MFile {     public:        MFile(const QString& path, const QString& ext);        ~MFile(); -      FILE* open(const char* mode, const char** pattern, +      //FILE* open(const char* mode, const char** pattern, +      FILE* open(const char* mode, const QStringList& pattern,           QWidget* parent, bool noError,           bool warnIfOverwrite, const QString& caption);        };  | 
