bool LOS::importMidi(const QString name, bool merge)/*{{{*/ { bool popenFlag; FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); QMessageBox::critical(this, QString("LOS"), s); return rv; } // // evaluate song Type (GM, XG, GS, unknown) // MType t = song->midiType(); if (!merge) { t = mf.mtype(); song->setMType(t); } MidiInstrument* instr = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { MidiInstrument* mi = *i; if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_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); return true; //abort(); } MidiFileTrackList* etl = mf.trackList(); int division = mf.division(); // // create MidiTrack and copy events to ->events() // - combine note on/off events // - calculate tick value for internal resolution // for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MPEventList* el = &((*t)->events); if (el->empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; // somewhat silly and slooow: for (int port = 0; port < kMaxMidiPorts; ++port) { for (int channel = 0; channel < kMaxMidiChannels; ++channel) { // // check if there are any events for port/channel in track: // iMPEvent i; for (i = el->begin(); i != el->end(); ++i) { MidiPlayEvent ev = *i; if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel && ev.port() == port) break; } if (i == el->end()) continue; MidiTrack* track = new MidiTrack(); if ((*t)->isDrumTrack) { track->setType(Track::DRUM); } track->setOutChannel(channel); track->setOutPort(port); MidiPort* mport = &midiPorts[track->outPort()]; // this overwrites any instrument set for this port: mport->setInstrument(instr); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, first); // Don't do loops. buildMidiEventList(mel, el, track, division, first, false); first = false; // Hmm. buildMidiEventList already takes care of this. // But it seems to work. How? Must test. if (channel == 9 && song->midiType() != MT_UNKNOWN) { track->setType(Track::DRUM); // // remap drum pitch with drumInmap // EventList* tevents = track->events(); for (iEvent i = tevents->begin(); i != tevents->end(); ++i) { Event ev = i->second; if (ev.isNote()) { int pitch = drumInmap[ev.pitch()]; ev.setPitch(pitch); } else if (ev.type() == Controller) { int ctl = ev.dataA(); MidiController *mc = mport->drumController(ctl); if (mc) ev.setA((ctl & ~0xff) | drumInmap[ctl & 0x7f]); } } } processTrack(track); song->insertTrack(track, -1); } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MidiTrack* track = new MidiTrack(); track->setOutChannel(0); track->setOutPort(0); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, true); // Do SysexMeta. Don't do loops. buildMidiEventList(mel, el, track, division, true, false); processTrack(track); song->insertTrack(track, -1); } } if (!merge) { TrackList* tl = song->tracks(); if (!tl->empty()) { Track* track = tl->front(); track->setSelected(true); } song->initLen(); int z, n; ///sigmap.timesig(0, z, n); sigmap.timesig(0, z, n); int tempo = tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !tempomap.empty(); song->setMasterFlag(masterF); transport->setMasterFlag(masterF); song->updatePos(); composer->reset(); ///composer->setMode(int(song->midiType())); // p4.0.7 Tim } else { song->initLen(); } return false; }/*}}}*/
bool LOS::importMidi(const QString name, bool merge)/*{{{*/ { bool popenFlag; FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); QMessageBox::critical(this, QString("LOS"), s); return rv; } // // evaluate song Type (GM, XG, GS, unknown) // MType t = song->midiType(); if (!merge) { t = mf.mtype(); song->setMType(t); } MidiInstrument* instr = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { MidiInstrument* mi = *i; if ((mi->iname() == "GM" && ((t == MT_UNKNOWN) || (t == MIDI_TYPE_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); return true; //abort(); } MidiFileTrackList* etl = mf.trackList(); int division = mf.division(); // // create MidiTrack and copy events to ->events() // - combine note on/off events // - calculate tick value for internal resolution // int mPort = getFreeMidiPort(); for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MPEventList* el = &((*t)->events); if (el->empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; // somewhat silly and slooow: QList<QPair<int, int> > eventChannelList; if(mPort >= 0 && mPort < kMaxMidiPorts) { for (int channel = 0; channel < kMaxMidiChannels; ++channel) { // // check if there are any events for port/channel in track: // iMPEvent i; for (i = el->begin(); i != el->end(); ++i) { MidiPlayEvent ev = *i; if (ev.type() != ME_SYSEX && ev.type() != ME_META && ev.channel() == channel) break; } if (i == el->end()) continue; MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); track->setOutChannel(channel); track->setOutPort(mPort); MidiPort* mport = &midiPorts[track->outPort()]; // this overwrites any instrument set for this port: mport->setInstrument(instr); EventList* mel = track->events(); buildMidiEventList(mel, el, track, division, first, false, false); first = false; processTrack(track); song->insertTrack(track, -1); //Create the Audio input side of the track Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false); if(input) { input->setMasterFlag(false); input->setChainMaster(track->id()); track->addManagedTrack(input->id()); } } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); track->setOutChannel(0); track->setOutPort(mPort); EventList* mel = track->events(); //buildMidiEventList(mel, el, track, division, true); // Do SysexMeta. Don't do loops. buildMidiEventList(mel, el, track, division, true, false, false); processTrack(track); song->insertTrack(track, -1); //Create the Audio input side of the track Track* input = song->addTrackByName(QString("i").append(track->name()), Track::AUDIO_INPUT, -1, false, false); if(input) { input->setMasterFlag(false); input->setChainMaster(track->id()); track->addManagedTrack(input->id()); } } mPort++; //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash //Or maintain a list of configured or inuse ports while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts) mPort++;//Just incase we have a configured port after an empty one } if (!merge) { TrackList* tl = song->tracks(); if (!tl->empty()) { Track* track = tl->front(); track->setSelected(true); } song->initLen(); int z, n; sigmap.timesig(0, z, n); int tempo = tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !tempomap.empty(); song->setMasterFlag(masterF); transport->setMasterFlag(masterF); song->updatePos(); composer->reset(); } else { song->initLen(); } return false; }/*}}}*/
bool LOS::importMidi(const QString name, bool merge)/*{{{*/ { bool popenFlag; FILE* fp = fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); QMessageBox::critical(this, QString("LOS"), s); return rv; } // // evaluate song Type (GM, XG, GS, unknown) // MidiType t = song->midiType(); if (!merge) { t = mf.midiType(); song->setMidiType(t); } MidiInstrument* instr = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i) { MidiInstrument* mi = *i; if ((mi->iname() == "GM" && ((t == MIDI_TYPE_NULL) || (t == MIDI_TYPE_GM))) || (mi->iname() == "GS" && t == MIDI_TYPE_GS) || (mi->iname() == "XG" && t == MIDI_TYPE_XG)) { instr = mi; break; } } if (instr == 0) { // the standard instrument files (GM, GS, XG) must be present printf("no instrument, type %d\n", t); return true; //abort(); } MidiFileTrackList* etl = mf.trackList(); int division = mf.division(); // // create MidiTrack and copy events to ->events() // - combine note on/off events // - calculate tick value for internal resolution // int mPort = getFreeMidiPort(); for (iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MPEventList* el = &((*t)->events); if (el->empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; QList<QPair<int, int> > portChannelList; iMPEvent i; for(i = el->begin(); i != el->end(); i++) { if (i->type() != ME_SYSEX && i->type() != ME_META) { int chan = i->channel(); int port = i->port(); if(portChannelList.isEmpty() || !portChannelList.contains(qMakePair(chan, port))) { portChannelList.append(qMakePair(chan, port)); MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); if(config.partColorNames[lastTrackPartColorIndex].contains("menu:", Qt::CaseSensitive)) lastTrackPartColorIndex ++; track->setDefaultPartColor(lastTrackPartColorIndex); lastTrackPartColorIndex ++; if(lastTrackPartColorIndex == NUM_PARTCOLORS) lastTrackPartColorIndex = 1; //Set track channel so buildMidiEventList can match the event to a channel track->setOutChannel(chan); track->setOutPort(mPort); MidiPort* mport = &midiPorts[track->outPort()]; // this overwrites any instrument set for this port: mport->setInstrument(instr); EventList* mel = track->events(); buildMidiEventList(mel, el, track, division, first, false, false); first = false; processTrack(track); //Update track to channel 1 //99% of all midi we import will be alien to our setup anyway, //so I'm making it easy for the user to just set the Instrument and go track->setOutChannel(0); song->insertTrack(track, -1); mPort++; //FIXME: Provice a non-iterative way to do this using the new losMidiPorts hash //Or maintain a list of configured or inuse ports while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts) mPort++;//Just incase we have a configured port after an empty one } } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MidiTrack* track = new MidiTrack(); track->setDefaultName(); track->setMasterFlag(true); track->setOutChannel(0); track->setOutPort(mPort); if(config.partColorNames[lastTrackPartColorIndex].contains("menu:", Qt::CaseSensitive)) lastTrackPartColorIndex ++; track->setDefaultPartColor(lastTrackPartColorIndex); lastTrackPartColorIndex ++; if(lastTrackPartColorIndex == NUM_PARTCOLORS) lastTrackPartColorIndex = 1; EventList* mel = track->events(); // Do SysexMeta. Don't do loops. // TODO: Properly support sysex dumps buildMidiEventList(mel, el, track, division, true, false, false); processTrack(track); song->insertTrack(track, -1); mPort++; while((&midiPorts[mPort])->device() && mPort < kMaxMidiPorts) mPort++; } } if (!merge) { MidiTrackList* tl = song->tracks(); if (!tl->empty()) { MidiTrack* track = tl->front(); track->setSelected(true); } song->initLen(); int z, n; sigmap.timesig(0, z, n); int tempo = tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !tempomap.empty(); song->setMasterFlag(masterF); transport->setMasterFlag(masterF); song->updatePos(); composer->reset(); } else { song->initLen(); } return false; }/*}}}*/
bool MusE::importMidi(const QString name, bool merge) { bool popenFlag; FILE* fp = MusEGui::fileOpen(this, name, QString(".mid"), "r", popenFlag); if (fp == 0) return true; MusECore::MidiFile mf(fp); bool rv = mf.read(); popenFlag ? pclose(fp) : fclose(fp); if (rv) { QString s(tr("reading midifile\n ")); s += name; s += tr("\nfailed: "); s += mf.error(); 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; } } } // // Need to set up ports and instruments first // 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 } 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 // - calculate tick value for internal resolution // for (MusECore::iMidiFileTrack t = etl->begin(); t != etl->end(); ++t) { MusECore::MPEventList& el = ((*t)->events); if (el.empty()) continue; // // if we split the track, SYSEX and META events go into // the first target track bool first = true; // vastly changed by flo: replaced that silly loop // with that already_processed-set-check. // this makes stuff really fast :) MusECore::iMPEvent ev; set< pair<int,int> > already_processed; for (ev = el.begin(); ev != el.end(); ++ev) { if (ev->type() != MusECore::ME_SYSEX && ev->type() != MusECore::ME_META) { int channel=ev->channel(); int port=ev->port(); if (already_processed.find(pair<int,int>(channel, port)) == already_processed.end()) { already_processed.insert(pair<int,int>(channel, port)); MusECore::MidiTrack* track = new MusECore::MidiTrack(); if ((*t)->_isDrumTrack) { if (MusEGlobal::config.importMidiNewStyleDrum) track->setType(MusECore::Track::NEW_DRUM); else track->setType(MusECore::Track::DRUM); } track->setOutChannel(channel); track->setOutPort(port); MusECore::MidiPort* mport = &MusEGlobal::midiPorts[port]; buildMidiEventList(&track->events, el, track, division, first, false); // Don't do loops. first = false; // Comment Added by T356. // Hmm. buildMidiEventList already takes care of this. // But it seems to work. How? Must test. //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 { track->setType(MusECore::Track::DRUM); // remap drum pitch with drumOutmap (was: Inmap. flo93 thought this was wrong) for (MusECore::iEvent i = track->events.begin(); i != track->events.end(); ++i) { MusECore::Event ev = i->second; if (ev.isNote()) { int pitch = MusEGlobal::drumOutmap[ev.pitch()]; ev.setPitch(pitch); } else if(ev.type() == MusECore::Controller) { int ctl = ev.dataA(); MusECore::MidiController *mc = mport->drumController(ctl); if(mc) ev.setA((ctl & ~0xff) | MusEGlobal::drumOutmap[ctl & 0x7f]); } } } } processTrack(track); MusEGlobal::song->insertTrack0(track, -1); } } } if (first) { // // track does only contain non-channel messages // (SYSEX or META) // MusECore::MidiTrack* track = new MusECore::MidiTrack(); track->setOutChannel(0); track->setOutPort(0); buildMidiEventList(&track->events, el, track, division, true, false); // Do SysexMeta. Don't do loops. processTrack(track); MusEGlobal::song->insertTrack0(track, -1); } } if (!merge) { MusECore::TrackList* tl = MusEGlobal::song->tracks(); if (!tl->empty()) { MusECore::Track* track = tl->front(); track->setSelected(true); } MusEGlobal::song->initLen(); int z, n; AL::sigmap.timesig(0, z, n); int tempo = MusEGlobal::tempomap.tempo(0); transport->setTimesig(z, n); transport->setTempo(tempo); bool masterF = !MusEGlobal::tempomap.empty(); MusEGlobal::song->setMasterFlag(masterF); transport->setMasterFlag(masterF); MusEGlobal::song->updatePos(); _arranger->reset(); } else { MusEGlobal::song->initLen(); } return false; }