diff options
32 files changed, 940 insertions, 725 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog index c2c1f075..a4688528 100644 --- a/muse/ChangeLog +++ b/muse/ChangeLog @@ -1,3 +1,5 @@ +16.11 (ws) + - implemented controller editor part of new list editor 12.11 (ws) - the internationalization files (*.qm) are now part of the MusE image via the qt resource system. Installing them is not diff --git a/muse/doc/dimpl/dimpl.tex b/muse/doc/dimpl/dimpl.tex index 31b28470..d8c91743 100644 --- a/muse/doc/dimpl/dimpl.tex +++ b/muse/doc/dimpl/dimpl.tex @@ -174,6 +174,75 @@ %%======================================================================= %% +\chapter{Process Structure} + +\chapter{Song} + \section{Multithreading} + + \section{Editing} + \subsection{Realtime Editing} + \M\ allows for realtime editing. That means that you can edit + a song while the sequencer is running. + Two threads want to access data in the main {\tt Song()} class: + the GUI thread and the realtime sequencer thread. + + This are the rules how \M\ handles {\tt Song()} data accesses: + + \startitemize[packed,broad] + \item the GUI thread can only read {\tt Song()} data + \item the GUI thread can request the sequencer thread to + modify Song data + \item the sequencer thread can modify {\tt Song()} data, but only + on request of the GUI thread + \stopitemize + + Interprocess communication is done via message passing. + Communication from the gui thread to the sequencer thread is + done in the following steps: + + \startitemize[packed,broad] + \item the GUI sends a Message to the sequencer thread + and waits for an answer + \item once the sequencer thread is running (the JACK + client {\tt process()} call) it processes the message and + sends back an answer to the GUI process. + \item the GUI process reads the answer and continues + \stopitemize + + This scheme stops the GUI process in a defined state while the + realtime process can safely manipulate the {\tt Song()} data. + + \subsection{User Transaction} + + A user transaction is a sequence of actions manipulating the + main {\Song()} structure. Each action involves sending a + message to the realtime thread. This means that every action + stops the GUI thread for at most one JACK cycle. + + If a transaction consists of lot of actions then this scheme + would be too slow. For such cases the sequencer thread is switched + to "idle" mode, which ensures it is not touching the {\tt Song()} + data anymore. Then safe manipulation of the data is possible. + + \subsection{Naming Conventions} + + There are several methods involved in an edit transaction; + example for adding a part: + + \startitemize[packed,broad] + \item {\tt cmdAddPart()} + This implements a complete undoable user transaction + and is called from the gui thread + \item {\tt addPart()} + This method is also called from the gui thread. It + implements part of a user transaction. It is not + surrounded by {\tt startUndo() endUndo()}. + \item the realtime part (actually removing the {\tt Part} from the + PartList) is done inline during processing of + messages in the sequencer thread. + \stopitemize + + \chapter{File Formats} \section{Instrument Definition Files} diff --git a/muse/muse/CMakeLists.txt b/muse/muse/CMakeLists.txt index 8de90026..e61c4a8f 100644 --- a/muse/muse/CMakeLists.txt +++ b/muse/muse/CMakeLists.txt @@ -64,6 +64,7 @@ QT4_WRAP_CPP ( muse_moc_headers cobject.h transpose.h track.h + miditrackbase.h midisynti.h miditrack.h wavetrack.h @@ -138,12 +139,14 @@ add_executable ( muse midiplugin.cpp muse.cpp song.cpp + songpart.cpp transport.cpp conf.cpp editor.cpp cobject.cpp transpose.cpp track.cpp + miditrackbase.cpp midisynti.cpp miditrack.cpp wavetrack.cpp diff --git a/muse/muse/arranger/canvas.cpp b/muse/muse/arranger/canvas.cpp index 85e2305e..4ee07a65 100644 --- a/muse/muse/arranger/canvas.cpp +++ b/muse/muse/arranger/canvas.cpp @@ -471,7 +471,7 @@ void PartCanvas::contextMenu(const QPoint& pos) renamePart(part); break; case 1: - audio->msgRemovePart(part, true); + song->cmdRemovePart(part); track->partListChanged(); break; case 2: @@ -610,7 +610,7 @@ void PartCanvas::mousePress(QMouseEvent* me) break; case RubberTool: if (part) - audio->msgRemovePart(part); + song->cmdRemovePart(part); break; case GlueTool: if (part) @@ -811,7 +811,7 @@ void PartCanvas::mouseRelease(QMouseEvent* me) Pos p2 = pix2pos(drag.x() + drag.width()).snaped(raster()); part->setPos(p1); part->setLenTick(p2.tick() - p1.tick()); - song->addPart(part); + song->cmdAddPart(part); } else widget()->update(); diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index aa58b30d..543dcdf4 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -588,27 +588,6 @@ void Audio::processMsg() midiSeq->initRealtimeTimer(); break; - case SEQM_ADD_TRACK: - song->insertTrack2(msg->track); - midiSeq->updatePollFd(); - break; - - case SEQM_REMOVE_TRACK: - song->removeTrack2(msg->track); - midiSeq->updatePollFd(); - break; - case SEQM_ADD_PART: - song->cmdAddPart((Part*)msg->p1); - break; - case SEQM_REMOVE_PART: - song->cmdRemovePart((Part*)msg->p1); - break; - case SEQM_CHANGE_PART: - song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2); - break; - case SEQM_MOVE_TRACK: - song->moveTrack((Track*)(msg->p1), (Track*)(msg->p2)); - break; case AUDIO_ADDMIDIPLUGIN: ((MidiTrackBase*)msg->track)->addPlugin(msg->mplugin, msg->ival); break; diff --git a/muse/muse/audio.h b/muse/muse/audio.h index 11f30d5e..050757fd 100644 --- a/muse/muse/audio.h +++ b/muse/muse/audio.h @@ -215,8 +215,8 @@ class Audio { void msgRemoveTrack(Track*); void msgRemoveTracks(); void msgMoveTrack(Track*, Track*); - void msgAddPart(Part*, bool u = true); - void msgRemovePart(Part*, bool u = true); +// void msgAddPart(Part*, bool u = true); +// void msgRemovePart(Part*, bool u = true); void msgChangePart(Part* oldPart, Part* newPart, bool u = true); void msgAddEvent(const Event&, Part*, bool u = true); void msgDeleteEvent(const Event&, Part*, bool u = true); diff --git a/muse/muse/importmidi.cpp b/muse/muse/importmidi.cpp index 83cae602..41a8dfd2 100644 --- a/muse/muse/importmidi.cpp +++ b/muse/muse/importmidi.cpp @@ -315,7 +315,7 @@ void MusE::addMidiFile(const QString name) int division = mf.division(); MidiOutPort* outPort = 0; - MidiInPort* inPort = 0; +// MidiInPort* inPort = 0; if (song->midiOutPorts()->empty()) { outPort = new MidiOutPort(); diff --git a/muse/muse/liste/ctrllistedit.cpp b/muse/muse/liste/ctrllistedit.cpp index 472e02f4..9c4a05eb 100644 --- a/muse/muse/liste/ctrllistedit.cpp +++ b/muse/muse/liste/ctrllistedit.cpp @@ -46,13 +46,17 @@ CtrlListEditor::CtrlListEditor(ListEdit* e, QWidget* parent) le.maxValue->setSingleStep(1.0); le.defaultValue->setSingleStep(1.0); - le.ctrlList->setColumnWidth(TICK_COL, 60); - le.ctrlList->setColumnWidth(TIME_COL, 120); + QFontMetrics fm(le.ctrlList->font()); + int zW = fm.width("0"); + le.ctrlList->setColumnWidth(TICK_COL, zW * 8); + le.ctrlList->setColumnWidth(TIME_COL, zW * 14); MidiTimeDelegate* midiTimeDelegate = new MidiTimeDelegate(this); le.ctrlList->setItemDelegate(midiTimeDelegate); 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))); @@ -136,8 +140,7 @@ void CtrlListEditor::updateList() QTreeWidgetItem* item = new QTreeWidgetItem; item->setData(TICK_COL, Qt::TextAlignmentRole, int(Qt::AlignRight | Qt::AlignVCenter)); item->setData(TIME_COL, Qt::TextAlignmentRole, int(Qt::AlignRight | Qt::AlignVCenter)); - item->setData(VAL_COL, Qt::TextAlignmentRole, int(Qt::AlignRight | Qt::AlignVCenter)); -// item->setItemDelegate(TIME_COL, midiTimeDelegate); + item->setData(VAL_COL, Qt::TextAlignmentRole, int(Qt::AlignHCenter | Qt::AlignVCenter)); item->setData(TICK_COL, Qt::DisplayRole, i.key()); item->setData(TIME_COL, Qt::DisplayRole, i.key()); @@ -165,10 +168,10 @@ void CtrlListEditor::controllerChanged(int id) } //--------------------------------------------------------- -// itemDoubleClicked +// itemActivated //--------------------------------------------------------- -void CtrlListEditor::itemDoubleClicked(QTreeWidgetItem* item, int column) +void CtrlListEditor::itemActivated(QTreeWidgetItem* item, int column) { le.ctrlList->openPersistentEditor(item, column); } @@ -179,11 +182,6 @@ void CtrlListEditor::itemDoubleClicked(QTreeWidgetItem* item, int column) void CtrlListEditor::itemChanged(QTreeWidgetItem* item, int column) { - if (column != VAL_COL) { - printf("time change not implemented\n"); - return; - } - CVal val; if (c->type() & Ctrl::INT) { val.i = item->data(VAL_COL, Qt::DisplayRole).toInt(); @@ -217,7 +215,29 @@ void CtrlListEditor::itemChanged(QTreeWidgetItem* item, int column) le.ctrlList->closePersistentEditor(item, TIME_COL); le.ctrlList->closePersistentEditor(item, VAL_COL); updateListDisabled = true; - song->addControllerVal(track, c, listEdit->pos(), val); + switch(column) { + case TICK_COL: + { + 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); + } + break; + case TIME_COL: + { + 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); + } + break; + case VAL_COL: + song->addControllerVal(track, c, listEdit->pos(), val); + break; + } updateListDisabled = false; } @@ -350,14 +370,31 @@ MidiTimeDelegate::MidiTimeDelegate(QObject* parent) // createEditor //--------------------------------------------------------- -QWidget* MidiTimeDelegate::createEditor(QWidget* parent, +QWidget* MidiTimeDelegate::createEditor(QWidget* pw, const QStyleOptionViewItem& option, const QModelIndex& index) const { - if (index.column() != CtrlListEditor::TIME_COL) - return QItemDelegate::createEditor(parent, option, index); - - Awl::PosEdit* pe = new Awl::PosEdit(parent); - return pe; + switch(index.column()) { + case CtrlListEditor::TICK_COL: + break; + case CtrlListEditor::TIME_COL: + return new Awl::PosEdit(pw); + case CtrlListEditor::VAL_COL: + { + CtrlListEditor* ce = static_cast<CtrlListEditor*>(parent()); + Ctrl* c = ce->ctrl(); + if (c->type() & Ctrl::INT) { + QSpinBox* w = new QSpinBox(pw); + w->setRange(c->minVal().i, c->maxVal().i); + w->installEventFilter(const_cast<MidiTimeDelegate*>(this)); + return w; + } + QDoubleSpinBox* w = new QDoubleSpinBox(pw); + w->setRange(c->minVal().f, c->maxVal().f); + w->installEventFilter(const_cast<MidiTimeDelegate*>(this)); + return w; + } + } + return QItemDelegate::createEditor(pw, option, index); } //--------------------------------------------------------- @@ -367,12 +404,31 @@ QWidget* MidiTimeDelegate::createEditor(QWidget* parent, void MidiTimeDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { - if (index.column() != CtrlListEditor::TIME_COL) { - QItemDelegate::setEditorData(editor, index); - return; + switch(index.column()) { + case CtrlListEditor::TICK_COL: + break; + case CtrlListEditor::TIME_COL: + { + Awl::PosEdit* pe = static_cast<Awl::PosEdit*>(editor); + pe->setValue(AL::Pos(index.data().toInt())); + } + return; + case CtrlListEditor::VAL_COL: + { + CtrlListEditor* ce = static_cast<CtrlListEditor*>(parent()); + Ctrl* c = ce->ctrl(); + if (c->type() & Ctrl::INT) { + QSpinBox* w = static_cast<QSpinBox*>(editor); + w->setValue(index.data().toInt()); + } + else { + QDoubleSpinBox* w = static_cast<QDoubleSpinBox*>(editor); + w->setValue(index.data().toDouble()); + } + } + return; } - Awl::PosEdit* pe = (Awl::PosEdit*)editor; - pe->setValue(AL::Pos(index.data().toInt())); + QItemDelegate::setEditorData(editor, index); } //--------------------------------------------------------- @@ -382,12 +438,31 @@ void MidiTimeDelegate::setEditorData(QWidget* editor, void MidiTimeDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - if (index.column() != CtrlListEditor::TIME_COL) { - QItemDelegate::setModelData(editor, model, index); - return; + switch(index.column()) { + case CtrlListEditor::TICK_COL: + break; + case CtrlListEditor::TIME_COL: + { + Awl::PosEdit* pe = static_cast<Awl::PosEdit*>(editor); + model->setData(index, pe->pos().tick(), Qt::DisplayRole); + } + return; + case CtrlListEditor::VAL_COL: + { + CtrlListEditor* ce = static_cast<CtrlListEditor*>(parent()); + Ctrl* c = ce->ctrl(); + if (c->type() & Ctrl::INT) { + QSpinBox* w = static_cast<QSpinBox*>(editor); + model->setData(index, w->value(), Qt::DisplayRole); + } + else { + QDoubleSpinBox* w = static_cast<QDoubleSpinBox*>(editor); + model->setData(index, w->value(), Qt::DisplayRole); + } + } + break; } - Awl::PosEdit* pe = (Awl::PosEdit*)editor; - model->setData(index, pe->pos().tick(), Qt::DisplayRole); + QItemDelegate::setModelData(editor, model, index); } //--------------------------------------------------------- @@ -431,3 +506,13 @@ 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 842ba7eb..a6384321 100644 --- a/muse/muse/liste/ctrllistedit.h +++ b/muse/muse/liste/ctrllistedit.h @@ -30,6 +30,7 @@ //--------------------------------------------------------- class MidiTimeDelegate : public QItemDelegate { + Q_OBJECT virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const; @@ -73,6 +74,7 @@ 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*); @@ -87,6 +89,7 @@ class CtrlListEditor : public ListWidget { CtrlListEditor(ListEdit*, QWidget* parent = 0); virtual void setup(const ListType&); void sendEscape(); + Ctrl* ctrl() const { return c; } enum { TICK_COL, TIME_COL, VAL_COL }; }; diff --git a/muse/muse/liste/listedit.cpp b/muse/muse/liste/listedit.cpp index 09e2ed86..df78dfe7 100644 --- a/muse/muse/liste/listedit.cpp +++ b/muse/muse/liste/listedit.cpp @@ -67,8 +67,9 @@ ListEdit::ListEdit(QWidget*) SLOT(itemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); connect(list, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(itemExpanded(QTreeWidgetItem*))); connect(list, SIGNAL(itemCollapsed(QTreeWidgetItem*)), SLOT(itemExpanded(QTreeWidgetItem*))); + connect(song, SIGNAL(songChanged(int)), SLOT(songChanged(int))); list->resizeColumnToContents(0); - resize(900, 300); + resize(900, 400); } //--------------------------------------------------------- @@ -153,6 +154,19 @@ void ListEdit::buildList() } //--------------------------------------------------------- +// songChanged +//--------------------------------------------------------- + +void ListEdit::songChanged(int flags) + { + if (flags & (SC_TRACK_INSERTED | SC_TRACK_REMOVED | SC_PART_INSERTED + | SC_PART_REMOVED)) { + buildList(); + selectItem(); + } + } + +//--------------------------------------------------------- // findItem //--------------------------------------------------------- @@ -189,12 +203,11 @@ void ListEdit::selectItem(const AL::Pos& p, Track* track, Part* part, Ctrl* ctrl lt.track = track; lt.part = part; lt.ctrl = ctrl; - selectItem(lt); + selectItem(); } -void ListEdit::selectItem(const ListType& l) +void ListEdit::selectItem() { - lt = l; stack->setCurrentWidget(ctrlPanel); buildList(); for (int i = 0;; ++i) { diff --git a/muse/muse/liste/listedit.h b/muse/muse/liste/listedit.h index 2c33cdab..66179cd0 100644 --- a/muse/muse/liste/listedit.h +++ b/muse/muse/liste/listedit.h @@ -75,11 +75,12 @@ class ListEdit : public TopWin { void buildList(); QTreeWidgetItem* findItem(const ListType& lt, QTreeWidgetItem* item); - void selectItem(const ListType& lt); + void selectItem(); private slots: void itemChanged(QTreeWidgetItem*, QTreeWidgetItem*); void itemExpanded(QTreeWidgetItem*); + void songChanged(int); public: ListEdit(QWidget* parent = 0); diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index 79eff684..37b5e5b4 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -568,7 +568,7 @@ void buildMidiEventList(EventList* del, const MidiEventList* el, MidiTrack* trac CVal val; val.i = ev.dataB(); - bool found = false; +// bool found = false; Ctrl* c = track->getController(id); if (c) c->add(tick, val); diff --git a/muse/muse/midiedit/drumedit.cpp b/muse/muse/midiedit/drumedit.cpp index 61537069..7d783245 100644 --- a/muse/muse/midiedit/drumedit.cpp +++ b/muse/muse/midiedit/drumedit.cpp @@ -123,7 +123,7 @@ DrumEdit::DrumEdit(PartList* pl, bool init) QToolBar* transport = addToolBar(tr("Transport")); muse->setupTransportToolbar(transport); - // dont´how pitch value in toolbar + // dont´ow pitch value in toolbar addToolBarBreak(); toolbar = new Toolbar1(initRaster, initQuant, false); addToolBar(toolbar); @@ -341,12 +341,14 @@ void DrumEdit::configChanged() initShortcuts(); } +#if 0 static int rasterTable[] = { //-9----8- 7 6 5 4 3(1/4) 2 1 4, 8, 16, 32, 64, 128, 256, 512, 1024, // triple 6, 12, 24, 48, 96, 192, 384, 768, 1536, 9, 18, 36, 72, 144, 288, 576, 1152, 2304 // dot }; +#endif //--------------------------------------------------------- // keyPressEvent diff --git a/muse/muse/midiinport.h b/muse/muse/midiinport.h index 4a7b8bf1..8589cf41 100644 --- a/muse/muse/midiinport.h +++ b/muse/muse/midiinport.h @@ -21,7 +21,7 @@ #ifndef __MIDIINPORT_H__ #define __MIDIINPORT_H__ -#include "track.h" +#include "miditrackbase.h" #include "midievent.h" static const int RECORD_FIFO_SIZE = 512; diff --git a/muse/muse/midiout.cpp b/muse/muse/midiout.cpp index 6ab98da7..31ed904d 100644 --- a/muse/muse/midiout.cpp +++ b/muse/muse/midiout.cpp @@ -20,7 +20,8 @@ #include "midiout.h" #include "midictrl.h" -#include "track.h" +#include "miditrackbase.h" +#include "al/al.h" #include "al/tempo.h" #include "event.h" #include "sync.h" diff --git a/muse/muse/midiout.h b/muse/muse/midiout.h index 9df88569..75e9cbd6 100644 --- a/muse/muse/midiout.h +++ b/muse/muse/midiout.h @@ -21,9 +21,6 @@ #ifndef __MIDIOUT_H__ #define __MIDIOUT_H__ -#include "al/al.h" -#include "globaldefs.h" -#include "midievent.h" #include "midififo.h" class Track; diff --git a/muse/muse/midioutport.h b/muse/muse/midioutport.h index aa056db5..e77af2e5 100644 --- a/muse/muse/midioutport.h +++ b/muse/muse/midioutport.h @@ -21,7 +21,7 @@ #ifndef __MIDIOUTPORT_H__ #define __MIDIOUTPORT_H__ -#include "track.h" +#include "miditrackbase.h" #include "midiout.h" //--------------------------------------------------------- diff --git a/muse/muse/midisynti.h b/muse/muse/midisynti.h index c74a0eb7..89c77764 100644 --- a/muse/muse/midisynti.h +++ b/muse/muse/midisynti.h @@ -21,7 +21,7 @@ #ifndef __MIDISYNTH_H__ #define __MIDISYNTH_H__ -#include "track.h" +#include "miditrackbase.h" //--------------------------------------------------------- // MidiSynti diff --git a/muse/muse/miditrack.cpp b/muse/muse/miditrack.cpp index b7e3a53d..3f380ba4 100644 --- a/muse/muse/miditrack.cpp +++ b/muse/muse/miditrack.cpp @@ -98,7 +98,7 @@ void MidiTrack::write(Xml& xml) const xml.intTag("compression", _compression); xml.intTag("useDrumMap", _useDrumMap); - const PartList* pl = cparts(); + const PartList* pl = parts(); for (ciPart p = pl->begin(); p != pl->end(); ++p) p->second->write(xml); xml.etag("miditrack"); @@ -195,7 +195,7 @@ void MidiTrack::startRecording() recordPart->setTick(startTick); recordPart->setLenTick(endTick - startTick); recordPart->setName(name()); - audio->msgAddPart(recordPart, false); + song->addPart(recordPart); partCreated = true; } } @@ -604,7 +604,7 @@ void MidiTrack::processMidi(unsigned from, unsigned to, unsigned, unsigned) // from/to - midi ticks //--------------------------------------------------------- -void MidiTrack::getEvents(unsigned from, unsigned to, int, MidiEventList* dst) +void MidiTrack::getEvents(unsigned /*from*/, unsigned /*to*/, int, MidiEventList* dst) { for (iMidiEvent i = schedEvents.begin(); i != schedEvents.end(); ++i) { dst->insert(*i); diff --git a/muse/muse/miditrack.h b/muse/muse/miditrack.h index d8b0d231..6424c1d8 100644 --- a/muse/muse/miditrack.h +++ b/muse/muse/miditrack.h @@ -21,7 +21,7 @@ #ifndef __MIDITRACK_H__ #define __MIDITRACK_H__ -#include "track.h" +#include "miditrackbase.h" #include "midififo.h" class Part; diff --git a/muse/muse/miditrackbase.cpp b/muse/muse/miditrackbase.cpp new file mode 100644 index 00000000..faf0ed4d --- /dev/null +++ b/muse/muse/miditrackbase.cpp @@ -0,0 +1,139 @@ +//============================================================================= +// 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 "miditrackbase.h" +#include "midiplugin.h" + +//--------------------------------------------------------- +// MidiTrackBase +//--------------------------------------------------------- + +MidiTrackBase::MidiTrackBase() + : Track() + { + _pipeline = new MidiPipeline(); + } + +//--------------------------------------------------------- +// MidiTrackBase +//--------------------------------------------------------- + +MidiTrackBase::~MidiTrackBase() + { + foreach(MidiPluginI* plugin, *_pipeline) + delete plugin; + delete _pipeline; + } + +//--------------------------------------------------------- +// MidiTrackBase::writeProperties +//--------------------------------------------------------- + +void MidiTrackBase::writeProperties(Xml& xml) const + { + Track::writeProperties(xml); + for (ciMidiPluginI ip = _pipeline->begin(); ip != _pipeline->end(); ++ip) { + if (*ip) + (*ip)->writeConfiguration(xml); + } + } + +//--------------------------------------------------------- +// MidiTrackBase::readProperties +//--------------------------------------------------------- + +bool MidiTrackBase::readProperties(QDomNode node) + { + QDomElement e = node.toElement(); + QString tag(e.tagName()); + if (tag == "midiPlugin") { + MidiPluginI* pi = new MidiPluginI(this); + if (pi->readConfiguration(node)) + delete pi; + else + addPlugin(pi, -1); + } + else + return Track::readProperties(node); + return false; + } + +//--------------------------------------------------------- +// plugin +//--------------------------------------------------------- + +MidiPluginI* MidiTrackBase::plugin(int idx) const + { + return _pipeline->value(idx); + } + +//--------------------------------------------------------- +// addPlugin +// idx = -1 append +// plugin = 0 remove slot +//--------------------------------------------------------- + +void MidiTrackBase::addPlugin(MidiPluginI* plugin, int idx) + { + if (plugin == 0) { +#if 0 + MidiPluginI* oldPlugin = (*_pipeline)[idx]; + if (oldPlugin) { + int controller = oldPlugin->plugin()->parameter(); + for (int i = 0; i < controller; ++i) { + int id = (idx + 1) * 0x1000 + i; + removeController(id); + } + } +#endif + } + if (idx == -1) + idx = _pipeline->size(); + + if (plugin) { + _pipeline->insert(idx, plugin); +#if 0 + int ncontroller = plugin->plugin()->parameter(); + for (int i = 0; i < ncontroller; ++i) { + int id = (idx + 1) * 0x1000 + i; + QString name(plugin->getParameterName(i)); + double min, max; + plugin->range(i, &min, &max); + Ctrl* cl = getController(id); + if (cl == 0) { + cl = new Ctrl(id, name); + cl->setRange(min, max); + double defaultValue = plugin->defaultValue(i); + cl->setDefault(defaultValue); + cl->setCurVal(defaultValue); + addController(cl); + } + plugin->setParam(i, cl->schedVal().f); + plugin->setControllerList(cl); + } +#endif + } + else { + _pipeline->removeAt(idx); + } + } + + + diff --git a/muse/muse/miditrackbase.h b/muse/muse/miditrackbase.h new file mode 100644 index 00000000..d10b2bb3 --- /dev/null +++ b/muse/muse/miditrackbase.h @@ -0,0 +1,53 @@ +//============================================================================= +// 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. +//============================================================================= + +#ifndef __MIDITRACKBASE_H__ +#define __MIDITRACKBASE_H__ + +#include "track.h" + +//--------------------------------------------------------- +// MidiTrackBase +//--------------------------------------------------------- + +class MidiTrackBase : public Track { + Q_OBJECT + + MidiPipeline* _pipeline; + + public: + MidiTrackBase(); + virtual ~MidiTrackBase(); + + bool readProperties(QDomNode); + void writeProperties(Xml&) const; + + MidiPipeline* pipeline() { return _pipeline; } + void addPlugin(MidiPluginI* plugin, int idx); + MidiPluginI* plugin(int idx) const; + + virtual void processMidi(unsigned, unsigned, unsigned, unsigned) {} + virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MidiEventList* /*dst*/) {} + }; + +#endif + + + diff --git a/muse/muse/muse.cpp b/muse/muse/muse.cpp index 31fcdc5b..f22e654b 100644 --- a/muse/muse/muse.cpp +++ b/muse/muse/muse.cpp @@ -82,7 +82,7 @@ static const char* fileSaveText = static const char* infoLoopButton = QT_TR_NOOP("loop between left mark and right mark"); static const char* infoPunchinButton = QT_TR_NOOP("record starts at left mark"); static const char* infoPunchoutButton = QT_TR_NOOP("record stops at right mark"); -static const char* infoStartButton = QT_TR_NOOP("rewind to start position"); +// static const char* infoStartButton = QT_TR_NOOP("rewind to start position"); static const char* infoRewindButton = QT_TR_NOOP("rewind current position"); static const char* infoForwardButton = QT_TR_NOOP("move current position"); static const char* infoStopButton = QT_TR_NOOP("stop sequencer"); @@ -1690,7 +1690,7 @@ void MusE::selectProject(QAction* a) // kbAccel //--------------------------------------------------------- -void MusE::kbAccel(int key) +void MusE::kbAccel(int /*key*/) { #if 0 //TODOB if (key == shortcuts[SHRT_TOGGLE_METRO].key) { @@ -1863,23 +1863,27 @@ void MusE::cmd(QAction* a) //TODO1 arranger->cmd(Arranger::CMD_PASTE_PART); break; case CMD_DELETE: - song->startUndo(); - if (song->msgRemoveParts()) { - song->endUndo(SC_PART_REMOVED); - break; + { + TrackList* tl = song->tracks(); + bool partsMarked = false; + for (iTrack it = tl->begin(); it != tl->end(); ++it) { + PartList* pl2 = (*it)->parts(); + for (iPart ip = pl2->begin(); ip != pl2->end(); ++ip) { + if (ip->second->selected()) { + partsMarked = true; + break; + } + } } - else { - // if there are no selected parts, delete - // selected tracks - // + if (partsMarked) + song->cmdRemoveParts(); + else audio->msgRemoveTracks(); - } - song->endUndo(SC_TRACK_REMOVED); + } break; + case CMD_DELETE_TRACK: - song->startUndo(); audio->msgRemoveTracks(); - song->endUndo(SC_TRACK_REMOVED); break; case CMD_SELECT_ALL: @@ -2193,7 +2197,7 @@ void MusE::globalCut() if (t + l <= lpos) continue; if ((t >= lpos) && ((t+l) <= rpos)) { - audio->msgRemovePart(part, false); + song->removePart(part); } else if ((t < lpos) && ((t+l) > lpos) && ((t+l) <= rpos)) { // remove part tail @@ -2337,7 +2341,7 @@ void MusE::globalSplit() Part* p2; track->splitPart(part, pos, p1, p2); audio->msgChangePart(part, p1, false); - audio->msgAddPart(p2, false); + song->addPart(p2); break; } } diff --git a/muse/muse/part.cpp b/muse/muse/part.cpp index b4a6bc86..ea8ca457 100644 --- a/muse/muse/part.cpp +++ b/muse/muse/part.cpp @@ -223,162 +223,6 @@ printf("remove part: not found\n"); } //--------------------------------------------------------- -// splitPart -// split part "part" at "tick" position -// create two new parts p1 and p2 -//--------------------------------------------------------- - -void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) - { - int l1 = 0; // len of first new part (ticks or samples) - int l2 = 0; // len of second new part - - int samplepos = AL::tempomap.tick2frame(tickpos); - - switch (type()) { - case WAVE: - l1 = samplepos - part->frame(); - l2 = part->lenFrame() - l1; - break; - case MIDI: - l1 = tickpos - part->tick(); - l2 = part->lenTick() - l1; - break; - default: - return; - } - - if (l1 <= 0 || l2 <= 0) - return; - - p1 = newPart(part); // new left part - p2 = newPart(part); // new right part - - switch (type()) { - case WAVE: - p1->setLenFrame(l1); - p2->setFrame(samplepos); - p2->setLenFrame(l2); - break; - case MIDI: - p1->setLenTick(l1); - p2->setTick(tickpos); - p2->setLenTick(l2); - break; - default: - break; - } - - EventList* se = part->events(); - EventList* de1 = p1->events(); - EventList* de2 = p2->events(); - - if (type() == WAVE) { - int ps = part->frame(); - int d1p1 = p1->frame(); - int d2p1 = p1->endFrame(); - int d1p2 = p2->frame(); - int d2p2 = p2->endFrame(); - for (iEvent ie = se->begin(); ie != se->end(); ++ie) { - Event event = ie->second; - int s1 = event.frame() + ps; - int s2 = event.endFrame() + ps; - - if ((s2 > d1p1) && (s1 < d2p1)) { - Event si = event.mid(d1p1 - ps, d2p1 - ps); - de1->add(si); - } - if ((s2 > d1p2) && (s1 < d2p2)) { - Event si = event.mid(d1p2 - ps, d2p2 - ps); - si.setFrame(si.frame() - l1); //?? - si.setFrame(0); //?? - de2->add(si); - } - } - } - else { - for (iEvent ie = se->begin(); ie != se->end(); ++ie) { - Event event = ie->second.clone(); - int t = event.tick(); - if (t >= l1) { - event.move(-l1); - de2->add(event); - } - else - de1->add(event); - } - } - } - -//--------------------------------------------------------- -// cmdSplitPart -//--------------------------------------------------------- - -void Song::cmdSplitPart(Part* part, const Pos& pos) - { - int tick = pos.tick(); - int l1 = tick - part->tick(); - int l2 = part->lenTick() - l1; - if (l1 <= 0 || l2 <= 0) - return; - Part* p1; - Part* p2; - part->track()->splitPart(part, tick, p1, p2); - - startUndo(); - audio->msgChangePart(part, p1, false); - audio->msgAddPart(p2, false); - endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_INSERTED); - part->track()->partListChanged(); - } - -//--------------------------------------------------------- -// cmdGluePart -//--------------------------------------------------------- - -void Song::cmdGluePart(Part* oPart) - { - Track* track = oPart->track(); - PartList* pl = track->parts(); - Part* nextPart = 0; - - for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { - if (ip->second == oPart) { - ++ip; - if (ip == pl->end()) - return; - nextPart = ip->second; - break; - } - } - - Part* nPart = track->newPart(oPart); - nPart->setLenTick(nextPart->tick() + nextPart->lenTick() - oPart->tick()); - - // populate nPart with Events from oPart and nextPart - - EventList* sl1 = oPart->events(); - EventList* dl = nPart->events(); - - for (iEvent ie = sl1->begin(); ie != sl1->end(); ++ie) - dl->add(ie->second); - - EventList* sl2 = nextPart->events(); - int tickOffset = nextPart->tick() - oPart->tick(); - - for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { - Event event = ie->second.clone(); - event.move(tickOffset); - dl->add(event); - } - startUndo(); - audio->msgRemovePart(nextPart, false); - audio->msgChangePart(oPart, nPart, false); - endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); - track->partListChanged(); - } - -//--------------------------------------------------------- // dump //--------------------------------------------------------- diff --git a/muse/muse/seqmsg.cpp b/muse/muse/seqmsg.cpp index 1033381a..28dfe043 100644 --- a/muse/muse/seqmsg.cpp +++ b/muse/muse/seqmsg.cpp @@ -336,7 +336,7 @@ void Audio::msgRemoveTrack(Track* track) AudioMsg msg; msg.id = SEQM_REMOVE_TRACK; msg.track = track; - sendMessage(&msg, false); + sendMessage(&msg, true); } //--------------------------------------------------------- @@ -376,55 +376,6 @@ void Audio::msgMoveTrack(Track* src, Track* dst) } //--------------------------------------------------------- -// msgAddPart -//--------------------------------------------------------- - -void Audio::msgAddPart(Part* part, bool doUndoFlag) - { - AudioMsg msg; - msg.id = SEQM_ADD_PART; - msg.p1 = part; - sendMessage(&msg, doUndoFlag); - } - -//--------------------------------------------------------- -// msgRemovePart -//--------------------------------------------------------- - -void Audio::msgRemovePart(Part* part, bool doUndoFlag) - { - AudioMsg msg; - msg.id = SEQM_REMOVE_PART; - msg.p1 = part; - sendMessage(&msg, doUndoFlag); - part->track()->partListChanged(); // emit signal - } - -//--------------------------------------------------------- -// msgRemoveParts -// remove selected parts; return true if any part was -// removed -//--------------------------------------------------------- - -bool Song::msgRemoveParts() - { - TrackList* tl = song->tracks(); - PartList pl; - - for (iTrack it = tl->begin(); it != tl->end(); ++it) { - PartList* pl2 = (*it)->parts(); - for (iPart ip = pl2->begin(); ip != pl2->end(); ++ip) { - if (ip->second->selected()) - pl.add(ip->second); - } - } - for (iPart ip = pl.begin(); ip != pl.end(); ++ip) - audio->msgRemovePart(ip->second, false); - - return !pl.empty(); - } - -//--------------------------------------------------------- // msgChangePart //--------------------------------------------------------- diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index a051d978..244b3a72 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -923,19 +923,7 @@ void Song::processMsg(AudioMsg* msg) case SEQM_REDO: doRedo2(); break; - case SEQM_MOVE_TRACK: - if (msg->a > msg->b) { - for (int i = msg->a; i > msg->b; --i) { - swapTracks(i, i-1); - } - } - else { - for (int i = msg->a; i < msg->b; ++i) { - swapTracks(i, i+1); - } - } - updateFlags = SC_TRACK_MODIFIED; - break; + case SEQM_ADD_EVENT: updateFlags = SC_EVENT_INSERTED; if (addEvent(msg->ev1, (Part*)(msg->p2))) { @@ -1004,63 +992,41 @@ void Song::processMsg(AudioMsg* msg) msg->track->removeControllerVal(msg->a, msg->time); break; - default: - printf("unknown seq message %d\n", msg->id); + case SEQM_ADD_TRACK: + insertTrack2(msg->track); break; - } - } -//--------------------------------------------------------- -// cmdAddPart -// realtime context -//--------------------------------------------------------- - -void Song::cmdAddPart(Part* part) - { - part->track()->addPart(part); - undoOp(UndoOp::AddPart, part); - updateFlags = SC_PART_INSERTED; - if (len() < part->endTick()) - setLen(part->endTick()); - } - -//--------------------------------------------------------- -// cmdRemovePart -//--------------------------------------------------------- - -void Song::cmdRemovePart(Part* part) - { - Track* track = part->track(); - track->parts()->remove(part); + case SEQM_REMOVE_TRACK: + removeTrack2(msg->track); + break; -//TD esettingsList->removeSettings(part->sn()); - undoOp(UndoOp::DeletePart, part); - part->events()->incARef(-1); - updateFlags = SC_PART_MODIFIED; - } + case SEQM_ADD_PART: + { + Part* part = (Part*)(msg->p1); + part->track()->addPart(part); + } + break; -//--------------------------------------------------------- -// changePart -//--------------------------------------------------------- + case SEQM_REMOVE_PART: + { + Part* part = (Part*)(msg->p1); + Track* track = part->track(); + track->parts()->remove(part); + } + break; -void Song::changePart(Part* oldPart, Part* newPart) - { - Part part = *newPart; - *newPart = *oldPart; - *oldPart = part; - } + case SEQM_CHANGE_PART: + cmdChangePart((Part*)msg->p1, (Part*)msg->p2); + break; -//--------------------------------------------------------- -// cmdChangePart -// realtime context -//--------------------------------------------------------- + case SEQM_MOVE_TRACK: + moveTrack((Track*)(msg->p1), (Track*)(msg->p2)); + break; -void Song::cmdChangePart(Part* oldPart, Part* newPart) - { - changePart(oldPart, newPart); - undoOp(UndoOp::ModifyPart, oldPart, newPart); - oldPart->events()->incARef(-1); - updateFlags = SC_PART_MODIFIED; + default: + printf("unknown seq message %d\n", msg->id); + break; + } } //--------------------------------------------------------- @@ -1228,52 +1194,6 @@ void Song::seqSignal(int fd) } } -#if 0 -//--------------------------------------------------------- -// recordEvent -//--------------------------------------------------------- - -void Song::recordEvent(MidiTrack* mt, Event& event) - { - //--------------------------------------------------- - // if tick points into a part, - // record to that part - // else - // create new part - //--------------------------------------------------- - - unsigned tick = event.tick(); - PartList* pl = mt->parts(); - Part* part = 0; - iPart ip; - for (ip = pl->begin(); ip != pl->end(); ++ip) { - part = ip->second; - unsigned partStart = part->tick(); - unsigned partEnd = partStart + part->lenTick(); - if (tick >= partStart && tick < partEnd) - break; - } - updateFlags |= SC_EVENT_INSERTED; - if (ip == pl->end()) { - // create new part - part = new Part(mt); - int startTick = roundDownBar(tick); - int endTick = roundUpBar(tick); - part->setTick(startTick); - part->setLenTick(endTick - startTick); - part->setName(mt->name()); - event.move(-startTick); - part->events()->add(event); - audio->msgAddPart(part); - return; - } - part = ip->second; - tick -= part->tick(); - event.setTick(tick); - audio->msgAddEvent(event, part); - } -#endif - //--------------------------------------------------------- // stopRolling //--------------------------------------------------------- @@ -1823,174 +1743,6 @@ std::vector<QString>* Song::synthesizer() const } //--------------------------------------------------------- -// changePart -// extend/shrink part in front or at end -//--------------------------------------------------------- - -void Song::changePart(Part* oPart, unsigned pos, unsigned len) - { - startUndo(); - // - // move events so they stay at same position in song - // - int delta = oPart->tick() - pos; - EventList* d = new EventList(); - EventList* s = oPart->events(); - for (iEvent ie = s->begin(); ie != s->end(); ++ie) { - int tick = ie->first + delta; - if (tick >= 0 && tick < int(len)) { - Event ev = ie->second.clone(); - ev.move(delta); - d->add(ev, unsigned(tick)); - } - } - if (oPart->fillLen() > 0 && len < (unsigned)oPart->fillLen()) - oPart->setFillLen(len); - if (oPart->lenTick() < len && oPart->fillLen() > 0) { - unsigned loop = oPart->fillLen(); - unsigned fillLen = len - oPart->lenTick(); - for (unsigned i = 0; i < fillLen / loop; ++i) { - int start = oPart->lenTick() + loop * i; - for (iEvent ie = s->begin(); ie != s->end(); ++ie) { - if (ie->first >= loop) - break; - Event ev = ie->second.clone(); - ev.move(start); - d->add(ev, ie->first + start); - } - } - } - Part* nPart = new Part(*oPart, d); - nPart->setLenTick(len); - nPart->setTick(pos); - audio->msgChangePart(oPart, nPart, false); - endUndo(SC_PART_MODIFIED); - oPart->track()->partListChanged(); - if (unsigned(_len) < oPart->endTick()) // update song len - setLen(oPart->endTick()); - } - -//--------------------------------------------------------- -// movePart -//--------------------------------------------------------- - -void Song::movePart(Part* oPart, unsigned pos, Track* track) - { - Track* oTrack = oPart->track(); - Part* nPart = new Part(*oPart); - nPart->setTrack(track); - nPart->setTick(pos); - startUndo(); - if (oPart->track() != track) { - audio->msgRemovePart(oPart, false); - audio->msgAddPart(nPart, false); - } - else { - audio->msgChangePart(oPart, nPart, false); - } - endUndo(0); - oTrack->partListChanged(); - if (len() < nPart->endTick()) - setLen(nPart->endTick()); - } - -//--------------------------------------------------------- -// linkPart -//--------------------------------------------------------- - -void Song::linkPart(Part* sPart, unsigned pos, Track* track) - { - Part* dPart = track->newPart(sPart, true); - dPart->setTick(pos); - audio->msgAddPart(dPart); - sPart->track()->partListChanged(); - dPart->track()->partListChanged(); - } - -//--------------------------------------------------------- -// copyPart -//--------------------------------------------------------- - -void Song::copyPart(Part* sPart, unsigned pos, Track* track) - { - bool clone = sPart->events()->arefCount() > 1; - Part* dPart = track->newPart(sPart, clone); - dPart->setTick(pos); - if (!clone) { - // - // Copy Events - // - EventList* se = sPart->events(); - EventList* de = dPart->events(); - for (iEvent i = se->begin(); i != se->end(); ++i) { - Event oldEvent = i->second; - Event ev = oldEvent.clone(); - de->add(ev); - } - } - audio->msgAddPart(dPart); - sPart->track()->partListChanged(); - dPart->track()->partListChanged(); - } - -//--------------------------------------------------------- -// createLRPart -//--------------------------------------------------------- - -void Song::createLRPart(Track* track) - { - Part* part = track->newPart(); - if (part) { - part->setTick(pos[1].tick()); - part->setLenTick(pos[2].tick()-pos[1].tick()); - part->setSelected(true); - addPart(part); - } - } - -//--------------------------------------------------------- -// addPart -//--------------------------------------------------------- - -void Song::addPart(Part* part) - { - audio->msgAddPart(part); - // adjust song len: - unsigned epos = part->tick() + part->lenTick(); - - if (epos > len()) - setLen(epos); - part->track()->partListChanged(); - } - -//--------------------------------------------------------- -// selectPart -//--------------------------------------------------------- - -void Song::selectPart(Part* part, bool add) - { - if (add) { - part->setSelected(!part->selected()); - part->track()->partListChanged(); - return; - } - for (iTrack it = _tracks.begin(); it != _tracks.end(); ++it) { - PartList* pl = (*it)->parts(); - bool changed = false; - for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { - bool f = part == ip->second; - if (ip->second->selected() != f) { - ip->second->setSelected(f); - changed = true; - } - } - if (changed) - (*it)->partListChanged(); - } - } - - -//--------------------------------------------------------- // setRecordFlag //--------------------------------------------------------- diff --git a/muse/muse/song.h b/muse/muse/song.h index 610b0eec..8e011fb9 100644 --- a/muse/muse/song.h +++ b/muse/muse/song.h @@ -235,8 +235,6 @@ class Song : public QObject { const Pos& lPos() const { return pos[1]; } const Pos& rPos() const { return pos[2]; } unsigned cpos() const { return pos[0].tick(); } -// unsigned vcpos() const { return _vcpos.tick(); } -// const Pos& vcPos() const { return _vcpos; } unsigned lpos() const { return pos[1].tick(); } unsigned rpos() const { return pos[2].tick(); } @@ -276,18 +274,22 @@ class Song : public QObject { // part manipulations //----------------------------------------- + void cmdAddPart(Part* part); + void addPart(Part* part); + + void cmdRemoveParts(); + void cmdRemovePart(Part* part); + void removePart(Part* part); + + void cmdChangePart(Part* oldPart, Part* newPart); + void changePart(Part*, Part*); + void cmdSplitPart(Part* p, const Pos&); void cmdGluePart(Part* p); - void changePart(Part*, Part*); - void addPart(Part* part); PartList* getSelectedMidiParts() const; PartList* getSelectedWaveParts() const; - bool msgRemoveParts(); - void cmdChangePart(Part* oldPart, Part* newPart); - void cmdRemovePart(Part* part); - void cmdAddPart(Part* part); void movePart(Part*, unsigned, Track*); void linkPart(Part*, unsigned, Track*); void copyPart(Part*, unsigned, Track*); @@ -324,7 +326,6 @@ class Song : public QObject { void insertTrack1(Track*, int idx); void insertTrack2(Track*); void readRoute(QDomNode); -// void recordEvent(MidiTrack*, Event&); std::vector<QString>* synthesizer() const; void deselectTracks(); diff --git a/muse/muse/songpart.cpp b/muse/muse/songpart.cpp new file mode 100644 index 00000000..7b49cdfa --- /dev/null +++ b/muse/muse/songpart.cpp @@ -0,0 +1,366 @@ +//============================================================================= +// 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 "part.h" +#include "audio.h" + +//--------------------------------------------------------- +// cmdAddPart +// GUI context + startUndo/endUndo +//--------------------------------------------------------- + +void Song::cmdAddPart(Part* part) + { + Track* track = part->track(); + // + // create default name: + // + for (int i = 1;;++i) { + PartList* pl = track->parts(); + bool found = false; + QString name = QString("Part-%1").arg(i); + for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { + if (name == ip->second->name()) { + found = true; + break; + } + } + if (!found) { + part->setName(name); + break; + } + } + startUndo(); + addPart(part); + endUndo(0); + track->partListChanged(); + } + +//--------------------------------------------------------- +// addPart +// GUI context +//--------------------------------------------------------- + +void Song::addPart(Part* part) + { + AudioMsg msg; + msg.id = SEQM_ADD_PART; + msg.p1 = part; + audio->sendMessage(&msg, false); + undoOp(UndoOp::AddPart, part); + updateFlags |= SC_PART_INSERTED; + if (len() < part->endTick()) + setLen(part->endTick()); + } + +//--------------------------------------------------------- +// cmdRemovePart +//--------------------------------------------------------- + +void Song::cmdRemovePart(Part* part) + { + startUndo(); + removePart(part); + endUndo(0); + part->track()->partListChanged(); + } + +//--------------------------------------------------------- +// removePart +//--------------------------------------------------------- + +void Song::removePart(Part* part) + { + AudioMsg msg; + msg.id = SEQM_REMOVE_PART; + msg.p1 = part; + audio->sendMessage(&msg, false); + undoOp(UndoOp::DeletePart, part); + part->events()->incARef(-1); + updateFlags |= SC_PART_REMOVED; + } + +//--------------------------------------------------------- +// cmdRemoveParts +// remove selected parts +//--------------------------------------------------------- + +void Song::cmdRemoveParts() + { + TrackList* tl = song->tracks(); + PartList pl; + + for (iTrack it = tl->begin(); it != tl->end(); ++it) { + PartList* pl2 = (*it)->parts(); + for (iPart ip = pl2->begin(); ip != pl2->end(); ++ip) { + if (ip->second->selected()) + pl.add(ip->second); + } + } + for (iPart ip = pl.begin(); ip != pl.end(); ++ip) + removePart(ip->second); + } + +//--------------------------------------------------------- +// cmdChangePart +// realtime context +//--------------------------------------------------------- + +void Song::cmdChangePart(Part* oldPart, Part* newPart) + { + changePart(oldPart, newPart); + undoOp(UndoOp::ModifyPart, oldPart, newPart); + oldPart->events()->incARef(-1); + updateFlags = SC_PART_MODIFIED; + } + +//--------------------------------------------------------- +// changePart +//--------------------------------------------------------- + +void Song::changePart(Part* oldPart, Part* newPart) + { + Part part = *newPart; + *newPart = *oldPart; + *oldPart = part; + } + +//--------------------------------------------------------- +// changePart +// extend/shrink part in front or at end +//--------------------------------------------------------- + +void Song::changePart(Part* oPart, unsigned pos, unsigned len) + { + startUndo(); + // + // move events so they stay at same position in song + // + int delta = oPart->tick() - pos; + EventList* d = new EventList(); + EventList* s = oPart->events(); + for (iEvent ie = s->begin(); ie != s->end(); ++ie) { + int tick = ie->first + delta; + if (tick >= 0 && tick < int(len)) { + Event ev = ie->second.clone(); + ev.move(delta); + d->add(ev, unsigned(tick)); + } + } + if (oPart->fillLen() > 0 && len < (unsigned)oPart->fillLen()) + oPart->setFillLen(len); + if (oPart->lenTick() < len && oPart->fillLen() > 0) { + unsigned loop = oPart->fillLen(); + unsigned fillLen = len - oPart->lenTick(); + for (unsigned i = 0; i < fillLen / loop; ++i) { + int start = oPart->lenTick() + loop * i; + for (iEvent ie = s->begin(); ie != s->end(); ++ie) { + if (ie->first >= loop) + break; + Event ev = ie->second.clone(); + ev.move(start); + d->add(ev, ie->first + start); + } + } + } + Part* nPart = new Part(*oPart, d); + nPart->setLenTick(len); + nPart->setTick(pos); + audio->msgChangePart(oPart, nPart, false); + endUndo(SC_PART_MODIFIED); + oPart->track()->partListChanged(); + if (unsigned(_len) < oPart->endTick()) // update song len + setLen(oPart->endTick()); + } + +//--------------------------------------------------------- +// movePart +//--------------------------------------------------------- + +void Song::movePart(Part* oPart, unsigned pos, Track* track) + { + Track* oTrack = oPart->track(); + Part* nPart = new Part(*oPart); + nPart->setTrack(track); + nPart->setTick(pos); + startUndo(); + if (oPart->track() != track) { + removePart(oPart); + addPart(nPart); + } + else { + audio->msgChangePart(oPart, nPart, false); + } + endUndo(0); + oTrack->partListChanged(); + if (len() < nPart->endTick()) + setLen(nPart->endTick()); + } + +//--------------------------------------------------------- +// linkPart +//--------------------------------------------------------- + +void Song::linkPart(Part* sPart, unsigned pos, Track* track) + { + Part* dPart = track->newPart(sPart, true); + dPart->setTick(pos); + cmdAddPart(dPart); + sPart->track()->partListChanged(); + dPart->track()->partListChanged(); + } + +//--------------------------------------------------------- +// copyPart +//--------------------------------------------------------- + +void Song::copyPart(Part* sPart, unsigned pos, Track* track) + { + bool clone = sPart->events()->arefCount() > 1; + Part* dPart = track->newPart(sPart, clone); + dPart->setTick(pos); + if (!clone) { + // + // Copy Events + // + EventList* se = sPart->events(); + EventList* de = dPart->events(); + for (iEvent i = se->begin(); i != se->end(); ++i) { + Event oldEvent = i->second; + Event ev = oldEvent.clone(); + de->add(ev); + } + } + cmdAddPart(dPart); + sPart->track()->partListChanged(); + dPart->track()->partListChanged(); + } + +//--------------------------------------------------------- +// createLRPart +//--------------------------------------------------------- + +void Song::createLRPart(Track* track) + { + Part* part = track->newPart(); + if (part) { + part->setTick(pos[1].tick()); + part->setLenTick(pos[2].tick()-pos[1].tick()); + part->setSelected(true); + cmdAddPart(part); + } + } + +//--------------------------------------------------------- +// selectPart +//--------------------------------------------------------- + +void Song::selectPart(Part* part, bool add) + { + if (add) { + part->setSelected(!part->selected()); + part->track()->partListChanged(); + return; + } + for (iTrack it = _tracks.begin(); it != _tracks.end(); ++it) { + PartList* pl = (*it)->parts(); + bool changed = false; + for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { + bool f = part == ip->second; + if (ip->second->selected() != f) { + ip->second->setSelected(f); + changed = true; + } + } + if (changed) + (*it)->partListChanged(); + } + } + +//--------------------------------------------------------- +// cmdSplitPart +//--------------------------------------------------------- + +void Song::cmdSplitPart(Part* part, const Pos& pos) + { + int tick = pos.tick(); + int l1 = tick - part->tick(); + int l2 = part->lenTick() - l1; + if (l1 <= 0 || l2 <= 0) + return; + Part* p1; + Part* p2; + part->track()->splitPart(part, tick, p1, p2); + + startUndo(); + audio->msgChangePart(part, p1, false); + addPart(p2); + endUndo(SC_TRACK_MODIFIED | SC_PART_MODIFIED | SC_PART_INSERTED); + part->track()->partListChanged(); + } + +//--------------------------------------------------------- +// cmdGluePart +//--------------------------------------------------------- + +void Song::cmdGluePart(Part* oPart) + { + Track* track = oPart->track(); + PartList* pl = track->parts(); + Part* nextPart = 0; + + for (iPart ip = pl->begin(); ip != pl->end(); ++ip) { + if (ip->second == oPart) { + ++ip; + if (ip == pl->end()) + return; + nextPart = ip->second; + break; + } + } + + Part* nPart = track->newPart(oPart); + nPart->setLenTick(nextPart->tick() + nextPart->lenTick() - oPart->tick()); + + // populate nPart with Events from oPart and nextPart + + EventList* sl1 = oPart->events(); + EventList* dl = nPart->events(); + + for (iEvent ie = sl1->begin(); ie != sl1->end(); ++ie) + dl->add(ie->second); + + EventList* sl2 = nextPart->events(); + int tickOffset = nextPart->tick() - oPart->tick(); + + for (iEvent ie = sl2->begin(); ie != sl2->end(); ++ie) { + Event event = ie->second.clone(); + event.move(tickOffset); + dl->add(event); + } + startUndo(); + removePart(nextPart); + audio->msgChangePart(oPart, nPart, false); + endUndo(SC_PART_MODIFIED | SC_PART_REMOVED); + track->partListChanged(); + } + + diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp index 14189c61..ca457ad6 100644 --- a/muse/muse/track.cpp +++ b/muse/muse/track.cpp @@ -21,6 +21,7 @@ #include "track.h" #include "midiplugin.h" #include "song.h" +#include "al/tempo.h" #include "al/xml.h" #include "icons.h" #include "muse.h" @@ -682,121 +683,6 @@ void Track::writeRouting(Xml& xml) const } //--------------------------------------------------------- -// MidiTrackBase -//--------------------------------------------------------- - -MidiTrackBase::MidiTrackBase() - : Track() - { - _pipeline = new MidiPipeline(); - } - -//--------------------------------------------------------- -// MidiTrackBase -//--------------------------------------------------------- - -MidiTrackBase::~MidiTrackBase() - { - foreach(MidiPluginI* plugin, *_pipeline) - delete plugin; - delete _pipeline; - } - -//--------------------------------------------------------- -// MidiTrackBase::writeProperties -//--------------------------------------------------------- - -void MidiTrackBase::writeProperties(Xml& xml) const - { - Track::writeProperties(xml); - for (ciMidiPluginI ip = _pipeline->begin(); ip != _pipeline->end(); ++ip) { - if (*ip) - (*ip)->writeConfiguration(xml); - } - } - -//--------------------------------------------------------- -// MidiTrackBase::readProperties -//--------------------------------------------------------- - -bool MidiTrackBase::readProperties(QDomNode node) - { - QDomElement e = node.toElement(); - QString tag(e.tagName()); - if (tag == "midiPlugin") { - MidiPluginI* pi = new MidiPluginI(this); - if (pi->readConfiguration(node)) - delete pi; - else - addPlugin(pi, -1); - } - else - return Track::readProperties(node); - return false; - } - -//--------------------------------------------------------- -// plugin -//--------------------------------------------------------- - -MidiPluginI* MidiTrackBase::plugin(int idx) const - { - return _pipeline->value(idx); - } - -//--------------------------------------------------------- -// addPlugin -// idx = -1 append -// plugin = 0 remove slot -//--------------------------------------------------------- - -void MidiTrackBase::addPlugin(MidiPluginI* plugin, int idx) - { - if (plugin == 0) { -#if 0 - MidiPluginI* oldPlugin = (*_pipeline)[idx]; - if (oldPlugin) { - int controller = oldPlugin->plugin()->parameter(); - for (int i = 0; i < controller; ++i) { - int id = (idx + 1) * 0x1000 + i; - removeController(id); - } - } -#endif - } - if (idx == -1) - idx = _pipeline->size(); - - if (plugin) { - _pipeline->insert(idx, plugin); -#if 0 - int ncontroller = plugin->plugin()->parameter(); - for (int i = 0; i < ncontroller; ++i) { - int id = (idx + 1) * 0x1000 + i; - QString name(plugin->getParameterName(i)); - double min, max; - plugin->range(i, &min, &max); - Ctrl* cl = getController(id); - if (cl == 0) { - cl = new Ctrl(id, name); - cl->setRange(min, max); - double defaultValue = plugin->defaultValue(i); - cl->setDefault(defaultValue); - cl->setCurVal(defaultValue); - addController(cl); - } - plugin->setParam(i, cl->schedVal().f); - plugin->setControllerList(cl); - } -#endif - } - else { - _pipeline->removeAt(idx); - } - } - - -//--------------------------------------------------------- // hwCtrlState //--------------------------------------------------------- @@ -1072,4 +958,92 @@ void Track::setSendSync(bool val) emit sendSyncChanged(val); } +//--------------------------------------------------------- +// splitPart +// split part "part" at "tick" position +// create two new parts p1 and p2 +//--------------------------------------------------------- + +void Track::splitPart(Part* part, int tickpos, Part*& p1, Part*& p2) + { + int l1 = 0; // len of first new part (ticks or samples) + int l2 = 0; // len of second new part + + int samplepos = AL::tempomap.tick2frame(tickpos); + + switch (type()) { + case WAVE: + l1 = samplepos - part->frame(); + l2 = part->lenFrame() - l1; + break; + case MIDI: + l1 = tickpos - part->tick(); + l2 = part->lenTick() - l1; + break; + default: + return; + } + + if (l1 <= 0 || l2 <= 0) + return; + + p1 = newPart(part); // new left part + p2 = newPart(part); // new right part + + switch (type()) { + case WAVE: + p1->setLenFrame(l1); + p2->setFrame(samplepos); + p2->setLenFrame(l2); + break; + case MIDI: + p1->setLenTick(l1); + p2->setTick(tickpos); + p2->setLenTick(l2); + break; + default: + break; + } + + EventList* se = part->events(); + EventList* de1 = p1->events(); + EventList* de2 = p2->events(); + + if (type() == WAVE) { + int ps = part->frame(); + int d1p1 = p1->frame(); + int d2p1 = p1->endFrame(); + int d1p2 = p2->frame(); + int d2p2 = p2->endFrame(); + for (iEvent ie = se->begin(); ie != se->end(); ++ie) { + Event event = ie->second; + int s1 = event.frame() + ps; + int s2 = event.endFrame() + ps; + + if ((s2 > d1p1) && (s1 < d2p1)) { + Event si = event.mid(d1p1 - ps, d2p1 - ps); + de1->add(si); + } + if ((s2 > d1p2) && (s1 < d2p2)) { + Event si = event.mid(d1p2 - ps, d2p2 - ps); + si.setFrame(si.frame() - l1); //?? + si.setFrame(0); //?? + de2->add(si); + } + } + } + else { + for (iEvent ie = se->begin(); ie != se->end(); ++ie) { + Event event = ie->second.clone(); + int t = event.tick(); + if (t >= l1) { + event.move(-l1); + de2->add(event); + } + else + de1->add(event); + } + } + } + diff --git a/muse/muse/track.h b/muse/muse/track.h index 7ffb76a6..c7a68d8e 100644 --- a/muse/muse/track.h +++ b/muse/muse/track.h @@ -233,8 +233,8 @@ class Track : public QObject { virtual TrackType type() const = 0; - PartList* parts() { return _parts; } - const PartList* cparts() const { return _parts; } + PartList* parts() const { return _parts; } + Part* findPart(unsigned tick); void addPart(Part* p); @@ -332,30 +332,6 @@ class Track : public QObject { Q_DECLARE_METATYPE(class Track*); -//--------------------------------------------------------- -// MidiTrackBase -//--------------------------------------------------------- - -class MidiTrackBase : public Track { - Q_OBJECT - - MidiPipeline* _pipeline; - - public: - MidiTrackBase(); - virtual ~MidiTrackBase(); - - bool readProperties(QDomNode); - void writeProperties(Xml&) const; - - MidiPipeline* pipeline() { return _pipeline; } - void addPlugin(MidiPluginI* plugin, int idx); - MidiPluginI* plugin(int idx) const; - - virtual void processMidi(unsigned, unsigned, unsigned, unsigned) {} - virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MidiEventList* /*dst*/) {} - }; - typedef QList<Track*> TrackList; typedef TrackList::iterator iTrack; typedef TrackList::const_iterator ciTrack; diff --git a/muse/muse/wave.cpp b/muse/muse/wave.cpp index 7ef0a665..934b8b9d 100644 --- a/muse/muse/wave.cpp +++ b/muse/muse/wave.cpp @@ -910,7 +910,7 @@ bool MusE::importWaveToTrack(const QString& wave, Track* track, const Pos& pos) part->addEvent(event); part->setName(srcInfo.baseName()); - audio->msgAddPart(part); + song->cmdAddPart(part); unsigned endTick = part->tick() + part->lenTick(); if (song->len() < endTick) song->setLen(endTick); diff --git a/muse/muse/wavetrack.cpp b/muse/muse/wavetrack.cpp index 8504d35c..c022c3c1 100644 --- a/muse/muse/wavetrack.cpp +++ b/muse/muse/wavetrack.cpp @@ -140,7 +140,7 @@ void WaveTrack::write(Xml& xml) const { xml.tag("wavetrack"); AudioTrack::writeProperties(xml); - const PartList* pl = cparts(); + const PartList* pl = parts(); for (ciPart p = pl->begin(); p != pl->end(); ++p) p->second->write(xml); xml.etag("wavetrack"); @@ -232,7 +232,7 @@ void WaveTrack::startRecording() recordPart->setPos(spos); recordPart->setLenTick(epos.tick() - spos.tick()); recordPart->setName(name()); - audio->msgAddPart(recordPart, false); + song->addPart(recordPart); partCreated = true; emit partsChanged(); } |