summaryrefslogtreecommitdiff
path: root/muse2/muse/midi.cpp
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
committerFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
commit9c4664d162c537ba4dd4fd8220971c0fb727103a (patch)
tree37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/midi.cpp
parente87fedf1be804f7ec774071d844b1f163be30b96 (diff)
final merge
Diffstat (limited to 'muse2/muse/midi.cpp')
-rw-r--r--muse2/muse/midi.cpp199
1 files changed, 173 insertions, 26 deletions
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index ae348b5f..503208e6 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -34,6 +34,7 @@
#include "marker/marker.h"
#include "midiport.h"
#include "midictrl.h"
+#include "sync.h"
#include "audio.h"
#include "mididev.h"
#include "driver/alsamidi.h"
@@ -860,31 +861,149 @@ void Audio::collectEvents(MusECore::MidiTrack* track, unsigned int cts, unsigned
void Audio::processMidi()
{
MusEGlobal::midiBusy=true;
+
+ bool extsync = MusEGlobal::extSyncFlag.value();
+
//
// TODO: syntis should directly write into recordEventList
//
- for (iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id) {
- MidiDevice* md = *id;
-
- // klumsy hack for synti devices:
- if(md->isSynti())
+ for (iMidiDevice id = MusEGlobal::midiDevices.begin(); id != MusEGlobal::midiDevices.end(); ++id)
+ {
+ MidiDevice* md = *id;
+
+ // klumsy hack for MESS synti devices:
+ if(md->isSynti())
+ {
+ SynthI* s = (SynthI*)md;
+ while (s->eventsPending())
+ {
+ MusECore::MidiRecordEvent ev = s->receiveEvent();
+ md->recordEvent(ev);
+ }
+ }
+
+ md->collectMidiEvents();
+
+ // Take snapshots of the current sizes of the recording fifos,
+ // because they may change while here in process, asynchronously.
+ md->beforeProcess();
+
+ //
+ // --------- Handle midi events for audio tracks -----------
+ //
+
+ int port = md->midiPort(); // Port should be same as event.port() from this device. Same idea event.channel().
+ if(port < 0)
+ continue;
+
+ for(int chan = 0; chan < MIDI_CHANNELS; ++chan)
+ {
+ MusECore::MidiRecFifo& rf = md->recordEvents(chan);
+ int count = md->tmpRecordCount(chan);
+ for(int i = 0; i < count; ++i)
+ {
+ MusECore::MidiRecordEvent event(rf.peek(i));
+
+ int etype = event.type();
+ if(etype == MusECore::ME_CONTROLLER || etype == MusECore::ME_PITCHBEND || etype == MusECore::ME_PROGRAM)
{
- SynthI* s = (SynthI*)md;
- while (s->eventsPending())
+ int ctl, val;
+ if(etype == MusECore::ME_CONTROLLER)
{
- MusECore::MidiRecordEvent ev = s->receiveEvent();
- md->recordEvent(ev);
+ ctl = event.dataA();
+ val = event.dataB();
}
+ else if(etype == MusECore::ME_PITCHBEND)
+ {
+ ctl = MusECore::CTRL_PITCH;
+ val = event.dataA();
+ }
+ else if(etype == MusECore::ME_PROGRAM)
+ {
+ ctl = MusECore::CTRL_PROGRAM;
+ val = event.dataA();
+ }
+
+ // Midi learn!
+ MusEGlobal::midiLearnPort = port;
+ MusEGlobal::midiLearnChan = chan;
+ MusEGlobal::midiLearnCtrl = ctl;
+
+ // Send to audio tracks...
+ for (MusECore::iTrack t = MusEGlobal::song->tracks()->begin(); t != MusEGlobal::song->tracks()->end(); ++t)
+ {
+ if((*t)->isMidiTrack())
+ continue;
+ MusECore::AudioTrack* track = static_cast<MusECore::AudioTrack*>(*t);
+ MidiAudioCtrlMap* macm = track->controller()->midiControls();
+ int h = macm->index_hash(port, chan, ctl);
+ std::pair<ciMidiAudioCtrlMap, ciMidiAudioCtrlMap> range = macm->equal_range(h);
+ for(ciMidiAudioCtrlMap imacm = range.first; imacm != range.second; ++imacm)
+ {
+ const MidiAudioCtrlStruct* macs = &imacm->second;
+ int actrl = macs->audioCtrlId();
+
+ iCtrlList icl = track->controller()->find(actrl);
+ if(icl == track->controller()->end())
+ continue;
+ CtrlList* cl = icl->second;
+ double dval = midi2AudioCtrlValue(cl, macs, ctl, val);
+
+ // Time here needs to be frames always.
+ unsigned int ev_t = event.time();
+ unsigned int t = ev_t;
+
+#ifdef _AUDIO_USE_TRUE_FRAME_
+ unsigned int pframe = _previousPos.frame();
+#else
+ unsigned int pframe = _pos.frame();
+#endif
+ if(pframe > t) // Technically that's an error, shouldn't happen
+ t = 0;
+ else
+ // Subtract the current audio position frame
+ t -= pframe;
+
+ // Add the current running sync frame to make the control processing happy
+ t += syncFrame;
+ track->addScheduledControlEvent(actrl, dval, t);
+
+ // Rec automation...
+
+ // For the record time, if stopped we don't want the circular running position,
+ // just the static one.
+ unsigned int rec_t = isPlaying() ? ev_t : pframe;
+
+ if(!MusEGlobal::automation)
+ continue;
+ AutomationType at = track->automationType();
+ // Unlike our built-in gui controls, there is not much choice here but to
+ // just do this:
+ if ( (at == AUTO_WRITE) ||
+ (at == AUTO_TOUCH && MusEGlobal::audio->isPlaying()) )
+ //if(isPlaying() && (at == AUTO_WRITE || at == AUTO_TOUCH)) DELETETHIS
+ track->enableController(actrl, false);
+ if(isPlaying())
+ {
+ if(at == AUTO_WRITE || at == AUTO_TOUCH)
+ track->recEvents()->push_back(CtrlRecVal(rec_t, actrl, dval));
+ }
+ else
+ {
+ if(at == AUTO_WRITE)
+ track->recEvents()->push_back(CtrlRecVal(rec_t, actrl, dval));
+ else if(at == AUTO_TOUCH)
+ // In touch mode and not playing. Send directly to controller list.
+ // Add will replace if found.
+ cl->add(rec_t, dval);
+ }
+ }
+ }
}
-
- md->collectMidiEvents();
-
- // Take snapshots of the current sizes of the recording fifos,
- // because they may change while here in process, asynchronously.
- md->beforeProcess();
- }
+ }
+ }
+ }
- bool extsync = MusEGlobal::extSyncFlag.value();
for (MusECore::iMidiTrack t = MusEGlobal::song->midis()->begin(); t != MusEGlobal::song->midis()->end(); ++t)
{
MusECore::MidiTrack* track = *t;
@@ -934,15 +1053,30 @@ void Audio::processMidi()
for(int i = 0; i < count; ++i)
{
- MusECore::MidiPlayEvent event(rf.peek(i));
+ MusECore::MidiRecordEvent event(rf.peek(i));
event.setPort(port);
// dont't echo controller changes back to software
// synthesizer:
if(!dev->isSynti() && md && track->recEcho())
+ {
+ // All recorded events arrived in the previous period. Shift into this period for playback.
+ unsigned int et = event.time();
+#ifdef _AUDIO_USE_TRUE_FRAME_
+ unsigned int t = et - _previousPos.frame() + _pos.frame() + frameOffset;
+#else
+ unsigned int t = et + frameOffset;
+#endif
+ event.setTime(t);
md->addScheduledEvent(event);
- // If syncing externally the event time is already in units of ticks, set above. p3.3.25
- if(!extsync)
- event.setTime(MusEGlobal::tempomap.frame2tick(event.time())); // set tick time
+ event.setTime(et); // Restore for recording.
+ }
+
+ // Make sure the event is recorded in units of ticks.
+ if(extsync)
+ event.setTime(event.tick()); // HACK: Transfer the tick to the frame time
+ else
+ event.setTime(MusEGlobal::tempomap.frame2tick(event.time()));
+
if(recording)
rl->add(event);
}
@@ -953,7 +1087,7 @@ void Audio::processMidi()
int count = dev->tmpRecordCount(channel);
for(int i = 0; i < count; ++i)
{
- MusECore::MidiPlayEvent event(rf.peek(i));
+ MusECore::MidiRecordEvent event(rf.peek(i));
int defaultPort = devport;
int drumRecPitch=0; //prevent compiler warning: variable used without initialization
MusECore::MidiController *mc = 0;
@@ -1073,7 +1207,16 @@ void Audio::processMidi()
if (!dev->isSynti())
{
- //Check if we're outputting to another port than default:
+ // All recorded events arrived in previous period. Shift into this period for playback.
+ // frameoffset needed to make process happy.
+ unsigned int et = event.time();
+#ifdef _AUDIO_USE_TRUE_FRAME_
+ unsigned int t = et - _previousPos.frame() + _pos.frame() + frameOffset;
+#else
+ unsigned int t = et + frameOffset;
+#endif
+ event.setTime(t);
+ // Check if we're outputting to another port than default:
if (devport == defaultPort) {
event.setPort(port);
if(md && track->recEcho())
@@ -1085,14 +1228,18 @@ void Audio::processMidi()
if(mdAlt && track->recEcho())
mdAlt->addScheduledEvent(event);
}
+ event.setTime(et); // Restore for recording.
+
// Shall we activate meters even while rec echo is off? Sure, why not...
if(event.isNote() && event.dataB() > track->activity())
track->setActivity(event.dataB());
}
- // If syncing externally the event time is already in units of ticks, set above. p3.3.25
- if(!extsync)
- event.setTime(MusEGlobal::tempomap.frame2tick(event.time())); // set tick time
+ // Make sure the event is recorded in units of ticks.
+ if(extsync)
+ event.setTime(event.tick()); // HACK: Transfer the tick to the frame time
+ else
+ event.setTime(MusEGlobal::tempomap.frame2tick(event.time()));
// Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
if (recording)