From 6ba5244898afe623cbd219539c796e286429a24b Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Thu, 21 Jan 2010 23:21:47 +0000 Subject: See ChangeLog --- muse/ChangeLog | 19 +++++ muse/muse/arranger/pcanvas.cpp | 3 +- muse/muse/audio.cpp | 23 +++++- muse/muse/globals.cpp | 167 +++++++++++++++++++++++++++++++++------ muse/muse/globals.h | 35 ++++++-- muse/muse/icons.cpp | 1 + muse/muse/master/lmaster.cpp | 1 + muse/muse/master/masteredit.cpp | 1 + muse/muse/midi.cpp | 115 +++++++++++++++++++++++---- muse/muse/midiedit/drumedit.cpp | 19 ++++- muse/muse/midiedit/pianoroll.cpp | 1 + muse/muse/midiseq.cpp | 9 ++- muse/muse/mixer/amixer.cpp | 1 + muse/muse/mixer/rack.cpp | 43 +++++++--- muse/muse/plugin.cpp | 15 +++- muse/muse/song.cpp | 1 + muse/muse/sync.cpp | 22 +++++- muse/muse/transport.cpp | 1 + muse/muse/wave.cpp | 7 +- muse/muse/waveedit/waveedit.cpp | 1 + muse/muse/widgets/filedialog.cpp | 109 +++++++++++++++---------- 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 -#include -#include +//#include +//#include #include -#include +//#include #include "value.h" #include "mtc.h" #include +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 +#include #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 #include #include +#include #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 #include #include +#include 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 #include #include +#include #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 #include #include +#include #include 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 #include +#include #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 #include #include +#include #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 #include #include +#include #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 #include #include +#include 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 @@ -262,12 +262,40 @@ void ContentsPreview::previewUrl(const QUrl& url) setBackgroundPixmap(*bg); } +//--------------------------------------------------------- +// 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 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); }; -- cgit v1.2.3