diff options
-rw-r--r-- | muse/TODO | 22 | ||||
-rw-r--r-- | muse/doc/man/de/man-de.tex | 3 | ||||
-rw-r--r-- | muse/doc/man/de/midirecording.tex | 1 | ||||
-rw-r--r-- | muse/muse/CMakeLists.txt | 1 | ||||
-rw-r--r-- | muse/muse/arranger/arranger.cpp | 4 | ||||
-rw-r--r-- | muse/muse/audio.cpp | 2 | ||||
-rw-r--r-- | muse/muse/ctrl.h | 6 | ||||
-rw-r--r-- | muse/muse/ctrl/ctrleditor.cpp | 27 | ||||
-rw-r--r-- | muse/muse/liste/ctrllistedit.cpp | 129 | ||||
-rw-r--r-- | muse/muse/liste/ctrllistedit.h | 2 | ||||
-rw-r--r-- | muse/muse/midiout.cpp | 71 | ||||
-rw-r--r-- | muse/muse/midioutport.cpp | 27 | ||||
-rw-r--r-- | muse/muse/miditrack.cpp | 33 | ||||
-rw-r--r-- | muse/muse/mixer/mstrip.cpp | 3 | ||||
-rw-r--r-- | muse/muse/song.cpp | 654 | ||||
-rw-r--r-- | muse/muse/song.h | 6 | ||||
-rw-r--r-- | muse/muse/songtrack.cpp | 662 | ||||
-rw-r--r-- | muse/muse/track.cpp | 8 | ||||
-rw-r--r-- | muse/muse/track.h | 3 |
19 files changed, 873 insertions, 791 deletions
@@ -3,6 +3,11 @@ ---------------------------------------------------------------------------- - dont allow for overlapping parts + - move shortcuts to Muse() class + - add shortcuts as QAction + - extend Shortcut with ShortcutContext + - extend shortcuts with Help Text, Icons etc. + BUGS - make sure all track names are unique @@ -14,17 +19,15 @@ BUGS - Do not allow switch track recording on/off during recording - ? audio prefetching is not stable - - looping does not work sample accurate due to jack transport limitations; looping should be implemented internally to work around this + - make export midi work + FEATURES - wave editor is completely broken - - list editor is missing - - missing time signature ruler in master editor - If events recorded outside part ask after recording what to do: @@ -43,22 +46,15 @@ FEATURES - actual thread state and priorities - actual used timer resource - - export midi - - Import MusE 0.7 song files + - use *.svg icons + - click free mute function CLEANUPS - Cleanup the icon/pixmap handling using Qt resource file: - - rename xpm directory to resources/images - remove all unreferenced files - transform *.xpm into *.pnm or *.jpg files and move into resource file - redirect all *xpm program references to resource file - remove icon.cpp icon.h - -Wishlist - - it should be possible to show controller events in the - tracklist for tracktypes which cannot contain - Parts to make better use of screen real estate. - GUI-wise a "Add Controller" button is needed. diff --git a/muse/doc/man/de/man-de.tex b/muse/doc/man/de/man-de.tex index a1dc0eae..2970276a 100644 --- a/muse/doc/man/de/man-de.tex +++ b/muse/doc/man/de/man-de.tex @@ -168,6 +168,9 @@ \chapter{\M\ Quickstart} \component midirecording.tex +\section{Audio Playback} +\section{Audio Recording} + \component projekte.tex \component struktur.tex \component miditracks.tex diff --git a/muse/doc/man/de/midirecording.tex b/muse/doc/man/de/midirecording.tex index 8036ba66..45490a44 100644 --- a/muse/doc/man/de/midirecording.tex +++ b/muse/doc/man/de/midirecording.tex @@ -34,5 +34,4 @@ Zunächst erzeugen wir einen ''MidiInput'' Track und checken, ob das Keyboard richtig angeschlossen ist: - diff --git a/muse/muse/CMakeLists.txt b/muse/muse/CMakeLists.txt index e61c4a8f..eabd5590 100644 --- a/muse/muse/CMakeLists.txt +++ b/muse/muse/CMakeLists.txt @@ -140,6 +140,7 @@ add_executable ( muse muse.cpp song.cpp songpart.cpp + songtrack.cpp transport.cpp conf.cpp editor.cpp diff --git a/muse/muse/arranger/arranger.cpp b/muse/muse/arranger/arranger.cpp index d3d2b560..6dedc0bb 100644 --- a/muse/muse/arranger/arranger.cpp +++ b/muse/muse/arranger/arranger.cpp @@ -455,11 +455,11 @@ Arranger::Arranger(QMainWindow* parent) connect(canvas, SIGNAL(contentsMoving(int,int)), SLOT(setTLViewPos(int,int))); connect(canvas, SIGNAL(posChanged(int,const AL::Pos&)), SLOT(setPos(int,const AL::Pos&))); - connect(canvas, SIGNAL(createLRPart(Track*)), song, SLOT(createLRPart(Track*))); + connect(canvas, SIGNAL(createLRPart(Track*)), song, SLOT(cmdCreateLRPart(Track*))); connect(canvas, SIGNAL(doubleClickPart(Part*)), SIGNAL(editPart(Part*))); connect(canvas, SIGNAL(startEditor(Part*,int)), muse, SLOT(startEditor(Part*,int))); connect(canvas, SIGNAL(partChanged(Part*,unsigned,unsigned)), - song, SLOT(changePart(Part*,unsigned,unsigned))); + song, SLOT(cmdChangePart(Part*,unsigned,unsigned))); connect(canvas, SIGNAL(addMarker(const AL::Pos&)), SLOT(addMarker(const AL::Pos&))); connect(canvas, SIGNAL(removeMarker(const AL::Pos&)), SLOT(removeMarker(const AL::Pos&))); diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index 543dcdf4..a6d34cd2 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -637,8 +637,6 @@ void Audio::startRolling() for (iTrack i = tracks->begin(); i != tracks->end(); ++i) { if ((*i)->isMidiTrack()) continue; - if ((*i)->type() == Track::WAVE) - ((WaveTrack*)(*i))->resetMeter(); ((AudioTrack*)(*i))->recEvents()->clear(); } } diff --git a/muse/muse/ctrl.h b/muse/muse/ctrl.h index 6426f5e8..f4f0922a 100644 --- a/muse/muse/ctrl.h +++ b/muse/muse/ctrl.h @@ -180,9 +180,9 @@ class Ctrl : public CTRL { void setDefault(int val) { _default.i = val; } const CVal& curVal() const { return _curVal; } - void setCurVal(CVal v) { _curVal = v; } - void setCurVal(float v) { _curVal.f = v; } - void setCurVal(int v) { _curVal.i = v; } + void setCurVal(CVal v) { _curVal = v; _changed = true; } + void setCurVal(float v) { _curVal.f = v; _changed = true; } + void setCurVal(int v) { _curVal.i = v; _changed = true; } int id() const { return _id; } void setId(int i) { _id = i; } diff --git a/muse/muse/ctrl/ctrleditor.cpp b/muse/muse/ctrl/ctrleditor.cpp index bd6ea03c..4a6f1e81 100644 --- a/muse/muse/ctrl/ctrleditor.cpp +++ b/muse/muse/ctrl/ctrleditor.cpp @@ -92,8 +92,7 @@ void CtrlEditor::paint(QPainter& p, const QRect& r) TType tt = track()->timeType(); - MidiController::ControllerType type = midiControllerType(ctrl()->id()); - if (type == MidiController::Velo) { + if (ctrl()->id() == CTRL_VELOCITY) { p.setPen(QPen(Qt::blue, veloWidth)); PartList* pl = track()->parts(); for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { @@ -133,7 +132,8 @@ void CtrlEditor::paint(QPainter& p, const QRect& r) } else { int x1, y1, x2, y2; - + int hx = -1; + int hy; Pos pos1 = tc()->pix2pos(from); ciCtrlVal i = ctrl()->lowerBound(pos1.time(tt)); @@ -154,7 +154,8 @@ void CtrlEditor::paint(QPainter& p, const QRect& r) --i; x1 = tc()->pos2pix(Pos(i.key(), tt)); y1 = ctrlY(x1, i.value()); - drawHandle(p, x1, y1, lselected); + hx = x1; + hy = y1; ++i; } do { @@ -168,14 +169,18 @@ void CtrlEditor::paint(QPainter& p, const QRect& r) p.drawLine(x1, y1, x2, y2); if (x2 >= to) break; - drawHandle(p, x2, y2, lselected); + if (hx != -1) + drawHandle(p, hx, hy, lselected); + hx = x2; + hy = y2; x1 = x2; y1 = y2; ++i; } while (i != ctrl()->end()); - if (x2 < to) { + if (x2 < to) p.drawLine(x2, y1, to, y1); - } + if (hx != -1) + drawHandle(p, hx, hy, lselected); } } if (!aR) { @@ -257,7 +262,7 @@ void CtrlEditor::mousePress(const QPoint& pos, int button, Qt::KeyboardModifiers else { // add controller: CVal val = ctrl()->pixel2val(dragy, wh); - song->addControllerVal(track(), ctrl(), selected, val); + song->cmdAddControllerVal(track(), ctrl(), selected, val); tc()->widget()->update(); } } @@ -285,7 +290,7 @@ void CtrlEditor::mousePress(const QPoint& pos, int button, Qt::KeyboardModifiers lselected = tc()->pos2pix(selected); if (tool == RubberTool || button == Qt::RightButton || modifiers & Qt::ControlModifier) { - song->removeControllerVal(track(), ctrl()->id(), i.key()); + song->cmdRemoveControllerVal(track(), ctrl()->id(), i.key()); dragy = -1; } else { @@ -374,7 +379,7 @@ void CtrlEditor::mouseRelease() int wh = cheight(); CVal val = ctrl()->pixel2val(dragy, wh); // modify controller: - song->addControllerVal(track(), ctrl(), selected, val); + song->cmdAddControllerVal(track(), ctrl(), selected, val); } dragy = -1; } @@ -461,7 +466,7 @@ void CtrlEditor::mouseMove(const QPoint& pos) else selected.setFrame(i.key()); lselected = tc()->pos2pix(selected); - song->removeControllerVal(track(), ctrl()->id(), i.key()); + song->cmdRemoveControllerVal(track(), ctrl()->id(), i.key()); dragy = -1; break; } diff --git a/muse/muse/liste/ctrllistedit.cpp b/muse/muse/liste/ctrllistedit.cpp index 9c4a05eb..695fe9a1 100644 --- a/muse/muse/liste/ctrllistedit.cpp +++ b/muse/muse/liste/ctrllistedit.cpp @@ -56,8 +56,6 @@ CtrlListEditor::CtrlListEditor(ListEdit* e, QWidget* parent) track = 0; connect(le.ctrlList, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(itemActivated(QTreeWidgetItem*,int))); - connect(le.ctrlList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), - SLOT(itemDoubleClicked(QTreeWidgetItem*,int))); connect(le.ctrlList, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(itemChanged(QTreeWidgetItem*, int))); connect(le.ctrlList, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), @@ -114,12 +112,25 @@ void CtrlListEditor::setup(const ListType& lt) le.defaultValue->setValue(c->getDefault().i); } else { - le.minValue->setDecimals(1); - le.minValue->setValue(c->minVal().f); - le.maxValue->setDecimals(1); - le.maxValue->setValue(c->maxVal().f); - le.defaultValue->setDecimals(1); - le.defaultValue->setValue(c->getDefault().f); + if (c->type() & Ctrl::LOG) { + le.minValue->setDecimals(0); + le.minValue->setValue(c->minVal().f * 20.0); + le.minValue->setSuffix(tr("dB")); + le.maxValue->setDecimals(0); + le.maxValue->setValue(c->maxVal().f * 20.0); + le.maxValue->setSuffix(tr("dB")); + le.defaultValue->setDecimals(0); + le.defaultValue->setValue(c->getDefault().f * 20.0); + le.defaultValue->setSuffix(tr("dB")); + } + else { + le.minValue->setDecimals(1); + le.minValue->setValue(c->minVal().f); + le.maxValue->setDecimals(1); + le.maxValue->setValue(c->maxVal().f); + le.defaultValue->setDecimals(1); + le.defaultValue->setValue(c->getDefault().f); + } } updateList(); } @@ -221,8 +232,8 @@ void CtrlListEditor::itemChanged(QTreeWidgetItem* item, int column) int otick = item->data(TIME_COL, Qt::DisplayRole).toInt(); int tick = item->data(TICK_COL, Qt::DisplayRole).toInt(); item->setData(TIME_COL, Qt::DisplayRole, tick); - song->removeControllerVal(track, c->id(), otick); - song->addControllerVal(track, c, tick, val); + song->cmdRemoveControllerVal(track, c->id(), otick); + song->cmdAddControllerVal(track, c, tick, val); } break; case TIME_COL: @@ -230,12 +241,12 @@ void CtrlListEditor::itemChanged(QTreeWidgetItem* item, int column) int otick = item->data(TICK_COL, Qt::DisplayRole).toInt(); int tick = item->data(TIME_COL, Qt::DisplayRole).toInt(); item->setData(TICK_COL, Qt::DisplayRole, tick); - song->removeControllerVal(track, c->id(), otick); - song->addControllerVal(track, c, tick, val); + song->cmdRemoveControllerVal(track, c->id(), otick); + song->cmdAddControllerVal(track, c, tick, val); } break; case VAL_COL: - song->addControllerVal(track, c, listEdit->pos(), val); + song->cmdAddControllerVal(track, c, listEdit->pos(), val); break; } updateListDisabled = false; @@ -266,8 +277,10 @@ void CtrlListEditor::currentItemChanged(QTreeWidgetItem* cur, QTreeWidgetItem* p le.ctrlList->closePersistentEditor(prev, TIME_COL); le.ctrlList->closePersistentEditor(prev, VAL_COL); } - if (cur) - listEdit->pos().setTick(cur->data(TICK_COL, Qt::DisplayRole).toInt()); + if (cur) { + Pos pos(cur->data(TICK_COL, Qt::DisplayRole).toInt(), track->timeType()); + listEdit->pos() = pos; + } le.deleteButton->setEnabled(cur); } @@ -290,7 +303,7 @@ void CtrlListEditor::insertClicked() else val.f = cur->data(VAL_COL, Qt::DisplayRole).toDouble(); } - song->addControllerVal(track, c, listEdit->pos(), val); + song->cmdAddControllerVal(track, c, listEdit->pos(), val); } //--------------------------------------------------------- @@ -303,7 +316,7 @@ void CtrlListEditor::deleteClicked() if (cur == 0) return; int tick = cur->data(TICK_COL, Qt::DisplayRole).toInt(); - song->removeControllerVal(track, c->id(), tick); + song->cmdRemoveControllerVal(track, c->id(), tick); } //--------------------------------------------------------- @@ -324,8 +337,11 @@ void CtrlListEditor::minValChanged(double v) CVal val; if (c->type() & Ctrl::INT) val.i = int(v); - else + else { + if (c->type() & Ctrl::LOG) + v /= 20.0; val.f = v; + } c->setRange(val, c->maxVal()); } @@ -338,8 +354,11 @@ void CtrlListEditor::maxValChanged(double v) CVal val; if (c->type() & Ctrl::INT) val.i = int(v); - else + else { + if (c->type() & Ctrl::LOG) + v /= 20.0; val.f = v; + } c->setRange(c->minVal(), val); } @@ -389,7 +408,9 @@ QWidget* MidiTimeDelegate::createEditor(QWidget* pw, return w; } QDoubleSpinBox* w = new QDoubleSpinBox(pw); - w->setRange(c->minVal().f, c->maxVal().f); + if (c->type() & Ctrl::LOG) + w->setSuffix(tr("dB")); +// w->setRange(c->minVal().f, c->maxVal().f); w->installEventFilter(const_cast<MidiTimeDelegate*>(this)); return w; } @@ -423,7 +444,11 @@ void MidiTimeDelegate::setEditorData(QWidget* editor, } else { QDoubleSpinBox* w = static_cast<QDoubleSpinBox*>(editor); - w->setValue(index.data().toDouble()); + double v = index.data().toDouble(); +printf("type %x\n", c->type()); + if (c->type() & Ctrl::LOG) + v *= 20.0; + w->setValue(v); } } return; @@ -457,7 +482,10 @@ void MidiTimeDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, } else { QDoubleSpinBox* w = static_cast<QDoubleSpinBox*>(editor); - model->setData(index, w->value(), Qt::DisplayRole); + double v = w->value(); + if (c->type() & Ctrl::LOG) + v /= 20.0; + model->setData(index, v, Qt::DisplayRole); } } break; @@ -472,15 +500,47 @@ void MidiTimeDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, void MidiTimeDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - if (index.column() != CtrlListEditor::TIME_COL) { - QItemDelegate::paint(painter, option, index); - return; - } - AL::Pos pos(index.data().toInt()); - int measure, beat, tick; - pos.mbt(&measure, &beat, &tick); QString text; - text.sprintf("%04d.%02d.%03u", measure+1, beat+1, tick); + CtrlListEditor* ce = static_cast<CtrlListEditor*>(parent()); + + switch(index.column()) { + case CtrlListEditor::TICK_COL: + { + Track* track = ce->getTrack(); + AL::Pos pos(index.data().toInt(), track->timeType()); + text = QString("%1").arg(pos.tick()); + } + break; + case CtrlListEditor::TIME_COL: + { + Track* track = ce->getTrack(); + AL::Pos pos(index.data().toInt(), track->timeType()); + int measure, beat, tick; + pos.mbt(&measure, &beat, &tick); + text.sprintf("%04d.%02d.%03u", measure+1, beat+1, tick); + } + break; + case CtrlListEditor::VAL_COL: + { + Ctrl* c = ce->ctrl(); + if (c->type() & Ctrl::INT) { + text = QString("%1").arg(index.data().toInt()); + } + else { + if (c->type() & Ctrl::LOG) { + double f = index.data().toDouble(); + if (f <= -1000.0f) + text = tr("off"); + else + text = QString("%1 dB").arg(f * 20.0); + } + else { + text = QString("%1").arg(index.data().toDouble()); + } + } + } + break; + } QStyleOptionViewItemV2 opt = setOptions(index, option); const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(&option); @@ -506,13 +566,4 @@ void MidiTimeDelegate::paint(QPainter* painter, painter->restore(); } -//--------------------------------------------------------- -// itemDoubleClicked -//--------------------------------------------------------- - -void CtrlListEditor::itemDoubleClicked(QTreeWidgetItem* item, int column) - { - printf("double clicked\n"); - } - diff --git a/muse/muse/liste/ctrllistedit.h b/muse/muse/liste/ctrllistedit.h index a6384321..74b0749d 100644 --- a/muse/muse/liste/ctrllistedit.h +++ b/muse/muse/liste/ctrllistedit.h @@ -75,7 +75,6 @@ class CtrlListEditor : public ListWidget { private slots: void controllerChanged(int id); void itemActivated(QTreeWidgetItem*,int); - void itemDoubleClicked(QTreeWidgetItem*,int); void itemChanged(QTreeWidgetItem*,int); void currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); void insertClicked(); @@ -90,6 +89,7 @@ class CtrlListEditor : public ListWidget { virtual void setup(const ListType&); void sendEscape(); Ctrl* ctrl() const { return c; } + Track* getTrack() const { return track; } enum { TICK_COL, TIME_COL, VAL_COL }; }; diff --git a/muse/muse/midiout.cpp b/muse/muse/midiout.cpp index 31ed904d..0f0af9d7 100644 --- a/muse/muse/midiout.cpp +++ b/muse/muse/midiout.cpp @@ -29,6 +29,7 @@ #include "gconfig.h" static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; +static const unsigned char mmcStopMsg[] = { 0x7f, 0x7f, 0x06, 0x01 }; //--------------------------------------------------------- // MidiOut @@ -208,21 +209,34 @@ void MidiOut::seek(unsigned tickPos, unsigned framePos) // set all controller //--------------------------------------------------- -#if 0 - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - MidiChannel* mc = channel(ch); - if (mc->mute() || mc->noInRoute() || !mc->autoRead()) + if (track->autoRead()) { + CtrlList* cl = track->controller(); + for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { + Ctrl* c = ic->second; + int val = c->value(tickPos).i; + if ((val != CTRL_VAL_UNKNOWN) && (c->curVal().i != val)) { + MidiEvent ev(0, -1, ME_CONTROLLER, c->id(), val); + track->routeEvent(ev); + c->setCurVal(val); + } + } + } + foreach (const Route& r, *track->inRoutes()) { + MidiTrackBase* t = (MidiTrackBase*)r.src.track; + int dstChannel = r.dst.channel; + if (t->isMute() || !t->autoRead()) continue; - CtrlList* cll = mc->controller(); - for (iCtrl ivl = cll->begin(); ivl != cll->end(); ++ivl) { - Ctrl* c = ivl->second; + CtrlList* cl = t->controller(); + for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { + Ctrl* c = ic->second; int val = c->value(tickPos).i; - if (val != CTRL_VAL_UNKNOWN && val != c->curVal().i) { - track->routeEvent(MidiEvent(0, ch, ME_CONTROLLER, c->id(), val)); + if ((val != CTRL_VAL_UNKNOWN) && (c->curVal().i != val)) { + MidiEvent ev(0, dstChannel, ME_CONTROLLER, c->id(), val); + track->routeEvent(ev); + c->setCurVal(val); } } } -#endif } //--------------------------------------------------------- @@ -250,18 +264,24 @@ void MidiOut::stop() // reset sustain //--------------------------------------------------- -#if 0 - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - MidiChannel* mc = channel(ch); - if (mc->noInRoute()) + foreach (const Route& r, *track->inRoutes()) { + MidiTrackBase* t = (MidiTrackBase*)r.src.track; + int dstChannel = r.dst.channel; + if (t->isMute() || !t->autoRead()) continue; - if (mc->hwCtrlState(CTRL_SUSTAIN) != CTRL_VAL_UNKNOWN) { - MidiEvent ev(0, 0, ME_CONTROLLER, CTRL_SUSTAIN, 0); - ev.setChannel(mc->channelNo()); - track->routeEvent(ev); + CtrlList* cl = t->controller(); + for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { + Ctrl* c = ic->second; + if (c->id() == CTRL_SUSTAIN) { + if (c->curVal().i > 0) { + MidiEvent ev(0, dstChannel, ME_CONTROLLER, c->id(), 0); + track->routeEvent(ev); + c->setCurVal(0); + } + } } } -#endif + if (track->sendSync()) { if (genMMC) { unsigned char mmcPos[] = { @@ -274,7 +294,7 @@ void MidiOut::stop() mmcPos[8] = mtc.s(); mmcPos[9] = mtc.f(); mmcPos[10] = mtc.sf(); -//TODO sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); + sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); sendSysex(mmcPos, sizeof(mmcPos)); } if (genMCSync) { // Midi Clock @@ -292,6 +312,8 @@ void MidiOut::stop() void MidiOut::start() { + // TODO: set sustain to old value? + if (!(genMMC || genMCSync || track->sendSync())) return; if (genMMC) @@ -342,7 +364,7 @@ void MidiOut::processMidi(MidiEventList& el, unsigned fromTick, unsigned toTick, el.insert(eventFifo.get()); // collect port controller - if (fromTick != toTick) { // if rolling + if (track->autoRead() && (fromTick != toTick)) { // if rolling CtrlList* cl = track->controller(); for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { Ctrl* c = ic->second; @@ -350,10 +372,9 @@ void MidiOut::processMidi(MidiEventList& el, unsigned fromTick, unsigned toTick, iCtrlVal ie = c->lowerBound(toTick); for (iCtrlVal ic = is; ic != ie; ++ic) { unsigned frame = AL::tempomap.tick2frame(ic.key()); - Event ev(Controller); - ev.setA(c->id()); - ev.setB(ic.value().i); - el.insert(MidiEvent(frame, -1, ev)); + MidiEvent ev(frame, -1, ME_CONTROLLER, c->id(), ic.value().i); + el.insert(ev); + c->setCurVal(ic.value().i); } } } diff --git a/muse/muse/midioutport.cpp b/muse/muse/midioutport.cpp index 698970a8..247af147 100644 --- a/muse/muse/midioutport.cpp +++ b/muse/muse/midioutport.cpp @@ -123,33 +123,6 @@ void MidiOutPort::read(QDomNode node) void MidiOutPort::routeEvent(const MidiEvent& event) { - if (event.type() == ME_CONTROLLER) { - int a = event.dataA(); - int b = event.dataB(); - int chn = event.channel(); - if (chn == 255) { - // port controller - if (hwCtrlState(a) == b) { -// printf(" controller change optimized away 1\n"); - return; - } - setHwCtrlState(a, b); - } -#if 0 - else { - MidiChannel* mc = channel(chn); - // - // optimize controller settings - // - if (mc->hwCtrlState(a) == b) { -// printf(" controller %02x change optimized away: value %02x\n", a, b); - return; - } - mc->setHwCtrlState(a, b); - } -#endif - } - for (iRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r) { switch (r->dst.type) { case RouteNode::MIDIPORT: diff --git a/muse/muse/miditrack.cpp b/muse/muse/miditrack.cpp index 3f380ba4..57a4830b 100644 --- a/muse/muse/miditrack.cpp +++ b/muse/muse/miditrack.cpp @@ -535,6 +535,24 @@ void MidiTrack::processMidi(unsigned from, unsigned to, unsigned, unsigned) } } } + // + // collect controller + // + if (autoRead()) { + for (iCtrl ic = controller()->begin(); ic != controller()->end(); ++ic) { + Ctrl* c = ic->second; + iCtrlVal is = c->lowerBound(from); + iCtrlVal ie = c->lowerBound(to); + for (iCtrlVal ic = is; ic != ie; ++ic) { + unsigned frame = AL::tempomap.tick2frame(ic.key()); + Event ev(Controller); + ev.setA(c->id()); + ev.setB(ic.value().i); + schedEvents.insert(MidiEvent(frame, -1, ev)); + c->setCurVal(ic.value().i); + } + } + } } // @@ -582,21 +600,6 @@ void MidiTrack::processMidi(unsigned from, unsigned to, unsigned, unsigned) } } } - // - // collect controller - // - for (iCtrl ic = controller()->begin(); ic != controller()->end(); ++ic) { - Ctrl* c = ic->second; - iCtrlVal is = c->lowerBound(from); - iCtrlVal ie = c->lowerBound(to); - for (iCtrlVal ic = is; ic != ie; ++ic) { - unsigned frame = AL::tempomap.tick2frame(ic.key()); - Event ev(Controller); - ev.setA(c->id()); - ev.setB(ic.value().i); - schedEvents.insert(MidiEvent(frame, -1, ev)); - } - } } //--------------------------------------------------------- diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp index c0ce56d9..2dd68cd9 100644 --- a/muse/muse/mixer/mstrip.cpp +++ b/muse/muse/mixer/mstrip.cpp @@ -346,7 +346,8 @@ void MidiStrip::heartBeat() void MidiStrip::controllerChanged(int id) { - double val = double(track->ctrlVal(id).i); + CVal cv = track->ctrlVal(id); + double val = double(cv.i); switch (id) { case CTRL_VOLUME: diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index 70906a54..c907ebe6 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -105,53 +105,6 @@ void Song::setSig(const AL::TimeSignature& sig) } //--------------------------------------------------------- -// deselectTracks -//--------------------------------------------------------- - -void Song::deselectTracks() - { - for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) - (*t)->setSelected(false); - } - -//--------------------------------------------------------- -// selectTrack -//--------------------------------------------------------- - -void Song::selectTrack(Track* track) - { - bool changed = false; - for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) { - bool select = *t == track; - if ((*t)->selected() != select) { - (*t)->setSelected(select); - changed = true; - } - } - if (changed) { - updateSelectedTrack(); - trackSelectionChanged(_selectedTrack); - } - } - -//--------------------------------------------------------- -// updateSelectedTrack -// set _selectedTrack to first selected track -//--------------------------------------------------------- - -void Song::updateSelectedTrack() - { - _selectedTrack = 0; - for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) { - bool select = (*t)->selected(); - if (select) { - _selectedTrack = *t; - break; - } - } - } - -//--------------------------------------------------------- // addEvent // return true if event was added //--------------------------------------------------------- @@ -1295,570 +1248,33 @@ void Song::stopRolling() } //--------------------------------------------------------- -// addTrack -// called from GUI context -//--------------------------------------------------------- - -Track* Song::addTrack(QAction* action) - { - int t = action->data().toInt(); - - deselectTracks(); - Track* track = 0; - - Track::TrackType type = (Track::TrackType) t; - if (t >= 5000) { - int idx = t - 5000; - type = Track::MIDI_SYNTI; - int k = 0; - iMidiPlugin i; - for (i = midiPlugins.begin(); i != midiPlugins.end(); ++i) { - if ((*i)->type() != MEMPI_GENERATOR) - continue; - if (k == idx) - break; - ++k; - } - if (i == midiPlugins.end()) { - fprintf(stderr, "Song::addTrack: midi synti not found\n"); - return 0; - } - MidiPlugin* s = *i; - MidiSynti* si = new MidiSynti(); - QString sName(s->name()); - for (k = s->instances(); k < 1000; ++k) { - QString instanceName = (k == 0) ? - sName : instanceName.arg(sName).arg(k); - - MidiSyntiList* sl = midiSyntis(); - iMidiSynti sii; - for (sii = sl->begin(); sii != sl->end(); ++sii) { - if ((*sii)->name() == instanceName) - break; - } - if (sii == sl->end()) { - si->setName(instanceName); - break; - } - } - if (si->initInstance(s)) { - delete si; - return 0; - } - track = si; - } - else if (t >= 1000) { - type = Track::AUDIO_SOFTSYNTH; - QString sclass = synthis[t-1000]->name(); - - Synth* s = findSynth(sclass); - if (s == 0) { - fprintf(stderr, "synthi class <%s> not found\n", sclass.toLatin1().data()); - return 0; - } - - SynthI* si = new SynthI(); - int i; - for (i = s->instances(); i < 1000; ++i) { - QString instanceName = (i == 0) ? - s->name() : QString("%1-%2").arg(s->name()).arg(i); - - SynthIList* sl = syntis(); - iSynthI sii; - for (sii = sl->begin(); sii != sl->end(); ++sii) { - if ((*sii)->name() == instanceName) - break; - } - if (sii == sl->end()) { - si->setName(instanceName); - break; - } - } - if (si->initInstance(s)) { - delete si; - return 0; - } - track = si; - } - else { - switch (type) { - case Track::MIDI: - track = new MidiTrack(); - break; - case Track::MIDI_OUT: - track = new MidiOutPort(); - break; - case Track::MIDI_IN: - track = new MidiInPort(); - break; - case Track::WAVE: - track = new WaveTrack(); - break; - case Track::AUDIO_OUTPUT: - track = new AudioOutput(); - break; - case Track::AUDIO_GROUP: - track = new AudioGroup(); - break; - case Track::AUDIO_INPUT: - track = new AudioInput(); - break; - case Track::AUDIO_SOFTSYNTH: - case Track::TRACK_TYPES: - default: - printf("Song::addTrack() illegal type %d\n", type); - abort(); - } - if (track == 0) - return 0; - } - track->setDefaultName(); - insertTrack(track, -1); - return track; - } - -//--------------------------------------------------------- -// insertTrack -//--------------------------------------------------------- - -void Song::insertTrack(Track* track, int idx) - { - // - // add default routes - // - OutputList* ol = outputs(); - AudioOutput* ao = 0; - if (!ol->empty()) - ao = ol->front(); - MidiOutPortList* mol = midiOutPorts(); - MidiOutPort* mo = 0; - if (!mol->empty()) - mo = mol->front(); - - switch (track->type()) { - case Track::TRACK_TYPES: - case Track::MIDI_OUT: - case Track::MIDI_IN: - case Track::MIDI_SYNTI: - break; - case Track::MIDI: - // - // connect to all midi inputs, if there is not already - // a route - // - if (!track->noInRoute()) { - MidiInPortList* mi = midiInPorts(); - for (iMidiInPort i = mi->begin(); i != mi->end(); ++i) { - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - RouteNode src(*i, ch, RouteNode::TRACK); - RouteNode dst(track, -1, RouteNode::TRACK); - Route r = Route(src, dst); - track->inRoutes()->push_back(r); - } - } - } - break; - case Track::AUDIO_SOFTSYNTH: - case Track::WAVE: - case Track::AUDIO_GROUP: - if (ao) - track->outRoutes()->push_back(Route(RouteNode(track), RouteNode(ao))); - break; - - case Track::AUDIO_INPUT: - { - // connect first input channel to first available jack output - // etc. - QList<PortName> op = audioDriver->outputPorts(false); - QList<PortName>::iterator is = op.begin(); - for (int ch = 0; ch < track->channels(); ++ch) { - if (is != op.end()) { - RouteNode src(is->port, -1, RouteNode::AUDIOPORT); - RouteNode dst(track, ch, RouteNode::TRACK); - Route r = Route(src, dst); - track->inRoutes()->push_back(r); - ++is; - } - } -// if (ao) -// track->outRoutes()->push_back(Route(ao)); - } - break; - case Track::AUDIO_OUTPUT: - { - QList<PortName> op = audioDriver->inputPorts(false); - QList<PortName>::iterator is = op.begin(); - for (int ch = 0; ch < track->channels(); ++ch) { - if (is != op.end()) { - RouteNode src(track, ch, RouteNode::TRACK); - RouteNode dst(is->port, -1, RouteNode::AUDIOPORT); - Route r = Route(src, dst); - track->outRoutes()->push_back(r); - ++is; - } - } - } - break; - } - insertTrack1(track, idx); - - startUndo(); - undoOp(UndoOp::AddTrack, idx, track); - AudioMsg msg; - msg.id = SEQM_ADD_TRACK; - msg.track = track; - msg.ival = idx; - audio->sendMsg(&msg); - endUndo(SC_TRACK_INSERTED | SC_ROUTE); - - emit trackAdded(track, idx); - selectTrack(track); - } - -//--------------------------------------------------------- -// insertTrack0 -// can only be called if sequencer is idle -// (during song load) -//--------------------------------------------------------- - -void Song::insertTrack0(Track* track, int idx) - { - insertTrack1(track, idx); - insertTrack2(track); - } - -//--------------------------------------------------------- -// insertTrack1 -// non realtime part of insertTrack -//--------------------------------------------------------- - -void Song::insertTrack1(Track* track, int idx) - { - if (idx == -1) - idx = _tracks.size(); - _tracks.insert(idx, track); - if (track->type() == Track::AUDIO_SOFTSYNTH) { - SynthI* s = (SynthI*)track; - Synth* sy = s->synth(); - if (!s->isActivated()) - s->initInstance(sy); - } - if (audioState == AUDIO_RUNNING) { - track->activate1(); - track->activate2(); - } - } - -//--------------------------------------------------------- -// insertTrack2 -// realtime part -//--------------------------------------------------------- - -void Song::insertTrack2(Track* track) - { - switch(track->type()) { - case Track::MIDI_SYNTI: - _midiSyntis.push_back((MidiSynti*)track); - break; - case Track::MIDI: - _midis.push_back((MidiTrack*)track); - break; - case Track::MIDI_OUT: - _midiOutPorts.push_back((MidiOutPort*)track); - break; - case Track::MIDI_IN: - _midiInPorts.push_back((MidiInPort*)track); - break; - case Track::WAVE: - _waves.push_back((WaveTrack*)track); - break; - case Track::AUDIO_OUTPUT: - _outputs.push_back((AudioOutput*)track); - break; - case Track::AUDIO_GROUP: - _groups.push_back((AudioGroup*)track); - break; - case Track::AUDIO_INPUT: - _inputs.push_back((AudioInput*)track); - break; - case Track::AUDIO_SOFTSYNTH: - { - SynthI* s = (SynthI*)track; - midiInstruments.push_back(s->instrument()); - _synthIs.push_back(s); - } - break; - default: - fprintf(stderr, "insertTrack2: unknown track type %d\n", track->type()); - // abort(); - return; - } - - // - // connect routes - // - if (track->type() == Track::AUDIO_OUTPUT || track->type() == Track::MIDI_OUT) { - foreach(Route r, *(track->inRoutes())) { - if (r.src.type != RouteNode::AUXPLUGIN) { - r.src.track->outRoutes()->push_back(r); - } - } - } - else if (track->type() == Track::AUDIO_INPUT || track->type() == Track::MIDI_IN) { - foreach(Route r, *(track->outRoutes())) { - if (r.dst.type != RouteNode::AUXPLUGIN) { - r.dst.track->inRoutes()->push_back(r); - } - } - } - else { - foreach(Route r, *(track->inRoutes())) { - if (r.src.type != RouteNode::AUXPLUGIN) { - r.src.track->outRoutes()->push_back(r); - } - } - foreach(Route r, *(track->outRoutes())) { - if (r.dst.type != RouteNode::AUXPLUGIN) { - r.dst.track->inRoutes()->push_back(r); - } - } - } - } - -//--------------------------------------------------------- -// removeTrack -// called from gui context -//--------------------------------------------------------- - -void Song::removeTrack(Track* track) - { - startUndo(); - int idx = _tracks.indexOf(track); - undoOp(UndoOp::DeleteTrack, idx, track); - removeTrack1(track); - audio->msgRemoveTrack(track); - removeTrack3(track); - - endUndo(SC_TRACK_REMOVED | SC_ROUTE); - } - -//--------------------------------------------------------- -// removeTrack1 -// non realtime part of removeTrack -//--------------------------------------------------------- - -void Song::removeTrack1(Track* track) - { - track->deactivate(); - _tracks.removeAt(_tracks.indexOf(track)); - } - -//--------------------------------------------------------- -// removeTrack2 -// called from RT context -//--------------------------------------------------------- - -void Song::removeTrack2(Track* track) - { - switch (track->type()) { - case Track::MIDI_SYNTI: - _midiSyntis.removeAt(_midiSyntis.indexOf((MidiSynti*)track)); - break; - case Track::MIDI: - _midis.removeAt(_midis.indexOf((MidiTrack*)track)); - break; - case Track::MIDI_OUT: - _midiOutPorts.removeAt(_midiOutPorts.indexOf((MidiOutPort*)track)); - break; - case Track::MIDI_IN: - _midiInPorts.removeAt(_midiInPorts.indexOf((MidiInPort*)track)); - break; - case Track::WAVE: - _waves.removeAt(_waves.indexOf((WaveTrack*)track)); - break; - case Track::AUDIO_OUTPUT: - _outputs.removeAt(_outputs.indexOf((AudioOutput*)track)); - break; - case Track::AUDIO_INPUT: - _inputs.removeAt(_inputs.indexOf((AudioInput*)track)); - break; - case Track::AUDIO_GROUP: - _groups.removeAt(_groups.indexOf((AudioGroup*)track)); - break; - case Track::AUDIO_SOFTSYNTH: - { - SynthI* s = (SynthI*) track; - s->deactivate2(); - _synthIs.removeAt(_synthIs.indexOf(s)); - } - break; - case Track::TRACK_TYPES: - return; - } - // - // remove routes - // - foreach (const Route r, *(track->inRoutes())) { - if (r.src.type != RouteNode::TRACK) - continue; - int idx = r.src.track->outRoutes()->indexOf(r); - if (idx != -1) - r.src.track->outRoutes()->removeAt(idx); - else - printf("Song::removeTrack2(): input route not found\n"); - } - foreach (const Route r, *(track->outRoutes())) { - if (r.dst.type != RouteNode::TRACK) - continue; - int idx = r.dst.track->inRoutes()->indexOf(r); - if (idx != -1) - r.dst.track->inRoutes()->removeAt(idx); - else { - printf("Song::removeTrack2(): output route not found\n"); - } - } - } - -//--------------------------------------------------------- -// removeTrack3 -// non realtime part of removeTrack -//--------------------------------------------------------- - -void Song::removeTrack3(Track* track) - { - if (track->type() == Track::AUDIO_SOFTSYNTH) { - SynthI* s = (SynthI*) track; - s->deactivate3(); - } - emit trackRemoved(track); - } - -//--------------------------------------------------------- -// synthesizer -//--------------------------------------------------------- - -std::vector<QString>* Song::synthesizer() const - { - std::vector<QString>* l = new std::vector<QString>; - - for (std::vector<Synth*>::const_iterator i = synthis.begin(); - i != synthis.end(); ++i) { - l->push_back((*i)->name()); - } - return l; - } - -//--------------------------------------------------------- -// setRecordFlag -//--------------------------------------------------------- - -void Song::setRecordFlag(Track* track, bool val) - { - if (track->type() == Track::AUDIO_OUTPUT) { - if (!val && track->recordFlag() == false) { - muse->bounceToFile(); - } - } - track->setRecordFlag(val); - } - -//--------------------------------------------------------- -// setMute -//--------------------------------------------------------- - -void Song::setMute(Track* track, bool val) - { - track->setMute(val); - emit muteChanged(track, track->mute()); - } - -//--------------------------------------------------------- -// setMonitor -//--------------------------------------------------------- - -void Song::setMonitor(Track* track, bool val) - { - track->setMonitor(val); -// emit monitorChanged(track, track->mute()); - } - -//--------------------------------------------------------- -// setOff -//--------------------------------------------------------- - -void Song::setOff(Track* track, bool val) - { - track->setOff(val); - emit offChanged(track, track->off()); - } - -//--------------------------------------------------------- -// setAutoRead -//--------------------------------------------------------- - -void Song::setAutoRead(Track* track, bool val) - { - track->setAutoRead(val); - emit autoReadChanged(track, track->autoRead()); - } - -//--------------------------------------------------------- -// setAutoWrite -//--------------------------------------------------------- - -void Song::setAutoWrite(Track* track, bool val) - { - track->setAutoWrite(val); - emit autoWriteChanged(track, track->autoRead()); - } - -//--------------------------------------------------------- -// setSolo -//--------------------------------------------------------- - -void Song::setSolo(Track* track, bool val) - { - if (!track->setSolo(val)) - return; - emit soloChanged(track, track->solo()); - soloFlag = false; - for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { - if ((*i)->solo()) { - soloFlag = true; - break; - } - } - for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { - (*i)->updateMute(); - } - } - -//--------------------------------------------------------- // addControllerVal // GUI context //--------------------------------------------------------- -void Song::addControllerVal(Track* t, int id, const Pos& pos, CVal val) +void Song::cmdAddControllerVal(Track* t, int id, const Pos& pos, CVal val) { Ctrl* c = t->getController(id); if (c == 0) { printf("Song::addControllerVal:: no controller %d found\n", id); return; } - addControllerVal(t, c, pos, val); + cmdAddControllerVal(t, c, pos, val); } -void Song::addControllerVal(Track* t, Ctrl* c, const Pos& p, CVal val) +void Song::cmdAddControllerVal(Track* t, Ctrl* c, const Pos& p, CVal val) { unsigned time = t->timeType() == AL::FRAMES ? p.frame() : p.tick(); iCtrlVal e = c->find(time); if (e == c->end()) { - // schedule new controller event + // add new controller event audio->msgAddController(t, c->id(), time, val); } else { + // + // change controller is handled inline: + // CVal oval = c->value(time); -// printf("change controller %f - %f\n", oval.f, val.f); startUndo(); undoOp(UndoOp::ModifyCtrl, t, c->id(), time, val, oval); c->add(time, val); @@ -1929,7 +1345,7 @@ void Song::setControllerVal(Track* t, Ctrl* c, CVal val) else { iCtrlVal e = c->find(time); if (e == c->end()) { - // schedule new controller event + // add new controller event audio->msgAddController(t, c->id(), time, val); } else { @@ -1945,66 +1361,16 @@ void Song::setControllerVal(Track* t, Ctrl* c, CVal val) } //--------------------------------------------------------- -// removeControllerVal +// cmdRemoveControllerVal //--------------------------------------------------------- -void Song::removeControllerVal(Track* t, int id, unsigned time) +void Song::cmdRemoveControllerVal(Track* t, int id, unsigned time) { audio->msgRemoveController(t, id, time); t->emitControllerChanged(id); } //--------------------------------------------------------- -// moveTrack -//--------------------------------------------------------- - -void Song::moveTrack(Track* src, Track* dst) - { - iTrack si = qFind(_tracks.begin(), _tracks.end(), src); - iTrack di = qFind(_tracks.begin(), _tracks.end(), dst); - if (si == _tracks.end() || di == _tracks.end()) { - printf("Song::moveTrack() track not found\n"); - return; - } - _tracks.erase(si); - _tracks.insert(di, src); - } - -//--------------------------------------------------------- -// changeTrackName -//--------------------------------------------------------- - -void Song::changeTrackName(Track* t, const QString& s) - { - startUndo(); - undoOp(UndoOp::RenameTrack, t, t->name(), s); - t->setName(s); - endUndo(SC_TRACK_MODIFIED); - } - -//--------------------------------------------------------- -// trackExists -//--------------------------------------------------------- - -bool Song::trackExists(Track* t) const - { - return findTrack(t->name()) != 0; - } - -//--------------------------------------------------------- -// findTrack -//--------------------------------------------------------- - -Track* Song::findTrack(const QString& name) const - { - for (int i = 0; i < _tracks.size(); ++i) { - if (_tracks[i]->name() == name) - return _tracks[i]; - } - return 0; - } - -//--------------------------------------------------------- // absoluteProjectPath //--------------------------------------------------------- diff --git a/muse/muse/song.h b/muse/muse/song.h index 1813dab8..62925d49 100644 --- a/muse/muse/song.h +++ b/muse/muse/song.h @@ -362,12 +362,12 @@ class Song : public QObject { // Controller //----------------------------------------- - void addControllerVal(Track*, Ctrl*, const Pos&, CVal); - void addControllerVal(Track*, int, const Pos&, CVal); + void cmdAddControllerVal(Track*, Ctrl*, const Pos&, CVal); + void cmdAddControllerVal(Track*, int, const Pos&, CVal); void setControllerVal(Track*, Ctrl*, CVal); void setControllerVal(Track*, int, CVal); - void removeControllerVal(Track*,int,unsigned); + void cmdRemoveControllerVal(Track*,int,unsigned); void setAutoRead(Track*,bool); void setAutoWrite(Track*,bool); diff --git a/muse/muse/songtrack.cpp b/muse/muse/songtrack.cpp new file mode 100644 index 00000000..e345da0a --- /dev/null +++ b/muse/muse/songtrack.cpp @@ -0,0 +1,662 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "song.h" +#include "audio.h" +#include "midiplugin.h" +#include "driver/audiodev.h" +#include "muse.h" + +//--------------------------------------------------------- +// deselectTracks +//--------------------------------------------------------- + +void Song::deselectTracks() + { + for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) + (*t)->setSelected(false); + } + +//--------------------------------------------------------- +// selectTrack +//--------------------------------------------------------- + +void Song::selectTrack(Track* track) + { + bool changed = false; + for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) { + bool select = *t == track; + if ((*t)->selected() != select) { + (*t)->setSelected(select); + changed = true; + } + } + if (changed) { + updateSelectedTrack(); + trackSelectionChanged(_selectedTrack); + } + } + +//--------------------------------------------------------- +// updateSelectedTrack +// set _selectedTrack to first selected track +//--------------------------------------------------------- + +void Song::updateSelectedTrack() + { + _selectedTrack = 0; + for (iTrack t = _tracks.begin(); t != _tracks.end(); ++t) { + bool select = (*t)->selected(); + if (select) { + _selectedTrack = *t; + break; + } + } + } + +//--------------------------------------------------------- +// addTrack +// called from GUI context +//--------------------------------------------------------- + +Track* Song::addTrack(QAction* action) + { + int t = action->data().toInt(); + + deselectTracks(); + Track* track = 0; + + Track::TrackType type = (Track::TrackType) t; + if (t >= 5000) { + int idx = t - 5000; + type = Track::MIDI_SYNTI; + int k = 0; + iMidiPlugin i; + for (i = midiPlugins.begin(); i != midiPlugins.end(); ++i) { + if ((*i)->type() != MEMPI_GENERATOR) + continue; + if (k == idx) + break; + ++k; + } + if (i == midiPlugins.end()) { + fprintf(stderr, "Song::addTrack: midi synti not found\n"); + return 0; + } + MidiPlugin* s = *i; + MidiSynti* si = new MidiSynti(); + QString sName(s->name()); + for (k = s->instances(); k < 1000; ++k) { + QString instanceName = (k == 0) ? + sName : instanceName.arg(sName).arg(k); + + MidiSyntiList* sl = midiSyntis(); + iMidiSynti sii; + for (sii = sl->begin(); sii != sl->end(); ++sii) { + if ((*sii)->name() == instanceName) + break; + } + if (sii == sl->end()) { + si->setName(instanceName); + break; + } + } + if (si->initInstance(s)) { + delete si; + return 0; + } + track = si; + } + else if (t >= 1000) { + type = Track::AUDIO_SOFTSYNTH; + QString sclass = synthis[t-1000]->name(); + + Synth* s = findSynth(sclass); + if (s == 0) { + fprintf(stderr, "synthi class <%s> not found\n", sclass.toLatin1().data()); + return 0; + } + + SynthI* si = new SynthI(); + int i; + for (i = s->instances(); i < 1000; ++i) { + QString instanceName = (i == 0) ? + s->name() : QString("%1-%2").arg(s->name()).arg(i); + + SynthIList* sl = syntis(); + iSynthI sii; + for (sii = sl->begin(); sii != sl->end(); ++sii) { + if ((*sii)->name() == instanceName) + break; + } + if (sii == sl->end()) { + si->setName(instanceName); + break; + } + } + if (si->initInstance(s)) { + delete si; + return 0; + } + track = si; + } + else { + switch (type) { + case Track::MIDI: + track = new MidiTrack(); + break; + case Track::MIDI_OUT: + track = new MidiOutPort(); + break; + case Track::MIDI_IN: + track = new MidiInPort(); + break; + case Track::WAVE: + track = new WaveTrack(); + break; + case Track::AUDIO_OUTPUT: + track = new AudioOutput(); + break; + case Track::AUDIO_GROUP: + track = new AudioGroup(); + break; + case Track::AUDIO_INPUT: + track = new AudioInput(); + break; + case Track::AUDIO_SOFTSYNTH: + case Track::TRACK_TYPES: + default: + printf("Song::addTrack() illegal type %d\n", type); + abort(); + } + if (track == 0) + return 0; + } + track->setDefaultName(); + insertTrack(track, -1); + return track; + } + +//--------------------------------------------------------- +// insertTrack +//--------------------------------------------------------- + +void Song::insertTrack(Track* track, int idx) + { + // + // add default routes + // + OutputList* ol = outputs(); + AudioOutput* ao = 0; + if (!ol->empty()) + ao = ol->front(); + MidiOutPortList* mol = midiOutPorts(); + MidiOutPort* mo = 0; + if (!mol->empty()) + mo = mol->front(); + + switch (track->type()) { + case Track::TRACK_TYPES: + case Track::MIDI_OUT: + case Track::MIDI_IN: + case Track::MIDI_SYNTI: + break; + case Track::MIDI: + // + // connect to all midi inputs, if there is not already + // a route + // + if (!track->noInRoute()) { + MidiInPortList* mi = midiInPorts(); + for (iMidiInPort i = mi->begin(); i != mi->end(); ++i) { + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { + RouteNode src(*i, ch, RouteNode::TRACK); + RouteNode dst(track, -1, RouteNode::TRACK); + Route r = Route(src, dst); + track->inRoutes()->push_back(r); + } + } + } + break; + case Track::AUDIO_SOFTSYNTH: + case Track::WAVE: + case Track::AUDIO_GROUP: + if (ao) + track->outRoutes()->push_back(Route(RouteNode(track), RouteNode(ao))); + break; + + case Track::AUDIO_INPUT: + { + // connect first input channel to first available jack output + // etc. + QList<PortName> op = audioDriver->outputPorts(false); + QList<PortName>::iterator is = op.begin(); + for (int ch = 0; ch < track->channels(); ++ch) { + if (is != op.end()) { + RouteNode src(is->port, -1, RouteNode::AUDIOPORT); + RouteNode dst(track, ch, RouteNode::TRACK); + Route r = Route(src, dst); + track->inRoutes()->push_back(r); + ++is; + } + } +// if (ao) +// track->outRoutes()->push_back(Route(ao)); + } + break; + case Track::AUDIO_OUTPUT: + { + QList<PortName> op = audioDriver->inputPorts(false); + QList<PortName>::iterator is = op.begin(); + for (int ch = 0; ch < track->channels(); ++ch) { + if (is != op.end()) { + RouteNode src(track, ch, RouteNode::TRACK); + RouteNode dst(is->port, -1, RouteNode::AUDIOPORT); + Route r = Route(src, dst); + track->outRoutes()->push_back(r); + ++is; + } + } + } + break; + } + insertTrack1(track, idx); + + startUndo(); + undoOp(UndoOp::AddTrack, idx, track); + AudioMsg msg; + msg.id = SEQM_ADD_TRACK; + msg.track = track; + msg.ival = idx; + audio->sendMsg(&msg); + endUndo(SC_TRACK_INSERTED | SC_ROUTE); + + emit trackAdded(track, idx); + selectTrack(track); + } + +//--------------------------------------------------------- +// insertTrack0 +// can only be called if sequencer is idle +// (during song load) +//--------------------------------------------------------- + +void Song::insertTrack0(Track* track, int idx) + { + insertTrack1(track, idx); + insertTrack2(track); + } + +//--------------------------------------------------------- +// insertTrack1 +// non realtime part of insertTrack +//--------------------------------------------------------- + +void Song::insertTrack1(Track* track, int idx) + { + if (idx == -1) + idx = _tracks.size(); + _tracks.insert(idx, track); + if (track->type() == Track::AUDIO_SOFTSYNTH) { + SynthI* s = (SynthI*)track; + Synth* sy = s->synth(); + if (!s->isActivated()) + s->initInstance(sy); + } + if (audioState == AUDIO_RUNNING) { + track->activate1(); + track->activate2(); + } + } + +//--------------------------------------------------------- +// insertTrack2 +// realtime part +//--------------------------------------------------------- + +void Song::insertTrack2(Track* track) + { + switch(track->type()) { + case Track::MIDI_SYNTI: + _midiSyntis.push_back((MidiSynti*)track); + break; + case Track::MIDI: + _midis.push_back((MidiTrack*)track); + break; + case Track::MIDI_OUT: + _midiOutPorts.push_back((MidiOutPort*)track); + break; + case Track::MIDI_IN: + _midiInPorts.push_back((MidiInPort*)track); + break; + case Track::WAVE: + _waves.push_back((WaveTrack*)track); + break; + case Track::AUDIO_OUTPUT: + _outputs.push_back((AudioOutput*)track); + break; + case Track::AUDIO_GROUP: + _groups.push_back((AudioGroup*)track); + break; + case Track::AUDIO_INPUT: + _inputs.push_back((AudioInput*)track); + break; + case Track::AUDIO_SOFTSYNTH: + { + SynthI* s = (SynthI*)track; + midiInstruments.push_back(s->instrument()); + _synthIs.push_back(s); + } + break; + default: + fprintf(stderr, "insertTrack2: unknown track type %d\n", track->type()); + // abort(); + return; + } + + // + // connect routes + // + if (track->type() == Track::AUDIO_OUTPUT || track->type() == Track::MIDI_OUT) { + foreach(Route r, *(track->inRoutes())) { + if (r.src.type != RouteNode::AUXPLUGIN) { + r.src.track->outRoutes()->push_back(r); + } + } + } + else if (track->type() == Track::AUDIO_INPUT || track->type() == Track::MIDI_IN) { + foreach(Route r, *(track->outRoutes())) { + if (r.dst.type != RouteNode::AUXPLUGIN) { + r.dst.track->inRoutes()->push_back(r); + } + } + } + else { + foreach(Route r, *(track->inRoutes())) { + if (r.src.type != RouteNode::AUXPLUGIN) { + r.src.track->outRoutes()->push_back(r); + } + } + foreach(Route r, *(track->outRoutes())) { + if (r.dst.type != RouteNode::AUXPLUGIN) { + r.dst.track->inRoutes()->push_back(r); + } + } + } + } + +//--------------------------------------------------------- +// removeTrack +// called from gui context +//--------------------------------------------------------- + +void Song::removeTrack(Track* track) + { + startUndo(); + int idx = _tracks.indexOf(track); + undoOp(UndoOp::DeleteTrack, idx, track); + removeTrack1(track); + audio->msgRemoveTrack(track); + removeTrack3(track); + + endUndo(SC_TRACK_REMOVED | SC_ROUTE); + } + +//--------------------------------------------------------- +// removeTrack1 +// non realtime part of removeTrack +//--------------------------------------------------------- + +void Song::removeTrack1(Track* track) + { + track->deactivate(); + _tracks.removeAt(_tracks.indexOf(track)); + } + +//--------------------------------------------------------- +// removeTrack2 +// called from RT context +//--------------------------------------------------------- + +void Song::removeTrack2(Track* track) + { + switch (track->type()) { + case Track::MIDI_SYNTI: + _midiSyntis.removeAt(_midiSyntis.indexOf((MidiSynti*)track)); + break; + case Track::MIDI: + _midis.removeAt(_midis.indexOf((MidiTrack*)track)); + break; + case Track::MIDI_OUT: + _midiOutPorts.removeAt(_midiOutPorts.indexOf((MidiOutPort*)track)); + break; + case Track::MIDI_IN: + _midiInPorts.removeAt(_midiInPorts.indexOf((MidiInPort*)track)); + break; + case Track::WAVE: + _waves.removeAt(_waves.indexOf((WaveTrack*)track)); + break; + case Track::AUDIO_OUTPUT: + _outputs.removeAt(_outputs.indexOf((AudioOutput*)track)); + break; + case Track::AUDIO_INPUT: + _inputs.removeAt(_inputs.indexOf((AudioInput*)track)); + break; + case Track::AUDIO_GROUP: + _groups.removeAt(_groups.indexOf((AudioGroup*)track)); + break; + case Track::AUDIO_SOFTSYNTH: + { + SynthI* s = (SynthI*) track; + s->deactivate2(); + _synthIs.removeAt(_synthIs.indexOf(s)); + } + break; + case Track::TRACK_TYPES: + return; + } + // + // remove routes + // + foreach (const Route r, *(track->inRoutes())) { + if (r.src.type != RouteNode::TRACK) + continue; + int idx = r.src.track->outRoutes()->indexOf(r); + if (idx != -1) + r.src.track->outRoutes()->removeAt(idx); + else + printf("Song::removeTrack2(): input route not found\n"); + } + foreach (const Route r, *(track->outRoutes())) { + if (r.dst.type != RouteNode::TRACK) + continue; + int idx = r.dst.track->inRoutes()->indexOf(r); + if (idx != -1) + r.dst.track->inRoutes()->removeAt(idx); + else { + printf("Song::removeTrack2(): output route not found\n"); + } + } + } + +//--------------------------------------------------------- +// removeTrack3 +// non realtime part of removeTrack +//--------------------------------------------------------- + +void Song::removeTrack3(Track* track) + { + if (track->type() == Track::AUDIO_SOFTSYNTH) { + SynthI* s = (SynthI*) track; + s->deactivate3(); + } + emit trackRemoved(track); + } + +//--------------------------------------------------------- +// synthesizer +//--------------------------------------------------------- + +std::vector<QString>* Song::synthesizer() const + { + std::vector<QString>* l = new std::vector<QString>; + + for (std::vector<Synth*>::const_iterator i = synthis.begin(); + i != synthis.end(); ++i) { + l->push_back((*i)->name()); + } + return l; + } + +//--------------------------------------------------------- +// setRecordFlag +//--------------------------------------------------------- + +void Song::setRecordFlag(Track* track, bool val) + { + if (track->type() == Track::AUDIO_OUTPUT) { + if (!val && track->recordFlag() == false) { + muse->bounceToFile(); + } + } + track->setRecordFlag(val); + } + +//--------------------------------------------------------- +// setMute +//--------------------------------------------------------- + +void Song::setMute(Track* track, bool val) + { + track->setMute(val); + emit muteChanged(track, track->mute()); + } + +//--------------------------------------------------------- +// setMonitor +//--------------------------------------------------------- + +void Song::setMonitor(Track* track, bool val) + { + track->setMonitor(val); +// emit monitorChanged(track, track->mute()); + } + +//--------------------------------------------------------- +// setOff +//--------------------------------------------------------- + +void Song::setOff(Track* track, bool val) + { + track->setOff(val); + emit offChanged(track, track->off()); + } + +//--------------------------------------------------------- +// setAutoRead +//--------------------------------------------------------- + +void Song::setAutoRead(Track* track, bool val) + { + track->setAutoRead(val); + emit autoReadChanged(track, track->autoRead()); + } + +//--------------------------------------------------------- +// setAutoWrite +//--------------------------------------------------------- + +void Song::setAutoWrite(Track* track, bool val) + { + track->setAutoWrite(val); + emit autoWriteChanged(track, track->autoRead()); + } + +//--------------------------------------------------------- +// setSolo +//--------------------------------------------------------- + +void Song::setSolo(Track* track, bool val) + { + if (!track->setSolo(val)) + return; + emit soloChanged(track, track->solo()); + soloFlag = false; + for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { + if ((*i)->solo()) { + soloFlag = true; + break; + } + } + for (iTrack i = _tracks.begin(); i != _tracks.end(); ++i) { + (*i)->updateMute(); + } + } + +//--------------------------------------------------------- +// moveTrack +//--------------------------------------------------------- + +void Song::moveTrack(Track* src, Track* dst) + { + iTrack si = qFind(_tracks.begin(), _tracks.end(), src); + iTrack di = qFind(_tracks.begin(), _tracks.end(), dst); + if (si == _tracks.end() || di == _tracks.end()) { + printf("Song::moveTrack() track not found\n"); + return; + } + _tracks.erase(si); + _tracks.insert(di, src); + } + +//--------------------------------------------------------- +// changeTrackName +//--------------------------------------------------------- + +void Song::changeTrackName(Track* t, const QString& s) + { + startUndo(); + undoOp(UndoOp::RenameTrack, t, t->name(), s); + t->setName(s); + endUndo(SC_TRACK_MODIFIED); + } + +//--------------------------------------------------------- +// trackExists +//--------------------------------------------------------- + +bool Song::trackExists(Track* t) const + { + return findTrack(t->name()) != 0; + } + +//--------------------------------------------------------- +// findTrack +//--------------------------------------------------------- + +Track* Song::findTrack(const QString& name) const + { + for (int i = 0; i < _tracks.size(); ++i) { + if (_tracks[i]->name() == name) + return _tracks[i]; + } + return 0; + } + diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp index ca457ad6..af2b2a3d 100644 --- a/muse/muse/track.cpp +++ b/muse/muse/track.cpp @@ -105,8 +105,8 @@ Track::Track() _channels = 0; // 1 - mono, 2 - stereo _selected = false; _locked = false; - _autoRead = false; - _autoWrite = false; + _autoRead = autoReadDefault(); + _autoWrite = autoWriteDefault(); for (int i = 0; i < MAX_CHANNELS; ++i) { _meter[i] = 0.0f; @@ -245,9 +245,9 @@ void Track::writeProperties(Xml& xml) const xml.intTag("locked", _locked); if (_monitor) xml.intTag("monitor", _monitor); - if (!_autoRead) + if (_autoRead != autoReadDefault()) xml.intTag("autoRead", _autoRead); - if (_autoWrite) + if (_autoWrite != autoWriteDefault()) xml.intTag("autoWrite", _autoWrite); if (_selected) xml.intTag("selected", _selected); diff --git a/muse/muse/track.h b/muse/muse/track.h index c7a68d8e..fa21b016 100644 --- a/muse/muse/track.h +++ b/muse/muse/track.h @@ -326,6 +326,9 @@ class Track : public QObject { void setDeviceId(int val) { _deviceId = val; } virtual bool muteDefault() const { return false; } + virtual bool autoReadDefault() const { return false; } + virtual bool autoWriteDefault() const { return false; } + virtual MidiOut* midiOut() { return 0; } virtual MidiInstrument* instrument() { return 0; } }; |