From fba295ae8b121425657f18bef82c038f30c1dd33 Mon Sep 17 00:00:00 2001 From: Werner Schweer Date: Mon, 30 Oct 2006 18:06:54 +0000 Subject: changed synth routing --- muse/muse/CMakeLists.txt | 2 + muse/muse/arranger/tlwidget.cpp | 9 +- muse/muse/arranger/trackinfo.cpp | 34 ++-- muse/muse/audio.cpp | 32 +++- muse/muse/audio.h | 1 - muse/muse/audiogroup.h | 3 +- muse/muse/audioinput.cpp | 2 +- muse/muse/audioinput.h | 1 + muse/muse/audiooutput.cpp | 2 +- muse/muse/audiooutput.h | 1 + muse/muse/audiotrack.cpp | 4 +- muse/muse/audiotrack.h | 2 +- muse/muse/ctrl/configmidictrl.cpp | 7 +- muse/muse/midi.cpp | 35 +--- muse/muse/midichannel.cpp | 11 +- muse/muse/midichannel.h | 9 +- muse/muse/midiedit/ctrledit.cpp | 5 +- muse/muse/midiinport.cpp | 2 +- muse/muse/midiinport.h | 1 + muse/muse/midiout.cpp | 389 ++++++++++++++++++++++++++++++++++++++ muse/muse/midiout.h | 74 ++++++++ muse/muse/midioutport.cpp | 305 +++++------------------------- muse/muse/midioutport.h | 47 +---- muse/muse/midisynti.cpp | 2 +- muse/muse/midisynti.h | 2 + muse/muse/miditrack.cpp | 2 +- muse/muse/miditrack.h | 5 +- muse/muse/mixer/astrip.cpp | 26 +-- muse/muse/mixer/mstrip.cpp | 264 +++++++++++++------------- muse/muse/mixer/mstrip.h | 2 +- muse/muse/muse.cpp | 5 +- muse/muse/song.cpp | 9 +- muse/muse/synth.cpp | 81 +++++--- muse/muse/synth.h | 15 +- muse/muse/track.cpp | 43 +++-- muse/muse/track.h | 24 ++- muse/muse/wavetrack.cpp | 2 +- muse/muse/wavetrack.h | 2 + 38 files changed, 872 insertions(+), 590 deletions(-) create mode 100644 muse/muse/midiout.cpp create mode 100644 muse/muse/midiout.h diff --git a/muse/muse/CMakeLists.txt b/muse/muse/CMakeLists.txt index 54b6146e..3d038136 100644 --- a/muse/muse/CMakeLists.txt +++ b/muse/muse/CMakeLists.txt @@ -71,6 +71,7 @@ QT4_WRAP_CPP ( muse_moc_headers audiooutput.h audioinput.h audiogroup.h + synth.h exportmidi.h importmidi.h midichannel.h @@ -129,6 +130,7 @@ add_executable ( muse midioutport.cpp midiinport.cpp midichannel.cpp + midiout.cpp projectpropsdialog.cpp projectdialog.cpp diff --git a/muse/muse/arranger/tlwidget.cpp b/muse/muse/arranger/tlwidget.cpp index 8249b22b..267e3b7b 100644 --- a/muse/muse/arranger/tlwidget.cpp +++ b/muse/muse/arranger/tlwidget.cpp @@ -36,6 +36,7 @@ #include "audio.h" #include "midioutport.h" #include "midichannel.h" +#include "instruments/minstrument.h" //--------------------------------------------------------- // TLWidget @@ -159,12 +160,12 @@ void TLWidget::mousePressEvent(QMouseEvent* ev) { int idx = song->tracks()->index(_track); if (_track->type() == Track::MIDI) { - MidiTrack* t = new MidiTrack; - t->clone((MidiTrack*)_track); + MidiTrack* t = new MidiTrack(); + t->clone((MidiTrack*)_track); song->insertTrack(t, idx); } else { - WaveTrack* t = new WaveTrack; + WaveTrack* t = new WaveTrack(); t->clone((WaveTrack*)_track); song->insertTrack(t, idx); } @@ -530,7 +531,7 @@ void TLWidget::outChannelChanged(int n) MidiChannel* mc = ((MidiTrack*)_track)->channel(); if (mc == 0) // no route to port? return; - MidiOutPort* mp = mc->port(); + MidiOut* mp = mc->port(); int id = mc->channelNo(); if (id == n) return; diff --git a/muse/muse/arranger/trackinfo.cpp b/muse/muse/arranger/trackinfo.cpp index c9dc7d1b..cba5a891 100644 --- a/muse/muse/arranger/trackinfo.cpp +++ b/muse/muse/arranger/trackinfo.cpp @@ -204,7 +204,7 @@ void MidiTrackInfo::init(Track* t) portIndex = k + 1; } if (midic) { - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); for (int i = 0; i < MIDI_CHANNELS; ++i) { MidiChannel* c = op->channel(i); if (midic == c) @@ -212,7 +212,7 @@ void MidiTrackInfo::init(Track* t) channel->addItem(c->name(), i); } connect(midic, SIGNAL(controllerChanged(int)), SLOT(controllerChanged(int))); - connect(op, SIGNAL(instrumentChanged()), SLOT(instrumentChanged())); +//TODO connect(op, SIGNAL(instrumentChanged()), SLOT(instrumentChanged())); channel->setCurrentIndex(channelIndex); port->setCurrentIndex(portIndex); MidiInstrument* mi = op->instrument(); @@ -224,7 +224,7 @@ void MidiTrackInfo::init(Track* t) curIdx = idx; } mp.instrument->setCurrentIndex(curIdx); - mp.deviceId->setValue(op->deviceId()); +//TODO mp.deviceId->setValue(op->deviceId()); autoChanged(midic, false); // update enable int val = midic->ctrlVal(CTRL_PROGRAM).i; int channelno = midic->channelNo(); @@ -277,7 +277,7 @@ void MidiTrackInfo::channelSelected(int ch) --ch; Route srcRoute(track); MidiChannel* midic = ((MidiTrack*)track)->channel(); - MidiOutPort* midip = midic->port(); + MidiOut* midip = midic->port(); if (midic) { Route odstRoute(midic); audio->msgRemoveRoute(srcRoute, odstRoute); @@ -299,7 +299,7 @@ void MidiTrackInfo::controllerChanged(int id) if (id == CTRL_PROGRAM) { MidiChannel* midic = ((MidiTrack*)track)->channel(); if (midic) { - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); int val = midic->ctrlVal(id).i; mc.patch->setText(mi->getPatchName(midic->channelNo(), val)); @@ -315,7 +315,7 @@ void MidiTrackInfo::instrumentChanged() { MidiChannel* midic = ((MidiTrack*)track)->channel(); if (midic) { - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); int idx = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i, ++idx) { @@ -365,7 +365,7 @@ void MidiTrackInfo::patchClicked() if (!midic) return; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); mi->populatePatchPopup(pop, 0); @@ -387,7 +387,7 @@ void MidiTrackInfo::instrumentSelected(int n) MidiChannel* midic = ((MidiTrack*)track)->channel(); if (midic == 0) return; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); op->setInstrument(midiInstruments[n]); } @@ -436,8 +436,8 @@ void MidiTrackInfo::deviceIdChanged(int val) MidiChannel* midic = ((MidiTrack*)track)->channel(); if (midic == 0) return; - MidiOutPort* op = midic->port(); - op->setDeviceId(val); +// MidiOut* op = midic->port(); +//TODO op->setDeviceId(val); } //--------------------------------------------------------- @@ -643,10 +643,10 @@ void MidiChannelInfo::init(Track* t) { TrackInfo::init(t); MidiChannel* midic = (MidiChannel*)t; - MidiOutPort* op = midic->port(); - connect(op, SIGNAL(instrumentChanged()), SLOT(instrumentChanged())); + MidiOut* op = midic->port(); +//TODO connect(op, SIGNAL(instrumentChanged()), SLOT(instrumentChanged())); connect(midic, SIGNAL(controllerChanged(int)), SLOT(controllerChanged(int))); - portName->setText(op->name()); + portName->setText(op->track->name()); MidiInstrument* mi = op->instrument(); int idx = 0; int curIdx = 0; @@ -666,7 +666,7 @@ void MidiChannelInfo::init(Track* t) void MidiChannelInfo::instrumentSelected(int n) { MidiChannel* midic = (MidiChannel*)track; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); op->setInstrument(midiInstruments[n]); } @@ -677,7 +677,7 @@ void MidiChannelInfo::instrumentSelected(int n) void MidiChannelInfo::instrumentChanged() { MidiChannel* midic = (MidiChannel*)track; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); int idx = 0; for (iMidiInstrument i = midiInstruments.begin(); i != midiInstruments.end(); ++i, ++idx) { @@ -695,7 +695,7 @@ void MidiChannelInfo::instrumentChanged() void MidiChannelInfo::patchClicked() { MidiChannel* midic = (MidiChannel*)track; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); mi->populatePatchPopup(pop, 0); @@ -715,7 +715,7 @@ void MidiChannelInfo::controllerChanged(int id) { if (id == CTRL_PROGRAM) { MidiChannel* midic = (MidiChannel*)track; - MidiOutPort* op = midic->port(); + MidiOut* op = midic->port(); MidiInstrument* mi = op->instrument(); int val = midic->ctrlVal(id).i; patch->setText(mi->getPatchName(midic->channelNo(), val)); diff --git a/muse/muse/audio.cpp b/muse/muse/audio.cpp index 864f221d..beab01b8 100644 --- a/muse/muse/audio.cpp +++ b/muse/muse/audio.cpp @@ -345,9 +345,9 @@ void Audio::process(unsigned frames, int jackState) startRolling(); } - OutputList* ol = song->outputs(); if (idle || state == START_PLAY) { // deliver silence + OutputList* ol = song->outputs(); for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) (*i)->silence(frames); return; @@ -433,14 +433,32 @@ void Audio::process(unsigned frames, int jackState) } } - MidiOutPortList* mol = song->midiOutPorts(); - for (iMidiOutPort i = mol->begin(); i != mol->end(); ++i) + //----------------------------------------- + // process midi + //----------------------------------------- + + SynthIList* sl = song->syntis(); + { + MidiOutPortList* ol = song->midiOutPorts(); + MidiInPortList* mil = song->midiInPorts(); + + for (iMidiOutPort i = ol->begin(); i != ol->end(); ++i) audioDriver->startMidiCycle((*i)->jackPort(0)); + for (iMidiInPort i = mil->begin(); i != mil->end(); ++i) + (*i)->beforeProcess(); + for (iMidiOutPort i = ol->begin(); i != ol->end(); ++i) + (*i)->processMidi(_curTickPos, _nextTickPos, _pos.frame(), _pos.frame() + segmentSize); + for (iSynthI i = sl->begin(); i != sl->end(); ++i) + (*i)->processMidi(_curTickPos, _nextTickPos, _pos.frame(), _pos.frame() + segmentSize); + for (iMidiInPort i = mil->begin(); i != mil->end(); ++i) + (*i)->afterProcess(); + } - processMidi(); + //----------------------------------------- + // process audio + //----------------------------------------- GroupList* gl = song->groups(); - SynthIList* sl = song->syntis(); InputList* il = song->inputs(); WaveTrackList* wl = song->waves(); @@ -486,7 +504,9 @@ void Audio::process(unsigned frames, int jackState) } for (iAudioGroup i = gl->begin(); i != gl->end(); ++i) (*i)->process(); - for (iAudioOutput i = ol->begin(); i != ol->end(); ++i) + + OutputList* aol = song->outputs(); + for (iAudioOutput i = aol->begin(); i != aol->end(); ++i) (*i)->process(); if (_bounce == 1 && song->bounceTrack && song->bounceTrack->type() == Track::WAVE) diff --git a/muse/muse/audio.h b/muse/muse/audio.h index 19f76b9b..c6fef4c2 100644 --- a/muse/muse/audio.h +++ b/muse/muse/audio.h @@ -194,7 +194,6 @@ class Audio { Pos endRecordPos; void process(unsigned frames, int jackState); - void processMidi(); bool sync(int state, unsigned frame); void shutdown(); diff --git a/muse/muse/audiogroup.h b/muse/muse/audiogroup.h index 6436ebd1..709166f5 100644 --- a/muse/muse/audiogroup.h +++ b/muse/muse/audiogroup.h @@ -31,7 +31,8 @@ class AudioGroup : public AudioTrack { Q_OBJECT public: - AudioGroup() : AudioTrack(AUDIO_GROUP) {} + AudioGroup() : AudioTrack() {} + virtual TrackType type() const { return AUDIO_GROUP; } virtual void read(QDomNode); virtual void write(Xml&) const; virtual bool hasAuxSend() const { return true; } diff --git a/muse/muse/audioinput.cpp b/muse/muse/audioinput.cpp index d4c6a12e..4ff3449b 100644 --- a/muse/muse/audioinput.cpp +++ b/muse/muse/audioinput.cpp @@ -28,7 +28,7 @@ //--------------------------------------------------------- AudioInput::AudioInput() - : AudioTrack(AUDIO_INPUT) + : AudioTrack() { // set Default for Input Ports: _mute = true; diff --git a/muse/muse/audioinput.h b/muse/muse/audioinput.h index 71998e13..ba8af1f6 100644 --- a/muse/muse/audioinput.h +++ b/muse/muse/audioinput.h @@ -35,6 +35,7 @@ class AudioInput : public AudioTrack { public: AudioInput(); virtual ~AudioInput(); + virtual TrackType type() const { return AUDIO_INPUT; } virtual void read(QDomNode); virtual void write(Xml&) const; diff --git a/muse/muse/audiooutput.cpp b/muse/muse/audiooutput.cpp index 2899cf7d..dbf61af9 100644 --- a/muse/muse/audiooutput.cpp +++ b/muse/muse/audiooutput.cpp @@ -30,7 +30,7 @@ //--------------------------------------------------------- AudioOutput::AudioOutput() - : AudioTrack(AUDIO_OUTPUT) + : AudioTrack() { _channels = 0; setChannels(2); diff --git a/muse/muse/audiooutput.h b/muse/muse/audiooutput.h index cb7980f3..384b5bde 100644 --- a/muse/muse/audiooutput.h +++ b/muse/muse/audiooutput.h @@ -33,6 +33,7 @@ class AudioOutput : public AudioTrack { public: AudioOutput(); virtual ~AudioOutput(); + virtual TrackType type() const { return AUDIO_OUTPUT; } virtual void read(QDomNode); virtual void write(Xml&) const; diff --git a/muse/muse/audiotrack.cpp b/muse/muse/audiotrack.cpp index e486b4b5..62fde5ca 100644 --- a/muse/muse/audiotrack.cpp +++ b/muse/muse/audiotrack.cpp @@ -34,8 +34,8 @@ // AudioTrack //--------------------------------------------------------- -AudioTrack::AudioTrack(TrackType t) - : Track(t) +AudioTrack::AudioTrack() + : Track() { _tt = AL::FRAMES; _prefader = false; diff --git a/muse/muse/audiotrack.h b/muse/muse/audiotrack.h index f6f5a89d..1dc77d65 100644 --- a/muse/muse/audiotrack.h +++ b/muse/muse/audiotrack.h @@ -63,7 +63,7 @@ class AudioTrack : public Track { virtual void setAutoWrite(bool); public: - AudioTrack(TrackType t); + AudioTrack(); virtual ~AudioTrack(); bool readProperties(QDomNode); diff --git a/muse/muse/ctrl/configmidictrl.cpp b/muse/muse/ctrl/configmidictrl.cpp index 5aefcba3..9e01e029 100644 --- a/muse/muse/ctrl/configmidictrl.cpp +++ b/muse/muse/ctrl/configmidictrl.cpp @@ -23,6 +23,7 @@ #include "midioutport.h" #include "midichannel.h" #include "midictrl.h" +#include "midiout.h" #include "instruments/minstrument.h" //--------------------------------------------------------- @@ -52,8 +53,8 @@ ConfigMidiCtrl::ConfigMidiCtrl(MidiTrack* t) else if (track->type() == Track::MIDI_CHANNEL) mc = (MidiChannel*)track; if (mc) { - MidiOutPort* mp = mc->port(); - portName->setText(mp->name()); + MidiOut* mp = mc->port(); + portName->setText(mp->track->name()); // // populate popup with all controllers available for // current instrument @@ -148,7 +149,7 @@ void ConfigMidiCtrl::done(int code) mc = (MidiChannel*)track; if (mc) { - MidiOutPort* port = mc->port(); + MidiOut* port = mc->port(); ControllerNameList* cn = track->controllerNames(); MidiInstrument* instr = port->instrument(); MidiControllerList* mcl = instr->controller(); diff --git a/muse/muse/midi.cpp b/muse/muse/midi.cpp index 0eaeceb4..fe9984d6 100644 --- a/muse/muse/midi.cpp +++ b/muse/muse/midi.cpp @@ -41,6 +41,7 @@ #include "midiinport.h" #include "midioutport.h" #include "midichannel.h" +#include "instruments/minstrument.h" extern void dump(const unsigned char* p, int n); @@ -630,37 +631,3 @@ void Audio::initDevices() } } -//--------------------------------------------------------- -// processMidi -// - called from midiseq thread, -// executed in audio thread -// Process one time slice of midi events -//--------------------------------------------------------- - -void Audio::processMidi() - { - MidiInPortList* il = song->midiInPorts(); - for (iMidiInPort id = il->begin(); id != il->end(); ++id) - (*id)->beforeProcess(); - - MidiOutPortList* ol = song->midiOutPorts(); - for (iMidiOutPort id = ol->begin(); id != ol->end(); ++id) { - (*id)->process(_curTickPos, _nextTickPos, _pos.frame(), _pos.frame() + segmentSize); - } - for (iMidiInPort id = il->begin(); id != il->end(); ++id) { - MidiInPort* port = *id; - // - // process routing to synti - // - RouteList* rl = port->outRoutes(); - for (iRoute i = rl->begin(); i != rl->end(); ++i) { - if (i->track->type() != Track::AUDIO_SOFTSYNTH) - continue; - SynthI* s = (SynthI*)(i->track); - MPEventList* dl = s->playEvents(); - port->getEvents(0, 0, -1, dl); - } - port->afterProcess(); - } - } - diff --git a/muse/muse/midichannel.cpp b/muse/muse/midichannel.cpp index afec354c..40294b2a 100644 --- a/muse/muse/midichannel.cpp +++ b/muse/muse/midichannel.cpp @@ -25,13 +25,14 @@ #include "midichannel.h" #include "midioutport.h" #include "miditrack.h" +#include "instruments/minstrument.h" //--------------------------------------------------------- // MidiChannel //--------------------------------------------------------- -MidiChannel::MidiChannel(MidiOutPort* p, int ch) - : MidiTrackBase(MIDI_CHANNEL) +MidiChannel::MidiChannel(MidiOut* p, int ch) + : MidiTrackBase() { _port = p; _channelNo = ch; @@ -88,7 +89,7 @@ void MidiChannel::read(QDomNode node) printf("MusE:MidiChannel: unknown tag %s\n", tag.toLatin1().data()); node = node.nextSibling(); } - MidiOutPort* op = port(); + MidiOut* op = port(); if (op) { MidiInstrument* mi = op->instrument(); int val = ctrlVal(CTRL_PROGRAM).i; @@ -121,7 +122,7 @@ void MidiChannel::setUseDrumMap(bool val) _useDrumMap = val; if (_useDrumMap) { int val = ctrlVal(CTRL_PROGRAM).i; - MidiOutPort* op = port(); + MidiOut* op = port(); MidiInstrument* mi = op->instrument(); DrumMap* dm = mi->getDrumMap(val); if (dm == 0) @@ -146,7 +147,7 @@ void MidiChannel::emitControllerChanged(int id) { if (id == CTRL_PROGRAM && _useDrumMap) { int val = ctrlVal(id).i; - MidiOutPort* op = port(); + MidiOut* op = port(); MidiInstrument* mi = op->instrument(); DrumMap* dm = mi->getDrumMap(val); if (dm == 0) diff --git a/muse/muse/midichannel.h b/muse/muse/midichannel.h index b4688375..8644c15e 100644 --- a/muse/muse/midichannel.h +++ b/muse/muse/midichannel.h @@ -23,6 +23,8 @@ #include "track.h" +class MidiOut; + //--------------------------------------------------------- // MidiChannel //--------------------------------------------------------- @@ -34,7 +36,7 @@ class MidiChannel : public MidiTrackBase { DrumMap* _drumMap; bool _useDrumMap; - MidiOutPort* _port; + MidiOut* _port; int _channelNo; void clearDevice(); @@ -43,10 +45,11 @@ class MidiChannel : public MidiTrackBase { void useDrumMapChanged(bool); public: - MidiChannel(MidiOutPort*, int); + MidiChannel(MidiOut*, int); ~MidiChannel(); + virtual TrackType type() const { return MIDI_CHANNEL; } - MidiOutPort* port() const { return _port; } + MidiOut* port() const { return _port; } int channelNo() const { return _channelNo; } virtual void write(Xml&) const; diff --git a/muse/muse/midiedit/ctrledit.cpp b/muse/muse/midiedit/ctrledit.cpp index 08c3a5c1..925f0247 100644 --- a/muse/muse/midiedit/ctrledit.cpp +++ b/muse/muse/midiedit/ctrledit.cpp @@ -91,8 +91,9 @@ void CtrlEdit::setCtrl(int id) MidiChannel* mc = mt->channel(); if (mc) { _ctrl = mc->getController(id); - if (!_ctrl) - _ctrl = mc->port()->getController(id); + if (!_ctrl) { + _ctrl = mc->port()->track->getController(id); + } } } } diff --git a/muse/muse/midiinport.cpp b/muse/muse/midiinport.cpp index 42fe2677..ac55a813 100644 --- a/muse/muse/midiinport.cpp +++ b/muse/muse/midiinport.cpp @@ -34,7 +34,7 @@ //--------------------------------------------------------- MidiInPort::MidiInPort() - : MidiTrackBase(MIDI_IN) + : MidiTrackBase() { _channels = 1; recordRead = 0; diff --git a/muse/muse/midiinport.h b/muse/muse/midiinport.h index 5d0d8464..760ed7fe 100644 --- a/muse/muse/midiinport.h +++ b/muse/muse/midiinport.h @@ -40,6 +40,7 @@ class MidiInPort : public MidiTrackBase { public: MidiInPort(); ~MidiInPort(); + virtual TrackType type() const { return MIDI_IN; } virtual void setName(const QString& s); virtual void write(Xml&) const; diff --git a/muse/muse/midiout.cpp b/muse/muse/midiout.cpp new file mode 100644 index 00000000..c499ba6b --- /dev/null +++ b/muse/muse/midiout.cpp @@ -0,0 +1,389 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 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 "midiout.h" +#include "midictrl.h" +#include "track.h" +#include "al/tempo.h" +#include "event.h" +#include "midichannel.h" +#include "sync.h" +#include "audio.h" +#include "gconfig.h" + +static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; + +//--------------------------------------------------------- +// sendGmOn +// send GM-On message to midi device and keep track +// of device state +//--------------------------------------------------------- + +void MidiOut::sendGmOn() + { + sendSysex(gmOnMsg, gmOnMsgLen); + track->setHwCtrlState(CTRL_PROGRAM, 0); + track->setHwCtrlState(CTRL_PITCH, 0); + track->setHwCtrlState(CTRL_VOLUME, 100); + track->setHwCtrlState(CTRL_PANPOT, 64); + track->setHwCtrlState(CTRL_REVERB_SEND, 40); + track->setHwCtrlState(CTRL_CHORUS_SEND, 0); + track->setMeter(0, 0.0); + } + +//--------------------------------------------------------- +// sendGsOn +// send Roland GS-On message to midi device and keep track +// of device state +//--------------------------------------------------------- + +void MidiOut::sendGsOn() + { + static unsigned char data2[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x33, 0x50, 0x3c }; + static unsigned char data3[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x34, 0x50, 0x3b }; + + sendSysex(data2, sizeof(data2)); + sendSysex(data3, sizeof(data3)); + } + +//--------------------------------------------------------- +// sendXgOn +// send Yamaha XG-On message to midi device and keep track +// of device state +//--------------------------------------------------------- + +void MidiOut::sendXgOn() + { + sendSysex(xgOnMsg, xgOnMsgLen); + track->setHwCtrlState(CTRL_PROGRAM, 0); + track->setHwCtrlState(CTRL_MODULATION, 0); + track->setHwCtrlState(CTRL_PORTAMENTO_TIME, 0); + track->setHwCtrlState(CTRL_VOLUME, 0x64); + track->setHwCtrlState(CTRL_PANPOT, 0x40); + track->setHwCtrlState(CTRL_EXPRESSION, 0x7f); + track->setHwCtrlState(CTRL_SUSTAIN, 0x0); + track->setHwCtrlState(CTRL_PORTAMENTO, 0x0); + track->setHwCtrlState(CTRL_SOSTENUTO, 0x0); + track->setHwCtrlState(CTRL_SOFT_PEDAL, 0x0); + track->setHwCtrlState(CTRL_HARMONIC_CONTENT, 0x40); + track->setHwCtrlState(CTRL_RELEASE_TIME, 0x40); + track->setHwCtrlState(CTRL_ATTACK_TIME, 0x40); + track->setHwCtrlState(CTRL_BRIGHTNESS, 0x40); + track->setHwCtrlState(CTRL_REVERB_SEND, 0x28); + track->setHwCtrlState(CTRL_CHORUS_SEND, 0x0); + track->setHwCtrlState(CTRL_VARIATION_SEND, 0x0); + track->setMeter(0, 0.0); + } + +//--------------------------------------------------------- +// sendSysex +// send SYSEX message to midi device +//--------------------------------------------------------- + +void MidiOut::sendSysex(const unsigned char* p, int n) + { + MidiEvent event(0, ME_SYSEX, p, n); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// sendStart +//--------------------------------------------------------- + +void MidiOut::sendStart() + { + MidiEvent event(0, 0, ME_START, 0, 0); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// sendStop +//--------------------------------------------------------- + +void MidiOut::sendStop() + { + MidiEvent event(0, 0, ME_STOP, 0, 0); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// sendClock +//--------------------------------------------------------- + +void MidiOut::sendClock() + { + MidiEvent event(0, 0, ME_CLOCK, 0, 0); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// sendContinue +//--------------------------------------------------------- + +void MidiOut::sendContinue() + { + MidiEvent event(0, 0, ME_CONTINUE, 0, 0); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// sendSongpos +//--------------------------------------------------------- + +void MidiOut::sendSongpos(int pos) + { + MidiEvent event(0, 0, ME_SONGPOS, pos, 0); + track->routeEvent(event); + } + +//--------------------------------------------------------- +// playMidiEvent +// called from GUI +//--------------------------------------------------------- + +void MidiOut::playMidiEvent(MidiEvent* ev) + { + if (eventFifo.put(*ev)) + printf("MidiPort::playMidiEvent(): port overflow, drop event\n"); + } + +//--------------------------------------------------------- +// seek +//--------------------------------------------------------- + +void MidiOut::seek(unsigned tickPos, unsigned framePos) + { + if (genMCSync && track->sendSync()) { + int beat = (tickPos * 4) / config.division; + sendStop(); + sendSongpos(beat); + sendContinue(); + } + if (track->mute()) + return; + +// if (pos == 0 && !song->record()) +// audio->initDevices(); + + //--------------------------------------------------- + // stop all notes + //--------------------------------------------------- + + for (iMPEvent i = _schedEvents.begin(); i != _schedEvents.end(); ++i) { + MidiEvent ev = *i; + if (ev.isNoteOff()) { + ev.setTime(framePos); + track->routeEvent(ev); + } + } + _schedEvents.clear(); + + //--------------------------------------------------- + // set all controller + //--------------------------------------------------- + + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { + MidiChannel* mc = channel(ch); + if (mc->mute() || mc->noInRoute() || !mc->autoRead()) + continue; + CtrlList* cll = mc->controller(); + for (iCtrl ivl = cll->begin(); ivl != cll->end(); ++ivl) { + Ctrl* c = ivl->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)); + } + } + } + } + +//--------------------------------------------------------- +// stop +//--------------------------------------------------------- + +void MidiOut::stop() + { + int frame = AL::tempomap.tick2frame(audio->curTickPos()); + + //--------------------------------------------------- + // stop all notes + //--------------------------------------------------- + + for (iMPEvent i = _schedEvents.begin(); i != _schedEvents.end(); ++i) { + MidiEvent ev = *i; + if (ev.isNoteOff()) { + ev.setTime(frame); + track->routeEvent(ev); + } + } + _schedEvents.clear(); + + //--------------------------------------------------- + // reset sustain + //--------------------------------------------------- + + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { + MidiChannel* mc = channel(ch); + if (mc->noInRoute()) + 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); + } + } + if (track->sendSync()) { + if (genMMC) { + unsigned char mmcPos[] = { + 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01, + 0, 0, 0, 0, 0 + }; + MTC mtc(double(frame) / double(AL::sampleRate)); + mmcPos[6] = mtc.h() | (AL::mtcType << 5); + mmcPos[7] = mtc.m(); + mmcPos[8] = mtc.s(); + mmcPos[9] = mtc.f(); + mmcPos[10] = mtc.sf(); +//TODO sendSysex(mmcStopMsg, sizeof(mmcStopMsg)); + sendSysex(mmcPos, sizeof(mmcPos)); + } + if (genMCSync) { // Midi Clock + // send STOP and + // "set song position pointer" + sendStop(); + sendSongpos(audio->curTickPos() * 4 / config.division); + } + } + } + +//--------------------------------------------------------- +// start +//--------------------------------------------------------- + +void MidiOut::start() + { + if (!(genMMC || genMCSync || track->sendSync())) + return; + if (genMMC) + sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg)); + if (genMCSync) { + if (audio->curTickPos()) + sendContinue(); + else + sendStart(); + } + } + +//--------------------------------------------------------- +// reset +//--------------------------------------------------------- + +void MidiOut::reset() + { +/* TODO + MidiEvent ev; + ev.setType(0x90); + for (int chan = 0; chan < MIDI_CHANNELS; ++chan) { + ev.setChannel(chan); + for (int pitch = 0; pitch < 128; ++pitch) { + ev.setA(pitch); + ev.setB(0); + mp->putEvent(ev); + } + } +*/ + } + +//------------------------------------------------------------------- +// process +// Collect all midi events for the current process cycle and put +// into _schedEvents queue. For note on events create the proper +// note off events. The note off events maybe played after the +// current process cycle. +// From _schedEvents queue copy all events for the current cycle +// to all output routes. Events routed to ALSA go into the +// _playEvents queue which is processed by the MidiSeq thread. +//------------------------------------------------------------------- + +void MidiOut::processMidi(MPEventList& el, unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame) + { + while (!eventFifo.isEmpty()) + el.add(eventFifo.get()); + + // collect port controller + if (fromTick != toTick) { // if rolling + CtrlList* cl = track->controller(); + for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { + Ctrl* c = ic->second; + iCtrlVal is = c->lower_bound(fromTick); + iCtrlVal ie = c->lower_bound(toTick); + for (iCtrlVal ic = is; ic != ie; ++ic) { + unsigned frame = AL::tempomap.tick2frame(ic->first); + Event ev(Controller); + ev.setA(c->id()); + ev.setB(ic->second.i); + el.add(MidiEvent(frame, -1, ev)); + } + } + } + + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { + MidiChannel* mc = channel(ch); + + if (mc->mute() || mc->noInRoute()) + continue; + // collect channel controller + if (fromTick != toTick) { + CtrlList* cl = mc->controller(); + for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { + Ctrl* c = ic->second; + iCtrlVal is = c->lower_bound(fromTick); + iCtrlVal ie = c->lower_bound(toTick); + for (; is != ie; ++is) { + unsigned frame = AL::tempomap.tick2frame(is->first); + Event ev(Controller); + ev.setA(c->id()); + ev.setB(is->second.i); + el.add(MidiEvent(frame, ch, ev)); + } + } + } + + // Collect midievents from all input tracks for outport + RouteList* rl = mc->inRoutes(); + for (iRoute i = rl->begin(); i != rl->end(); ++i) { + MidiTrackBase* track = (MidiTrackBase*)i->track; + if (track->isMute()) + continue; + MPEventList ell; + track->getEvents(fromTick, toTick, 0, &ell); + int velo = 0; + for (iMPEvent i = ell.begin(); i != ell.end(); ++i) { + MidiEvent ev(*i); + ev.setChannel(ch); + el.insert(ev); + if (ev.type() == ME_NOTEON) + velo += ev.dataB(); + } + mc->addMidiMeter(velo); + } + } + } + diff --git a/muse/muse/midiout.h b/muse/muse/midiout.h new file mode 100644 index 00000000..8fffb8fe --- /dev/null +++ b/muse/muse/midiout.h @@ -0,0 +1,74 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 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 __MIDIOUT_H__ +#define __MIDIOUT_H__ + +#include "al/al.h" +#include "globaldefs.h" +#include "midievent.h" +#include "midififo.h" + +class Track; +class MidiInstrument; +class MidiChannel; + +//--------------------------------------------------------- +// MidiOut +//--------------------------------------------------------- + +class MidiOut + { + public: + Track* track; + MidiInstrument* _instrument; + MidiChannel* _channel[MIDI_CHANNELS]; + MPEventList _schedEvents; // scheduled events by process() + + // fifo for midi events send from gui + // direct to midi port: + + MidiFifo eventFifo; + + void processMidi(MPEventList& el, unsigned fromTick, unsigned toTick, + unsigned fromFrame, unsigned toFrame); + MidiChannel* channel(int n) { return _channel[n]; } + MidiInstrument* instrument() { return _instrument; } + void setInstrument(MidiInstrument* i) { _instrument = i; } + + void seek(unsigned, unsigned); + void stop(); + void start(); + void reset(); + + void sendSysex(const unsigned char*, int); + void sendSongpos(int); + void sendGmOn(); + void sendGsOn(); + void sendXgOn(); + void sendStart(); + void sendStop(); + void sendContinue(); + void sendClock(); + void playMidiEvent(MidiEvent* ev); + }; + +#endif + diff --git a/muse/muse/midioutport.cpp b/muse/muse/midioutport.cpp index 471eed3d..3b5a8ba1 100644 --- a/muse/muse/midioutport.cpp +++ b/muse/muse/midioutport.cpp @@ -32,21 +32,20 @@ #include "midiseq.h" #include "sync.h" #include "gconfig.h" - -static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 }; +#include "instruments/minstrument.h" //--------------------------------------------------------- // MidiOutPort //--------------------------------------------------------- MidiOutPort::MidiOutPort() - : MidiTrackBase(MIDI_OUT) + : MidiTrackBase() { + track = this; _instrument = genericMidiInstrument; for (int ch = 0; ch < MIDI_CHANNELS; ++ch) _channel[ch] = new MidiChannel(this, ch); - _sendSync = false; - _deviceId = 127; // all + setDeviceId(127); // all addMidiController(_instrument, CTRL_MASTER_VOLUME); _channels = 1; } @@ -90,8 +89,8 @@ void MidiOutPort::write(Xml& xml) const if (!_channel[i]->noInRoute()) _channel[i]->write(xml); } - xml.intTag("sendSync", _sendSync); - xml.intTag("deviceId", _deviceId); + xml.intTag("sendSync", sendSync()); + xml.intTag("deviceId", deviceId()); xml.etag("MidiOutPort"); } @@ -113,246 +112,14 @@ void MidiOutPort::read(QDomNode node) _instrument = registerMidiInstrument(iname); } else if (tag == "sendSync") - _sendSync = e.text().toInt(); + setSendSync(e.text().toInt()); else if (tag == "deviceId") - _deviceId = e.text().toInt(); + setDeviceId(e.text().toInt()); else if (MidiTrackBase::readProperties(node)) printf("MusE:MidiOutPort: unknown tag %s\n", tag.toLatin1().data()); } } -//--------------------------------------------------------- -// sendGmOn -// send GM-On message to midi device and keep track -// of device state -//--------------------------------------------------------- - -void MidiOutPort::sendGmOn() - { - sendSysex(gmOnMsg, gmOnMsgLen); - setHwCtrlState(CTRL_PROGRAM, 0); - setHwCtrlState(CTRL_PITCH, 0); - setHwCtrlState(CTRL_VOLUME, 100); - setHwCtrlState(CTRL_PANPOT, 64); - setHwCtrlState(CTRL_REVERB_SEND, 40); - setHwCtrlState(CTRL_CHORUS_SEND, 0); - _meter[0] = 0.0f; - } - -//--------------------------------------------------------- -// sendGsOn -// send Roland GS-On message to midi device and keep track -// of device state -//--------------------------------------------------------- - -void MidiOutPort::sendGsOn() - { - static unsigned char data2[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x33, 0x50, 0x3c }; - static unsigned char data3[] = { 0x41, 0x10, 0x42, 0x12, 0x40, 0x01, 0x34, 0x50, 0x3b }; - - sendSysex(data2, sizeof(data2)); - sendSysex(data3, sizeof(data3)); - } - -//--------------------------------------------------------- -// sendXgOn -// send Yamaha XG-On message to midi device and keep track -// of device state -//--------------------------------------------------------- - -void MidiOutPort::sendXgOn() - { - sendSysex(xgOnMsg, xgOnMsgLen); - setHwCtrlState(CTRL_PROGRAM, 0); - setHwCtrlState(CTRL_MODULATION, 0); - setHwCtrlState(CTRL_PORTAMENTO_TIME, 0); - setHwCtrlState(CTRL_VOLUME, 0x64); - setHwCtrlState(CTRL_PANPOT, 0x40); - setHwCtrlState(CTRL_EXPRESSION, 0x7f); - setHwCtrlState(CTRL_SUSTAIN, 0x0); - setHwCtrlState(CTRL_PORTAMENTO, 0x0); - setHwCtrlState(CTRL_SOSTENUTO, 0x0); - setHwCtrlState(CTRL_SOFT_PEDAL, 0x0); - setHwCtrlState(CTRL_HARMONIC_CONTENT, 0x40); - setHwCtrlState(CTRL_RELEASE_TIME, 0x40); - setHwCtrlState(CTRL_ATTACK_TIME, 0x40); - setHwCtrlState(CTRL_BRIGHTNESS, 0x40); - setHwCtrlState(CTRL_REVERB_SEND, 0x28); - setHwCtrlState(CTRL_CHORUS_SEND, 0x0); - setHwCtrlState(CTRL_VARIATION_SEND, 0x0); - _meter[0] = 0.0f; - } - -//--------------------------------------------------------- -// sendSysex -// send SYSEX message to midi device -//--------------------------------------------------------- - -void MidiOutPort::sendSysex(const unsigned char* p, int n) - { - MidiEvent event(0, ME_SYSEX, p, n); - routeEvent(event); - } - -//--------------------------------------------------------- -// sendStart -//--------------------------------------------------------- - -void MidiOutPort::sendStart() - { - MidiEvent event(0, 0, ME_START, 0, 0); - routeEvent(event); - } - -//--------------------------------------------------------- -// sendStop -//--------------------------------------------------------- - -void MidiOutPort::sendStop() - { - MidiEvent event(0, 0, ME_STOP, 0, 0); - routeEvent(event); - } - -//--------------------------------------------------------- -// sendClock -//--------------------------------------------------------- - -void MidiOutPort::sendClock() - { - MidiEvent event(0, 0, ME_CLOCK, 0, 0); - routeEvent(event); - } - -//--------------------------------------------------------- -// sendContinue -//--------------------------------------------------------- - -void MidiOutPort::sendContinue() - { - MidiEvent event(0, 0, ME_CONTINUE, 0, 0); - routeEvent(event); - } - -//--------------------------------------------------------- -// sendSongpos -//--------------------------------------------------------- - -void MidiOutPort::sendSongpos(int pos) - { - MidiEvent event(0, 0, ME_SONGPOS, pos, 0); - routeEvent(event); - } - -//--------------------------------------------------------- -// playMidiEvent -// called from GUI -//--------------------------------------------------------- - -void MidiOutPort::playMidiEvent(MidiEvent* ev) - { - if (eventFifo.put(*ev)) - printf("MidiPort::playMidiEvent(): port overflow, drop event\n"); - } - -//------------------------------------------------------------------- -// process -// Collect all midi events for the current process cycle and put -// into _schedEvents queue. For note on events create the proper -// note off events. The note off events maybe played after the -// current process cycle. -// From _schedEvents queue copy all events for the current cycle -// to all output routes. Events routed to ALSA go into the -// _playEvents queue which is processed by the MidiSeq thread. -//------------------------------------------------------------------- - -void MidiOutPort::process(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame) - { - if (mute()) - return; - - MPEventList el; - while (!eventFifo.isEmpty()) - el.add(eventFifo.get()); - - // collect port controller - if (fromTick != toTick) { // if rolling - CtrlList* cl = controller(); - for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { - Ctrl* c = ic->second; - iCtrlVal is = c->lower_bound(fromTick); - iCtrlVal ie = c->lower_bound(toTick); - for (iCtrlVal ic = is; ic != ie; ++ic) { - unsigned frame = AL::tempomap.tick2frame(ic->first); - Event ev(Controller); - ev.setA(c->id()); - ev.setB(ic->second.i); - el.add(MidiEvent(frame, -1, ev)); - } - } - } - - for (int ch = 0; ch < MIDI_CHANNELS; ++ch) { - MidiChannel* mc = channel(ch); - - if (mc->mute() || mc->noInRoute()) - continue; - // collect channel controller - if (fromTick != toTick) { - CtrlList* cl = mc->controller(); - for (iCtrl ic = cl->begin(); ic != cl->end(); ++ic) { - Ctrl* c = ic->second; - iCtrlVal is = c->lower_bound(fromTick); - iCtrlVal ie = c->lower_bound(toTick); - for (; is != ie; ++is) { - unsigned frame = AL::tempomap.tick2frame(is->first); - Event ev(Controller); - ev.setA(c->id()); - ev.setB(is->second.i); - el.add(MidiEvent(frame, ch, ev)); -printf("add controller %d %d %d\n", fromFrame, frame, toFrame); - } - } - } - - // Collect midievents from all input tracks for outport - RouteList* rl = mc->inRoutes(); - for (iRoute i = rl->begin(); i != rl->end(); ++i) { - MidiTrackBase* track = (MidiTrackBase*)i->track; - if (track->isMute()) - continue; - MPEventList ell; - track->getEvents(fromTick, toTick, 0, &ell); - int velo = 0; - for (iMPEvent i = ell.begin(); i != ell.end(); ++i) { - MidiEvent ev(*i); - ev.setChannel(ch); - el.insert(ev); - if (ev.type() == ME_NOTEON) - velo += ev.dataB(); - } - mc->addMidiMeter(velo); - } - } - pipeline()->apply(fromTick, toTick, &el, &_schedEvents); - - // - // route events to destination - // - - int portVelo = 0; - iMPEvent i = _schedEvents.begin(); - for (; i != _schedEvents.end(); ++i) { - if (i->time() >= toFrame) - break; - routeEvent(*i); - if (i->type() == ME_NOTEON) - portVelo += i->dataB(); - } - _schedEvents.erase(_schedEvents.begin(), i); - addMidiMeter(portVelo); - } - //--------------------------------------------------------- // routeEvent //--------------------------------------------------------- @@ -389,10 +156,12 @@ void MidiOutPort::routeEvent(const MidiEvent& event) case Route::MIDIPORT: queueAlsaEvent(event); break; +#if 0 case Route::SYNTIPORT: case Route::TRACK: ((SynthI*)(r->track))->playEvents()->insert(event); break; +#endif case Route::JACKMIDIPORT: queueJackEvent(event); break; @@ -434,7 +203,7 @@ void MidiOutPort::queueAlsaEvent(const MidiEvent& ev) unsigned char sysex[] = { 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 }; - sysex[1] = _deviceId; + sysex[1] = deviceId(); sysex[4] = b & 0x7f; sysex[5] = (b >> 7) & 0x7f; _playEvents.insert(MidiEvent(t, ME_SYSEX, sysex, 6)); @@ -524,7 +293,7 @@ void MidiOutPort::queueJackEvent(const MidiEvent& ev) unsigned char sysex[] = { 0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00 }; - sysex[1] = _deviceId; + sysex[1] = deviceId(); sysex[4] = b & 0x7f; sysex[5] = (b >> 7) & 0x7f; JO(MidiEvent(t, ME_SYSEX, sysex, 6)); @@ -604,16 +373,7 @@ void MidiOutPort::setInstrument(MidiInstrument* i) emit instrumentChanged(); } -//--------------------------------------------------------- -// setSendSync -//--------------------------------------------------------- - -void MidiOutPort::setSendSync(bool val) - { - _sendSync = val; - emit sendSyncChanged(val); - } - +#if 0 //TODO //--------------------------------------------------------- // seek //--------------------------------------------------------- @@ -763,6 +523,7 @@ void MidiOutPort::reset() } */ } +#endif #if 0 //--------------------------------------------------------- @@ -798,4 +559,42 @@ void MidiSeq::processMidiClock() } #endif +//------------------------------------------------------------------- +// process +// Collect all midi events for the current process cycle and put +// into _schedEvents queue. For note on events create the proper +// note off events. The note off events maybe played after the +// current process cycle. +// From _schedEvents queue copy all events for the current cycle +// to all output routes. Events routed to ALSA go into the +// _playEvents queue which is processed by the MidiSeq thread. +//------------------------------------------------------------------- + +void MidiOutPort::processMidi(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame) + { + if (track->mute()) + return; + + MPEventList el; + MidiOut::processMidi(el, fromTick, toTick, fromFrame, toFrame); + + pipeline()->apply(fromTick, toTick, &el, &_schedEvents); + + // + // route events to destination + // + + int portVelo = 0; + iMPEvent i = _schedEvents.begin(); + for (; i != _schedEvents.end(); ++i) { + if (i->time() >= toFrame) + break; + routeEvent(*i); + if (i->type() == ME_NOTEON) + portVelo += i->dataB(); + } + _schedEvents.erase(_schedEvents.begin(), i); + addMidiMeter(portVelo); + } + diff --git a/muse/muse/midioutport.h b/muse/muse/midioutport.h index bb9552df..0d28c923 100644 --- a/muse/muse/midioutport.h +++ b/muse/muse/midioutport.h @@ -22,39 +22,28 @@ #define __MIDIOUTPORT_H__ #include "track.h" +#include "midiout.h" //--------------------------------------------------------- // MidiOutPort //--------------------------------------------------------- -class MidiOutPort : public MidiTrackBase { +class MidiOutPort : public MidiTrackBase, public MidiOut { Q_OBJECT - MidiInstrument* _instrument; - MidiChannel* _channel[MIDI_CHANNELS]; - - bool _sendSync; // this port sends mtc/mmc events - int _deviceId; // 0-126; 127 == all - - MPEventList _schedEvents; // scheduled events by process() MPEventList _playEvents; // event queue for MidiSeq - // fifo for midi events send from gui - // direct to midi port: - - MidiFifo eventFifo; - void routeEvent(const MidiEvent&); void queueAlsaEvent(const MidiEvent& event); void queueJackEvent(const MidiEvent& event); signals: void instrumentChanged(); - void sendSyncChanged(bool); public: MidiOutPort(); ~MidiOutPort(); + virtual TrackType type() const { return MIDI_OUT; } MidiChannel* channel(int n) { return _channel[n]; } @@ -64,42 +53,16 @@ class MidiOutPort : public MidiTrackBase { virtual bool isMute() const { return _mute; } virtual Part* newPart(Part*, bool) { return 0; } - MidiInstrument* instrument() const { return _instrument; } + MidiInstrument* instrument() const { return _instrument; } void setInstrument(MidiInstrument* i); bool guiVisible() const; bool hasGui() const; -// void putEvent(const MidiEvent&); - MPEventList* playEvents() { return &_playEvents; } - void process(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame); - - void playMidiEvent(MidiEvent*); - - void sendSysex(const unsigned char*, int); - void sendSongpos(int); - void sendGmOn(); - void sendGsOn(); - void sendXgOn(); - void sendStart(); - void sendStop(); - void sendContinue(); - void sendClock(); - - bool sendSync() const { return _sendSync; } - void setSendSync(bool val); - - int deviceId() const { return _deviceId; } - void setDeviceId(int val) { _deviceId = val; } - - void seek(unsigned, unsigned); - void stop(); - void start(); - void reset(); - void playAlsaEvent(const MidiEvent& event) const; + void processMidi(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame); }; #endif diff --git a/muse/muse/midisynti.cpp b/muse/muse/midisynti.cpp index 9a420da3..d8b8191b 100644 --- a/muse/muse/midisynti.cpp +++ b/muse/muse/midisynti.cpp @@ -30,7 +30,7 @@ //--------------------------------------------------------- MidiSynti::MidiSynti() - : MidiTrackBase(MIDI_SYNTI) + : MidiTrackBase() { _synti = 0; init(); diff --git a/muse/muse/midisynti.h b/muse/muse/midisynti.h index 95eac83c..4e3afe62 100644 --- a/muse/muse/midisynti.h +++ b/muse/muse/midisynti.h @@ -35,6 +35,8 @@ class MidiSynti : public MidiTrackBase { public: MidiSynti(); virtual ~MidiSynti(); + virtual TrackType type() const { return MIDI_SYNTI; } + void init(); virtual void read(QDomNode); diff --git a/muse/muse/miditrack.cpp b/muse/muse/miditrack.cpp index 6f621dc8..f1c7c7c2 100644 --- a/muse/muse/miditrack.cpp +++ b/muse/muse/miditrack.cpp @@ -34,7 +34,7 @@ //--------------------------------------------------------- MidiTrack::MidiTrack() - : MidiTrackBase(MIDI) + : MidiTrackBase() { init(); _events = new EventList; diff --git a/muse/muse/miditrack.h b/muse/muse/miditrack.h index 6f15831c..e0ade62d 100644 --- a/muse/muse/miditrack.h +++ b/muse/muse/miditrack.h @@ -53,8 +53,11 @@ class MidiTrack : public MidiTrackBase { public: MidiTrack(); virtual ~MidiTrack(); - void init(); + virtual TrackType type() const { return MIDI; } + void clone(MidiTrack*); + + void init(); MidiChannel* channel() const; void changeDrumMap() const; diff --git a/muse/muse/mixer/astrip.cpp b/muse/muse/mixer/astrip.cpp index c6c2ec52..c7a6c071 100644 --- a/muse/muse/mixer/astrip.cpp +++ b/muse/muse/mixer/astrip.cpp @@ -193,14 +193,20 @@ AudioStrip::AudioStrip(Mixer* m, AudioTrack* t, bool align) //--------------------------------------------------- QHBoxLayout* rBox = new QHBoxLayout(0); - iR = new QToolButton(this); - iR->setFont(config.fonts[1]); - iR->setFixedWidth((STRIP_WIDTH-4)/2); - iR->setText(tr("iR")); - iR->setCheckable(false); - iR->setToolTip(tr("input routing")); - rBox->addWidget(iR); - connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed())); + + if (track->type() == Track::AUDIO_SOFTSYNTH) { + rBox->addStretch(100); + } + else { + iR = new QToolButton(this); + iR->setFont(config.fonts[1]); + iR->setFixedWidth((STRIP_WIDTH-4)/2); + iR->setText(tr("iR")); + iR->setCheckable(false); + iR->setToolTip(tr("input routing")); + rBox->addWidget(iR); + connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed())); + } oR = new QToolButton(this); oR->setFont(config.fonts[1]); oR->setFixedWidth((STRIP_WIDTH-4)/2); @@ -717,10 +723,6 @@ void AudioStrip::iRoutePressed() addGroupPorts(t, &pup, irl); addSyntiPorts(t, &pup, irl); break; - case Track::AUDIO_SOFTSYNTH: - addMidiOutPorts(t, &pup, irl); - addMidiInPorts(t, &pup, irl); - break; } if (pup.isEmpty()) return; diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp index 23b873c2..bb6a0d34 100644 --- a/muse/muse/mixer/mstrip.cpp +++ b/muse/muse/mixer/mstrip.cpp @@ -31,6 +31,95 @@ enum { KNOB_PAN, KNOB_CHOR_SEND, KNOB_VAR_SEND, KNOB_REV_SEND }; +//--------------------------------------------------------- +// addSyntiPorts +//--------------------------------------------------------- + +static void addSyntiPorts(QMenu* menu, RouteList* r, int channel) + { + SynthIList* sl = song->syntis(); + for (iSynthI i = sl->begin(); i != sl->end(); ++i) { + SynthI* track = *i; + QAction* oa = menu->addAction(track->name()); + oa->setCheckable(true); + Route dst(track, channel, Route::SYNTIPORT); + oa->setData(QVariant::fromValue(dst)); + + for (iRoute ir = r->begin(); ir != r->end(); ++ir) { + if (*ir == dst) { + oa->setChecked(true); + break; + } + } + } + } + +//--------------------------------------------------------- +// addMidiTracks +//--------------------------------------------------------- + +static void addMidiTracks(QMenu* menu, RouteList* r, int channel) + { + MidiTrackList* tl = song->midis(); + for (iMidiTrack i = tl->begin();i != tl->end(); ++i) { + MidiTrack* track = *i; + QAction* action = menu->addAction(track->name()); + action->setCheckable(true); + Route src(track, channel, Route::TRACK); + action->setData(QVariant::fromValue(src)); + for (iRoute ir = r->begin(); ir != r->end(); ++ir) { + if (*ir == src) { + action->setChecked(true); + break; + } + } + } + } + +//--------------------------------------------------------- +// addMidiOutPorts +//--------------------------------------------------------- + +static void addMidiOutPorts(QMenu* menu, RouteList* r, int channel) + { + MidiOutPortList* tl = song->midiOutPorts(); + for (iMidiOutPort i = tl->begin();i != tl->end(); ++i) { + MidiChannel* track = (*i)->channel(channel); + QAction* action = menu->addAction(track->name()); + action->setCheckable(true); + Route src(track, -1, Route::TRACK); + action->setData(QVariant::fromValue(src)); + for (iRoute ir = r->begin(); ir != r->end(); ++ir) { + if (*ir == src) { + action->setChecked(true); + break; + } + } + } + } + +//--------------------------------------------------------- +// addMidiInPorts +//--------------------------------------------------------- + +static void addMidiInPorts(QMenu* menu, RouteList* r, int channel) + { + MidiInPortList* tl = song->midiInPorts(); + for (iMidiInPort i = tl->begin();i != tl->end(); ++i) { + MidiInPort* track = *i; + QAction* action = menu->addAction(track->name()); + action->setCheckable(true); + Route src(track, channel, Route::TRACK); + action->setData(QVariant::fromValue(src)); + for (iRoute ir = r->begin(); ir != r->end(); ++ir) { + if (*ir == src) { + action->setChecked(true); + break; + } + } + } + } + //--------------------------------------------------------- // addKnob //--------------------------------------------------------- @@ -357,21 +446,9 @@ void MidiChannelStrip::iRoutePressed() MidiChannel* t = (MidiChannel*)track; RouteList* irl = t->inRoutes(); - MidiTrackList* tl = song->midis(); - int tn = 0; - for (iMidiTrack i = tl->begin();i != tl->end(); ++i, ++tn) { - MidiTrack* track = *i; - QAction* action = pup.addAction(track->name()); - action->setCheckable(true); - Route src(track, -1, Route::TRACK); - action->setData(QVariant::fromValue(src)); - for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) { - if (*ir == src) { - action->setChecked(true); - break; - } - } - } + addMidiTracks(&pup, irl, -1); // add midi tracks to menu + addMidiInPorts(&pup, irl, -1); // add midi inputs to menu + if (pup.isEmpty()) return; QAction* n = pup.exec(QCursor::pos()); @@ -624,10 +701,32 @@ void MidiStrip::oRoutePressed() RouteList* orl = track->outRoutes(); MidiOutPortList* mpl = song->midiOutPorts(); - int pn = 0; - for (iMidiOutPort i = mpl->begin(); i != mpl->end(); ++i, ++pn) { + for (iMidiOutPort i = mpl->begin(); i != mpl->end(); ++i) { MidiOutPort* op = *i; QMenu* m = pup.addMenu(op->name()); + m->setSeparatorsCollapsible(false); + m->addSeparator()->setText(tr("Channel")); + for (int channel = 0; channel < MIDI_CHANNELS; ++channel) { + QString s; + s.setNum(channel+1); + QAction* action = m->addAction(s); + action->setCheckable(true); + MidiChannel* mc = op->channel(channel); + Route dst(mc, -1, Route::TRACK); + action->setData(QVariant::fromValue(dst)); + for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { + if (dst == *ir) { + action->setChecked(true); + break; + } + } + } + } + SynthIList* sl = song->syntis(); + for (iSynthI i = sl->begin(); i != sl->end(); ++i) { + SynthI* op = *i; + QMenu* m = pup.addMenu(op->name()); + m->setSeparatorsCollapsible(false); m->addSeparator()->setText(tr("Channel")); for (int channel = 0; channel < MIDI_CHANNELS; ++channel) { QString s; @@ -911,6 +1010,9 @@ void MidiOutPortStrip::oRoutePressed() pup.addSeparator()->setText(tr("MidiDevices")); RouteList* orl = track->outRoutes(); + // + // add ALSA midi ports to list + // QList ol = midiDriver->outputPorts(true); foreach (PortName ip, ol) { QAction* oa = pup.addAction(ip.name); @@ -927,26 +1029,7 @@ void MidiOutPortStrip::oRoutePressed() } // - // add software synthesizer to list - // - SynthIList* sl = song->syntis(); - for (iSynthI i = sl->begin(); i != sl->end(); ++i) { - SynthI* track = *i; - QAction* oa = pup.addAction(track->name()); - oa->setCheckable(true); - Route dst(track, -1, Route::SYNTIPORT); - oa->setData(QVariant::fromValue(dst)); - - for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { - if (*ir == dst) { - oa->setChecked(true); - break; - } - } - } - - // - // add JACK midi port to list + // add JACK midi ports to list // ol = audioDriver->inputPorts(true); foreach (PortName ip, ol) { @@ -1132,114 +1215,27 @@ void MidiInPortStrip::oRoutePressed() pup.setSeparatorsCollapsible(false); pup.addSeparator()->setText(tr("Channel")); - MidiTrackList* tl = song->midis(); - MidiSyntiList* sl = song->midiSyntis(); - RouteList* orl = track->outRoutes(); - SynthIList* asl = song->syntis(); - - int sn = 0; - for (iSynthI i = asl->begin(); i != asl->end(); ++i,++sn) { - QAction* action = pup.addAction((*i)->name()); - - QMap data; - data["id"] = QVariant(0x20000 + sn); - data["was_checked"] = false; - action->setData(data); + RouteList* orl = track->outRoutes(); - Route dst(*i, -1, Route::SYNTIPORT); - for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { - if (*ir == dst) { - action->setCheckable(true); - action->setChecked(true); - data["was_checked"] = true; - action->setData(data); - break; - } - } - } for (int channel = 0; channel < MIDI_CHANNELS; ++channel) { QMenu* m = pup.addMenu(QString(tr("Channel %1")).arg(channel + 1)); m->addSeparator()->setText(tr("Tracks")); - // - // route to midi track for recording - // and monitoring - // - int tn = 0; - for (iMidiTrack i = tl->begin(); i != tl->end(); ++i, ++tn) { - QAction* trackno_action = m->addAction((*i)->name()); - - QMap data; - data["id"] = tn * 16 + channel; - data["was_checked"] = false; - trackno_action->setData(data); - - Route dst(*i, channel, Route::TRACK); - for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { - if (*ir == dst) { - trackno_action->setCheckable(true); - trackno_action->setChecked(true); - data["was_checked"] = true; - trackno_action->setData(data); - break; - } - } - } - // - // route to midi synthesizer (arpeggiator etc.) - // - tn = 0; - for (iMidiSynti i = sl->begin(); i != sl->end(); ++i, ++tn) { - QAction* trackno_action = m->addAction((*i)->name()); - - QMap data; - data["id"] = 0x10000 + tn * 16 + channel; - data["was_checked"] = false; - trackno_action->setData(data); - - Route dst(*i, channel, Route::TRACK); - for (iRoute ir = orl->begin(); ir != orl->end(); ++ir) { - if (*ir == dst) { - trackno_action->setCheckable(true); - trackno_action->setChecked(true); - data["was_checked"] = true; - trackno_action->setData(data); - break; - } - } - } + addMidiTracks(m, orl, channel); + addSyntiPorts(m, orl, channel); + addMidiOutPorts(m, orl, channel); } + if (pup.isEmpty()) return; QAction* action = pup.exec(QCursor::pos()); if (action) { - int n = action->data().toMap()["id"].toInt(); - int was_checked = action->data().toMap()["was_checked"].toInt(); Route srcRoute(track, -1, Route::TRACK); - Route dstRoute; - if (n >= 0x20000) { - dstRoute.track = asl->index(n - 0x20000); - dstRoute.channel = -1; - dstRoute.type = Route::SYNTIPORT; - } - else if (n >= 0x10000) { - int channel = (n-0x10000) & 0xf; - srcRoute.channel = channel; - dstRoute.track = sl->index((n - 0x10000) >> 4); - dstRoute.channel = channel; - dstRoute.type = Route::TRACK; - } - else { - int channel = n & 0xf; - srcRoute.channel = channel; - dstRoute.track = tl->index(n >> 4); - dstRoute.channel = channel; - dstRoute.type = Route::TRACK; - } - if (was_checked) - audio->msgRemoveRoute(srcRoute, dstRoute); - else + Route dstRoute = action->data().value(); + if (action->isChecked()) audio->msgAddRoute(srcRoute, dstRoute); + else + audio->msgRemoveRoute(srcRoute, dstRoute); song->update(SC_ROUTE); } oR->setDown(false); // pup->exec() catches mouse release event @@ -1397,6 +1393,7 @@ MidiSyntiStrip::MidiSyntiStrip(Mixer* m, MidiSynti* t, bool align) connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed())); oR = new QToolButton(this); + rBox->addWidget(oR); oR->setFont(config.fonts[1]); oR->setFixedWidth((STRIP_WIDTH-4)/2); oR->setText(tr("oR")); @@ -1604,7 +1601,6 @@ void MidiSyntiStrip::oRoutePressed() } oR->setDown(false); // pup->exec() catches mouse release event } - //--------------------------------------------------------- // iRoutePressed //--------------------------------------------------------- diff --git a/muse/muse/mixer/mstrip.h b/muse/muse/mixer/mstrip.h index cfec0183..41afcd5e 100644 --- a/muse/muse/mixer/mstrip.h +++ b/muse/muse/mixer/mstrip.h @@ -161,8 +161,8 @@ class MidiSyntiStrip : public Strip { void sliderReleased(int); void autoReadToggled(bool); void autoWriteToggled(bool); - void iRoutePressed(); void oRoutePressed(); + void iRoutePressed(); protected slots: virtual void heartBeat(); diff --git a/muse/muse/muse.cpp b/muse/muse/muse.cpp index 25a0a1ff..36e25c06 100644 --- a/muse/muse/muse.cpp +++ b/muse/muse/muse.cpp @@ -68,6 +68,8 @@ #include "projectpropsdialog.h" #include "midichannel.h" +extern void initMidiInstruments(); + static pthread_t watchdogThread; static const char* fileOpenText = @@ -538,8 +540,6 @@ MusE::MusE() panicAction->setWhatsThis(tr(infoPanicButton)); connect(panicAction, SIGNAL(triggered()), song, SLOT(panic())); - initMidiInstruments(); - #ifdef __APPLE__ if (coreMidi.init()) { QMessageBox::critical(NULL, "MusE fatal error.", @@ -2851,6 +2851,7 @@ int main(int argc, char* argv[]) srand(time(0)); // initialize random number generator initMidiController(); + initMidiInstruments(); MuseApplication app(argc, argv); config.fonts[0] = QFont(QString("arial"), 10, QFont::Normal); diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp index 66fa6aea..0875a106 100644 --- a/muse/muse/song.cpp +++ b/muse/muse/song.cpp @@ -44,6 +44,7 @@ #include "midichannel.h" #include "midioutport.h" #include "midiinport.h" +#include "instruments/minstrument.h" Song* song; @@ -592,6 +593,7 @@ void Song::update(int flags) // // remove unconnected channels // +// printf("update tracks %d %d\n", _tracks.size(), _midiChannel.size()); bool again; do { again = false; @@ -1472,7 +1474,6 @@ Track* Song::addTrack(QAction* action) switch (type) { case Track::MIDI: track = new MidiTrack(); - track->setType(Track::MIDI); break; case Track::MIDI_OUT: track = new MidiOutPort(); @@ -1687,8 +1688,12 @@ void Song::insertTrack2(Track* track) case Track::AUDIO_SOFTSYNTH: { SynthI* s = (SynthI*)track; - midiInstruments.push_back(s); + midiInstruments.push_back(s->instrument()); _synthIs.push_back(s); + for (int i = 0; i < MIDI_CHANNELS; ++i) { + MidiChannel* mc = ((SynthI*)track)->channel(i); + _midiChannel.push_back(mc); + } } break; default: diff --git a/muse/muse/synth.cpp b/muse/muse/synth.cpp index 4e941ced..12c3ba21 100644 --- a/muse/muse/synth.cpp +++ b/muse/muse/synth.cpp @@ -21,18 +21,21 @@ #include #include "al/al.h" +#include "al/xml.h" +#include "al/tempo.h" #include "muse.h" #include "synth.h" -#include "al/xml.h" #include "midi.h" #include "synti/libsynti/mess.h" #include "song.h" #include "audio.h" #include "event.h" #include "midievent.h" +#include "midichannel.h" #include "audio.h" #include "midiseq.h" #include "midictrl.h" +#include "instruments/minstrument.h" std::vector synthis; // array of available synthis @@ -178,12 +181,39 @@ void* MessSynth::instantiate(const QString& instanceName) //--------------------------------------------------------- SynthI::SynthI() - : AudioTrack(AUDIO_SOFTSYNTH) + : AudioTrack() { + track = this; synthesizer = 0; _sif = 0; // setVolume(1.0); // setPan(0.0); + _instrument = genericMidiInstrument; //TODO + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) + _channel[ch] = new MidiChannel(this, ch); + } + +//--------------------------------------------------------- +// ~SynthI +//--------------------------------------------------------- + +SynthI::~SynthI() + { + deactivate2(); + deactivate3(); + for (int ch = 0; ch < MIDI_CHANNEL; ++ch) + delete _channel[ch]; + } + +//--------------------------------------------------------- +// setName +//--------------------------------------------------------- + +void SynthI::setName(const QString& s) + { + Track::setName(s); + for (int ch = 0; ch < MIDI_CHANNELS; ++ch) + _channel[ch]->setDefaultName(); } //--------------------------------------------------------- @@ -226,7 +256,7 @@ bool SynthI::initInstance(Synth* s) synthesizer = s; _sif = s->createSIF(this); - setIName(name()); // set instrument name + _instrument->setIName(name()); // set instrument name AudioTrack::setChannels(_sif->channels()); //--------------------------------------------------- @@ -234,7 +264,7 @@ bool SynthI::initInstance(Synth* s) //--------------------------------------------------- int id = 0; - MidiControllerList* cl = MidiInstrument::controller(); + MidiControllerList* cl = _instrument->controller(); for (;;) { const char* name; int ctrl; @@ -247,7 +277,7 @@ bool SynthI::initInstance(Synth* s) cl->push_back(c); } - EventList* iel = midiState(); + EventList* iel = _instrument->midiState(); if (!iel->empty()) { for (iEvent i = iel->begin(); i != iel->end(); ++i) { Event ev = i->second; @@ -291,7 +321,7 @@ int MessSynthIF::getControllerInfo(int id, const char** name, int* ctrl, int* mi void SynthI::deactivate2() { - removeMidiInstrument(this); + removeMidiInstrument(_instrument); } //--------------------------------------------------------- @@ -318,16 +348,6 @@ MessSynthIF::~MessSynthIF() deactivate3(); } -//--------------------------------------------------------- -// ~SynthI -//--------------------------------------------------------- - -SynthI::~SynthI() - { - deactivate2(); - deactivate3(); - } - //--------------------------------------------------------- // initMidiSynth // search for software synthis and advertise @@ -433,7 +453,7 @@ void SynthI::read(QDomNode node) else if (e.tagName() == "guiVisible") startGui = e.text().toInt(); else if (e.tagName() == "midistate") - readMidiState(node.firstChild()); + _instrument->readMidiState(node.firstChild()); else if (e.tagName() == "param") { float val = e.text().toFloat(); initParams.push_back(val); @@ -572,11 +592,28 @@ bool MessSynthIF::putEvent(const MidiEvent& ev) void SynthI::collectInputData() { bufferEmpty = false; - while (!_eventFifo.isEmpty()) - _playEvents.add(_eventFifo.get()); - iMPEvent ie = _playEvents.begin(); + while (!eventFifo.isEmpty()) + _schedEvents.add(eventFifo.get()); + iMPEvent ie = _schedEvents.begin(); unsigned pos = audio->pos().frame(); - _sif->getData(&_playEvents, ie, pos, channels(), segmentSize, buffer); - _playEvents.clear(); + _sif->getData(&_schedEvents, ie, pos, channels(), segmentSize, buffer); + _schedEvents.clear(); } +//------------------------------------------------------------------- +// process +// Collect all midi events for the current process cycle and put +// into _schedEvents queue. For note on events create the proper +// note off events. The note off events maybe played after the +// current process cycle. +// From _schedEvents queue copy all events for the current cycle +// to all output routes. Events routed to ALSA go into the +// _playEvents queue which is processed by the MidiSeq thread. +//------------------------------------------------------------------- + +void SynthI::processMidi(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame) + { + if (mute()) + return; + MidiOut::processMidi(_schedEvents, fromTick, toTick, fromFrame, toFrame); + } diff --git a/muse/muse/synth.h b/muse/muse/synth.h index c4c469de..460cee2f 100644 --- a/muse/muse/synth.h +++ b/muse/muse/synth.h @@ -22,8 +22,9 @@ #define __SYNTH_H__ #include "globals.h" -#include "instruments/minstrument.h" +// #include "instruments/minstrument.h" #include "audiotrack.h" +#include "midiout.h" class Mess; struct MESS; @@ -114,11 +115,11 @@ class SynthIF { // MidiInstrument //--------------------------------------------------------- -class SynthI : public AudioTrack, public MidiInstrument +class SynthI : public AudioTrack, public MidiOut { + Q_OBJECT + SynthIF* _sif; - MPEventList _playEvents; - MidiFifo _eventFifo; protected: Synth* synthesizer; @@ -135,6 +136,9 @@ class SynthI : public AudioTrack, public MidiInstrument public: SynthI(); virtual ~SynthI(); + virtual TrackType type() const { return AUDIO_SOFTSYNTH; } + + virtual void setName(const QString& s); SynthIF* sif() const { return _sif; } bool initInstance(Synth* s); @@ -169,8 +173,7 @@ class SynthI : public AudioTrack, public MidiInstrument void deactivate3(); bool isActivated() const { return synthesizer && _sif; } virtual bool hasAuxSend() const { return _sif->hasAuxSend(); } - MPEventList* playEvents() { return &_playEvents; } - MidiFifo* eventFifo() { return &_eventFifo; } + void processMidi(unsigned fromTick, unsigned toTick, unsigned fromFrame, unsigned toFrame); }; //--------------------------------------------------------- diff --git a/muse/muse/track.cpp b/muse/muse/track.cpp index 276585c8..d3e18ee3 100644 --- a/muse/muse/track.cpp +++ b/muse/muse/track.cpp @@ -68,7 +68,7 @@ ArrangerTrack::ArrangerTrack() QColor Track::ccolor() const { - return config.trackBg[_type]; + return config.trackBg[type()]; } //--------------------------------------------------------- @@ -92,10 +92,10 @@ QPixmap* Track::pixmap(TrackType t) } //--------------------------------------------------------- -// Track::init +// Track //--------------------------------------------------------- -void Track::init() +Track::Track() { _tt = AL::TICKS; _recordFlag = false; @@ -114,16 +114,8 @@ void Track::init() _peak[i] = 0.0f; _peakTimer[i] = 0; } - } - -//--------------------------------------------------------- -// Track -//--------------------------------------------------------- - -Track::Track(Track::TrackType t) - { - init(); - _type = t; + _sendSync = false; + _deviceId = 127; _parts = new PartList; } @@ -152,16 +144,16 @@ Track::~Track() void Track::setDefaultName() { QString base; - switch(_type) { + switch(type()) { case MIDI: case WAVE: base = QString("Track"); break; case MIDI_CHANNEL: { - MidiOutPort* mop = ((MidiChannel*)this)->port(); + MidiOut* mop = ((MidiChannel*)this)->port(); int no = ((MidiChannel*)this)->channelNo(); - base.sprintf("%s:%d", mop->name().toLatin1().data(), no + 1); + base = QString("%1:%2").arg(mop->track->name()).arg(no + 1); setName(base); return; } @@ -212,7 +204,7 @@ void Track::setDefaultName() break; } } - if (_type == MIDI_OUT) { + if (type() == MIDI_OUT) { MidiOutPort* mop = (MidiOutPort*) this; for (int i = 0; i < MIDI_CHANNELS; ++i) mop->channel(i)->setDefaultName(); @@ -226,7 +218,7 @@ void Track::setDefaultName() void Track::dump() const { printf("Track <%s>: typ %d, parts %zd sel %d\n", - _name.toLatin1().data(), _type, _parts->size(), _selected); + _name.toLatin1().data(), type(), _parts->size(), _selected); } //--------------------------------------------------------- @@ -723,8 +715,8 @@ void Track::writeRouting(Xml& xml) const // MidiTrackBase //--------------------------------------------------------- -MidiTrackBase::MidiTrackBase(TrackType t) - : Track(t) +MidiTrackBase::MidiTrackBase() + : Track() { _pipeline = new MidiPipeline(); } @@ -1102,3 +1094,14 @@ void Track::deactivate() } } +//--------------------------------------------------------- +// setSendSync +//--------------------------------------------------------- + +void Track::setSendSync(bool val) + { + _sendSync = val; + emit sendSyncChanged(val); + } + + diff --git a/muse/muse/track.h b/muse/muse/track.h index f07a3282..3eb248ef 100644 --- a/muse/muse/track.h +++ b/muse/muse/track.h @@ -109,12 +109,11 @@ class Track : public QObject { }; private: - TrackType _type; QString _comment; PartList* _parts; Port _alsaPort[MAX_CHANNELS], _jackPort[MAX_CHANNELS]; - - void init(); + bool _sendSync; // this port sends mtc/mmc events + int _deviceId; // midi device id: 0-126; 127 == all protected: TType _tt; // time type @@ -160,6 +159,7 @@ class Track : public QObject { void partsChanged(); void nameChanged(const QString&); void routeChanged(); + void sendSyncChanged(bool); private slots: void setAutoRead(bool); @@ -167,7 +167,6 @@ class Track : public QObject { public: Track(); - Track(TrackType); virtual ~Track(); static const char* _cname[]; @@ -178,8 +177,8 @@ class Track : public QObject { TType timeType() const { return _tt; } void setTimeType(TType t) { _tt = t; } - QString cname() const { return QString(_cname[_type]); } - QString clname() const { return QString(_clname[_type]); } + QString cname() const { return QString(_cname[type()]); } + QString clname() const { return QString(_clname[type()]); } // // called before and after use @@ -225,7 +224,7 @@ class Track : public QObject { //---------------------------------------------------------- QColor ccolor() const; - QPixmap* pixmap() const { return pixmap(_type); } + QPixmap* pixmap() const { return pixmap(type()); } static QPixmap* pixmap(TrackType); bool selected() const { return _selected; } @@ -237,8 +236,7 @@ class Track : public QObject { const QString name() const { return _name; } virtual void setName(const QString& s); - TrackType type() const { return _type; } - void setType(TrackType t) { _type = t; } + virtual TrackType type() const = 0; PartList* parts() { return _parts; } const PartList* cparts() const { return _parts; } @@ -326,6 +324,12 @@ class Track : public QObject { ArrangerTrackList subtracks; friend class Song; + + virtual void routeEvent(const MidiEvent&) {} + bool sendSync() const { return _sendSync; } + void setSendSync(bool val); + int deviceId() const { return _deviceId; } + void setDeviceId(int val) { _deviceId = val; } }; //--------------------------------------------------------- @@ -338,7 +342,7 @@ class MidiTrackBase : public Track { MidiPipeline* _pipeline; public: - MidiTrackBase(TrackType t); + MidiTrackBase(); virtual ~MidiTrackBase(); bool readProperties(QDomNode); diff --git a/muse/muse/wavetrack.cpp b/muse/muse/wavetrack.cpp index 1f964789..65b91ceb 100644 --- a/muse/muse/wavetrack.cpp +++ b/muse/muse/wavetrack.cpp @@ -37,7 +37,7 @@ bool WaveTrack::firstWaveTrack = true; //--------------------------------------------------------- WaveTrack::WaveTrack() - : AudioTrack(Track::WAVE) + : AudioTrack() { // // allocate prefetch buffer diff --git a/muse/muse/wavetrack.h b/muse/muse/wavetrack.h index 519a0692..c766e9b1 100644 --- a/muse/muse/wavetrack.h +++ b/muse/muse/wavetrack.h @@ -51,6 +51,8 @@ class WaveTrack : public AudioTrack { WaveTrack(); ~WaveTrack(); + virtual TrackType type() const { return WAVE; } + void clone(WaveTrack*); virtual Part* newPart(Part*p=0, bool clone=false); -- cgit v1.2.3