void Piano::draw(QPainter& p, const QRect& r) { QPoint offset(0, KH*2); p.drawTiledPixmap(r, *octave, r.topLeft()+offset); if (_curSelectedPitch != -1 && _curSelectedPitch != curPitch) { int y = pitch2y(_curSelectedPitch); QPixmap* pm; switch(_curSelectedPitch % 12) { case 0: case 5: pm = mk7; break; case 2: case 7: case 9: pm = mk6; break; case 4: case 11: pm = mk5; break; default: pm = mk8; break; } p.drawPixmap(0, y, *pm); } if (curPitch != -1) { int y = pitch2y(curPitch); QPixmap* pm; switch(curPitch % 12) { case 0: case 5: pm = mk3; break; case 2: case 7: case 9: pm = mk2; break; case 4: case 11: pm = mk1; break; default: pm = mk4; break; } p.drawPixmap(0, y, *pm); } // draw C notes for (int drawKey = 0; drawKey < 8; drawKey++) { int octaveSize=91; int drawY = octaveSize * drawKey + 82 - KH*2; if (drawY > r.y() && drawY < r.y() + r.height()) { p.drawPixmap(0,drawY,*c_keys[drawKey]); } } if(!_midiEditor) return; MusECore::PartList* part_list = _midiEditor->parts(); MusECore::Part* cur_part = _midiEditor->curCanvasPart(); if(!part_list || !cur_part) return; MusECore::MidiTrack* track = (MusECore::MidiTrack*)(cur_part->track()); int channel = track->outChannel(); MusECore::MidiPort* port = &MusEGlobal::midiPorts[track->outPort()]; MusECore::MidiCtrlValListList* cll = port->controller(); const int min = channel << 24; const int max = min + 0x1000000; for(MusECore::ciMidiCtrlValList it = cll->lower_bound(min); it != cll->lower_bound(max); ++it) { MusECore::MidiCtrlValList* cl = it->second; MusECore::MidiController* c = port->midiController(cl->num()); if(!c->isPerNoteController()) continue; int cnum = c->num(); int num = cl->num(); int pitch = num & 0x7f; bool used = false; MusECore::EventList* el = cur_part->events(); for (MusECore::ciEvent ie = el->begin(); ie != el->end(); ++ie) { MusECore::Event e = ie->second; if(e.type() != MusECore::Controller) continue; int ctl_num = e.dataA(); if((ctl_num | 0xff) == cnum && (ctl_num & 0x7f) == pitch) { used = true; break; } } bool off = cl->hwVal() == MusECore::CTRL_VAL_UNKNOWN; // Does it have a value or is it 'off'? int y = pitch2y(pitch) + 3; if(used) { if(off) p.drawPixmap(0, y, 6, 6, *greendot12x12Icon); else p.drawPixmap(0, y, 6, 6, *orangedot12x12Icon); } else { if(off) p.drawPixmap(0, y, 6, 6, *graydot12x12Icon); else p.drawPixmap(0, y, 6, 6, *bluedot12x12Icon); } } }
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; }