summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/ChangeLog19
-rw-r--r--muse/muse/arranger/pcanvas.cpp3
-rw-r--r--muse/muse/audio.cpp23
-rw-r--r--muse/muse/globals.cpp167
-rw-r--r--muse/muse/globals.h35
-rw-r--r--muse/muse/icons.cpp1
-rw-r--r--muse/muse/master/lmaster.cpp1
-rw-r--r--muse/muse/master/masteredit.cpp1
-rw-r--r--muse/muse/midi.cpp115
-rw-r--r--muse/muse/midiedit/drumedit.cpp19
-rw-r--r--muse/muse/midiedit/pianoroll.cpp1
-rw-r--r--muse/muse/midiseq.cpp9
-rw-r--r--muse/muse/mixer/amixer.cpp1
-rw-r--r--muse/muse/mixer/rack.cpp43
-rw-r--r--muse/muse/plugin.cpp15
-rw-r--r--muse/muse/song.cpp1
-rw-r--r--muse/muse/sync.cpp22
-rw-r--r--muse/muse/transport.cpp1
-rw-r--r--muse/muse/wave.cpp7
-rw-r--r--muse/muse/waveedit/waveedit.cpp1
-rw-r--r--muse/muse/widgets/filedialog.cpp109
-rw-r--r--muse/muse/widgets/filedialog.h15
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);
};