void unchainTrackParts(Track* t, bool decRefCount)/*{{{*/ { PartList* pl = t->parts(); for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { Part* p = ip->second; chainCheckErr(p); // Do we want to decrease the reference count? if (decRefCount) p->events()->incARef(-1); // Unchain the part. p->prevClone()->setNextClone(p->nextClone()); p->nextClone()->setPrevClone(p->prevClone()); // Isolate the part. p->setPrevClone(p); p->setNextClone(p); } }/*}}}*/
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; } } }/*}}}*/
void EventCanvas::populateMultiSelect(CItem* baseItem)/*{{{*/ { if(editor->isGlobalEdit() && baseItem) { PartList* pl = editor->parts(); int curTranspose = ((MidiTrack*)baseItem->part()->track())->getTransposition(); Event curEvent = baseItem->event(); int curPitch = curEvent.pitch(); int curRawPitch = curPitch - curTranspose; //int curLen = curEvent.lenTick(); m_multiSelect.clear(); for(iPart p = pl->begin(); p != pl->end(); ++p) { if(p->second == _curPart) continue; CItemList pitems = getItemlistForPart(p->second); for (iCItem i = pitems.begin(); i != pitems.end(); ++i) { MidiTrack* mtrack = (MidiTrack*)i->second->part()->track(); int transp = mtrack->getTransposition(); Event e = i->second->event(); if(e.empty()) continue; int pitch = e.pitch(); int rpitch = pitch - transp; //int len = e.lenTick(); //printf("Current pitch: %d, rawpitch: %d - note pitch: %d, raw: %d\n", curPitch, curRawPitch, pitch, rpitch); if(e.tick() == curEvent.tick() && rpitch == curRawPitch/*, len == curLen*/) { m_multiSelect.add(i->second); break; } } } //printf("MultiSelect list size: %d \n", (int)m_multiSelect.size()); } }/*}}}*/
void WaveTrack::fetchData(unsigned pos, unsigned samples, float** bp, bool doSeek) { #ifdef WAVETRACK_DEBUG printf("WaveTrack::fetchData %s samples:%lu pos:%u\n", name().toLatin1().constData(), samples, pos); #endif // reset buffer to zero for (int i = 0; i < channels(); ++i) memset(bp[i], 0, samples * sizeof(float)); // Process only if track is not off. if(!off()) { PartList* pl = parts(); unsigned n = samples; for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { WavePart* part = (WavePart*)(ip->second); if (part->mute()) continue; unsigned p_spos = part->frame(); unsigned p_epos = p_spos + part->lenFrame(); if (pos + n < p_spos) break; if (pos >= p_epos) continue; for (iEvent ie = part->nonconst_events().begin(); ie != part->nonconst_events().end(); ++ie) { Event& event = ie->second; unsigned e_spos = event.frame() + p_spos; unsigned nn = event.lenFrame(); unsigned e_epos = e_spos + nn; if (pos + n < e_spos) break; if (pos >= e_epos) continue; int offset = e_spos - pos; unsigned srcOffset, dstOffset; if (offset > 0) { nn = n - offset; srcOffset = 0; dstOffset = offset; } else { srcOffset = -offset; dstOffset = 0; nn += offset; if (nn > n) nn = n; } float* bpp[channels()]; for (int i = 0; i < channels(); ++i) bpp[i] = bp[i] + dstOffset; event.readAudio(part, srcOffset, bpp, channels(), nn, doSeek, false); } } } if(MusEGlobal::config.useDenormalBias) { // add denormal bias to outdata for (int i = 0; i < channels(); ++i) for (unsigned int j = 0; j < samples; ++j) bp[i][j] +=MusEGlobal::denormalBias; } _prefetchFifo.add(); }
void chainTrackParts(MidiTrack* 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... { 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; } } // 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 LOS::processTrack(MidiTrack* track) { EventList* tevents = track->events(); if (tevents->empty()) return; //--------------------------------------------------- // Identify Parts // The MIDI tracks are broken up into parts // A new Part will be located based on track. // Events will be aligned on new track //--------------------------------------------------- PartList* pl = track->parts(); int lastTick = 0; for (iEvent i = tevents->begin(); i != tevents->end(); ++i) { Event event = i->second; int epos = event.tick() + event.lenTick(); if (epos > lastTick) lastTick = epos; } QString partname = track->name(); int len = song->roundUpBar(lastTick + 1); // p3.3.27 if (config.importMidiSplitParts) { int bar2, beat; unsigned tick; sigmap.tickValues(len, &bar2, &beat, &tick); int lastOff = 0; int st = -1; // start tick current part int x1 = 0; // start tick current measure int x2 = 0; // end tick current measure for (int bar = 0; bar < bar2; ++bar, x1 = x2) { ///x2 = sigmap.bar2tick(bar+1, 0, 0); x2 = sigmap.bar2tick(bar + 1, 0, 0); if (lastOff > x2) { // this measure is busy! continue; } iEvent i1 = tevents->lower_bound(x1); iEvent i2 = tevents->lower_bound(x2); if (i1 == i2) { // empty? if (st != -1) { MidiPart* part = new MidiPart(track); part->setTick(st); part->setLenTick(x1 - st); // printf("new part %d len: %d\n", st, x1-st); part->setName(partname); pl->add(part); st = -1; } } else { if (st == -1) st = x1; // begin new part //HACK: //lastOff: for (iEvent i = i1; i != i2; ++i) { Event event = i->second; if (event.type() == Note) { int off = event.tick() + event.lenTick(); if (off > lastOff) lastOff = off; } } } } if (st != -1) { MidiPart* part = new MidiPart(track); part->setTick(st); // printf("new part %d len: %d\n", st, x2-st); part->setLenTick(x2 - st); part->setName(partname); pl->add(part); } } else { // Just one long part... MidiPart* part = new MidiPart(track); //part->setTick(st); part->setTick(0); part->setLenTick(len); part->setName(partname); pl->add(part); } //------------------------------------------------------------- // assign events to parts //------------------------------------------------------------- for (iPart p = pl->begin(); p != pl->end(); ++p) { MidiPart* part = (MidiPart*) (p->second); int stick = part->tick(); int etick = part->tick() + part->lenTick(); iEvent r1 = tevents->lower_bound(stick); iEvent r2 = tevents->lower_bound(etick); int startTick = part->tick(); EventList* el = part->events(); for (iEvent i = r1; i != r2; ++i) { Event ev = i->second; int ntick = ev.tick() - startTick; ev.setTick(ntick); el->add(ev); } tevents->erase(r1, r2); } if (tevents->size()) printf("-----------events left: %zd\n", tevents->size()); for (iEvent i = tevents->begin(); i != tevents->end(); ++i) { printf("%d===\n", i->first); i->second.dump(); } // all events should be processed: assert(tevents->empty()); }
void globalCut(bool onlySelectedTracks) { int lpos = MusEGlobal::song->lpos(); int rpos = MusEGlobal::song->rpos(); if ((lpos - rpos) >= 0) return; Undo operations; TrackList* tracks = MusEGlobal::song->tracks(); for (iTrack it = tracks->begin(); it != tracks->end(); ++it) { Track* track = *it; if (track == 0 || (onlySelectedTracks && !track->selected())) continue; PartList* pl = track->parts(); for (iPart p = pl->begin(); p != pl->end(); ++p) { Part* part = p->second; int t = part->tick(); int l = part->lenTick(); if (t + l <= lpos) continue; if ((t >= lpos) && ((t+l) <= rpos)) { operations.push_back(UndoOp(UndoOp::DeletePart,part)); } else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) { // remove part tail int len = lpos - t; if (part->nextClone()==part) // no clones { // cut Events const EventList& el = part->events(); for (ciEvent ie = el.lower_bound(len); ie != el.end(); ++ie) operations.push_back(UndoOp(UndoOp::DeleteEvent,ie->second, part, false, false)); } operations.push_back(UndoOp(UndoOp::ModifyPartLength, part, part->lenTick(), len, true, true)); } else if ((t < lpos) && ((t+l) > lpos) && ((t+l) > rpos)) { //---------------------- // remove part middle //---------------------- Part* p1; Part* p2; Part* p3; part->splitPart(lpos, p1, p2); delete p2; part->splitPart(rpos, p2, p3); delete p2; p3->setTick(lpos); MusEGlobal::song->informAboutNewParts(part,p1,p3); operations.push_back(UndoOp(UndoOp::DeletePart,part)); operations.push_back(UndoOp(UndoOp::AddPart,p1)); operations.push_back(UndoOp(UndoOp::AddPart,p3)); } else if ((t >= lpos) && (t < rpos) && (t+l) > rpos) { // remove part head Part* p1; Part* p2; part->splitPart(rpos, p1, p2); delete p1; p2->setTick(lpos); MusEGlobal::song->informAboutNewParts(part,p2); operations.push_back(UndoOp(UndoOp::DeletePart,part)); operations.push_back(UndoOp(UndoOp::AddPart,p2)); } else if (t >= rpos) { // move part to the left int nt = part->tick(); operations.push_back(UndoOp(UndoOp::ModifyPartTick,part,part->tick(), nt - (rpos -lpos) )); } } } int diff = lpos - rpos; adjustGlobalLists(operations, lpos, diff); MusEGlobal::song->applyOperationGroup(operations); }
void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts) { int port = track->outPort(); int channel = track->outChannel(); int defaultPort = port; MidiDevice* md = midiPorts[port].device(); MPEventList* playEvents = md->playEvents(); MPEventList* stuckNotes = md->stuckNotes(); PartList* pl = track->parts(); for (iPart p = pl->begin(); p != pl->end(); ++p) { MidiPart* part = (MidiPart*) (p->second); // dont play muted parts if (part->mute()) continue; EventList* events = part->events(); unsigned partTick = part->tick(); unsigned partLen = part->lenTick(); int delay = track->delay; if (cts > nts) { printf("processMidi: FATAL: cur > next %d > %d\n", cts, nts); return; } unsigned offset = delay + partTick; if (offset > nts) continue; unsigned stick = (offset > cts) ? 0 : cts - offset; unsigned etick = nts - offset; // By T356. Do not play events which are past the end of this part. if (etick > partLen) continue; iEvent ie = events->lower_bound(stick); iEvent iend = events->lower_bound(etick); for (; ie != iend; ++ie) { Event ev = ie->second; port = defaultPort; //Reset each loop // // dont play any meta events // if (ev.type() == Meta) continue; if (track->type() == Track::DRUM) { int instr = ev.pitch(); // ignore muted drums if (ev.isNote() && drumMap[instr].mute) continue; } unsigned tick = ev.tick() + offset; unsigned frame = tempomap.tick2frame(tick) + frameOffset; switch (ev.type()) { case Note: { int len = ev.lenTick(); int pitch = ev.pitch(); int velo = ev.velo(); if (track->type() == Track::DRUM) { // // Map drum-notes to the drum-map values // int instr = ev.pitch(); pitch = drumMap[instr].anote; port = drumMap[instr].port; //This changes to non-default port channel = drumMap[instr].channel; velo = int(double(velo) * (double(drumMap[instr].vol) / 100.0)); } else { // // transpose non drum notes // pitch += (track->transposition + song->globalPitchShift()); } 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) // dont allow zero length len = 1; int veloOff = ev.veloOff(); if (port == defaultPort) { //printf("Adding event normally: frame=%d port=%d channel=%d pitch=%d velo=%d\n",frame, port, channel, pitch, velo); // p3.3.25 // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. if (extSyncFlag.value()) playEvents->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo)); else playEvents->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); stuckNotes->add(MidiPlayEvent(tick + len, port, channel, veloOff ? 0x80 : 0x90, pitch, veloOff)); } else { //Handle events to different port than standard. MidiDevice* mdAlt = midiPorts[port].device(); if (mdAlt) { // p3.3.25 if (extSyncFlag.value()) mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo)); else mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo)); mdAlt->stuckNotes()->add(MidiPlayEvent(tick + len, port, channel, veloOff ? 0x80 : 0x90, pitch, veloOff)); } } if (velo > track->activity()) track->setActivity(velo); } break; // Added by T356. case Controller: { //int len = ev.lenTick(); //int pitch = ev.pitch(); if (track->type() == Track::DRUM) { int ctl = ev.dataA(); // Is it a drum controller event, according to the track port's instrument? MidiController *mc = midiPorts[defaultPort].drumController(ctl); if (mc) { int instr = ctl & 0x7f; ctl &= ~0xff; int pitch = drumMap[instr].anote & 0x7f; port = drumMap[instr].port; //This changes to non-default port channel = drumMap[instr].channel; MidiDevice* mdAlt = midiPorts[port].device(); if (mdAlt) { // p3.3.25 // If syncing to external midi sync, we cannot use the tempo map. // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. if (extSyncFlag.value()) mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, ME_CONTROLLER, ctl | pitch, ev.dataB())); else //playEvents->add(MidiPlayEvent(frame, port, channel, ev)); mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, ME_CONTROLLER, ctl | pitch, ev.dataB())); } break; } } // p3.3.25 if (extSyncFlag.value()) playEvents->add(MidiPlayEvent(tick, port, channel, ev)); else playEvents->add(MidiPlayEvent(frame, port, channel, ev)); } break; default: // p3.3.25 if (extSyncFlag.value()) playEvents->add(MidiPlayEvent(tick, port, channel, ev)); else playEvents->add(MidiPlayEvent(frame, port, channel, ev)); 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 TrackListView::toggleTrackPart(QStandardItem* item)/*{{{*/ { if(!item) return; m_editing = true; int type = item->data(TrackRole).toInt(); int column = item->column(); bool checked = (item->checkState() == Qt::Checked); qint64 tid = item->data(TrackIdRole).toLongLong(); QString trackName = item->data(TrackNameRole).toString(); QString partName; m_selectedIndex = item->row(); QString newName = item->text(); if(type == 1) { if(trackName == newName) column = 0; else column = 1; } else { partName = item->data(PartNameRole).toString(); if(partName == newName) column = 0; else column = 1; } MidiTrack* track = song->findTrackById(tid); if(!track || !m_editor) { m_editing = false; return; } PartList* list = track->parts(); if(list->empty()) { m_editing = false; updateCheck(); return; } switch(type) { case 1: //Track { if(!column) { if(checked) { m_editor->addParts(list); m_selectedTracks.append(track->id()); if(!list->empty()) { updatePartSelection(list->begin()->second); updateCheck(list, checked); } } else { m_editor->removeParts(list); m_editor->updateCanvas(); m_selectedTracks.removeAll(track->id()); updateCheck(); song->update(SC_SELECTION); } } else { bool valid = true; if(newName.isEmpty()) { valid = false; } if(valid) { for (iMidiTrack i = song->tracks()->begin(); i != song->tracks()->end(); ++i) { if ((*i)->name() == newName) { valid = false; break; } } } if(!valid) { QMessageBox::critical(this, tr("LOS: bad trackname"), tr("please choose a unique track name"), QMessageBox::Ok, Qt::NoButton, Qt::NoButton); m_model->blockSignals(true); item->setText(item->data(TrackNameRole).toString()); m_model->blockSignals(false); update(); m_editing = false; return; } m_model->blockSignals(true); item->setData(newName, TrackNameRole); m_model->blockSignals(false); Track* newTrack = track->clone(false); newTrack->setName(newName); track->setName(newName); audio->msgChangeTrack((MidiTrack*)newTrack, track); } } break; case 2: //Part { int sn = item->data(PartRole).toInt(); unsigned tick = item->data(TickRole).toInt(); Part* part = list->find(tick, sn); if(part) { if(!column) { if(checked) { m_editor->addPart(part); updatePartSelection(part); } else { m_editor->removePart(sn); m_editor->updateCanvas(); updateCheck(); song->update(SC_SELECTION); } } else { if(partName.isEmpty()) { QMessageBox::critical(this, tr("LOS: Invalid part name"), tr("Please choose a name with at least one charactor"), QMessageBox::Ok, Qt::NoButton, Qt::NoButton); m_model->blockSignals(true); item->setText(item->data(PartNameRole).toString()); m_model->blockSignals(false); update(); m_editing = false; return; } m_model->blockSignals(true); item->setData(newName, PartNameRole); m_model->blockSignals(false); Part* newPart = part->clone(); newPart->setName(newName); // Indicate do undo, and do port controller values but not clone parts. audio->msgChangePart(part, newPart, true, true, false); song->update(SC_PART_MODIFIED); } } } break; } update(); if(m_selectedIndex < m_model->rowCount()) { m_table->selectRow(m_selectedIndex); m_table->scrollTo(m_model->index(m_selectedIndex, 0)); } m_editing = false; }/*}}}*/
void TrackListView::populateTable()/*{{{*/ { if(debugMsg) printf("TrackListView::populateTable\n"); QScrollBar *bar = m_table->verticalScrollBar(); int barPos = 0; if(bar) barPos = bar->sliderPosition(); m_model->clear(); for(iMidiTrack i = song->artracks()->begin(); i != song->artracks()->end(); ++i) { MidiTrack* track = (MidiTrack*)(*i); PartList* pl = track->parts(); if(m_displayRole == PartRole && pl->empty()) { continue; } QStandardItem* trackName = new QStandardItem(); trackName->setForeground(QBrush(QColor(205,209,205))); trackName->setBackground(QBrush(QColor(20,20,20))); trackName->setFont(QFont("fixed-width", 10, QFont::Bold)); trackName->setText(track->name()); trackName->setCheckable(true); trackName->setCheckState(m_selectedTracks.contains(track->id()) ? Qt::Checked : Qt::Unchecked); trackName->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); trackName->setData(1, TrackRole); trackName->setData(track->name(), TrackNameRole); trackName->setData(track->id(), TrackIdRole); trackName->setEditable(true); m_model->appendRow(trackName); for(iPart ip = pl->begin(); ip != pl->end(); ++ip) { Part* part = ip->second; QStandardItem* partName = new QStandardItem(); partName->setFont(QFont("fixed-width", 9, QFont::Bold)); partName->setText(part->name()); partName->setData(part->sn(), PartRole); partName->setData(2, TrackRole); partName->setData(track->name(), TrackNameRole); partName->setData(part->name(), PartNameRole); partName->setData(part->tick(), TickRole); partName->setData(track->id(), TrackIdRole); partName->setEditable(true); partName->setCheckable(true); partName->setCheckState(m_editor->hasPart(part->sn()) ? Qt::Checked : Qt::Unchecked); if(!partColorIcons.isEmpty() && part->colorIndex() < partColorIcons.size()) partName->setIcon(partColorIcons.at(part->colorIndex())); m_model->appendRow(partName); } } m_model->setHorizontalHeaderLabels(m_headers); if(m_selectedIndex < m_model->rowCount()) { m_table->selectRow(m_selectedIndex); m_table->scrollTo(m_model->index(m_selectedIndex, 0)); } if(bar) bar->setSliderPosition(barPos); }/*}}}*/
void Song::cmdGluePart(Track* track, Part* oPart) { // p3.3.54 if (track->type() != Track::WAVE && !track->isMidiTrack()) return; PartList* pl = track->parts(); Part* nextPart = 0; for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { if (ip->second == oPart) { ++ip; if (ip == pl->end()) return; nextPart = ip->second; break; } } Part* nPart = track->newPart(oPart); nPart->setLenTick(nextPart->tick() + nextPart->lenTick() - oPart->tick()); // populate nPart with Events from oPart and nextPart EventList* sl1 = oPart->events(); EventList* dl = nPart->events(); for (iEvent ie = sl1->begin(); ie != sl1->end(); ++ie) dl->add(ie->second); EventList* sl2 = nextPart->events(); //int frameOffset = nextPart->frame() - oPart->frame(); //for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { // Event event = ie->second.clone(); // event.setFrame(event.frame() + frameOffset); // dl->add(event); // } // p3.3.54 Changed. if (track->type() == Track::WAVE) { int frameOffset = nextPart->frame() - oPart->frame(); for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { Event event = ie->second.clone(); event.setFrame(event.frame() + frameOffset); dl->add(event); } } else if (track->isMidiTrack()) { int tickOffset = nextPart->tick() - oPart->tick(); for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { Event event = ie->second.clone(); event.setTick(event.tick() + tickOffset); dl->add(event); } } startUndo(); audio->msgRemovePart(nextPart, false); // Indicate no undo, and do port controller values but not clone parts. //audio->msgChangePart(oPart, nPart, false); audio->msgChangePart(oPart, nPart, false, true, false); endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); }
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; }/*}}}*/
PyObject* getParts(PyObject*, PyObject* args) { TrackList* tracks = song->tracks(); const char* trackname; if (!PyArg_ParseTuple(args, "s", &trackname)) { return NULL; } PyObject* pyparts = Py_BuildValue("[]"); for (ciTrack t = tracks->begin(); t != tracks->end(); ++t) { Track* track = *t; if (track->name() != trackname) continue; PartList* parts = track->parts(); for (ciPart p = parts->begin(); p != parts->end(); p++) { Part* part = p->second; MidiPart* mpart = (MidiPart*) part; PyObject* pypart = PyDict_New(); int tick = mpart->tick(); int lentick = mpart->lenTick(); int serialnr = mpart->sn(); PyObject* pstrtick = Py_BuildValue("s", "tick"); PyObject* pitick = Py_BuildValue("i", tick); PyObject* pstrid = Py_BuildValue("s", "id"); PyObject* pstrserial = Py_BuildValue("i", serialnr); PyObject* pstrlen = Py_BuildValue("s", "len"); PyObject* pstrtick2 = Py_BuildValue("i", lentick); PyDict_SetItem(pypart, pstrtick, pitick); PyDict_SetItem(pypart, pstrid, pstrserial); PyDict_SetItem(pypart, pstrlen, pstrtick2); Py_DECREF(pstrtick); Py_DECREF(pitick); Py_DECREF(pstrid); Py_DECREF(pstrserial); Py_DECREF(pstrlen); Py_DECREF(pstrtick2); // Pack midi events into list before wrapping it all up EventList* events = mpart->events(); PyObject* pyevents = Py_BuildValue("[]"); for (ciEvent e = events->begin(); e != events->end(); e++) { PyObject* pyevent = PyDict_New(); // The event structure - a dictionary with keys 'type','tick','data' const Event& event = e->second; unsigned tick = e->first; PyObject* eventdata = Py_BuildValue("[i,i,i]", event.dataA(), event.dataB(), event.dataC()); PyObject* pstrdata = Py_BuildValue("s", "data"); pstrtick = Py_BuildValue("s", "tick"); PyObject* pitickval = Py_BuildValue("i", tick); PyDict_SetItem(pyevent, pstrdata, eventdata); PyDict_SetItem(pyevent, pstrtick, pitickval); Py_DECREF(eventdata); Py_DECREF(pstrdata); Py_DECREF(pstrtick); Py_DECREF(pitickval); switch (event.type()) { case Note: { PyObject* pstrtype = Py_BuildValue("s", "type"); PyObject* pstrnote = Py_BuildValue("s", "note"); PyObject* pstrlen = Py_BuildValue("s", "len"); PyObject* pilentick = Py_BuildValue("i", event.lenTick()); PyDict_SetItem(pyevent, pstrtype, pstrnote); PyDict_SetItem(pyevent, pstrlen, pilentick); Py_DECREF(pstrtype); Py_DECREF(pstrnote); Py_DECREF(pstrlen); Py_DECREF(pilentick); break; } case Controller: { PyObject* pstrtype = Py_BuildValue("s", "type"); PyObject* pstrctrl = Py_BuildValue("s", "ctrl"); PyDict_SetItem(pyevent, pstrtype, pstrctrl); Py_DECREF(pstrtype); Py_DECREF(pstrctrl); break; } default: printf("Event type not supported yet: %d\n", event.type()); break; } PyList_Append(pyevents, pyevent); Py_DECREF(pyevent); } Py_DECREF(pyevents); // Add the event list to the pypart dictionary PyObject* pystrevents = Py_BuildValue("s", "events"); PyDict_SetItem(pypart, pystrevents, pyevents); Py_DECREF(pystrevents); PyList_Append(pyparts, pypart); Py_DECREF(pypart); } return pyparts; } return NULL; }