summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--muse/TODO22
-rw-r--r--muse/doc/man/de/man-de.tex3
-rw-r--r--muse/doc/man/de/midirecording.tex1
-rw-r--r--muse/muse/CMakeLists.txt1
-rw-r--r--muse/muse/arranger/arranger.cpp4
-rw-r--r--muse/muse/audio.cpp2
-rw-r--r--muse/muse/ctrl.h6
-rw-r--r--muse/muse/ctrl/ctrleditor.cpp27
-rw-r--r--muse/muse/liste/ctrllistedit.cpp129
-rw-r--r--muse/muse/liste/ctrllistedit.h2
-rw-r--r--muse/muse/midiout.cpp71
-rw-r--r--muse/muse/midioutport.cpp27
-rw-r--r--muse/muse/miditrack.cpp33
-rw-r--r--muse/muse/mixer/mstrip.cpp3
-rw-r--r--muse/muse/song.cpp654
-rw-r--r--muse/muse/song.h6
-rw-r--r--muse/muse/songtrack.cpp662
-rw-r--r--muse/muse/track.cpp8
-rw-r--r--muse/muse/track.h3
19 files changed, 873 insertions, 791 deletions
diff --git a/muse/TODO b/muse/TODO
index 4b045263..b36fc594 100644
--- a/muse/TODO
+++ b/muse/TODO
@@ -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; }
};