summaryrefslogtreecommitdiff
path: root/muse2/muse
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2012-10-09 20:04:43 +0000
committerTim E. Real <termtech@rogers.com>2012-10-09 20:04:43 +0000
commit0368494d2ba85b24da193512972ccfeada99cf52 (patch)
treefff25f5a6aecdd722c98a938fa9b03f1fec9febc /muse2/muse
parentc5e6b8cfa9d8615a32ce2aad28f4d091482be91d (diff)
!!! Song type is now removed !!! : See ChangeLog
Diffstat (limited to 'muse2/muse')
-rw-r--r--muse2/muse/arranger/arranger.cpp38
-rw-r--r--muse2/muse/arranger/arranger.h3
-rw-r--r--muse2/muse/arranger/arrangerview.cpp3
-rw-r--r--muse2/muse/arranger/tlist.cpp12
-rw-r--r--muse2/muse/audio.cpp2
-rw-r--r--muse2/muse/conf.cpp99
-rw-r--r--muse2/muse/ctrl/ctrlcanvas.cpp40
-rw-r--r--muse2/muse/driver/alsamidi.cpp4
-rw-r--r--muse2/muse/driver/jackmidi.cpp1
-rw-r--r--muse2/muse/dssihost.cpp4
-rw-r--r--muse2/muse/dssihost.h5
-rw-r--r--muse2/muse/exportmidi.cpp394
-rw-r--r--muse2/muse/gconfig.cpp6
-rw-r--r--muse2/muse/gconfig.h23
-rw-r--r--muse2/muse/importmidi.cpp206
-rw-r--r--muse2/muse/instruments/editinstrument.cpp89
-rw-r--r--muse2/muse/instruments/minstrument.cpp186
-rw-r--r--muse2/muse/instruments/minstrument.h16
-rw-r--r--muse2/muse/liste/editevent.cpp4
-rw-r--r--muse2/muse/midi.cpp105
-rw-r--r--muse2/muse/midi.h35
-rw-r--r--muse2/muse/mididev.cpp4
-rw-r--r--muse2/muse/midifile.cpp105
-rw-r--r--muse2/muse/midifile.h39
-rw-r--r--muse2/muse/mpevent.cpp106
-rw-r--r--muse2/muse/mpevent.h5
-rw-r--r--muse2/muse/song.cpp8
-rw-r--r--muse2/muse/song.h5
-rw-r--r--muse2/muse/songfile.cpp5
-rw-r--r--muse2/muse/synth.cpp6
-rw-r--r--muse2/muse/synth.h18
-rw-r--r--muse2/muse/ticksynth.cpp5
-rw-r--r--muse2/muse/vst.h5
-rw-r--r--muse2/muse/widgets/configmidifilebase.ui442
-rw-r--r--muse2/muse/widgets/gensetbase.ui4
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp16
-rw-r--r--muse2/muse/widgets/musewidgetsplug.cpp6
37 files changed, 1336 insertions, 718 deletions
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp
index 8d2328c3..942a5013 100644
--- a/muse2/muse/arranger/arranger.cpp
+++ b/muse2/muse/arranger/arranger.cpp
@@ -268,18 +268,6 @@ Arranger::Arranger(ArrangerView* parent, const char* name)
toolbar->addWidget(lenEntry);
connect(lenEntry, SIGNAL(valueChanged(int)), SLOT(songlenChanged(int)));
- typeBox = new LabelCombo(tr("Type"), 0);
- typeBox->insertItem(0, tr("NO"));
- typeBox->insertItem(1, tr("GM"));
- typeBox->insertItem(2, tr("GS"));
- typeBox->insertItem(3, tr("XG"));
- typeBox->setCurrentIndex(0);
- typeBox->setToolTip(tr("midi song type"));
- typeBox->setWhatsThis(tr("midi song type"));
- typeBox->setFocusPolicy(Qt::TabFocus);
- toolbar->addWidget(typeBox);
- connect(typeBox, SIGNAL(activated(int)), SLOT(modeChange(int)));
-
label = new QLabel(tr("Pitch"));
label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
label->setIndent(3);
@@ -668,9 +656,6 @@ void Arranger::songChanged(MusECore::SongChangedFlags_t type)
lenEntry->blockSignals(false);
}
- if(type & SC_SONG_TYPE)
- setMode(MusEGlobal::song->mtype());
-
if(type & (SC_SELECTION | SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_TRACK_MODIFIED))
trackSelectionChanged();
@@ -739,29 +724,6 @@ void Arranger::trackSelectionChanged()
}
//---------------------------------------------------------
-// modeChange
-//---------------------------------------------------------
-
-void Arranger::modeChange(int mode)
- {
- MusEGlobal::song->setMType(MType(mode));
- updateTrackInfo(-1);
- focusCanvas();
- }
-
-//---------------------------------------------------------
-// setMode
-//---------------------------------------------------------
-
-void Arranger::setMode(int mode)
- {
- typeBox->blockSignals(true);
- // This will only set if different.
- typeBox->setCurrentIndex(mode);
- typeBox->blockSignals(false);
- }
-
-//---------------------------------------------------------
// writeStatus
//---------------------------------------------------------
diff --git a/muse2/muse/arranger/arranger.h b/muse2/muse/arranger/arranger.h
index dd2c5290..e7d48d70 100644
--- a/muse2/muse/arranger/arranger.h
+++ b/muse2/muse/arranger/arranger.h
@@ -135,7 +135,6 @@ class Arranger : public QWidget {
MusECore::Track* selected;
- LabelCombo* typeBox;
QToolButton* ib;
int trackInfoType;
Splitter* split;
@@ -159,7 +158,6 @@ class Arranger : public QWidget {
void trackSelectionChanged();
void trackInfoScroll(int);
void songChanged(MusECore::SongChangedFlags_t);
- void modeChange(int);
void setTime(unsigned);
void globalPitchChanged(int);
void globalTempoChanged(int);
@@ -216,7 +214,6 @@ class Arranger : public QWidget {
Arranger(ArrangerView* parent, const char* name = 0);
PartCanvas* getCanvas() { return canvas; }
- void setMode(int);
void reset();
void writeStatus(int level, MusECore::Xml&);
diff --git a/muse2/muse/arranger/arrangerview.cpp b/muse2/muse/arranger/arrangerview.cpp
index 66e3bbbb..a2024159 100644
--- a/muse2/muse/arranger/arrangerview.cpp
+++ b/muse2/muse/arranger/arrangerview.cpp
@@ -388,8 +388,7 @@ void ArrangerView::songChanged(MusECore::SongChangedFlags_t type)
//SC_SIG | SC_TEMPO | SC_MASTER |
//SC_MIDI_TRACK_PROP |
SC_CONFIG |
- SC_DRUMMAP|
- SC_SONG_TYPE))
+ SC_DRUMMAP))
visTracks->updateVisibleTracksButtons();
}
diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp
index d16a8d29..dc65b0c1 100644
--- a/muse2/muse/arranger/tlist.cpp
+++ b/muse2/muse/arranger/tlist.cpp
@@ -492,7 +492,7 @@ void TList::paint(const QRect& r)
MusECore::MidiInstrument* instr = mp->instrument();
QString name;
if (val!=MusECore::CTRL_VAL_UNKNOWN)
- name = instr->getPatchName(mt->outChannel(), val, MusEGlobal::song->mtype(), mt->isDrumTrack());
+ name = instr->getPatchName(mt->outChannel(), val, mt->isDrumTrack());
else
name = tr("<unknown>");
@@ -2123,8 +2123,8 @@ void TList::mousePressEvent(QMouseEvent* ev)
else
{
MusECore::MidiInstrument* instr = mp->instrument();
- if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false);
- else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false);
+ if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, false);
+ else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, false);
}
if (val != oldval)
@@ -2169,7 +2169,7 @@ void TList::mousePressEvent(QMouseEvent* ev)
MusECore::MidiInstrument* instr = mp->instrument();
PopupMenu* pup = new PopupMenu(true);
- instr->populatePatchPopup(pup, mt->outChannel(), MusEGlobal::song->mtype(), mt->isDrumTrack());
+ instr->populatePatchPopup(pup, mt->outChannel(), mt->isDrumTrack());
if(pup->actions().count() == 0)
{
@@ -2623,8 +2623,8 @@ void TList::wheelEvent(QWheelEvent* ev)
else
{
MusECore::MidiInstrument* instr = mp->instrument();
- if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false);
- else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, MusEGlobal::song->mtype(), false);
+ if (delta>0) val=instr->getNextPatch(mt->outChannel(), val, false);
+ else if (delta<0) val=instr->getPrevPatch(mt->outChannel(), val, false);
}
if (val != oldval)
diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp
index 6349971b..b03366e1 100644
--- a/muse2/muse/audio.cpp
+++ b/muse2/muse/audio.cpp
@@ -702,7 +702,7 @@ void Audio::processMsg(AudioMsg* msg)
for (int i = 0; i < MIDI_PORTS; ++i)
{
if(MusEGlobal::midiPorts[i].device())
- MusEGlobal::midiPorts[i].instrument()->reset(i, MusEGlobal::song->mtype());
+ MusEGlobal::midiPorts[i].instrument()->reset(i);
}
break;
case SEQM_INIT_DEVICES:
diff --git a/muse2/muse/conf.cpp b/muse2/muse/conf.cpp
index 37959f0f..21a50e3d 100644
--- a/muse2/muse/conf.cpp
+++ b/muse2/muse/conf.cpp
@@ -804,6 +804,28 @@ void readConfiguration(Xml& xml, bool doReadMidiPortConfig, bool doReadGlobalCon
MusEGlobal::config.expOptimNoteOffs = xml.parseInt();
else if (tag == "importMidiSplitParts")
MusEGlobal::config.importMidiSplitParts = xml.parseInt();
+ else if (tag == "importDevNameMetas")
+ MusEGlobal::config.importDevNameMetas = xml.parseInt();
+ else if (tag == "importInstrNameMetas")
+ MusEGlobal::config.importInstrNameMetas = xml.parseInt();
+ else if (tag == "exportPortsDevices")
+ {
+ int i = xml.parseInt();
+ if(i >= MusEGlobal::EXPORT_PORTS_DEVICES_END)
+ i = MusEGlobal::EXPORT_PORTS_DEVICES_ALL;
+ MusEGlobal::config.exportPortsDevices = MusEGlobal::ExportPortsDevices_t(i);
+ }
+ else if (tag == "exportPortDeviceSMF0")
+ MusEGlobal::config.exportPortDeviceSMF0 = xml.parseInt();
+ else if (tag == "exportModeInstr")
+ {
+ int i = xml.parseInt();
+ if(i >= MusEGlobal::EXPORT_MODE_INSTR_END)
+ i = MusEGlobal::EXPORT_MODE_INSTR_ALL;
+ MusEGlobal::config.exportModeInstr = MusEGlobal::ExportModeInstr_t(i);
+ }
+ else if (tag == "importMidiDefaultInstr")
+ MusEGlobal::config.importMidiDefaultInstr = xml.parse1();
else if (tag == "showSplashScreen")
MusEGlobal::config.showSplashScreen = xml.parseInt();
@@ -1087,7 +1109,7 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
// or ALSA reorders or renames devices etc etc, then we have at least kept the track <-> port routes.
mport->defaultInChannels() != (1<<MIDI_CHANNELS)-1 || // p4.0.17 Default is now to connect to all channels.
mport->defaultOutChannels() ||
- (!mport->instrument()->iname().isEmpty() && mport->instrument()->iname() != "GM") ||
+ (!mport->instrument()->iname().isEmpty() && mport->instrument()->midiType() != MT_GM) ||
!mport->syncInfo().isDefault())
used = true;
else
@@ -1114,7 +1136,8 @@ static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)
xml.intTag(level, "defaultOutChans", mport->defaultOutChannels());
if(!mport->instrument()->iname().isEmpty() && // Tim.
- (mport->instrument()->iname() != "GM")) // FIXME: TODO: Make this user configurable.
+ (mport->instrument()->iname() != "GM")) // FIXME: TODO: Make this user configurable.
+ //(mport->instrument()->midiType() != MT_GM))
xml.strTag(level, "instrument", mport->instrument()->iname());
if (dev) {
@@ -1203,6 +1226,12 @@ void MusE::writeGlobalConfiguration(int level, MusECore::Xml& xml) const
xml.intTag(level, "exp2ByteTimeSigs", MusEGlobal::config.exp2ByteTimeSigs);
xml.intTag(level, "expOptimNoteOffs", MusEGlobal::config.expOptimNoteOffs);
xml.intTag(level, "importMidiSplitParts", MusEGlobal::config.importMidiSplitParts);
+ xml.intTag(level, "importDevNameMetas", MusEGlobal::config.importDevNameMetas);
+ xml.intTag(level, "importInstrNameMetas", MusEGlobal::config.importInstrNameMetas);
+ xml.intTag(level, "exportPortsDevices", MusEGlobal::config.exportPortsDevices);
+ xml.intTag(level, "exportPortDeviceSMF0", MusEGlobal::config.exportPortDeviceSMF0);
+ xml.intTag(level, "exportModeInstr", MusEGlobal::config.exportModeInstr);
+ xml.strTag(level, "importMidiDefaultInstr", MusEGlobal::config.importMidiDefaultInstr);
xml.intTag(level, "startMode", MusEGlobal::config.startMode);
xml.strTag(level, "startSong", MusEGlobal::config.startSong);
xml.intTag(level, "startSongLoadConfig", MusEGlobal::config.startSongLoadConfig);
@@ -1478,6 +1507,18 @@ MidiFileConfig::MidiFileConfig(QWidget* parent)
void MidiFileConfig::updateValues()
{
+ importDefaultInstr->clear();
+ for(MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i)
+ if(!dynamic_cast<MusECore::SynthI*>(*i)) // Sorry, no synths for now.
+ importDefaultInstr->addItem((*i)->iname());
+ int idx = importDefaultInstr->findText(MusEGlobal::config.importMidiDefaultInstr);
+ if(idx != -1)
+ importDefaultInstr->setCurrentIndex(idx);
+
+ QString defInstr = importDefaultInstr->currentText();
+ if(!defInstr.isEmpty())
+ MusEGlobal::config.importMidiDefaultInstr = defInstr;
+
int divisionIdx = 2;
switch(MusEGlobal::config.midiDivision) {
case 96: divisionIdx = 0; break;
@@ -1493,6 +1534,37 @@ void MidiFileConfig::updateValues()
splitPartsCheckBox->setChecked(MusEGlobal::config.importMidiSplitParts);
newDrumsCheckbox->setChecked(MusEGlobal::config.importMidiNewStyleDrum);
oldDrumsCheckbox->setChecked(!MusEGlobal::config.importMidiNewStyleDrum);
+ importDevNameMetas->setChecked(MusEGlobal::config.importDevNameMetas);
+ importInstrNameMetas->setChecked(MusEGlobal::config.importInstrNameMetas);
+ exportPortDeviceSMF0->setChecked(MusEGlobal::config.exportPortDeviceSMF0);
+ switch(MusEGlobal::config.exportPortsDevices)
+ {
+ case MusEGlobal::PORT_NUM_META:
+ exportPortMetas->setChecked(true);
+ break;
+ case MusEGlobal::DEVICE_NAME_META:
+ exportDeviceNameMetas->setChecked(true);
+ break;
+ case MusEGlobal::EXPORT_PORTS_DEVICES_ALL:
+ exportPortAndDeviceNameMetas->setChecked(true);
+ break;
+ default:
+ printf("MidiFileConfig::updateValues FIXME: Unknown exportPortsDevices type\n");
+ }
+ switch(MusEGlobal::config.exportModeInstr)
+ {
+ case MusEGlobal::MODE_SYSEX:
+ exportModeSysexes->setChecked(true);
+ break;
+ case MusEGlobal::INSTRUMENT_NAME_META:
+ exportInstrumentNames->setChecked(true);
+ break;
+ case MusEGlobal::EXPORT_MODE_INSTR_ALL:
+ exportModeAndInstrName->setChecked(true);
+ break;
+ default:
+ printf("MidiFileConfig::updateValues FIXME: Unknown exportModeInstr type\n");
+ }
}
//---------------------------------------------------------
@@ -1501,6 +1573,10 @@ void MidiFileConfig::updateValues()
void MidiFileConfig::okClicked()
{
+ QString defInstr = importDefaultInstr->currentText();
+ if(!defInstr.isEmpty())
+ MusEGlobal::config.importMidiDefaultInstr = defInstr;
+
int divisionIdx = divisionCombo->currentIndex();
int divisions[3] = { 96, 192, 384 };
@@ -1513,7 +1589,24 @@ void MidiFileConfig::okClicked()
MusEGlobal::config.exp2ByteTimeSigs = twoByteTimeSigs->isChecked();
MusEGlobal::config.importMidiSplitParts = splitPartsCheckBox->isChecked();
MusEGlobal::config.importMidiNewStyleDrum = newDrumsCheckbox->isChecked();
-
+
+ MusEGlobal::config.importDevNameMetas = importDevNameMetas->isChecked();
+ MusEGlobal::config.importInstrNameMetas = importInstrNameMetas->isChecked();
+ MusEGlobal::config.exportPortDeviceSMF0 = exportPortDeviceSMF0->isChecked();
+ if(exportPortMetas->isChecked())
+ MusEGlobal::config.exportPortsDevices = MusEGlobal::PORT_NUM_META;
+ else if(exportDeviceNameMetas->isChecked())
+ MusEGlobal::config.exportPortsDevices = MusEGlobal::DEVICE_NAME_META;
+ else if(exportPortAndDeviceNameMetas->isChecked())
+ MusEGlobal::config.exportPortsDevices = MusEGlobal::EXPORT_PORTS_DEVICES_ALL;
+
+ if(exportModeSysexes->isChecked())
+ MusEGlobal::config.exportModeInstr = MusEGlobal::MODE_SYSEX;
+ else if(exportInstrumentNames->isChecked())
+ MusEGlobal::config.exportModeInstr = MusEGlobal::INSTRUMENT_NAME_META;
+ else if(exportModeAndInstrName->isChecked())
+ MusEGlobal::config.exportModeInstr = MusEGlobal::EXPORT_MODE_INSTR_ALL;
+
MusEGlobal::muse->changeConfig(true); // write config file
close();
}
diff --git a/muse2/muse/ctrl/ctrlcanvas.cpp b/muse2/muse/ctrl/ctrlcanvas.cpp
index 8d4bc8a3..1b243204 100644
--- a/muse2/muse/ctrl/ctrlcanvas.cpp
+++ b/muse2/muse/ctrl/ctrlcanvas.cpp
@@ -943,12 +943,7 @@ void CtrlCanvas::newValRamp(int x1, int y1, int x2, int y2)
if (type == MusECore::CTRL_PROGRAM)
{
if (lastpv == MusECore::CTRL_VAL_UNKNOWN)
- {
- if (MusEGlobal::song->mtype() == MT_GM)
- event.setB(0xffff00 | (nval - 1));
- else
- event.setB(nval - 1);
- }
+ event.setB(nval - 1);
else
event.setB((lastpv & 0xffff00) | (nval - 1));
}
@@ -991,11 +986,7 @@ void CtrlCanvas::changeValRamp(int x1, int y1, int x2, int y2)
if (type == MusECore::CTRL_PROGRAM)
{
if (event.dataB() == MusECore::CTRL_VAL_UNKNOWN)
- {
--nval;
- if(MusEGlobal::song->mtype() == MT_GM)
- nval |= 0xffff00;
- }
else
nval = (event.dataB() & 0xffff00) | (nval - 1);
}
@@ -1066,11 +1057,7 @@ void CtrlCanvas::changeVal(int x1, int x2, int y)
if(type == MusECore::CTRL_PROGRAM)
{
if(event.dataB() == MusECore::CTRL_VAL_UNKNOWN)
- {
--nval;
- if(MusEGlobal::song->mtype() == MT_GM)
- nval |= 0xffff00;
- }
else
nval = (event.dataB() & 0xffff00) | (nval - 1);
}
@@ -1167,11 +1154,7 @@ void CtrlCanvas::newVal(int x1, int y)
if(event.dataB() == MusECore::CTRL_VAL_UNKNOWN)
{
if(lastpv == MusECore::CTRL_VAL_UNKNOWN)
- {
--nval;
- if(MusEGlobal::song->mtype() == MT_GM)
- nval |= 0xffff00;
- }
else
nval = (lastpv & 0xffff00) | (nval - 1);
}
@@ -1238,12 +1221,7 @@ void CtrlCanvas::newVal(int x1, int y)
if(type == MusECore::CTRL_PROGRAM)
{
if(lastpv == MusECore::CTRL_VAL_UNKNOWN)
- {
- if(MusEGlobal::song->mtype() == MT_GM)
- event.setB(0xffff00 | (newval - 1));
- else
- event.setB(newval - 1);
- }
+ event.setB(newval - 1);
else
event.setB((lastpv & 0xffff00) | (newval - 1));
}
@@ -1411,12 +1389,7 @@ void CtrlCanvas::newVal(int x1, int y1, int x2, int y2)
if(type == MusECore::CTRL_PROGRAM)
{
if(lastpv == MusECore::CTRL_VAL_UNKNOWN)
- {
- if(MusEGlobal::song->mtype() == MT_GM)
- event.setB(0xffff00 | (nval - 1));
- else
- event.setB(nval - 1);
- }
+ event.setB(nval - 1);
else
event.setB((lastpv & 0xffff00) | (nval - 1));
}
@@ -1900,7 +1873,12 @@ void CtrlCanvas::setCurDrumPitch(int instrument)
curDrumPitch = instrument;
else // new style drummap mode
{
- if (drumedit->get_instrument_map()[instrument].tracks.contains(curTrack))
+ // Crash protection by Tim.
+ // FIXME: Still, drum list is blank, editor can't edit. Other values of instrument or curDrumPitch just crash too.
+ // Seems only with drum tracks that were created by importing a midi file (then changed to use fluidsynth device?).
+ if(instrument == -1) curDrumPitch = -1;
+
+ else if (drumedit->get_instrument_map()[instrument].tracks.contains(curTrack))
curDrumPitch = drumedit->get_instrument_map()[instrument].pitch;
else
curDrumPitch = -2; // this means "invalid", but not "unused"
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp
index e3e71365..d8b3a947 100644
--- a/muse2/muse/driver/alsamidi.cpp
+++ b/muse2/muse/driver/alsamidi.cpp
@@ -426,8 +426,8 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
event.type = SND_SEQ_EVENT_STOP;
break;
default:
- printf("MidiAlsaDevice::putEvent(): event type %d not implemented\n",
- e.type());
+ if(MusEGlobal::debugMsg)
+ printf("MidiAlsaDevice::putEvent(): event type %d not implemented\n", e.type());
return true;
}
return putEvent(&event);
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index e3e67dfb..6b1506e1 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -752,7 +752,6 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
if(MusEGlobal::debugMsg)
printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
return true; // Absorb the event. Don't want it hanging around in the list.
- break;
}
return true;
diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp
index 01f9c0f3..c76631e4 100644
--- a/muse2/muse/dssihost.cpp
+++ b/muse2/muse/dssihost.cpp
@@ -2114,7 +2114,7 @@ void DssiSynthIF::doSelectProgram(LADSPA_Handle handle, int bank, int prog)
// getPatchName
//---------------------------------------------------------
-const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, MType /*type*/, bool /*drum*/)
+const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, bool /*drum*/)
{
unsigned program = prog & 0x7f;
int lbank = (prog >> 8) & 0xff;
@@ -2138,7 +2138,7 @@ const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, MType /*type*/, bo
// populatePatchPopup
//---------------------------------------------------------
-void DssiSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/)
+void DssiSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int /*ch*/, bool /*drum*/)
{
// The plugin can change the programs, patches etc.
// So make sure we're up to date by calling queryPrograms.
diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h
index 93038011..baa6adbe 100644
--- a/muse2/muse/dssihost.h
+++ b/muse2/muse/dssihost.h
@@ -171,9 +171,8 @@ class DssiSynthIF : public SynthIF, public PluginIBase
virtual void deactivate3() {}
- virtual const char* getPatchName(int, int, int, bool) const { return ""; }
- virtual const char* getPatchName(int, int, MType, bool);
- virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool);
+ virtual const char* getPatchName(int, int, bool);
+ virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool);
virtual void write(int level, Xml& xml) const;
diff --git a/muse2/muse/exportmidi.cpp b/muse2/muse/exportmidi.cpp
index 8f5af4c5..8e10884c 100644
--- a/muse2/muse/exportmidi.cpp
+++ b/muse2/muse/exportmidi.cpp
@@ -4,6 +4,7 @@
// $Id: exportmidi.cpp,v 1.9.2.1 2009/04/01 01:37:10 terminator356 Exp $
//
// (C) Copyright 1999-2003 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -23,9 +24,9 @@
#include <stdio.h>
#include <QString>
+#include <QMessageBox>
#include "al/sig.h" // Tim.
-
#include "app.h"
#include "midifile.h"
#include "midi.h"
@@ -83,12 +84,13 @@ static void addController(MPEventList* l, int tick, int port, int channel, int a
int lb = (b >> 8) & 0xff;
int pr = b & 0x7f;
int tickoffset = 0;
- switch(MusEGlobal::song->mtype()) {
- case MT_GM: // no HBANK/LBANK
- break;
- case MT_GS:
- case MT_XG:
- case MT_UNKNOWN:
+ // REMOVE Tim. Song type removal.
+ //switch(MusEGlobal::song->mtype()) {
+ // case MT_GM: // no HBANK/LBANK
+ // break;
+ // case MT_GS:
+ // case MT_XG:
+ // case MT_UNKNOWN:
if (hb != 0xff) {
l->add(MidiPlayEvent(tick, port, channel, ME_CONTROLLER, CTRL_HBANK, hb));
++tickoffset;
@@ -97,8 +99,8 @@ static void addController(MPEventList* l, int tick, int port, int channel, int a
l->add(MidiPlayEvent(tick+tickoffset, port, channel, ME_CONTROLLER, CTRL_LBANK, lb));
++tickoffset;
}
- break;
- }
+ // break;
+ // }
l->add(MidiPlayEvent(tick+tickoffset, port, channel, ME_PROGRAM, pr, 0));
}
else if (a < CTRL_NRPN14_OFFSET) { // RPN14 Controller
@@ -123,6 +125,109 @@ static void addController(MPEventList* l, int tick, int port, int channel, int a
}
}
+//---------------------------------------------------------
+// addEventList
+// part can be NULL meaning no part used.
+// track can be NULL meaning no concept of drum notes is allowed in init sequences.
+//---------------------------------------------------------
+
+static void addEventList(MusECore::EventList* evlist, MusECore::MPEventList* mpevlist, MusECore::MidiTrack* track, MusECore::Part* part, int port, int channel)
+{
+ for (MusECore::iEvent i = evlist->begin(); i != evlist->end(); ++i)
+ {
+ MusECore::Event ev = i->second;
+ int tick = ev.tick();
+ if(part)
+ tick += part->tick();
+ switch (ev.type())
+ {
+ case MusECore::Note:
+ {
+ if (ev.velo() == 0) {
+ printf("Warning: midi note has velocity 0, (ignored)\n");
+ continue;
+ }
+ int pitch;
+ if (track && track->type() == MusECore::Track::DRUM) {
+ // Map drum-notes to the drum-map values
+ int instr = ev.pitch();
+ pitch = MusEGlobal::drumMap[instr].anote;
+ }
+ else
+ pitch = ev.pitch();
+
+ int velo = ev.velo();
+ int len = ev.lenTick();
+
+ //---------------------------------------
+ // apply trackinfo values
+ //---------------------------------------
+
+ if (track && (track->transposition
+ || track->velocity
+ || track->compression != 100
+ || track->len != 100)) {
+ pitch += track->transposition;
+ if (pitch > 127)
+ pitch = 127;
+ if (pitch < 0)
+ pitch = 0;
+
+ velo += track->velocity;
+ velo = (velo * track->compression) / 100;
+ if (velo > 127)
+ velo = 127;
+ if (velo < 1) // no off event
+ velo = 1;
+ len = (len * track->len) / 100;
+ }
+ if (len <= 0)
+ len = 1;
+ mpevlist->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_NOTEON, pitch, velo));
+
+ if(MusEGlobal::config.expOptimNoteOffs) // Save space by replacing note offs with note on velocity 0
+ mpevlist->add(MusECore::MidiPlayEvent(tick+len, port, channel, MusECore::ME_NOTEON, pitch, 0));
+ else
+ mpevlist->add(MusECore::MidiPlayEvent(tick+len, port, channel, MusECore::ME_NOTEOFF, pitch, velo));
+ }
+ break;
+
+ case MusECore::Controller:
+ addController(mpevlist, tick, port, channel, ev.dataA(), ev.dataB());
+ break;
+
+ case MusECore::Sysex:
+ {
+ mpevlist->add(MusECore::MidiPlayEvent(tick, port, MusECore::ME_SYSEX, ev.eventData()));
+ //MusECore::MidiPlayEvent ev(tick, port, MusECore::ME_SYSEX, ev.eventData());
+ //ev.setChannel(channel); // Sysex are channelless, but this is required for sorting!
+ //mpevlist->add(ev);
+ }
+ break;
+
+ case MusECore::PAfter:
+ mpevlist->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_AFTERTOUCH, ev.dataA(), ev.dataB()));
+ break;
+
+ case MusECore::CAfter:
+ mpevlist->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_POLYAFTER, ev.dataA(), ev.dataB()));
+ break;
+
+ case MusECore::Meta:
+ {
+ MusECore::MidiPlayEvent mpev(tick, port, MusECore::ME_META, ev.eventData());
+ mpev.setA(ev.dataA());
+ //mpev.setChannel(channel); // Metas are channelless, but this is required for sorting!
+ mpevlist->add(mpev);
+ }
+ break;
+ case MusECore::Wave:
+ break;
+ }
+ }
+}
+
+
} // namespace MusECore
namespace MusEGui {
@@ -133,6 +238,34 @@ namespace MusEGui {
void MusE::exportMidi()
{
+ if(MusEGlobal::config.smfFormat == 0) // Want single track? Warn if multiple ports in song...
+ {
+ MusECore::MidiTrackList* mtl = MusEGlobal::song->midis();
+ int prev_port = -1;
+ for(MusECore::ciMidiTrack im = mtl->begin(); im != mtl->end(); ++im)
+ {
+ int port = (*im)->outPort();
+ if(prev_port == -1)
+ {
+ prev_port = port;
+ continue;
+ }
+ if(port != prev_port)
+ {
+ if(QMessageBox::warning(this,
+ tr("MusE: Warning"),
+ tr("The song uses multiple ports but export format 0 (single track) is set.\n"
+ "The first track's port will be used. Playback will likely be wrong\n"
+ " unless the channels used in one port are different from all other ports.\n"
+ "Canceling and setting a different export format would be better.\nContinue?"),
+ QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok)
+ != QMessageBox::Ok)
+ return;
+ break;
+ }
+ }
+ }
+
MusEGui::MFile file(QString("midis"), QString(".mid"));
FILE* fp = file.open("w", MusEGlobal::midi_file_save_pattern, this, false, true,
@@ -144,6 +277,8 @@ void MusE::exportMidi()
MusECore::TrackList* tl = MusEGlobal::song->tracks(); // Changed to full track list so user can rearrange tracks.
MusECore::MidiFileTrackList* mtl = new MusECore::MidiFileTrackList;
+ std::set<int> used_ports;
+
int i = 0;
MusECore::MidiFileTrack* mft = 0;
for (MusECore::ciTrack im = tl->begin(); im != tl->end(); ++im) {
@@ -153,7 +288,7 @@ void MusE::exportMidi()
MusECore::MidiTrack* track = (MusECore::MidiTrack*)(*im);
- if (i == 0 || (i != 0 && MusEGlobal::config.smfFormat != 0)) // Changed to single track. Tim
+ if (i == 0 || MusEGlobal::config.smfFormat != 0) // Changed to single track. Tim
{
mft = new MusECore::MidiFileTrack;
mtl->push_back(mft);
@@ -162,14 +297,13 @@ void MusE::exportMidi()
MusECore::MPEventList* l = &(mft->events);
int port = track->outPort();
int channel = track->outChannel();
-
+
//---------------------------------------------------
// only first midi track contains
// - Track Marker
// - copyright
// - time signature
// - tempo map
- // - GM/GS/XG Initialization
//---------------------------------------------------
if (i == 0) {
@@ -181,8 +315,8 @@ void MusE::exportMidi()
QByteArray ba = m->second.name().toLatin1();
const char* name = ba.constData();
int len = ba.length();
- MusECore::MidiPlayEvent ev(m->first, port, MusECore::ME_META, (unsigned char*)name, len);
- ev.setA(0x6);
+ MusECore::MidiPlayEvent ev(m->first, port, MusECore::ME_META, (const unsigned char*)name, len);
+ ev.setA(MusECore::ME_META_TEXT_6_MARKER);
l->add(ev);
}
@@ -193,8 +327,8 @@ void MusE::exportMidi()
const char* copyright = ba.constData();
if (copyright && *copyright) {
int len = ba.length();
- MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)copyright, len);
- ev.setA(0x2);
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)copyright, len);
+ ev.setA(MusECore::ME_META_TEXT_2_COPYRIGHT);
l->add(ev);
}
@@ -203,36 +337,21 @@ void MusE::exportMidi()
//
//if (MusEGlobal::config.smfFormat == 0) // Only for smf 0 added by Tim. FIXME: Is this correct? See below.
{
- QString comment = track->comment();
- if (!comment.isEmpty()) {
- int len = comment.length();
- MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)(comment.toLatin1().constData()), len);
- ev.setA(0x1);
+ //QString comment = track->comment();
+ //if (!comment.isEmpty()) {
+ if (!track->comment().isEmpty()) {
+ //int len = comment.length();
+ QByteArray ba = track->comment().toLatin1();
+ const char* comment = ba.constData();
+ int len = ba.length();
+ //MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)(comment.toLatin1().constData()), len);
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)comment, len);
+ ev.setA(MusECore::ME_META_TEXT_1_COMMENT);
l->add(ev);
}
}
//---------------------------------------------------
- // Write Songtype SYSEX: GM/GS/XG
- //
-
- switch(MusEGlobal::song->mtype()) {
- case MT_GM:
- l->add(MusECore::MidiPlayEvent(0, port, MusECore::ME_SYSEX, MusECore::gmOnMsg, MusECore::gmOnMsgLen));
- break;
- case MT_GS:
- l->add(MusECore::MidiPlayEvent(0, port, MusECore::ME_SYSEX, MusECore::gmOnMsg, MusECore::gmOnMsgLen));
- l->add(MusECore::MidiPlayEvent(250, port, MusECore::ME_SYSEX, MusECore::gsOnMsg, MusECore::gsOnMsgLen));
- break;
- case MT_XG:
- l->add(MusECore::MidiPlayEvent(0, port, MusECore::ME_SYSEX, MusECore::gmOnMsg, MusECore::gmOnMsgLen));
- l->add(MusECore::MidiPlayEvent(250, port, MusECore::ME_SYSEX, MusECore::xgOnMsg, MusECore::xgOnMsgLen));
- break;
- case MT_UNKNOWN:
- break;
- }
-
- //---------------------------------------------------
// Write Tempomap
//
MusECore::TempoList* tl = &MusEGlobal::tempomap;
@@ -244,7 +363,7 @@ void MusE::exportMidi()
data[1] = (tempo >> 8) & 0xff;
data[0] = (tempo >> 16) & 0xff;
MusECore::MidiPlayEvent ev(event->tick, port, MusECore::ME_META, data, 3);
- ev.setA(0x51);
+ ev.setA(MusECore::ME_META_SET_TEMPO);
l->add(ev);
}
@@ -279,7 +398,7 @@ void MusE::exportMidi()
MusECore::MidiPlayEvent ev(event->tick, port, MusECore::ME_META, data, sz);
- ev.setA(0x58);
+ ev.setA(MusECore::ME_META_TIME_SIGNATURE);
l->add(ev);
}
}
@@ -288,14 +407,15 @@ void MusE::exportMidi()
// track name
//-----------------------------------
- if (i == 0 || (i != 0 && MusEGlobal::config.smfFormat != 0))
+ if (i == 0 || MusEGlobal::config.smfFormat != 0)
{
if (!track->name().isEmpty()) {
QByteArray ba = track->name().toLatin1();
const char* name = ba.constData();
int len = ba.length();
- MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)name, len+1);
- ev.setA(0x3); // Meta Sequence/Track Name
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)name, len);
+ ev.setA(MusECore::ME_META_TEXT_3_TRACK_NAME); // Meta Sequence/Track Name
+ //ev.setChannel(channel); // Metas are channelless, but this is required for sorting!
l->add(ev);
}
}
@@ -310,104 +430,112 @@ void MusE::exportMidi()
QByteArray ba = track->comment().toLatin1();
const char* comment = ba.constData();
int len = ba.length();
- MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (unsigned char*)comment, len+1);
- ev.setA(0xf); // Meta Text
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)comment, len);
+ ev.setA(MusECore::ME_META_TEXT_F_TRACK_COMMENT); // Meta Text
+ //ev.setChannel(channel); // Metas are channelless, but this is required for sorting!
l->add(ev);
}
}
+ //-----------------------------------------
+ // Write device name or port change meta
+ //-----------------------------------------
+
+ if((i == 0 && MusEGlobal::config.exportPortDeviceSMF0) || (MusEGlobal::config.smfFormat != 0))
+ {
+ if(port >= 0 && port < MIDI_PORTS)
+ {
+ if(MusEGlobal::config.exportPortsDevices == MusEGlobal::EXPORT_PORTS_DEVICES_ALL ||
+ MusEGlobal::config.exportPortsDevices == MusEGlobal::PORT_NUM_META)
+ {
+ unsigned char port_char = (unsigned char)port;
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, &port_char, 1);
+ ev.setA(MusECore::ME_META_PORT_CHANGE); // Meta port change
+ //ev.setChannel(channel); // Metas are channelless, but this is required for sorting!
+ l->add(ev);
+ }
+
+ if(MusEGlobal::config.exportPortsDevices == MusEGlobal::EXPORT_PORTS_DEVICES_ALL ||
+ MusEGlobal::config.exportPortsDevices == MusEGlobal::DEVICE_NAME_META)
+ {
+ MusECore::MidiDevice* dev = MusEGlobal::midiPorts[port].device();
+ const char* str;
+ int len;
+ QByteArray ba;
+ if(dev && !dev->name().isEmpty())
+ ba = dev->name().toLatin1();
+ else
+ ba = QString::number(port).toLatin1();
+ str = ba.constData();
+ len = ba.length();
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)str, len);
+ ev.setA(MusECore::ME_META_TEXT_9_DEVICE_NAME); // Meta Device Name
+ //ev.setChannel(channel); // Metas are channelless, but this is required for sorting!
+ l->add(ev);
+ }
+ }
+ }
+
+ //---------------------------------------------------
+ // Write midi port init sequence: GM/GS/XG etc.
+ // and Instrument Name meta.
+ //---------------------------------------------------
+
+ std::set<int>::iterator iup = used_ports.find(port);
+ if(iup == used_ports.end())
+ {
+ if(port >= 0 && port < MIDI_PORTS)
+ {
+ MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
+ if(instr)
+ {
+ if(i == 0 || MusEGlobal::config.smfFormat != 0)
+ {
+ //--------------------------
+ // Port midi init sequence
+ //--------------------------
+ if(MusEGlobal::config.exportModeInstr == MusEGlobal::EXPORT_MODE_INSTR_ALL ||
+ MusEGlobal::config.exportModeInstr == MusEGlobal::MODE_SYSEX)
+ {
+ MusECore::EventList* el = instr->midiInit();
+ if(!el->empty())
+ MusECore::addEventList(el, l, NULL, NULL, port, channel); // No track or part passed for init sequences
+ }
+
+ //--------------------------
+ // Instrument Name meta
+ //--------------------------
+ if(!instr->iname().isEmpty() &&
+ (MusEGlobal::config.exportModeInstr == MusEGlobal::EXPORT_MODE_INSTR_ALL ||
+ MusEGlobal::config.exportModeInstr == MusEGlobal::INSTRUMENT_NAME_META))
+ {
+ const char* str;
+ int len;
+ QByteArray ba = instr->iname().toLatin1();
+ str = ba.constData();
+ len = ba.length();
+ MusECore::MidiPlayEvent ev(0, port, MusECore::ME_META, (const unsigned char*)str, len);
+ ev.setA(MusECore::ME_META_TEXT_4_INSTRUMENT_NAME); // Meta Instrument Name
+ //ev.setChannel(channel); // Metas are channelless, but this is required for sorting!
+ l->add(ev);
+ }
+ }
+ }
+ used_ports.insert(port);
+ }
+ }
+
MusECore::PartList* parts = track->parts();
for (MusECore::iPart p = parts->begin(); p != parts->end(); ++p) {
MusECore::MidiPart* part = (MusECore::MidiPart*) (p->second);
MusECore::EventList* evlist = part->events();
- for (MusECore::iEvent i = evlist->begin(); i != evlist->end(); ++i) {
- MusECore::Event ev = i->second;
- int tick = ev.tick() + part->tick();
- switch (ev.type()) {
- case MusECore::Note:
- {
- if (ev.velo() == 0) {
- printf("Warning: midi note has velocity 0, (ignored)\n");
- continue;
- }
- int pitch;
- if (track->type() == MusECore::Track::DRUM) {
- // Map drum-notes to the drum-map values
- int instr = ev.pitch();
- pitch = MusEGlobal::drumMap[instr].anote;
- }
- else
- pitch = ev.pitch();
-
- int velo = ev.velo();
- int len = ev.lenTick();
-
- //---------------------------------------
- // apply trackinfo values
- //---------------------------------------
-
- if (track->transposition
- || track->velocity
- || track->compression != 100
- || track->len != 100) {
- pitch += track->transposition;
- if (pitch > 127)
- pitch = 127;
- if (pitch < 0)
- pitch = 0;
-
- velo += track->velocity;
- velo = (velo * track->compression) / 100;
- if (velo > 127)
- velo = 127;
- if (velo < 1) // no off event
- velo = 1;
- len = (len * track->len) / 100;
- }
- if (len <= 0)
- len = 1;
- l->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_NOTEON, pitch, velo));
-
- if(MusEGlobal::config.expOptimNoteOffs) // Save space by replacing note offs with note on velocity 0
- l->add(MusECore::MidiPlayEvent(tick+len, port, channel, MusECore::ME_NOTEON, pitch, 0));
- else
- l->add(MusECore::MidiPlayEvent(tick+len, port, channel, MusECore::ME_NOTEOFF, pitch, velo));
- }
- break;
-
- case MusECore::Controller:
- addController(l, tick, port, channel, ev.dataA(), ev.dataB());
- break;
-
- case MusECore::Sysex:
- l->add(MusECore::MidiPlayEvent(tick, port, MusECore::ME_SYSEX, ev.eventData()));
- break;
-
- case MusECore::PAfter:
- l->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_AFTERTOUCH, ev.dataA(), ev.dataB()));
- break;
-
- case MusECore::CAfter:
- l->add(MusECore::MidiPlayEvent(tick, port, channel, MusECore::ME_POLYAFTER, ev.dataA(), ev.dataB()));
- break;
-
- case MusECore::Meta:
- {
- MusECore::MidiPlayEvent mpev(tick, port, MusECore::ME_META, ev.eventData());
- mpev.setA(ev.dataA());
- l->add(mpev);
- }
- break;
- case MusECore::Wave:
- break;
- }
- }
+ MusECore::addEventList(evlist, l, track, part, port, channel);
}
- ++i;
-
+
+ ++i;
}
+
mf.setDivision(MusEGlobal::config.midiDivision);
- mf.setMType(MusEGlobal::song->mtype());
mf.setTrackList(mtl, i);
mf.write();
diff --git a/muse2/muse/gconfig.cpp b/muse2/muse/gconfig.cpp
index 302007b3..ff5545ef 100644
--- a/muse2/muse/gconfig.cpp
+++ b/muse2/muse/gconfig.cpp
@@ -141,6 +141,12 @@ GlobalConfigValues config = {
true, // optimize midi export file note offs
true, // Split imported tracks into multiple parts.
true, // importMidiNewStyleDrum
+ true, // importDevNameMetas Import Prefer Device Name metas over port number metas if both exist.
+ true, // importInstrNameMetas Import Prefer Instrument Name metas over Mode sysexes if both exist.
+ EXPORT_PORTS_DEVICES_ALL, // exportPortsDevices Export port number metas and/or device name metas.
+ true, // exportPortDeviceSMF0 Export a port and/or device meta even for SMF0.
+ EXPORT_MODE_INSTR_ALL, // exportModeInstr Export mode sysexes and/or instrument name metas.
+ QString("GM"), // importMidiDefaultInstr Default to this instrument not Generic, if no match found
1, // startMode
QString(""), // start song path
false, // startSongLoadConfig
diff --git a/muse2/muse/gconfig.h b/muse2/muse/gconfig.h
index ead9f258..a9d2c0a0 100644
--- a/muse2/muse/gconfig.h
+++ b/muse2/muse/gconfig.h
@@ -54,6 +54,23 @@ enum drumTrackPreference_t
ONLY_OLD = 2,
ONLY_NEW = 3
};
+
+enum ExportPortsDevices_t
+{
+ EXPORT_PORTS_DEVICES_ALL = 0,
+ PORT_NUM_META = 1,
+ DEVICE_NAME_META = 2,
+ EXPORT_PORTS_DEVICES_END = 3
+};
+
+enum ExportModeInstr_t
+{
+ EXPORT_MODE_INSTR_ALL = 0,
+ MODE_SYSEX = 1,
+ INSTRUMENT_NAME_META = 2,
+ EXPORT_MODE_INSTR_END = 3
+};
+
//---------------------------------------------------------
// MixerConfig
//---------------------------------------------------------
@@ -133,6 +150,12 @@ struct GlobalConfigValues {
bool expOptimNoteOffs; // Save space by replacing note offs with note on velocity 0
bool importMidiSplitParts; // Split imported tracks into multiple parts.
bool importMidiNewStyleDrum; // Use new style drum tracks
+ bool importDevNameMetas; // Import Prefer Device Name metas over port number metas if both exist.
+ bool importInstrNameMetas; // Import Prefer Instrument Name metas over Mode sysexes if both exist.
+ ExportPortsDevices_t exportPortsDevices; // Export port number metas and/or device name metas.
+ bool exportPortDeviceSMF0; // Export a port and/or device meta even for SMF0.
+ ExportModeInstr_t exportModeInstr; // Export mode sysexes and/or instrument name metas.
+ QString importMidiDefaultInstr; // Default to this instrument not Generic, if no match found
int startMode; // 0 - start with last song
// 1 - start with default template
diff --git a/muse2/muse/importmidi.cpp b/muse2/muse/importmidi.cpp
index 4f5871d6..73f2e071 100644
--- a/muse2/muse/importmidi.cpp
+++ b/muse2/muse/importmidi.cpp
@@ -4,6 +4,7 @@
// $Id: importmidi.cpp,v 1.26.2.10 2009/11/05 03:14:35 terminator356 Exp $
//
// (C) Copyright 1999-2003 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -36,6 +37,7 @@
#include "midi.h"
#include "midifile.h"
#include "midiport.h"
+#include "midiseq.h"
#include "transport.h"
#include "arranger.h"
#include "mpevent.h"
@@ -117,33 +119,130 @@ bool MusE::importMidi(const QString name, bool merge)
QMessageBox::critical(this, QString("MusE"), s);
return rv;
}
+
+ MusECore::MidiFileTrackList* etl = mf.trackList();
+ int division = mf.division();
+
+ // Find the default instrument, we may need it later...
+ MusECore::MidiInstrument* def_instr = 0;
+ if(!MusEGlobal::config.importMidiDefaultInstr.isEmpty())
+ {
+ for(MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i)
+ {
+ if((*i)->iname() == MusEGlobal::config.importMidiDefaultInstr)
+ {
+ def_instr = *i;
+ break;
+ }
+ }
+ }
+
//
- // evaluate song Type (GM, XG, GS, unknown)
+ // Need to set up ports and instruments first
//
- MType t = MusEGlobal::song->mtype();
- if (!merge) {
- t = mf.mtype();
- MusEGlobal::song->setMType(t);
- }
- MusECore::MidiInstrument* instr = 0;
- for (MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i) {
- MusECore::MidiInstrument* mi = *i;
- if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MT_GM)))
- || ((mi->iname() == "GS") && (t == MT_GS))
- || ((mi->iname() == "XG") && (t == MT_XG))) {
- instr = mi;
- break;
- }
- }
- if (instr == 0) {
- // the standard instrument files (GM, GS, XG) must be present
- printf("no instrument, type %d\n", t);
- abort();
- }
+
+ MusECore::MidiFilePortMap* usedPortMap = mf.usedPortMap();
+ bool dev_changed = false;
+ for(MusECore::iMidiFilePort imp = usedPortMap->begin(); imp != usedPortMap->end(); ++imp)
+ {
+ MType midi_type = imp->second._midiType;
+ QString instr_name = MusEGlobal::config.importInstrNameMetas ? imp->second._instrName : QString();
+ MusECore::MidiInstrument* typed_instr = 0;
+ MusECore::MidiInstrument* named_instr = 0;
+ // Find a typed instrument and a named instrument, if requested
+ for(MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i)
+ {
+ MusECore::MidiInstrument* mi = *i;
+ if(midi_type != MT_UNKNOWN && midi_type == mi->midiType())
+ typed_instr = mi;
+ if(!instr_name.isEmpty() && instr_name == mi->iname())
+ named_instr = mi;
+ if((typed_instr && named_instr) || ((typed_instr && instr_name.isEmpty()) || (named_instr && midi_type == MT_UNKNOWN)))
+ break; // Done searching
+ }
- MusECore::MidiFileTrackList* etl = mf.trackList();
- int division = mf.division();
+ int port = imp->first;
+ MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
+ MusECore::MidiDevice* md = mp->device();
+ // Take care of assigning devices to empty ports here rather than in midifile.
+ //if(MusEGlobal::config.importDevNameMetas) // TODO
+ {
+ if(!md)
+ {
+ QString dev_name = imp->second._subst4DevName;
+ md = MusEGlobal::midiDevices.find(dev_name); // Find any type of midi device - HW, synth etc.
+ if(md)
+ {
+ // TEST: Hopefully shouldn't require any routing saves/restorations as in midi port config set device name...
+ MusEGlobal::midiSeq->msgSetMidiDevice(mp, md);
+ // TEST: Hopefully can get away with this ouside the loop below...
+ //MusEGlobal::muse->changeConfig(true); // save configuration file
+ //MusEGlobal::audio->msgUpdateSoloStates();
+ //MusEGlobal::song->update();
+ dev_changed = true;
+ }
+ else
+ printf("importMidi error: assign to empty port: device not found: %s\n", dev_name.toLatin1().constData());
+ }
+ }
+ MusECore::MidiInstrument* instr = 0;
+ // Priority is exact named instrument over a typed instrument.
+ // This allows a named instrument plus a typed sysex, and the name will take priority.
+ // But it is possible that named mismatches may occur. So this named/typed order is user-selectable.
+ if(named_instr && (!typed_instr || MusEGlobal::config.importInstrNameMetas))
+ {
+ instr = named_instr;
+ if(MusEGlobal::debugMsg)
+ printf("port:%d named instrument found:%s\n",
+ port, instr->iname().toLatin1().constData());
+ }
+ else if(typed_instr)
+ {
+ instr = typed_instr;
+ if(MusEGlobal::debugMsg)
+ printf("port:%d typed instrument found:%s\n",
+ port, instr->iname().toLatin1().constData());
+ }
+ else if(def_instr)
+ {
+ instr = def_instr;
+ if(MusEGlobal::debugMsg)
+ printf("port:%d no named or typed instrument found. Using default:%s\n",
+ port, instr->iname().toLatin1().constData());
+ }
+ else
+ {
+ instr = MusECore::genericMidiInstrument;
+ if(MusEGlobal::debugMsg)
+ printf("port:%d no named, typed, or default instrument found! Using:%s\n",
+ port, instr->iname().toLatin1().constData());
+ }
+
+ // If the instrument is one of the three standard GM, GS, or XG, mark the usedPort as "ch 10 is drums".
+ // Otherwise it's anybody's guess what channel(s) drums are on.
+ // Code is a bit HACKISH just to accomplish passing this bool value to the next stage, where tracks are created.
+ if(instr->midiType() != MT_UNKNOWN)
+ imp->second._isStandardDrums = true;
+
+ // Set the device's instrument - ONLY for non-synths because they provide their own.
+ if(!md || (md->deviceType() != MusECore::MidiDevice::SYNTH_MIDI))
+ {
+ // this overwrites any instrument set for this port:
+ if(mp->instrument() != instr)
+ mp->setInstrument(instr);
+ }
+ }
+
+ if(dev_changed)
+ {
+ // TEST: Hopefully can get away with this here instead of inside the loop above...
+ // TEST: Are these really necessary as in midi port config set device name?
+ MusEGlobal::muse->changeConfig(true); // save configuration file
+ MusEGlobal::audio->msgUpdateSoloStates(); //
+ MusEGlobal::song->update();
+ }
+
//
// create MidiTrack and copy events to ->events()
// - combine note on/off events
@@ -177,7 +276,7 @@ bool MusE::importMidi(const QString name, bool merge)
already_processed.insert(pair<int,int>(channel, port));
MusECore::MidiTrack* track = new MusECore::MidiTrack();
- if ((*t)->isDrumTrack)
+ if ((*t)->_isDrumTrack)
{
if (MusEGlobal::config.importMidiNewStyleDrum)
track->setType(MusECore::Track::NEW_DRUM);
@@ -188,10 +287,8 @@ bool MusE::importMidi(const QString name, bool merge)
track->setOutChannel(channel);
track->setOutPort(port);
- MusECore::MidiPort* mport = &MusEGlobal::midiPorts[track->outPort()];
- // this overwrites any instrument set for this port:
- mport->setInstrument(instr);
-
+ MusECore::MidiPort* mport = &MusEGlobal::midiPorts[port];
+ //MusECore::MidiInstrument* instr = mport->instrument();
MusECore::EventList* mel = track->events();
buildMidiEventList(mel, el, track, division, first, false); // Don't do loops.
first = false;
@@ -199,7 +296,9 @@ bool MusE::importMidi(const QString name, bool merge)
// Comment Added by T356.
// Hmm. buildMidiEventList already takes care of this.
// But it seems to work. How? Must test.
- if (channel == 9 && MusEGlobal::song->mtype() != MT_UNKNOWN) {
+ //if (channel == 9 && instr->midiType() != MT_UNKNOWN) {
+ MusECore::ciMidiFilePort imp = usedPortMap->find(port);
+ if(imp != usedPortMap->end() && imp->second._isStandardDrums && channel == 9) { // A bit HACKISH, see above
if (MusEGlobal::config.importMidiNewStyleDrum)
track->setType(MusECore::Track::NEW_DRUM);
else
@@ -246,7 +345,7 @@ bool MusE::importMidi(const QString name, bool merge)
MusEGlobal::song->insertTrack0(track, -1);
}
}
-
+
if (!merge) {
MusECore::TrackList* tl = MusEGlobal::song->tracks();
if (!tl->empty()) {
@@ -324,8 +423,7 @@ void MusE::processTrack(MusECore::MidiTrack* track)
for (int bar = 0; bar < bar2; ++bar, x1 = x2) {
x2 = AL::sigmap.bar2tick(bar+1, 0, 0);
- if (lastOff > x2) {
- // this measure is busy!
+ if (lastOff > x2) {
continue;
}
MusECore::iEvent i1 = tevents->lower_bound(x1);
@@ -335,7 +433,7 @@ void MusE::processTrack(MusECore::MidiTrack* track)
if (st != -1) {
MusECore::MidiPart* part = new MusECore::MidiPart(track);
part->setTick(st);
- part->setLenTick(x1-st);
+ part->setLenTick((lastOff > x1 ? x2 : x1) - st);
part->setName(partname);
pl->add(part);
st = -1;
@@ -495,48 +593,6 @@ void MusE::importPart()
//---------------------------------------------------------
void MusE::importPartToTrack(QString& filename, unsigned tick, MusECore::Track* track)
{
- // DELETETHIS 41
- // Changed by T356
- /*
- bool popenFlag = false;
- FILE* fp = MusEGui::fileOpen(this, filename, ".mpt", "r", popenFlag, false, false);
-
- if(fp)
- {
- MusECore::MidiPart* importedPart = new MusECore::MidiPart((MusECore::MidiTrack*)track);
- MusECore::Xml tmpXml = MusECore::Xml(fp);
-
- MusECore::Xml::Token token = tmpXml.parse();
- const QString& tag = tmpXml.s1();
- if (token == MusECore::Xml::TagStart && tag == "part")
- {
- // Make a backup of the current clone list, to retain any 'copy' items,
- // so that pasting works properly after.
- MusECore::CloneList copyCloneList = MusEGlobal::cloneList;
- // Clear the clone list to prevent any dangerous associations with
- // current non-original parts.
- MusEGlobal::cloneList.clear();
-
- importedPart->read(tmpXml);
- importedPart->setTick(tick);
-
- // Restore backup of the clone list, to retain any 'copy' items,
- // so that pasting works properly after.
- MusEGlobal::cloneList.clear();
- MusEGlobal::cloneList = copyCloneList;
-
- MusEGlobal::audio->msgAddPart(importedPart);
- }
- else
- {
- printf("Unknown tag: %s\n", tag.toLatin1().constData());
- }
- fclose(fp);
- }
- return;
- */
-
-
bool popenFlag = false;
FILE* fp = MusEGui::fileOpen(this, filename, ".mpt", "r", popenFlag, false, false);
diff --git a/muse2/muse/instruments/editinstrument.cpp b/muse2/muse/instruments/editinstrument.cpp
index 8378bd68..57c466b8 100644
--- a/muse2/muse/instruments/editinstrument.cpp
+++ b/muse2/muse/instruments/editinstrument.cpp
@@ -79,6 +79,14 @@ EditInstrument::EditInstrument(QWidget* parent, Qt::WFlags fl)
toolBar->addAction(QWhatsThis::createAction(this));
Help->addAction(QWhatsThis::createAction(this));
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ checkBoxGM->setEnabled(false);
+ checkBoxGS->setEnabled(false);
+ checkBoxXG->setEnabled(false);
+ checkBoxGM->setVisible(false);
+ checkBoxGS->setVisible(false);
+ checkBoxXG->setVisible(false);
+
// populate instrument list
// Populate common controller list.
for(int i = 0; i < 128; ++i)
@@ -1405,9 +1413,10 @@ void EditInstrument::patchChanged()
spinBoxLBank->setEnabled(false);
spinBoxProgram->setEnabled(false);
checkBoxDrum->setEnabled(false);
- checkBoxGM->setEnabled(false);
- checkBoxGS->setEnabled(false);
- checkBoxXG->setEnabled(false);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setEnabled(false);
+ //checkBoxGS->setEnabled(false);
+ //checkBoxXG->setEnabled(false);
return;
}
@@ -1420,9 +1429,10 @@ void EditInstrument::patchChanged()
spinBoxLBank->setEnabled(true);
spinBoxProgram->setEnabled(true);
checkBoxDrum->setEnabled(true);
- checkBoxGM->setEnabled(true);
- checkBoxGS->setEnabled(true);
- checkBoxXG->setEnabled(true);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setEnabled(true);
+ //checkBoxGS->setEnabled(true);
+ //checkBoxXG->setEnabled(true);
int hb = ((p->hbank + 1) & 0xff);
int lb = ((p->lbank + 1) & 0xff);
@@ -1431,9 +1441,10 @@ void EditInstrument::patchChanged()
spinBoxLBank->setValue(lb);
spinBoxProgram->setValue(pr);
checkBoxDrum->setChecked(p->drum);
- checkBoxGM->setChecked(p->typ & 1);
- checkBoxGS->setChecked(p->typ & 2);
- checkBoxXG->setChecked(p->typ & 4);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setChecked(p->typ & 1);
+ //checkBoxGS->setChecked(p->typ & 2);
+ //checkBoxXG->setChecked(p->typ & 4);
}
else
// The item is a patch group item.
@@ -1443,9 +1454,10 @@ void EditInstrument::patchChanged()
spinBoxLBank->setEnabled(false);
spinBoxProgram->setEnabled(false);
checkBoxDrum->setEnabled(false);
- checkBoxGM->setEnabled(false);
- checkBoxGS->setEnabled(false);
- checkBoxXG->setEnabled(false);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setEnabled(false);
+ //checkBoxGS->setEnabled(false);
+ //checkBoxXG->setEnabled(false);
}
}
@@ -2550,7 +2562,7 @@ void EditInstrument::newPatchClicked()
patch->hbank = hb;
patch->lbank = lb;
patch->prog = prg;
- patch->typ = -1;
+ //patch->typ = -1;
patch->drum = false;
if(selpatch)
@@ -2558,7 +2570,7 @@ void EditInstrument::newPatchClicked()
hb = selpatch->hbank;
lb = selpatch->lbank;
prg = selpatch->prog;
- patch->typ = selpatch->typ;
+ //patch->typ = selpatch->typ;
patch->drum = selpatch->drum;
}
@@ -2638,9 +2650,10 @@ void EditInstrument::newPatchClicked()
spinBoxLBank->setEnabled(true);
spinBoxProgram->setEnabled(true);
checkBoxDrum->setEnabled(true);
- checkBoxGM->setEnabled(true);
- checkBoxGS->setEnabled(true);
- checkBoxXG->setEnabled(true);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setEnabled(true);
+ //checkBoxGS->setEnabled(true);
+ //checkBoxXG->setEnabled(true);
oldPatchItem = 0;
patchChanged();
@@ -2706,9 +2719,10 @@ void EditInstrument::newGroupClicked()
spinBoxLBank->setEnabled(false);
spinBoxProgram->setEnabled(false);
checkBoxDrum->setEnabled(false);
- checkBoxGM->setEnabled(false);
- checkBoxGS->setEnabled(false);
- checkBoxXG->setEnabled(false);
+ // REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+ //checkBoxGM->setEnabled(false);
+ //checkBoxGS->setEnabled(false);
+ //checkBoxXG->setEnabled(false);
workingInstrument.setDirty(true);
}
@@ -2957,23 +2971,24 @@ void EditInstrument::updatePatch(MusECore::MidiInstrument* instrument, MusECore:
}
// there is no logical xor in c++
- bool a = p->typ & 1;
- bool b = p->typ & 2;
- bool c = p->typ & 4;
- bool aa = checkBoxGM->isChecked();
- bool bb = checkBoxGS->isChecked();
- bool cc = checkBoxXG->isChecked();
- if ((a ^ aa) || (b ^ bb) || (c ^ cc)) {
- int value = 0;
- if (checkBoxGM->isChecked())
- value |= 1;
- if (checkBoxGS->isChecked())
- value |= 2;
- if (checkBoxXG->isChecked())
- value |= 4;
- p->typ = value;
- instrument->setDirty(true);
- }
+// REMOVE Tim. OBSOLETE. When gui boxes are finally removed.
+// bool a = p->typ & 1;
+// bool b = p->typ & 2;
+// bool c = p->typ & 4;
+// bool aa = checkBoxGM->isChecked();
+// bool bb = checkBoxGS->isChecked();
+// bool cc = checkBoxXG->isChecked();
+// if ((a ^ aa) || (b ^ bb) || (c ^ cc)) {
+// int value = 0;
+// if (checkBoxGM->isChecked())
+// value |= 1;
+// if (checkBoxGS->isChecked())
+// value |= 2;
+// if (checkBoxXG->isChecked())
+// value |= 4;
+// p->typ = value;
+// instrument->setDirty(true);
+// }
}
//---------------------------------------------------------
diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp
index 196ce513..e2477e60 100644
--- a/muse2/muse/instruments/minstrument.cpp
+++ b/muse2/muse/instruments/minstrument.cpp
@@ -49,8 +49,6 @@ namespace MusECore {
MidiInstrumentList midiInstruments;
MidiInstrument* genericMidiInstrument;
-static const char* gmdrumname = "GM-drums";
-
//---------------------------------------------------------
// string2sysex
// Return -1 if cannot be converted.
@@ -369,7 +367,7 @@ MidiInstrument::~MidiInstrument()
MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
{
//---------------------------------------------------------
- // TODO: Copy the _initScript, and _midiInit, _midiReset, and _midiState lists.
+ // TODO: Copy the _initScript (if and when it is ever used)
//---------------------------------------------------------
for(iMidiController i = _controller->begin(); i != _controller->end(); ++i)
@@ -399,6 +397,10 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
_sysex.append(new MusECore::SysEx(*(ins.sysex().at(i))));
}
+ *(_midiInit) = *(ins._midiInit);
+ *(_midiReset) = *(ins._midiReset);
+ *(_midiState) = *(ins._midiState);
+
for (ciPatchGroup g = pg.begin(); g != pg.end(); ++g)
{
PatchGroup* pgp = *g;
@@ -424,7 +426,7 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
{
Patch* pp = *p;
Patch* np = new Patch;
- np->typ = pp->typ;
+ //np->typ = pp->typ;
np->hbank = pp->hbank;
np->lbank = pp->lbank;
np->prog = pp->prog;
@@ -448,11 +450,26 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
}
//---------------------------------------------------------
+// midiType
+//---------------------------------------------------------
+
+MType MidiInstrument::midiType() const
+{
+ if(_name == "GM")
+ return MT_GM;
+ if(_name == "GS")
+ return MT_GS;
+ if(_name == "XG")
+ return MT_XG;
+ return MT_UNKNOWN;
+}
+
+//---------------------------------------------------------
// reset
// send note off to all channels
//---------------------------------------------------------
-void MidiInstrument::reset(int portNo, MType)
+void MidiInstrument::reset(int portNo)
{
MusECore::MidiPort* port = &MusEGlobal::midiPorts[portNo];
if(port->device() == 0) // p4.0.15
@@ -517,7 +534,7 @@ void PatchGroup::read(Xml& xml)
void Patch::read(Xml& xml)
{
- typ = -1;
+ //typ = -1;
hbank = -1;
lbank = -1;
prog = 0;
@@ -535,8 +552,11 @@ void Patch::read(Xml& xml)
case Xml::Attribut:
if (tag == "name")
name = xml.s2();
- else if (tag == "mode")
- typ = xml.s2().toInt();
+ else if (tag == "mode") // Obsolete
+ {
+ //typ = xml.s2().toInt();
+ xml.s2().toInt();
+ }
else if (tag == "hbank")
hbank = xml.s2().toInt();
else if (tag == "lbank")
@@ -562,8 +582,8 @@ void Patch::read(Xml& xml)
void Patch::write(int level, Xml& xml)
{
xml.nput(level, "<Patch name=\"%s\"", Xml::xmlString(name).toLatin1().constData());
- if(typ != -1)
- xml.nput(" mode=\"%d\"", typ);
+ //if(typ != -1)
+ // xml.nput(" mode=\"%d\"", typ); // Obsolete
if(hbank != -1)
xml.nput(" hbank=\"%d\"", hbank);
@@ -982,10 +1002,6 @@ void MidiInstrument::write(int level, Xml& xml)
}
xml.put(">");
- // -------------
- // TODO: What about Init, Reset, State, and InitScript ?
- // -------------
-
level++;
for (ciPatchGroup g = pg.begin(); g != pg.end(); ++g) {
PatchGroup* pgp = *g;
@@ -1006,6 +1022,15 @@ void MidiInstrument::write(int level, Xml& xml)
_sysex.at(i)->write(level, xml);
}
+ xml.tag(level++, "Init");
+ for(ciEvent ev=_midiInit->begin(); ev != _midiInit->end(); ++ev)
+ ev->second.write(level, xml, MusECore::Pos(0, true));
+ xml.etag(--level, "Init");
+
+ // -------------
+ // TODO: What about _midiReset, _midiState, and _initScript ?
+ // -------------
+
writeDrummaps(level, xml);
level--;
@@ -1019,45 +1044,30 @@ void MidiInstrument::write(int level, Xml& xml)
// populatePatchPopup
//---------------------------------------------------------
-void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MType songType, bool drum)
+void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int /*chan*/, bool drum)
{
menu->clear();
- int mask = 0;
- bool drumchan = chan == 9;
- switch (songType) {
- case MT_XG: mask = 4; break;
- case MT_GS: mask = 2; break;
- case MT_GM:
- if(drumchan)
- {
- int id = (0xff << 16) + (0xff << 8) + 0x00; // First patch
- QAction* act = menu->addAction(gmdrumname);
- act->setData(id);
- return;
- }
- mask = 1;
- break;
- case MT_UNKNOWN: mask = 7; break;
- }
+ //int mask = 7;
+
if (pg.size() > 1) {
for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
PatchGroup* pgp = *i;
- MusEGui::PopupMenu* pm = new MusEGui::PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here.
- menu->addMenu(pm);
- pm->setFont(MusEGlobal::config.fonts[0]);
+ MusEGui::PopupMenu* pm = 0;
const PatchList& pl = pgp->patches;
for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
const Patch* mp = *ipl;
- if ((mp->typ & mask) &&
- ((drum && songType != MT_GM) ||
- (mp->drum == drumchan)) )
- {
+ if (//(mp->typ & mask) &&
+ (mp->drum == drum)) {
+ if(!pm) {
+ pm = new MusEGui::PopupMenu(pgp->name, menu, menu->stayOpen()); // Use the parent stayOpen here.
+ menu->addMenu(pm);
+ pm->setFont(MusEGlobal::config.fonts[0]);
+ }
int id = ((mp->hbank & 0xff) << 16)
+ ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff);
QAction* act = pm->addAction(mp->name);
act->setData(id);
}
-
}
}
}
@@ -1066,12 +1076,12 @@ void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MTyp
const PatchList& pl = pg.front()->patches;
for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
const Patch* mp = *ipl;
- if (mp->typ & mask) {
+ //if (mp->typ & mask) {
int id = ((mp->hbank & 0xff) << 16)
+ ((mp->lbank & 0xff) << 8) + (mp->prog & 0xff);
QAction* act = menu->addAction(mp->name);
act->setData(id);
- }
+ //}
}
}
@@ -1083,7 +1093,7 @@ void MidiInstrument::populatePatchPopup(MusEGui::PopupMenu* menu, int chan, MTyp
// getPatchName
//---------------------------------------------------------
-QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool drum)
+QString MidiInstrument::getPatchName(int /*channel*/, int prog, bool drum)
{
int pr = prog & 0xff;
if(prog == CTRL_VAL_UNKNOWN || pr == 0xff)
@@ -1091,38 +1101,17 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru
int hbank = (prog >> 16) & 0xff;
int lbank = (prog >> 8) & 0xff;
- int tmask = 1;
- bool drumchan = channel == 9;
- bool hb = false;
- bool lb = false;
- switch (mode) {
- case MT_GS:
- tmask = 2;
- hb = true;
- break;
- case MT_XG:
- hb = true;
- lb = true;
- tmask = 4;
- break;
- case MT_GM:
- if(drumchan)
- return gmdrumname;
- tmask = 1;
- break;
- default:
- hb = true; // MSB bank matters
- lb = true; // LSB bank matters
- break;
- }
+ //int tmask = 1;
+
+ bool hb = hbank != 0xff;
+ bool lb = lbank != 0xff;
for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
const PatchList& pl = (*i)->patches;
for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
const Patch* mp = *ipl;
- if ((mp->typ & tmask)
- && (pr == mp->prog)
- && ((drum && mode != MT_GM) ||
- (mp->drum == drumchan))
+ if (//(mp->typ & tmask) &&
+ (pr == mp->prog)
+ && (mp->drum == drum)
&& (hbank == mp->hbank || !hb || mp->hbank == -1)
&& (lbank == mp->lbank || !lb || mp->lbank == -1))
@@ -1132,14 +1121,9 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru
return "<unknown>";
}
-
-
-
-
-
-unsigned MidiInstrument::getNextPatch(int channel, unsigned patch, MType songType, bool drum)
+unsigned MidiInstrument::getNextPatch(int channel, unsigned patch, bool drum)
{
- QList<dumb_patchlist_entry_t> haystack=getPatches(channel,songType,drum);
+ QList<dumb_patchlist_entry_t> haystack=getPatches(channel,drum);
if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN;
int prog=patch&0xFF;
@@ -1168,9 +1152,9 @@ unsigned MidiInstrument::getNextPatch(int channel, unsigned patch, MType songTyp
((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000);
}
-unsigned MidiInstrument::getPrevPatch(int channel, unsigned patch, MType songType, bool drum)
+unsigned MidiInstrument::getPrevPatch(int channel, unsigned patch, bool drum)
{
- QList<dumb_patchlist_entry_t> haystack=getPatches(channel,songType,drum);
+ QList<dumb_patchlist_entry_t> haystack=getPatches(channel,drum);
if (haystack.empty()) return MusECore::CTRL_VAL_UNKNOWN;
int prog=patch&0xFF;
@@ -1197,51 +1181,21 @@ unsigned MidiInstrument::getPrevPatch(int channel, unsigned patch, MType songTyp
((((it->hbank==-1)?0xFF:it->hbank)<<16)&0xFF0000);
}
-QList<dumb_patchlist_entry_t> MidiInstrument::getPatches(int channel, MType mode, bool drum)
+QList<dumb_patchlist_entry_t> MidiInstrument::getPatches(int /*channel*/, bool drum)
{
- int tmask = 1;
- bool drumchan = channel == 9;
- bool hb = false;
- bool lb = false;
- switch (mode) {
- case MT_GS:
- tmask = 2;
- hb = true;
- break;
- case MT_XG:
- hb = true;
- lb = true;
- tmask = 4;
- break;
- case MT_GM:
- if(drumchan)
- {
- QList<dumb_patchlist_entry_t> tmp;
- tmp.push_back(dumb_patchlist_entry_t(0,-1,-1));
- }
- else
- tmask = 1;
- break;
- default:
- hb = true; // MSB bank matters
- lb = true; // LSB bank matters
- break;
- }
-
-
+ //int tmask = 1;
QList<dumb_patchlist_entry_t> tmp;
for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {
const PatchList& pl = (*i)->patches;
for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) {
const Patch* mp = *ipl;
- if ((mp->typ & tmask) &&
- ((drum && mode != MT_GM) ||
- (mp->drum == drumchan)) )
+ if (//(mp->typ & tmask) &&
+ (mp->drum == drum))
{
int prog = mp->prog;
- int lbank = (mp->lbank==-1 || !lb) ? -1 : mp->lbank;
- int hbank = (mp->hbank==-1 || !hb) ? -1 : mp->hbank;
+ int lbank = mp->lbank;
+ int hbank = mp->hbank;
tmp.push_back(dumb_patchlist_entry_t(prog,lbank,hbank));
}
}
diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h
index 6b534672..7ff6f7d8 100644
--- a/muse2/muse/instruments/minstrument.h
+++ b/muse2/muse/instruments/minstrument.h
@@ -47,7 +47,8 @@ class DrumMap;
//---------------------------------------------------------
struct Patch {
- signed char typ; // 1 - GM 2 - GS 4 - XG
+ // REMOVE Tim. OBSOLETE.
+ //signed char typ; // 1 - GM 2 - GS 4 - XG
signed char hbank, lbank, prog;
QString name;
bool drum;
@@ -200,6 +201,7 @@ class MidiInstrument {
MidiInstrument(const QString& txt);
const QString& iname() const { return _name; }
void setIName(const QString& txt) { _name = txt; }
+ MType midiType() const;
//MidiInstrument& uniqueCopy(const MidiInstrument&);
// Assign will 'delete' all existing patches and groups from the instrument.
@@ -214,9 +216,9 @@ class MidiInstrument {
void addSysex(SysEx* sysex) { _sysex.append(sysex); }
const DrumMap* drummap_for_patch(int patch) const;
- QList<dumb_patchlist_entry_t> getPatches(int channel, MType songType, bool drum);
- unsigned getNextPatch(int channel, unsigned patch, MType songType, bool drum);
- unsigned getPrevPatch(int channel, unsigned patch, MType songType, bool drum);
+ QList<dumb_patchlist_entry_t> getPatches(int channel, bool drum);
+ unsigned getNextPatch(int channel, unsigned patch, bool drum);
+ unsigned getPrevPatch(int channel, unsigned patch, bool drum);
EventList* midiInit() const { return _midiInit; }
EventList* midiReset() const { return _midiReset; }
@@ -235,9 +237,9 @@ class MidiInstrument {
virtual bool hasNativeGui() const { return false; }
virtual void writeToGui(const MidiPlayEvent&) {}
- virtual void reset(int, MType);
- virtual QString getPatchName(int,int,MType,bool);
- virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool);
+ virtual void reset(int);
+ virtual QString getPatchName(int,int,bool);
+ virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool);
void read(Xml&);
void write(int level, Xml&);
diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp
index a60ea229..415c6385 100644
--- a/muse2/muse/liste/editevent.cpp
+++ b/muse2/muse/liste/editevent.cpp
@@ -823,7 +823,7 @@ void EditCtrlDialog::updatePatch()
int port = track->outPort();
int channel = track->outChannel();
MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
- patchName->setText(instr->getPatchName(channel, val, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ patchName->setText(instr->getPatchName(channel, val, track->isDrumTrack()));
int hb = ((val >> 16) & 0xff) + 1;
if (hb == 0x100)
@@ -860,7 +860,7 @@ void EditCtrlDialog::instrPopup()
MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
MusEGui::PopupMenu* pup = new MusEGui::PopupMenu(this);
- instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack());
+ instr->populatePatchPopup(pup, channel, track->isDrumTrack());
if(pup->actions().count() == 0)
{
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index 503208e6..f1d5124d 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -4,7 +4,7 @@
// $Id: midi.cpp,v 1.43.2.22 2009/11/09 20:28:28 terminator356 Exp $
//
// (C) Copyright 1999/2004 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2011-2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -71,6 +71,7 @@ const unsigned int mmcStopMsgLen = sizeof(mmcStopMsg);
const unsigned int mmcLocateMsgLen = sizeof(mmcLocateMsg);
#define CALC_TICK(the_tick) lrintf((float(the_tick) * float(MusEGlobal::config.division) + float(div/2)) / float(div));
+
/*---------------------------------------------------------
* midi_meta_name
*---------------------------------------------------------*/
@@ -79,22 +80,22 @@ QString midiMetaName(int meta)
{
const char* s = "";
switch (meta) {
- case 0: s = "Sequence Number"; break;
- case 1: s = "Text Event"; break;
- case 2: s = "Copyright"; break;
- case 3: s = "Sequence/Track Name"; break;
- case 4: s = "Instrument Name"; break;
- case 5: s = "Lyric"; break;
- case 6: s = "Marker"; break;
- case 7: s = "Cue Point"; break;
- case 8:
- case 9:
- case 0x0a:
- case 0x0b:
- case 0x0c:
- case 0x0d:
- case 0x0e:
- case 0x0f: s = "Text"; break;
+ case 0: s = "Text 0: Sequence Number"; break;
+ case 1: s = "Text 1: Track comment"; break;
+ case 2: s = "Text 2: Copyright"; break;
+ case 3: s = "Text 3: Sequence/Track Name"; break;
+ case 4: s = "Text 4: Instrument Name"; break;
+ case 5: s = "Text 5: Lyric"; break;
+ case 6: s = "Text 6: Marker"; break;
+ case 7: s = "Text 7: Cue Point"; break;
+ case 8: s = "Text 8"; break;
+ case 9: s = "Text 9: Device Name"; break;
+ case 0x0a: s = "Text A"; break;
+ case 0x0b: s = "Text B"; break;
+ case 0x0c: s = "Text C"; break;
+ case 0x0d: s = "Text D"; break;
+ case 0x0e: s = "Text E"; break;
+ case 0x0f: s = "Text F"; break;
case 0x20: s = "Channel Prefix"; break;
case 0x21: s = "Port Change"; break;
case 0x2f: s = "End of Track"; break;
@@ -411,31 +412,30 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
{
const unsigned char* data = ev.data();
switch (ev.dataA()) {
- case 0x01: // Text
+ case ME_META_TEXT_1_COMMENT: // Text
if (track->comment().isEmpty())
track->setComment(QString((const char*)data));
else
track->setComment(track->comment() + "\n" + QString((const char*)data));
break;
- case 0x03: // Sequence-/TrackName
+ case ME_META_TEXT_3_TRACK_NAME: // Sequence-/TrackName
track->setName(QString((char*)data));
break;
- case 0x6: // Marker
+ case ME_META_TEXT_6_MARKER: // Marker
{
unsigned ltick = CALC_TICK(tick);
MusEGlobal::song->addMarker(QString((const char*)(data)), ltick, false);
}
break;
- case 0x5: // Lyrics
- case 0x8: // text
- case 0x9:
- case 0xa:
+ case ME_META_TEXT_5_LYRIC: // Lyrics
+ case ME_META_TEXT_8: // text
+ case ME_META_TEXT_9_DEVICE_NAME:
+ case ME_META_TEXT_A:
break;
-
- case 0x0f: // Track Comment
+ case ME_META_TEXT_F_TRACK_COMMENT: // Track Comment
track->setComment(QString((char*)data));
break;
- case 0x51: // Tempo
+ case ME_META_SET_TEMPO: // Tempo
{
unsigned tempo = data[2] + (data[1] << 8) + (data[0] <<16);
unsigned ltick = CALC_TICK(tick);
@@ -443,7 +443,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
MusEGlobal::tempomap.addTempo(ltick, tempo);
}
break;
- case 0x58: // Time Signature
+ case ME_META_TIME_SIGNATURE: // Time Signature
{
int timesig_z = data[0];
int n = data[1];
@@ -454,10 +454,13 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
AL::sigmap.add(ltick, AL::TimeSignature(timesig_z, timesig_n));
}
break;
- case 0x59: // Key Signature
+ case ME_META_KEY_SIGNATURE: // Key Signature
break;
- default:
- printf("unknown Meta 0x%x %d\n", ev.dataA(), ev.dataA());
+ default:
+ printf("buildMidiEventList: unknown Meta 0x%x %d unabsorbed, adding instead to track:%s\n", ev.dataA(), ev.dataA(), track->name().toLatin1().constData());
+ e.setType(Meta);
+ e.setA(ev.dataA());
+ e.setData(ev.data(), ev.len());
}
}
break;
@@ -633,46 +636,6 @@ void Audio::initDevices()
activePorts[i] = false; // no standard initialization
}
}
- //
- // First all ports are initialized to GM and then are changed
- // to XG/GS in order to prevent that devices with more than one
- // port, e.g. Korg NS5R, toggle between GM and XG/GS several times.
- //
- // Standard initialization...
- for (int i = 0; i < MIDI_PORTS; ++i) {
- if (!activePorts[i])
- continue;
- MusECore::MidiPort* port = &MusEGlobal::midiPorts[i];
- switch(MusEGlobal::song->mtype()) {
- case MT_GS:
- case MT_UNKNOWN:
- break;
- case MT_GM:
- case MT_XG:
- port->sendGmOn();
- break;
- }
- }
- for (int i = 0; i < MIDI_PORTS; ++i) {
- if (!activePorts[i])
- continue;
- MusECore::MidiPort* port = &MusEGlobal::midiPorts[i];
- switch(MusEGlobal::song->mtype()) {
- case MT_UNKNOWN:
- break;
- case MT_GM:
- port->sendGmInitValues();
- break;
- case MT_GS:
- port->sendGsOn();
- port->sendGsInitValues();
- break;
- case MT_XG:
- port->sendXgOn();
- port->sendXgInitValues();
- break;
- }
- }
}
//---------------------------------------------------------
diff --git a/muse2/muse/midi.h b/muse2/muse/midi.h
index 711b36d5..1aab8ab0 100644
--- a/muse2/muse/midi.h
+++ b/muse2/muse/midi.h
@@ -4,7 +4,7 @@
// $Id: midi.h,v 1.4.2.2 2009/11/09 20:28:28 terminator356 Exp $
//
// (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2011-2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -58,8 +58,37 @@ enum {
ME_SENSE = 0xfe
};
-#define ME_TIMESIG 0x58
-
+//--------------------------------------
+// Recognized / transmitted meta events:
+//--------------------------------------
+enum {
+ ME_META_TEXT_0_SEQUENCE_NUMBER = 0x00,
+ ME_META_TEXT_1_COMMENT = 0x01,
+ ME_META_TEXT_2_COPYRIGHT = 0x02,
+ ME_META_TEXT_3_TRACK_NAME = 0x03,
+ ME_META_TEXT_4_INSTRUMENT_NAME = 0x04,
+ ME_META_TEXT_5_LYRIC = 0x05,
+ ME_META_TEXT_6_MARKER = 0x06,
+ ME_META_TEXT_7_CUE_POINT = 0x07,
+ ME_META_TEXT_8 = 0x08,
+ ME_META_TEXT_9_DEVICE_NAME = 0x09,
+ ME_META_TEXT_A = 0x0a,
+ ME_META_TEXT_B = 0x0b,
+ ME_META_TEXT_C = 0x0c,
+ ME_META_TEXT_D = 0x0d,
+ ME_META_TEXT_E = 0x0e,
+ ME_META_TEXT_F_TRACK_COMMENT = 0x0f,
+ ME_META_CHANNEL_CHANGE = 0x20,
+ ME_META_PORT_CHANGE = 0x21,
+ ME_META_END_OF_TRACK = 0x2f,
+ ME_META_SET_TEMPO = 0x51,
+ ME_META_SMPTE_OFFSET = 0x54,
+ ME_META_TIME_SIGNATURE = 0x58,
+ ME_META_KEY_SIGNATURE = 0x59,
+ ME_META_SEQ_SPECIFIC_1 = 0x74,
+ ME_META_SEQ_SPECIFIC_2 = 0x7f
+};
+
extern const unsigned char gmOnMsg[];
extern const unsigned char gsOnMsg[];
diff --git a/muse2/muse/mididev.cpp b/muse2/muse/mididev.cpp
index 5ff8bf94..9f303e43 100644
--- a/muse2/muse/mididev.cpp
+++ b/muse2/muse/mididev.cpp
@@ -445,8 +445,6 @@ bool MidiDevice::putEvent(const MidiPlayEvent& ev)
return putMidiEvent(MidiPlayEvent(0, 0, chn, ME_PITCHBEND, b, 0));
}
if (a == CTRL_PROGRAM) {
- // don't output program changes for GM drum channel
- if (!(MusEGlobal::song->mtype() == MT_GM && chn == 9)) {
int hb = (b >> 16) & 0xff;
int lb = (b >> 8) & 0xff;
int pr = b & 0x7f;
@@ -455,8 +453,6 @@ bool MidiDevice::putEvent(const MidiPlayEvent& ev)
if (lb != 0xff)
putMidiEvent(MidiPlayEvent(0, 0, chn, ME_CONTROLLER, CTRL_LBANK, lb));
return putMidiEvent(MidiPlayEvent(0, 0, chn, ME_PROGRAM, pr, 0));
- }
- return false; // Should absorb anyway and return, right? p4.0.48 Tim.
}
#if 1 // if ALSA cannot handle RPN NRPN etc. DELETETHIS? remove the wrapping #if #endif
diff --git a/muse2/muse/midifile.cpp b/muse2/muse/midifile.cpp
index bc546729..6f92d0f5 100644
--- a/muse2/muse/midifile.cpp
+++ b/muse2/muse/midifile.cpp
@@ -4,6 +4,7 @@
// $Id: midifile.cpp,v 1.17 2004/06/18 08:36:43 wschweer Exp $
//
// (C) Copyright 1999-2003 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -75,14 +76,16 @@ MidiFile::MidiFile(FILE* f)
{
fp = f;
curPos = 0;
- _mtype = MT_GM; // MT_UNKNOWN;
+ lastMtype = MT_UNKNOWN;
_error = MF_NO_ERROR;
_tracks = new MidiFileTrackList;
+ _usedPortMap = new MidiFilePortMap;
}
MidiFile::~MidiFile()
{
delete _tracks;
+ delete _usedPortMap;
}
//---------------------------------------------------------
@@ -243,11 +246,14 @@ bool MidiFile::readTrack(MidiFileTrack* t)
int port = 0;
int channel = 0;
-
+
for (;;) {
MidiPlayEvent event;
lastport = -1;
lastchannel = -1;
+ lastMtype = MT_UNKNOWN;
+ lastInstrName.clear();
+ lastDeviceName.clear();
int rv = readEvent(&event, t);
if (lastport != -1) {
@@ -264,6 +270,67 @@ bool MidiFile::readTrack(MidiFileTrack* t)
channel = 0;
}
}
+
+ if(!lastDeviceName.isEmpty())
+ {
+ iMidiFilePort iup = _usedPortMap->begin();
+ for( ; iup != _usedPortMap->end(); ++iup)
+ {
+ if(iup->second._subst4DevName == lastDeviceName)
+ {
+ port = iup->first;
+ break;
+ }
+ }
+ if(iup == _usedPortMap->end())
+ {
+ MidiDevice* md = MusEGlobal::midiDevices.find(lastDeviceName);
+ if(md)
+ {
+ int pn = md->midiPort();
+ if(pn != -1)
+ port = pn;
+ else
+ {
+ for(int i = 0; i < MIDI_PORTS; ++i)
+ {
+ iMidiFilePort ip = _usedPortMap->find(i);
+ MidiPort* mp = &MusEGlobal::midiPorts[i];
+ if(!mp->device() && (ip == _usedPortMap->end() || ip->second._subst4DevName.isEmpty()))
+ {
+ //mp->setMidiDevice(); // No, done in importMidi
+ //msgSetMidiDevice(
+ port = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ iMidiFilePort iup = _usedPortMap->find(port);
+ if(iup == _usedPortMap->end())
+ {
+ MidiFilePort up;
+ if(lastMtype != MT_UNKNOWN)
+ up._midiType = lastMtype;
+ if(!lastInstrName.isEmpty())
+ up._instrName = lastInstrName;
+ if(!lastDeviceName.isEmpty())
+ up._subst4DevName = lastDeviceName;
+ _usedPortMap->insert(std::pair<int, MidiFilePort>(port, up));
+ }
+ else
+ {
+ if(lastMtype != MT_UNKNOWN)
+ iup->second._midiType = lastMtype;
+ if(!lastInstrName.isEmpty())
+ iup->second._instrName = lastInstrName;
+ if(!lastDeviceName.isEmpty())
+ iup->second._subst4DevName = lastDeviceName;
+ }
+
if (rv == 0)
break;
else if (rv == -1)
@@ -278,6 +345,7 @@ bool MidiFile::readTrack(MidiFileTrack* t)
channel = event.channel();
el->add(event);
}
+
int end = curPos;
if (end != endPos) {
printf("MidiFile::readTrack(): TRACKLEN does not fit %d+%d != %d, %d too much\n",
@@ -332,6 +400,7 @@ int MidiFile::readEvent(MidiPlayEvent* event, MidiFileTrack* t)
printf("readEvent: error 3\n");
return -2;
}
+ // Buffer can be deleted by caller's event when it goes out of scope.
buffer = new unsigned char[len];
if (read(buffer, len)) {
printf("readEvent: error 4\n");
@@ -347,24 +416,22 @@ int MidiFile::readEvent(MidiPlayEvent* event, MidiFileTrack* t)
event->setType(ME_SYSEX);
event->setData(buffer, len);
if (((unsigned)len == gmOnMsgLen) && memcmp(buffer, gmOnMsg, gmOnMsgLen) == 0) {
- setMType(MT_GM);
+ lastMtype = MT_GM;
return -1;
}
if (((unsigned)len == gsOnMsgLen) && memcmp(buffer, gsOnMsg, gsOnMsgLen) == 0) {
- setMType(MT_GS);
+ lastMtype = MT_GS;
return -1;
}
if (((unsigned)len == xgOnMsgLen) && memcmp(buffer, xgOnMsg, xgOnMsgLen) == 0) {
- setMType(MT_XG);
+ lastMtype = MT_XG;
return -1;
}
if (buffer[0] == 0x41) { // Roland
- if (mtype() != MT_UNKNOWN)
- setMType(MT_GS);
+ lastMtype = MT_GS;
}
else if (buffer[0] == 0x43) { // Yamaha
- if (mtype() == MT_UNKNOWN || mtype() == MT_GM)
- setMType(MT_XG);
+ lastMtype = MT_XG;
int type = buffer[1] & 0xf0;
switch (type) {
case 0x00: // bulk dump
@@ -384,7 +451,7 @@ int MidiFile::readEvent(MidiPlayEvent* event, MidiFileTrack* t)
// 5 - DRUM 4
printf("xg set part mode channel %d to %d\n", buffer[4]+1, buffer[6]);
if (buffer[6] != 0)
- t->isDrumTrack = true;
+ t->_isDrumTrack = true;
}
break;
case 0x20:
@@ -398,6 +465,8 @@ int MidiFile::readEvent(MidiPlayEvent* event, MidiFileTrack* t)
return -1;
}
}
+ if(MusEGlobal::debugMsg)
+ printf("MidiFile::readEvent: unknown Sysex 0x%02x unabsorbed, passing thru intead\n", me & 0xff);
return 3;
}
if (me == 0xff) {
@@ -424,18 +493,28 @@ int MidiFile::readEvent(MidiPlayEvent* event, MidiFileTrack* t)
}
buffer[len] = 0;
switch(type) {
- case 0x21: // switch port
+ case ME_META_TEXT_9_DEVICE_NAME: // device name
+ lastDeviceName = QString((const char*)buffer);
+ delete[] buffer;
+ return -1;
+ case ME_META_TEXT_4_INSTRUMENT_NAME: // instrument name
+ lastInstrName = QString((const char*)buffer);
+ delete[] buffer;
+ return -1;
+ case ME_META_PORT_CHANGE: // switch port
lastport = buffer[0];
delete[] buffer;
return -1;
- case 0x20: // switch channel
+ case ME_META_CHANNEL_CHANGE: // switch channel
lastchannel = buffer[0];
delete[] buffer;
return -1;
- case 0x2f: // End of Track
+ case ME_META_END_OF_TRACK: // End of Track
delete[] buffer;
return 0;
default:
+ if(MusEGlobal::debugMsg)
+ printf("MidiFile::readEvent: unknown Meta 0x%x %d unabsorbed, passing thru instead\n", type, type);
event->setType(ME_META);
event->setData(buffer, len+1);
event->setA(type);
diff --git a/muse2/muse/midifile.h b/muse2/muse/midifile.h
index 9ef169e0..0baf2af9 100644
--- a/muse2/muse/midifile.h
+++ b/muse2/muse/midifile.h
@@ -4,6 +4,7 @@
// $Id: midifile.h,v 1.3 2004/01/04 18:24:43 wschweer Exp $
//
// (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -24,6 +25,8 @@
#ifndef __MIDIFILE_H__
#define __MIDIFILE_H__
+#include <QString>
+
#include <stdio.h>
#include <list>
@@ -34,6 +37,27 @@ namespace MusECore {
struct MPEventList;
class MidiPlayEvent;
+class MidiInstrument;
+
+//---------------------------------------------------------
+// MidiFileTrack
+//---------------------------------------------------------
+
+struct MidiFilePort {
+ bool _isStandardDrums;
+ MType _midiType;
+ QString _instrName;
+ QString _subst4DevName;
+ MidiFilePort() {
+ _midiType = MT_UNKNOWN;
+ _isStandardDrums = false;
+ }
+};
+
+
+typedef std::map<int, MidiFilePort> MidiFilePortMap;
+typedef MidiFilePortMap::iterator iMidiFilePort;
+typedef MidiFilePortMap::const_iterator ciMidiFilePort;
//---------------------------------------------------------
// MidiFileTrack
@@ -41,9 +65,9 @@ class MidiPlayEvent;
struct MidiFileTrack {
MPEventList events;
- bool isDrumTrack;
+ bool _isDrumTrack;
MidiFileTrack() {
- isDrumTrack = false;
+ _isDrumTrack = false;
}
};
@@ -60,12 +84,18 @@ class MidiFile {
int format; // smf file format
int ntracks; // number of midi tracks
int _division;
- MType _mtype;
+ //MType _mtype;
MidiFileTrackList* _tracks;
int status, click;
int sstatus;
int lastport, lastchannel;
+ MType lastMtype;
+ //QString lastMtypeInstrument;
+ QString lastInstrName;
+ QString lastDeviceName;
+ //MidiInstrument* def_instr;
+ MidiFilePortMap* _usedPortMap;
FILE* fp;
int curPos;
@@ -92,6 +122,7 @@ class MidiFile {
bool read();
bool write();
QString error();
+ MidiFilePortMap* usedPortMap() { return _usedPortMap; }
MidiFileTrackList* trackList() { return _tracks; }
int tracks() const { return ntracks; }
void setTrackList(MidiFileTrackList* tr, int n) {
@@ -100,8 +131,6 @@ class MidiFile {
}
void setDivision(int d) { _division = d; }
int division() const { return _division; }
- void setMType(MType t) { _mtype = t; }
- MType mtype() const { return _mtype; }
};
} // namespace MusECore
diff --git a/muse2/muse/mpevent.cpp b/muse2/muse/mpevent.cpp
index a8596224..1ad09ff3 100644
--- a/muse2/muse/mpevent.cpp
+++ b/muse2/muse/mpevent.cpp
@@ -4,6 +4,7 @@
// $Id: mpevent.cpp,v 1.6.2.2 2009/11/25 09:09:43 terminator356 Exp $
//
// (C) Copyright 2002-2004 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -101,6 +102,101 @@ void MEvent::dump() const
}
//---------------------------------------------------------
+// sortingWeight
+//---------------------------------------------------------
+
+int MEvent::sortingWeight() const
+{
+ // Sorting weight initially worked out by Tim E. Real
+ // Sorted here by most popular for quickest reponse.
+
+ switch(_type)
+ {
+ case ME_NOTEON:
+ return 98;
+ case ME_NOTEOFF:
+ return 7;
+
+ case ME_PITCHBEND:
+ return 25;
+ case ME_CONTROLLER:
+ switch(_a)
+ {
+ case CTRL_PROGRAM:
+ return 21;
+ default:
+ return 24;
+ }
+ case ME_PROGRAM:
+ return 20;
+
+ case ME_CLOCK:
+ return 0;
+ case ME_MTC_QUARTER:
+ return 1;
+ case ME_TICK:
+ return 2;
+ case ME_SENSE:
+ return 3;
+
+ case ME_SYSEX_END:
+ return 4;
+ case ME_AFTERTOUCH:
+ return 5;
+ case ME_POLYAFTER:
+ return 6;
+ case ME_STOP:
+ return 8;
+
+ case ME_SONGSEL:
+ return 9;
+ case ME_SYSEX:
+ return 18;
+ case ME_META:
+ switch(_a)
+ {
+ case ME_META_TEXT_2_COPYRIGHT:
+ return 10;
+ case ME_META_TEXT_1_COMMENT:
+ return 11;
+ case ME_META_PORT_CHANGE:
+ return 12;
+ case ME_META_TEXT_9_DEVICE_NAME:
+ return 13;
+ case ME_META_CHANNEL_CHANGE:
+ return 14;
+
+ case ME_META_TEXT_3_TRACK_NAME:
+ return 15;
+ case ME_META_TEXT_F_TRACK_COMMENT:
+ return 16;
+ case ME_META_TEXT_0_SEQUENCE_NUMBER:
+ return 17;
+
+ case ME_META_TEXT_4_INSTRUMENT_NAME:
+ return 19;
+ case ME_META_END_OF_TRACK:
+ return 99;
+ default:
+ return 97;
+ }
+
+ case ME_TUNE_REQ:
+ return 22;
+ case ME_SONGPOS:
+ return 23;
+
+ case ME_START:
+ return 26;
+ case ME_CONTINUE:
+ return 27;
+ }
+
+ printf("FIXME: MEvent::sortingWeight: unknown event type:%d\n", _type);
+ return 100;
+}
+
+//---------------------------------------------------------
// operator <
//---------------------------------------------------------
@@ -115,9 +211,13 @@ bool MEvent::operator<(const MEvent& e) const
// notes
if (channel() == e.channel())
- return type() == ME_NOTEOFF
- || (type() == ME_NOTEON && dataB() == 0)
- || type() != ME_NOTEON; // Make note-ons last so that controllers such as program come before notes played. 1/31/2012 Tim.
+ {
+// REMOVE Tim.
+// return (type() == ME_NOTEOFF
+// || (type() == ME_NOTEON && dataB() == 0)
+// || type() != ME_NOTEON; // Make note-ons last so that controllers such as program come before notes played. 1/31/2012 Tim.
+ return sortingWeight() < e.sortingWeight();
+ }
int map[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15 };
return map[channel()] < map[e.channel()];
diff --git a/muse2/muse/mpevent.h b/muse2/muse/mpevent.h
index 903a8126..7c28bde4 100644
--- a/muse2/muse/mpevent.h
+++ b/muse2/muse/mpevent.h
@@ -4,6 +4,7 @@
// $Id: mpevent.h,v 1.8.2.5 2009/11/25 09:09:43 terminator356 Exp $
//
// (C) Copyright 1999-2002 Werner Schweer (ws@seh.de)
+// (C) Copyright 2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -77,7 +78,9 @@ class MEvent {
_loopNum = ed._loopNum;
return *this;
}
-
+
+ int sortingWeight() const;
+
int port() const { return _port; }
int channel() const { return _channel; }
int type() const { return _type; }
diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp
index 026ec1a9..000bbec3 100644
--- a/muse2/muse/song.cpp
+++ b/muse2/muse/song.cpp
@@ -1583,12 +1583,6 @@ PartList* Song::getSelectedWaveParts() const
return parts;
}
-void Song::setMType(MType t)
- {
- _mtype = t;
- MusEGlobal::song->update(SC_SONG_TYPE);
- }
-
//---------------------------------------------------------
// beat
//---------------------------------------------------------
@@ -2129,8 +2123,6 @@ void Song::clear(bool signal, bool clear_all)
punchoutFlag = false;
recordFlag = false;
soloFlag = false;
- // seq
- _mtype = MT_UNKNOWN;
_recMode = REC_OVERDUP;
_cycleMode = CYCLE_NORMAL;
_click = false;
diff --git a/muse2/muse/song.h b/muse2/muse/song.h
index e9e893f1..63256af3 100644
--- a/muse2/muse/song.h
+++ b/muse2/muse/song.h
@@ -97,7 +97,6 @@ class AudioDevice;
#define SC_CLIP_MODIFIED 0x4000000
#define SC_MIDI_CONTROLLER_ADD 0x8000000 // a hardware midi controller was added or deleted
#define SC_MIDI_TRACK_PROP 0x10000000 // a midi track's properties changed (channel, compression etc)
-#define SC_SONG_TYPE 0x20000000 // the midi song type (mtype) changed
#define SC_KEY 0x40000000 // key map changed
#define SC_EVERYTHING -1 // global update
@@ -153,7 +152,6 @@ class Song : public QObject {
bool punchoutFlag;
bool recordFlag;
bool soloFlag;
- enum MType _mtype;
int _recMode;
int _cycleMode;
bool _click;
@@ -181,9 +179,6 @@ class Song : public QObject {
void endMsgCmd();
void processMsg(AudioMsg* msg);
- void setMType(MType t);
- MType mtype() const { return _mtype; }
-
void setFollow(FollowMode m) { _follow = m; }
FollowMode follow() const { return _follow; }
diff --git a/muse2/muse/songfile.cpp b/muse2/muse/songfile.cpp
index 07430c26..90805175 100644
--- a/muse2/muse/songfile.cpp
+++ b/muse2/muse/songfile.cpp
@@ -937,8 +937,8 @@ void Song::read(Xml& xml, bool isTemplate)
setRecord(xml.parseInt());
else if (tag == "solo")
soloFlag = xml.parseInt();
- else if (tag == "type")
- _mtype = MType(xml.parseInt());
+ else if (tag == "type") // Obsolete.
+ xml.parseInt();
else if (tag == "recmode")
_recMode = xml.parseInt();
else if (tag == "cycle")
@@ -1088,7 +1088,6 @@ void Song::write(int level, Xml& xml) const
xml.intTag(level, "punchout", punchoutFlag);
xml.intTag(level, "record", recordFlag);
xml.intTag(level, "solo", soloFlag);
- xml.intTag(level, "type", _mtype);
xml.intTag(level, "recmode", _recMode);
xml.intTag(level, "cycle", _cycleMode);
xml.intTag(level, "click", _click);
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index 332ff90f..781cab3f 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -863,11 +863,11 @@ void SynthI::read(Xml& xml)
// getPatchName
//---------------------------------------------------------
-const char* MessSynthIF::getPatchName(int channel, int prog, MType type, bool drum)
+const char* MessSynthIF::getPatchName(int channel, int prog, bool drum)
{
if (_mess)
{
- const char* s = _mess->getPatchName(channel, prog, type, drum);
+ const char* s = _mess->getPatchName(channel, prog, drum);
if(s)
return s;
}
@@ -878,7 +878,7 @@ const char* MessSynthIF::getPatchName(int channel, int prog, MType type, bool dr
// populatePatchPopup
//---------------------------------------------------------
-void MessSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int ch, MType, bool)
+void MessSynthIF::populatePatchPopup(MusEGui::PopupMenu* menu, int ch, bool)
{
menu->clear();
const MidiPatch* mp = _mess->getPatchInfo(ch, 0);
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index efa76f5f..f5ecc9ab 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -153,9 +153,8 @@ class SynthIF {
virtual int totalOutChannels() const = 0;
virtual int totalInChannels() const = 0;
virtual void deactivate3() = 0;
- virtual const char* getPatchName(int, int, int, bool) const = 0;
- virtual const char* getPatchName(int, int, MType, bool) = 0;
- virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool) = 0;
+ virtual const char* getPatchName(int, int, bool) = 0;
+ virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool) = 0;
virtual void write(int level, Xml& xml) const = 0;
virtual float getParameter(unsigned long idx) const = 0;
virtual void setParameter(unsigned long idx, float value) = 0;
@@ -228,12 +227,12 @@ class SynthI : public AudioTrack, public MidiDevice,
Synth* synth() const { return synthesizer; }
virtual bool isSynti() const { return true; }
- virtual QString getPatchName(int ch, int prog, MType t, bool dr) {
- return _sif->getPatchName(ch, prog, t, dr);
+ virtual QString getPatchName(int ch, int prog, bool dr) {
+ return _sif->getPatchName(ch, prog, dr);
}
- virtual void populatePatchPopup(MusEGui::PopupMenu* m, int i, MType t, bool d) {
- _sif->populatePatchPopup(m, i, t, d);
+ virtual void populatePatchPopup(MusEGui::PopupMenu* m, int i, bool d) {
+ _sif->populatePatchPopup(m, i, d);
}
void currentProg(unsigned long *prog, unsigned long *bankL, unsigned long *bankH);
@@ -316,9 +315,8 @@ class MessSynthIF : public SynthIF {
virtual int totalOutChannels() const;
virtual int totalInChannels() const;
virtual void deactivate3();
- virtual const char* getPatchName(int, int, int, bool) const { return ""; }
- virtual const char* getPatchName(int, int, MType, bool);
- virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool);
+ virtual const char* getPatchName(int, int, bool);
+ virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool);
virtual void write(int level, Xml& xml) const;
virtual float getParameter(unsigned long) const { return 0.0; }
virtual void setParameter(unsigned long, float) {}
diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp
index 48e1ba2b..f03414fc 100644
--- a/muse2/muse/ticksynth.cpp
+++ b/muse2/muse/ticksynth.cpp
@@ -100,9 +100,8 @@ class MetronomeSynthIF : public SynthIF
virtual int totalOutChannels() const { return 1; }
virtual int totalInChannels() const { return 0; }
virtual void deactivate3() {}
- virtual const char* getPatchName(int, int, int, bool) const { return ""; }
- virtual const char* getPatchName(int, int, MType, bool) { return ""; }
- virtual void populatePatchPopup(MusEGui::PopupMenu*, int, MType, bool) {};
+ virtual const char* getPatchName(int, int, bool) { return ""; }
+ virtual void populatePatchPopup(MusEGui::PopupMenu*, int, bool) {};
virtual void write(int, Xml&) const {}
virtual float getParameter(unsigned long) const { return 0.0; }
virtual void setParameter(unsigned long, float) {}
diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h
index 3490cb39..52c45f16 100644
--- a/muse2/muse/vst.h
+++ b/muse2/muse/vst.h
@@ -93,9 +93,8 @@ class VstSynthIF : public SynthIF
virtual int totalOutChannels() const;
virtual int totalInChannels() const;
virtual void deactivate3();
- virtual const char* getPatchName(int, int, int, bool) const { return ""; }
- virtual const char* getPatchName(int, int, MType, bool) { return ""; }
- virtual void populatePatchPopup(PopupMenu*, int, MType, bool) {};
+ virtual const char* getPatchName(int, int, bool) { return ""; }
+ virtual void populatePatchPopup(PopupMenu*, int, bool) {};
virtual void write(int level, Xml& xml) const;
virtual float getParameter(unsigned long idx) const;
virtual void setParameter(unsigned long idx, float value);
diff --git a/muse2/muse/widgets/configmidifilebase.ui b/muse2/muse/widgets/configmidifilebase.ui
index 3eb7063e..50e28c19 100644
--- a/muse2/muse/widgets/configmidifilebase.ui
+++ b/muse2/muse/widgets/configmidifilebase.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>546</width>
- <height>367</height>
+ <width>408</width>
+ <height>537</height>
</rect>
</property>
<property name="windowTitle">
@@ -16,8 +16,8 @@
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
- <layout class="QVBoxLayout">
- <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
<widget class="QGroupBox" name="midiImportGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
@@ -28,8 +28,55 @@
<property name="title">
<string>Import:</string>
</property>
- <layout class="QGridLayout">
+ <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Default instrument:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="importDefaultInstr">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>164</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QCheckBox" name="importDevNameMetas">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Device Name metas trump Port metas if both exist</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <widget class="QCheckBox" name="importInstrNameMetas">
+ <property name="text">
+ <string>Instrument Name metas trump Mode sysexes if both exist</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="splitPartsCheckBox">
<property name="toolTip">
<string>Split tracks into parts, or one single part</string>
@@ -42,7 +89,7 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="4" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="newDrumsCheckbox">
@@ -56,6 +103,12 @@
</item>
<item>
<widget class="QRadioButton" name="oldDrumsCheckbox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="text">
<string>Use old-style drum tracks</string>
</property>
@@ -66,7 +119,62 @@
</layout>
</widget>
</item>
- <item>
+ <item row="3" column="0">
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="Horizontal Spacing2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonOk">
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="shortcut">
+ <string/>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel">
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="shortcut">
+ <string/>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
<widget class="QGroupBox" name="midiExportGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
@@ -77,12 +185,61 @@
<property name="title">
<string>Export:</string>
</property>
- <layout class="QGridLayout">
- <item row="3" column="1">
- <widget class="QLineEdit" name="copyrightEdit"/>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="textLabel3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Format:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
</item>
- <item row="2" column="1">
+ <item row="0" column="1">
+ <widget class="QComboBox" name="formatCombo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <item>
+ <property name="text">
+ <string>0 (single track)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>1 (multiple tracks)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="textLabel1">
+ <property name="text">
+ <string>Division:</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
<widget class="QComboBox" name="divisionCombo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<item>
<property name="text">
<string>96</string>
@@ -100,73 +257,80 @@
</item>
</widget>
</item>
- <item row="4" column="0" colspan="2">
- <widget class="QCheckBox" name="extendedFormat">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="text">
- <string>Enable extended smf format (currently not implemented)</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0" colspan="2">
- <widget class="QCheckBox" name="twoByteTimeSigs">
- <property name="text">
- <string>Use &amp;2-byte time signatures instead of standard 4</string>
+ <item row="0" column="4">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
</property>
- <property name="shortcut">
- <string>Alt+2</string>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>59</width>
+ <height>20</height>
+ </size>
</property>
- </widget>
+ </spacer>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="textLabel2">
- <property name="text">
- <string>Copyright:</string>
+ <item row="1" column="0" colspan="5">
+ <widget class="QLabel" name="textLabel4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="wordWrap">
- <bool>false</bool>
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ </font>
</property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="textLabel3">
<property name="text">
- <string>Format:</string>
+ <string>Note: Format 0 uses the FIRST midi track's name/comment in the arranger</string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
- <item row="1" column="0" colspan="2">
- <widget class="QLabel" name="textLabel4">
+ <item row="2" column="0">
+ <widget class="QLabel" name="textLabel2">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
- <string>Note: Format 0 uses the FIRST midi track's name/comment in the arranger</string>
+ <string>Copyright:</string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
- <item row="2" column="0">
- <widget class="QLabel" name="textLabel1">
+ <item row="2" column="1" colspan="4">
+ <widget class="QLineEdit" name="copyrightEdit"/>
+ </item>
+ <item row="3" column="0" colspan="5">
+ <widget class="QCheckBox" name="extendedFormat">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="text">
- <string>Division:</string>
+ <string>Enable extended smf format (currently not implemented)</string>
</property>
- <property name="wordWrap">
- <bool>false</bool>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="4">
+ <widget class="QCheckBox" name="twoByteTimeSigs">
+ <property name="text">
+ <string>Use &amp;2-byte time signatures instead of standard 4</string>
+ </property>
+ <property name="shortcut">
+ <string>Alt+2</string>
</property>
</widget>
</item>
- <item row="6" column="0" colspan="2">
+ <item row="5" column="0" colspan="5">
<widget class="QCheckBox" name="optNoteOffs">
<property name="text">
<string>Save space by replacing note-offs with &amp;zero velocity note-ons</string>
@@ -176,77 +340,133 @@
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QComboBox" name="formatCombo">
- <item>
- <property name="text">
- <string>0 (single track)</string>
+ <item row="6" column="0" colspan="5">
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="spacing">
+ <number>6</number>
</property>
- </item>
- <item>
- <property name="text">
- <string>1 (multiple tracks)</string>
+ <property name="margin">
+ <number>0</number>
</property>
- </item>
+ <item>
+ <widget class="QRadioButton" name="exportModeSysexes">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Mode sysexes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="exportInstrumentNames">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Instrument name metas</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="exportModeAndInstrName">
+ <property name="text">
+ <string>Both</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="7" column="0" colspan="5">
+ <widget class="QFrame" name="frame_2">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="exportPortMetas">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Port metas</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="exportDeviceNameMetas">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Device name metas</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="exportPortAndDeviceNameMetas">
+ <property name="text">
+ <string>Both</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="8" column="0" colspan="3">
+ <widget class="QCheckBox" name="exportPortDeviceSMF0">
+ <property name="text">
+ <string>Export a Port/Device meta for format 0</string>
+ </property>
</widget>
</item>
</layout>
</widget>
</item>
- <item>
- <layout class="QHBoxLayout">
- <property name="spacing">
- <number>6</number>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
</property>
- <property name="margin">
- <number>0</number>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
</property>
- <item>
- <spacer name="Horizontal Spacing2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Expanding</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QPushButton" name="buttonOk">
- <property name="text">
- <string>&amp;OK</string>
- </property>
- <property name="shortcut">
- <string/>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- <property name="default">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="buttonCancel">
- <property name="text">
- <string>&amp;Cancel</string>
- </property>
- <property name="shortcut">
- <string/>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- </layout>
+ </spacer>
</item>
</layout>
</widget>
diff --git a/muse2/muse/widgets/gensetbase.ui b/muse2/muse/widgets/gensetbase.ui
index f1dc405b..c204b9f4 100644
--- a/muse2/muse/widgets/gensetbase.ui
+++ b/muse2/muse/widgets/gensetbase.ui
@@ -1526,7 +1526,7 @@ left button behave like the middle button in such areas.</string>
<property name="title">
<string>Drum tracks</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
+ <layout class="QGridLayout" name="gridLayout9">
<item row="0" column="0">
<widget class="QRadioButton" name="onlyOldDrumBtn">
<property name="text">
@@ -1559,7 +1559,7 @@ left button behave like the middle button in such areas.</string>
</widget>
</item>
<item>
- <spacer name="verticalSpacer_2">
+ <spacer name="verticalSpacer_21">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp
index 1b98f100..23c7bf34 100644
--- a/muse2/muse/widgets/mtrackinfo.cpp
+++ b/muse2/muse/widgets/mtrackinfo.cpp
@@ -407,7 +407,7 @@ void MidiTrackInfo::heartBeat()
else
{
MusECore::MidiInstrument* instr = mp->instrument();
- QString name = instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->isDrumTrack());
+ QString name = instr->getPatchName(outChannel, nprogram, track->isDrumTrack());
if(name.isEmpty())
{
const QString n("???");
@@ -448,7 +448,7 @@ void MidiTrackInfo::heartBeat()
//else
//{
MusECore::MidiInstrument* instr = mp->instrument();
- QString name = instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->isDrumTrack());
+ QString name = instr->getPatchName(outChannel, program, track->isDrumTrack());
if(iPatch->text() != name)
iPatch->setText(name);
@@ -827,7 +827,7 @@ void MidiTrackInfo::iProgHBankChanged()
MusEGlobal::audio->msgPlayMidiEvent(&ev);
MusECore::MidiInstrument* instr = mp->instrument();
- iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ iPatch->setText(instr->getPatchName(channel, program, track->isDrumTrack()));
// updateTrackInfo();
}
@@ -905,7 +905,7 @@ void MidiTrackInfo::iProgLBankChanged()
MusEGlobal::audio->msgPlayMidiEvent(&ev);
MusECore::MidiInstrument* instr = mp->instrument();
- iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ iPatch->setText(instr->getPatchName(channel, program, track->isDrumTrack()));
// updateTrackInfo();
}
@@ -983,7 +983,7 @@ void MidiTrackInfo::iProgramChanged()
MusEGlobal::audio->msgPlayMidiEvent(&ev);
MusECore::MidiInstrument* instr = mp->instrument();
- iPatch->setText(instr->getPatchName(channel, program, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ iPatch->setText(instr->getPatchName(channel, program, track->isDrumTrack()));
}
// updateTrackInfo();
@@ -1150,7 +1150,7 @@ void MidiTrackInfo::instrPopup()
MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
PopupMenu* pup = new PopupMenu(true);
- instr->populatePatchPopup(pup, channel, MusEGlobal::song->mtype(), track->isDrumTrack());
+ instr->populatePatchPopup(pup, channel, track->isDrumTrack());
if(pup->actions().count() == 0)
{
@@ -1479,7 +1479,7 @@ void MidiTrackInfo::updateTrackInfo(MusECore::SongChangedFlags_t flags)
else
{
MusECore::MidiInstrument* instr = mp->instrument();
- iPatch->setText(instr->getPatchName(outChannel, nprogram, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ iPatch->setText(instr->getPatchName(outChannel, nprogram, track->isDrumTrack()));
}
}
else
@@ -1495,7 +1495,7 @@ void MidiTrackInfo::updateTrackInfo(MusECore::SongChangedFlags_t flags)
//else
//{
MusECore::MidiInstrument* instr = mp->instrument();
- iPatch->setText(instr->getPatchName(outChannel, program, MusEGlobal::song->mtype(), track->isDrumTrack()));
+ iPatch->setText(instr->getPatchName(outChannel, program, track->isDrumTrack()));
int hb = ((program >> 16) & 0xff) + 1;
if (hb == 0x100)
diff --git a/muse2/muse/widgets/musewidgetsplug.cpp b/muse2/muse/widgets/musewidgetsplug.cpp
index 9c82b5f5..83a9fca9 100644
--- a/muse2/muse/widgets/musewidgetsplug.cpp
+++ b/muse2/muse/widgets/musewidgetsplug.cpp
@@ -169,6 +169,12 @@ MusEGlobal::GlobalConfigValues config = {
true, // optimize midi export file note offs
true, // Split imported tracks into multiple parts.
true, // importMidiNewStyleDrum
+ true, // importDevNameMetas Import Prefer Device Name metas over port number metas if both exist.
+ true, // importInstrNameMetas Import Prefer Instrument Name metas over Mode sysexes if both exist.
+ MusEGlobal::EXPORT_PORTS_DEVICES_ALL, // exportPortsDevices Export port number metas and/or device name metas.
+ true, // exportPortDeviceSMF0 Export a port and/or device meta even for SMF0.
+ MusEGlobal::EXPORT_MODE_INSTR_ALL, // exportModeInstr Export mode sysexes and/or instrument name metas.
+ QString("GM"), // importMidiDefaultInstr Default to this instrument not Generic, if no match found
1, // startMode
QString(""), // start song path
false, // startSongLoadConfig