void chainCloneInternal(Part* p)/*{{{*/ { Track* t = p->track(); Part* p1 = 0; // Look for a part with the same event list, that we can chain to. // It's faster if track type is known... { MidiTrack* mt = 0; MidiTrackList* mtl = song->midis(); for (ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) { mt = *imt; const PartList* pl = mt->cparts(); for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) { // Added by Tim. p3.3.6 //printf("chainCloneInternal track %p %s part %p %s evlist %p\n", (*imt), (*imt)->name().toLatin1().constData(), ip->second, ip->second->name().toLatin1().constData(), ip->second->cevents()); if (ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } // If a suitable part was found on a different track, we're done. We will chain to it. // Otherwise keep looking for parts on another track. If no others found, then we // chain to any suitable part which was found on the same given track t. if (p1 && mt != t) break; } } // No part found with same event list? Done. if (!p1) return; // Make sure the part to be chained is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Link the part to be chained. p->setPrevClone(p1); p->setNextClone(p1->nextClone()); // Re-link the existing part. p1->nextClone()->setPrevClone(p); p1->setNextClone(p); }/*}}}*/
void LOS::importPart() { unsigned curPos = song->cpos(); MidiTrackList* tracks = song->tracks(); MidiTrack* track = 0; // Get first selected track: for (iMidiTrack i = tracks->begin(); i != tracks->end(); i++) { MidiTrack* t = *i; if (t->selected()) { // Changed by T356. Support mixed .mpt files. { track = t; break; } } } if (track) { bool loadAll; QString filename = getOpenFileName(QString(""), part_file_pattern, this, tr("LOS: load part"), &loadAll); if (!filename.isEmpty()) { // Make a backup of the current clone list, to retain any 'copy' items, // so that pasting works properly after. CloneList copyCloneList = cloneList; // Clear the clone list to prevent any dangerous associations with // current non-original parts. cloneList.clear(); importPartToTrack(filename, curPos, track); // Restore backup of the clone list, to retain any 'copy' items, // so that pasting works properly after. cloneList.clear(); cloneList = copyCloneList; } } else { QMessageBox::warning(this, QString("LOS"), tr("No track selected for import")); } }
void AbstractMidiEditor::genPartlist()/*{{{*/ { _pl->clear(); for (std::list<int>::iterator i = _parts.begin(); i != _parts.end(); ++i) { MidiTrackList* tl = song->tracks(); for (iMidiTrack it = tl->begin(); it != tl->end(); ++it) { PartList* pl = (*it)->parts(); iPart ip; for (ip = pl->begin(); ip != pl->end(); ++ip) { if (ip->second->sn() == *i) { _pl->add(ip->second); break; } } if (ip != pl->end()) break; } } }/*}}}*/
static void writeSeqConfiguration(int level, Xml& xml, bool writePortInfo)/*{{{*/ { xml.tag(level++, "sequencer"); if (writePortInfo) { // // write information about all midi ports, their assigned // instruments and all managed midi controllers // for (int i = 0; i < MIDI_PORTS; ++i) { bool used = false; MidiPort* mport = &midiPorts[i]; // Route check by Tim. Port can now be used for routing even if no device. // Also, check for other non-defaults and save port, to preserve settings even if no device. // Dont write the config for the global inputs list they will be auto created with each startup if (mport->defaultInChannels() || mport->defaultOutChannels() || (mport->instrument() && !mport->instrument()->iname().isEmpty() && mport->instrument()->iname() != "GM") /*|| !mport->syncInfo().isDefault()*/ ) { used = true; } else {//Put the ID of this track into a list MidiTrackList* tl = song->midis(); for (iMidiTrack it = tl->begin(); it != tl->end(); ++it) { MidiTrack* t = *it; if (t->outPort() == i) { used = true; break; } } } MidiDevice* dev = mport->device(); if (!used && !dev) continue; bool isGlobal = gInputListPorts.contains(mport->portno()); xml.tag(level++, "midiport portId=\"%lld\" isGlobalInput=\"%d\"", mport->id(), isGlobal); if (mport->defaultInChannels()) xml.intTag(level, "defaultInChans", mport->defaultInChannels()); if (mport->defaultOutChannels()) xml.intTag(level, "defaultOutChans", mport->defaultOutChannels()); if (mport->instrument() && !mport->instrument()->iname().isEmpty() && (mport->instrument()->iname() != "GM")) // FIXME: TODO: Make this user configurable. { xml.strTag(level, "instrument", mport->instrument()->iname()); } if (dev) { xml.strTag(level, "name", dev->name()); xml.intTag(level, "cacheNRPN", (int)dev->cacheNRPN()); if (dev->deviceType() != MidiDevice::ALSA_MIDI) xml.intTag(level, "type", dev->deviceType()); xml.intTag(level, "openFlags", dev->openFlags()); } // write out registered controller for all channels MidiCtrlValListList* vll = mport->controller(); for (int k = 0; k < MIDI_CHANNELS; ++k) { int min = k << 24; int max = min + 0x100000; xml.tag(level++, "channel idx=\"%d\"", k); iMidiCtrlValList s = vll->lower_bound(min); iMidiCtrlValList e = vll->lower_bound(max); if (s != e) { for (iMidiCtrlValList i = s; i != e; ++i) { if(i->second->num() != 262145) { xml.tag(level++, "controller id=\"%d\"", i->second->num()); if (i->second->hwVal() != CTRL_VAL_UNKNOWN) xml.intTag(level, "val", i->second->hwVal()); xml.etag(--level, "controller"); } } } xml.etag(--level, "channel"); } QList<PatchSequence*> *patchSequences = mport->patchSequences(); if (patchSequences && !patchSequences->isEmpty()) { for (int p = 0; p < patchSequences->size(); ++p) { PatchSequence* ps = patchSequences->at(p); QString pm = ps->name.replace('\n', " "); xml.put(level, "<patchSequence id=\"%d\" name=\"%s\" checked=\"%d\" />", ps->id, pm.toLatin1().constData(), ps->selected); } } if(!mport->presets()->isEmpty()) { QHashIterator<int, QString> iter(*mport->presets()); while(iter.hasNext()) { iter.next(); xml.put(level, "<midiPreset id=\"%d\" sysex=\"%s\"/>", iter.key(), iter.value().toLatin1().constData()); } } xml.etag(--level, "midiport"); } } xml.tag(--level, "/sequencer"); }/*}}}*/
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; }/*}}}*/
void Audio::initDevices() { // // mark all used ports // bool activePorts[MIDI_PORTS]; for (int i = 0; i < MIDI_PORTS; ++i) activePorts[i] = false; MidiTrackList* tracks = song->midis(); for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it) { MidiTrack* track = *it; activePorts[track->outPort()] = true; } if (song->click()) activePorts[clickPort] = true; // // test for explicit instrument initialization // for (int i = 0; i < MIDI_PORTS; ++i) { if (!activePorts[i]) continue; MidiPort* port = &midiPorts[i]; MidiInstrument* instr = port->instrument(); MidiDevice* md = port->device(); if (instr && md) { EventList* events = instr->midiInit(); if (events->empty()) continue; for (iEvent ie = events->begin(); ie != events->end(); ++ie) { MidiPlayEvent ev(0, i, 0, ie->second); md->putEvent(ev); } activePorts[i] = false; // no standard initialization } } // // damit Midi-Devices, die mehrere Ports besitzen, wie z.B. // das Korg NS5R, nicht mehrmals zwischen GM und XG/GS hin und // hergeschaltet werden, wird zunïÿýhst auf allen Ports GM // initialisiert, und dann erst XG/GS // // Standard initialization... for (int i = 0; i < MIDI_PORTS; ++i) { if (!activePorts[i]) continue; MidiPort* port = &midiPorts[i]; switch (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; MidiPort* port = &midiPorts[i]; switch (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; } } }
void Audio::preloadControllers()/*{{{*/ { midiBusy = true; MidiTrackList* tracks = song->midis(); for (iMidiTrack it = tracks->begin(); it != tracks->end(); ++it) { MidiTrack* track = *it; //activePorts[track->outPort()] = true; QList<ProcessList*> pcevents; int port = track->outPort(); int channel = track->outChannel(); int defaultPort = port; MidiDevice* md = midiPorts[port].device(); if (!md) { continue; } MPEventList* playEvents = md->playEvents(); playEvents->erase(playEvents->begin(), playEvents->end()); PartList* pl = track->parts(); for (iPart p = pl->begin(); p != pl->end(); ++p) { MidiPart* part = (MidiPart*) (p->second); EventList* events = part->events(); unsigned partTick = part->tick(); //unsigned partLen = part->lenTick(); int delay = track->delay; unsigned offset = delay + partTick; for (iEvent ie = events->begin(); ie != events->end(); ++ie) { Event ev = ie->second; port = defaultPort; unsigned tick = ev.tick() + offset; //unsigned frame = tempomap.tick2frame(tick) + frameOffset; switch (ev.dataA()) { case CTRL_PROGRAM: { ProcessList *pl = new ProcessList; pl->port = port; pl->channel = channel; pl->dataB = ev.dataB(); bool addEvent = true; for(int i = 0; i < pcevents.size(); ++i) { ProcessList* ipl = pcevents.at(i); if(ipl->port == pl->port && ipl->channel == pl->channel && ipl->dataB == pl->dataB) { addEvent = false; break; } } if(addEvent) { printf("Audio::preloadControllers() Loading event @ tick: %d - on channel: %d - on port: %d - dataA: %d - dataB: %d\n", tick, channel, port, ev.dataA(), ev.dataB()); pcevents.append(pl); playEvents->add(MidiPlayEvent(tick, port, channel, ev)); } } break; default: break; } } } md->setNextPlayEvent(playEvents->begin()); } midiBusy = false; }/*}}}*/
void chainTrackParts(Track* t, bool incRefCount) { PartList* pl = t->parts(); for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { Part* p = ip->second; chainCheckErr(p); // Do we want to increase the reference count? if (incRefCount) p->events()->incARef(1); // Added by Tim. p3.3.6 //printf("chainTrackParts track %p %s part %p %s evlist %p\n", t, t->name().toLatin1().constData(), p, p->name().toLatin1().constData(), p->cevents()); Part* p1 = 0; // Look for a part with the same event list, that we can chain to. // It's faster if track type is known... if (!t || (t && t->isMidiTrack())) { MidiTrack* mt = 0; MidiTrackList* mtl = song->midis(); for (ciMidiTrack imt = mtl->begin(); imt != mtl->end(); ++imt) { mt = *imt; const PartList* pl = mt->cparts(); for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) { // Added by Tim. p3.3.6 //printf("chainTrackParts track %p %s part %p %s evlist %p\n", mt, mt->name().toLatin1().constData(), ip->second, ip->second->name().toLatin1().constData(), ip->second->cevents()); if (ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } // If a suitable part was found on a different track, we're done. We will chain to it. // Otherwise keep looking for parts on another track. If no others found, then we // chain to any suitable part which was found on the same given track t. if (p1 && mt != t) break; } } if ((!p1 && !t) || (t && t->type() == Track::WAVE)) { WaveTrack* wt = 0; WaveTrackList* wtl = song->waves(); for (ciWaveTrack iwt = wtl->begin(); iwt != wtl->end(); ++iwt) { wt = *iwt; const PartList* pl = wt->cparts(); for (ciPart ip = pl->begin(); ip != pl->end(); ++ip) { if (ip->second != p && ip->second->cevents() == p->cevents()) { p1 = ip->second; break; } } if (p1 && wt != t) break; } } // No part found with same event list? Done. if (!p1) continue; // Make sure the part to be chained is unchained first. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Link the part to be chained. p->setPrevClone(p1); p->setNextClone(p1->nextClone()); // Re-link the existing part. p1->nextClone()->setPrevClone(p); p1->setNextClone(p); } }
void CanvasNavigator::updateParts()/*{{{*/ { m_editing = true; m_playhead = 0; m_start = 0; m_canvasBox = 0; m_punchIn = 0; m_punchOut = 0; m_parts.clear(); m_markers.clear(); m_scene->clear(); /*foreach(PartItem* i, m_parts) m_scene->removeItem(i); while(m_parts.size()) delete m_parts.takeFirst();*/ m_heightList.clear(); m_scene->setSceneRect(QRectF()); int index = 1; //QList<QGraphicsItem*> group; MidiTrackList* tl = song->visibletracks(); ciMidiTrack ci = tl->begin(); for(; ci != tl->end(); ci++) { m_heightList.append((*ci)->height()); } ci = tl->begin(); if(ci != tl->end()) { int mh = (*ci)->height(); double partHeight = (mh * 8)/100; m_start = m_scene->addRect(0.0, 0.0, calcSize(song->len()), partHeight); m_start->setBrush(QColor(63, 63, 63)); m_start->setPen(QPen(QColor(63, 63, 63))); m_start->setZValue(-50); ci++;//Special case for master } for(; ci != tl->end(); ci++) { MidiTrack* track = *ci; if(track) { QList<int> list = m_heightList.mid(0, index); int ypos = 0; foreach(int i, list) ypos += i; ypos = (ypos * 8)/100; int ih = m_heightList.at(index); double partHeight = (ih * 8)/100; //qDebug("CanvasNavigator::updateParts: partHeight: %2f, ypos: %d", partHeight, ypos); PartList* parts = track->parts(); if(parts && !parts->empty()) { for(iPart p = parts->begin(); p != parts->end(); p++) { Part *part = p->second; int tick, len; if(part) { tick = part->tick(); len = part->lenTick(); } double w = calcSize(len); double pos = calcSize(tick); PartItem* item = new PartItem(pos, ypos, w, partHeight); item->setPart(part); m_parts.append(item); //group.append((QGraphicsItem*)item); int i = part->colorIndex(); QColor partWaveColor(config.partWaveColors[i]); QColor partColor(config.partColors[i]); //partWaveColor.setAlpha(150); partColor.setAlpha(150); item->setBrush(part->selected() ? partWaveColor : partColor); item->setPen(part->selected() ? partColor : partWaveColor); m_scene->addItem(item); } } ++index; } } QColor colTimeLine = QColor(0, 186, 255); int kpos = 0; foreach(int i, m_heightList) kpos += i; //kpos = ((kpos + 400) * 8)/100; kpos = ((kpos + 400) * 8)/100; m_playhead = new QGraphicsRectItem(0, 0, 1, kpos); m_playhead->setBrush(colTimeLine); m_playhead->setPen(Qt::NoPen); m_playhead->setZValue(124001.0f); m_playhead->setFlags(QGraphicsItem::ItemIgnoresTransformations); m_scene->addItem(m_playhead); QColor loopColor(139, 225, 69); QColor markerColor(243,191,124); MarkerList* markers = song->marker(); for (iMarker m = markers->begin(); m != markers->end(); ++m) { //double xp = calcSize(m->second.tick()); QGraphicsRectItem *marker = m_scene->addRect(0, 0, 1, kpos); marker->setData(Qt::UserRole, m->second.id()); m_markers[m->second.id()] = marker; marker->setPen(Qt::NoPen); marker->setBrush(markerColor); marker->setZValue(124002.0f); marker->setFlags(QGraphicsItem::ItemIgnoresTransformations); m_updateMarkers = true; } m_punchIn = new QGraphicsRectItem(0, 0, 1, kpos); m_punchIn->setBrush(loopColor); m_punchIn->setPen(Qt::NoPen); m_punchIn->setZValue(124003.0f); m_punchIn->setFlags(QGraphicsItem::ItemIgnoresTransformations); m_scene->addItem(m_punchIn); m_punchIn->setVisible(song->loop() || song->punchin()); m_punchOut = new QGraphicsRectItem(0, 0, 1, kpos); m_punchOut->setBrush(loopColor); m_punchOut->setPen(Qt::NoPen); m_punchOut->setZValue(124003.0f); m_punchOut->setFlags(QGraphicsItem::ItemIgnoresTransformations); m_scene->addItem(m_punchOut); m_punchOut->setVisible(song->loop() || song->punchout()); createCanvasBox(); //group.append((QGraphicsItem*)m_start); //group.append((QGraphicsItem*)m_playhead); //if(group.size()) //{ // m_partGroup = m_scene->createItemGroup(group); //} //else m_partGroup = 0; updateSpacing(); m_editing = false; }/*}}}*/
void Track::resetAllMeter() { MidiTrackList* tl = song->tracks(); for (iMidiTrack i = tl->begin(); i != tl->end(); ++i) (*i)->resetMeter(); }