summaryrefslogtreecommitdiff
path: root/muse2/muse/midi.cpp
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2011-09-09 10:04:11 +0000
committerTim E. Real <termtech@rogers.com>2011-09-09 10:04:11 +0000
commit2120ea4f083228dde0d7307203391a4ec8f57e2d (patch)
tree3f8b5c3aeb6691c962d42fb4e3a01bcf511f023f /muse2/muse/midi.cpp
parentad72332d2cbd0d22e5d49d9fd60c985e563b17d0 (diff)
Mostly engine fixes/corrections. Please see ChangeLog.
Diffstat (limited to 'muse2/muse/midi.cpp')
-rw-r--r--muse2/muse/midi.cpp756
1 files changed, 209 insertions, 547 deletions
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index 42f5bed7..39642348 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -4,6 +4,7 @@
// $Id: midi.cpp,v 1.43.2.22 2009/11/09 20:28:28 terminator356 Exp $
//
// (C) Copyright 1999/2004 Werner Schweer (ws@seh.de)
+// (C) Copyright 2011 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -216,9 +217,7 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
|| ((ev.channel() == track->outChannel()) && (ev.port() == track->outPort()))))
continue;
unsigned tick = ev.time();
- // Added by Tim. p3.3.8
- // Added by T356.
if(doLoops)
{
if(tick >= song->lPos().tick() && tick < song->rPos().tick())
@@ -475,13 +474,10 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
// read NoteOn events and remove corresponding NoteOffs
//---------------------------------------------------
- // Added by Tim. p3.3.8
- // Loop removed by flo
for (iEvent i = mel.begin(); i != mel.end(); ++i) {
Event ev = i->second;
if (ev.isNote()) {
if (!ev.isNoteOff()) {
- // Added by Tim. p3.3.8
// If the event length is not zero, it means the event and its
// note on/off have already been taken care of. So ignore it.
@@ -520,10 +516,10 @@ void buildMidiEventList(EventList* del, const MPEventList* el, MidiTrack* track,
if (k==i)
//this will never happen, because i->second has to be a NOTE ON,
//while k has to be a NOTE OFF. but in case something changes:
- printf("ERROR: THIS SHOULD NEVER HAPPEN: k==i in midi.cpp:buildMidiEventList()\n");
+ printf("ERROR: THIS SHOULD NEVER HAPPEN: k==i in midi.cpp:buildMidiEventList()\n");
else
- mel.erase(k);
-
+ mel.erase(k);
+ i = mel.begin(); // p4.0.34
continue;
}
}
@@ -690,8 +686,6 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
int defaultPort = port;
MidiDevice* md = midiPorts[port].device();
- MPEventList* playEvents = md->playEvents();
- MPEventList* stuckNotes = md->stuckNotes();
PartList* pl = track->parts();
for (iPart p = pl->begin(); p != pl->end(); ++p) {
@@ -714,7 +708,7 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
continue;
unsigned stick = (offset > cts) ? 0 : cts - offset;
unsigned etick = nts - offset;
- // By T356. Do not play events which are past the end of this part.
+ // Do not play events which are past the end of this part.
if(etick > partLen)
continue;
@@ -776,33 +770,26 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
int veloOff = ev.veloOff();
if (port == defaultPort) {
- //printf("Adding event normally: frame=%d port=%d channel=%d pitch=%d velo=%d\n",frame, port, channel, pitch, velo);
-
- // p3.3.25
// If syncing to external midi sync, we cannot use the tempo map.
- // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
+ // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. p3.3.25
if(extSyncFlag.value())
- playEvents->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo));
+ md->addScheduledEvent(MidiPlayEvent(tick, port, channel, ME_NOTEON, pitch, velo));
else
-
- playEvents->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo));
+ md->addScheduledEvent(MidiPlayEvent(frame, port, channel, ME_NOTEON, pitch, velo));
- stuckNotes->add(MidiPlayEvent(tick + len, port, channel,
- veloOff ? 0x80 : 0x90, pitch, veloOff));
+ md->addStuckNote(MidiPlayEvent(tick + len, port, channel,
+ veloOff ? ME_NOTEOFF : ME_NOTEON, pitch, veloOff));
}
else { //Handle events to different port than standard.
MidiDevice* mdAlt = midiPorts[port].device();
if (mdAlt) {
-
- // p3.3.25
- if(extSyncFlag.value())
- mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel, 0x90, pitch, velo));
+ if(extSyncFlag.value()) // p3.3.25
+ mdAlt->addScheduledEvent(MidiPlayEvent(tick, port, channel, ME_NOTEON, pitch, velo));
else
+ mdAlt->addScheduledEvent(MidiPlayEvent(frame, port, channel, ME_NOTEON, pitch, velo));
- mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel, 0x90, pitch, velo));
-
- mdAlt->stuckNotes()->add(MidiPlayEvent(tick + len, port, channel,
- veloOff ? 0x80 : 0x90, pitch, veloOff));
+ mdAlt->addStuckNote(MidiPlayEvent(tick + len, port, channel,
+ veloOff ? ME_NOTEOFF : ME_NOTEON, pitch, veloOff));
}
}
@@ -811,7 +798,6 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
}
break;
- // Added by T356.
case Controller:
{
if (track->type() == Track::DRUM)
@@ -829,37 +815,30 @@ void Audio::collectEvents(MidiTrack* track, unsigned int cts, unsigned int nts)
MidiDevice* mdAlt = midiPorts[port].device();
if(mdAlt)
{
- // p3.3.25
// If syncing to external midi sync, we cannot use the tempo map.
- // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
+ // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames. p3.3.25
if(extSyncFlag.value())
- mdAlt->playEvents()->add(MidiPlayEvent(tick, port, channel,
+ mdAlt->addScheduledEvent(MidiPlayEvent(tick, port, channel,
ME_CONTROLLER, ctl | pitch, ev.dataB()));
else
- mdAlt->playEvents()->add(MidiPlayEvent(frame, port, channel,
+ mdAlt->addScheduledEvent(MidiPlayEvent(frame, port, channel,
ME_CONTROLLER, ctl | pitch, ev.dataB()));
-
}
break;
}
}
- // p3.3.25
- if(extSyncFlag.value())
- playEvents->add(MidiPlayEvent(tick, port, channel, ev));
+ if(extSyncFlag.value()) // p3.3.25
+ md->addScheduledEvent(MidiPlayEvent(tick, port, channel, ev));
else
-
- playEvents->add(MidiPlayEvent(frame, port, channel, ev));
+ md->addScheduledEvent(MidiPlayEvent(frame, port, channel, ev));
}
break;
-
-
+
default:
- // p3.3.25
- if(extSyncFlag.value())
- playEvents->add(MidiPlayEvent(tick, port, channel, ev));
+ if(extSyncFlag.value()) // p3.3.25
+ md->addScheduledEvent(MidiPlayEvent(tick, port, channel, ev));
else
-
- playEvents->add(MidiPlayEvent(frame, port, channel, ev));
+ md->addScheduledEvent(MidiPlayEvent(frame, port, channel, ev));
break;
}
@@ -885,30 +864,6 @@ void Audio::processMidi()
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
MidiDevice* md = *id;
- //
- // erase already played events:
- //
- ///MPEventList* playEvents = md->playEvents();
- ///iMPEvent nextPlayEvent = md->nextPlayEvent();
-
- //if(md->playEvents()->size())
- //{
- //printf("Audio::processMidi before erase md play events size:%d nextPlayEvent isEnd:%d\n", md->playEvents()->size(), md->nextPlayEvent() == md->playEvents()->end());
- // printf("Audio::processMidi md play events size:%d first item:\n", md->playEvents()->size());
- // md->playEvents()->begin()->dump();
- //}
-
- // p4.0.15 Tim. Moved into MidiJackDevice::processMidi (for Jack), and MidiSeq::processTimerTick (for ALSA).
- // Why do this here? Instead, let each device erase their just-played events.
- ///playEvents->erase(playEvents->begin(), nextPlayEvent);
-
- //if(playEvents->size())
- //{
- // printf("Audio::processMidi after erase md play events size:%d nextPlayEvent isEnd:%d events:\n", playEvents->size(), nextPlayEvent == playEvents->end());
- //for(iMPEvent ie = playEvents->begin(); ie != playEvents->end(); ++ie)
- // ie->dump();
- //}
-
// klumsy hack for synti devices:
if(md->isSynti())
{
@@ -920,10 +875,6 @@ void Audio::processMidi()
}
}
- // Is it a Jack midi device?
- //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
- //if(mjd)
- // mjd->collectMidiEvents();
md->collectMidiEvents();
// Take snapshots of the current sizes of the recording fifos,
@@ -931,33 +882,14 @@ void Audio::processMidi()
md->beforeProcess();
}
- // p4.0.15 Tim. Moved into SynthI::getData.
- // Why do this here? Instead, let each device erase their just-played events.
- ///MPEventList* playEvents = metronome->playEvents();
- ///iMPEvent nextPlayEvent = metronome->nextPlayEvent();
- ///playEvents->erase(playEvents->begin(), nextPlayEvent);
-
- // p3.3.25
bool extsync = extSyncFlag.value();
-
for (iMidiTrack t = song->midis()->begin(); t != song->midis()->end(); ++t)
{
MidiTrack* track = *t;
int port = track->outPort();
MidiDevice* md = midiPorts[port].device();
-
- // Changed by Tim. p3.3.8
- //if(md == 0)
- // continue;
- //MPEventList* playEvents = md->playEvents();
- //if (playEvents == 0)
- // continue;
- //if (!track->isMute())
- MPEventList* playEvents = 0;
if(md)
{
- playEvents = md->playEvents();
-
// only add track events if the track is unmuted
if(!track->isMute())
{
@@ -971,66 +903,26 @@ void Audio::processMidi()
//
if (track->recordFlag())
{
- //int portMask = track->inPortMask();
- // p3.3.38 Removed
- //unsigned int portMask = track->inPortMask();
- //int channelMask = track->inChannelMask();
-
MPEventList* rl = track->mpevents();
MidiPort* tport = &midiPorts[port];
-
- // p3.3.38
- //for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
- //{
RouteList* irl = track->inRoutes();
for(ciRoute r = irl->begin(); r != irl->end(); ++r)
{
- //if(!r->isValid() || (r->type != Route::ALSA_MIDI_ROUTE && r->type != Route::JACK_MIDI_ROUTE))
- //if(!r->isValid() || (r->type != Route::MIDI_DEVICE_ROUTE))
if(!r->isValid() || (r->type != Route::MIDI_PORT_ROUTE)) // p3.3.49
continue;
-
- int devport = r->midiPort; // p3.3.49
+ int devport = r->midiPort; //
if (devport == -1)
- continue;
-
- //MidiDevice* dev = *id;
- //MidiDevice* dev = r->device;
- MidiDevice* dev = midiPorts[devport].device(); // p3.3.49
+ continue;
+ MidiDevice* dev = midiPorts[devport].device(); //
if(!dev)
continue;
-
-
- // p3.3.50 Removed
- //int channel = r->channel;
- // NOTE: TODO: Special for input device sysex 'channel' marked as -1, ** IF we end up going with that method **.
- // This would mean having a separate 'System' channel listed in the routing popups.
- // The other alternative is to accept sysex from a device as long as ANY regular channel is routed from it,
- // this does not require a 'System' channel listed in the routing popups.
- // But that requires more code below... Done.
- //if(channel == -1)
- //channel = MIDI_CHANNELS; // Special channel '17'
- // continue;
-
- //int devport = dev->midiPort();
-
- // record only from ports marked in portMask:
- //if (devport == -1 || !(portMask & (1 << devport)))
- //if (devport == -1)
- // continue;
-
- //MREventList* el = dev->recordEvents();
- //MidiFifo& rf = dev->recordEvents();
-
-
- int channelMask = r->channel; // p3.3.50
+ int channelMask = r->channel;
if(channelMask == -1 || channelMask == 0)
continue;
- for(int channel = 0; channel < MIDI_CHANNELS; ++channel) // p3.3.50
+ for(int channel = 0; channel < MIDI_CHANNELS; ++channel)
{
if(!(channelMask & (1 << channel)))
continue;
-
if(!dev->sysexFIFOProcessed())
{
// Set to the sysex fifo at first.
@@ -1041,323 +933,192 @@ void Audio::processMidi()
for(int i = 0; i < count; ++i)
{
MidiPlayEvent event(rf.peek(i));
-
- //unsigned time = event.time() + segmentSize*(segmentCount-1);
- //unsigned time = event.time() + (extsync ? MusEConfig::config.division/24 : segmentSize*(segmentCount-1));
- //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
- //event.setTime(time);
- //if(!extsync)
- // event.setTime(event.time() + segmentSize*(segmentCount-1));
-
event.setPort(port);
-
// dont't echo controller changes back to software
// synthesizer:
if(!dev->isSynti() && md && track->recEcho())
- playEvents->add(event);
-
- // If syncing externally the event time is already in units of ticks, set above.
+ md->addScheduledEvent(event);
+ // If syncing externally the event time is already in units of ticks, set above. p3.3.25
if(!extsync)
- {
- //time = tempomap.frame2tick(event.time());
- //event.setTime(time); // set tick time
event.setTime(tempomap.frame2tick(event.time())); // set tick time
- }
-
if(recording)
rl->add(event);
}
-
dev->setSysexFIFOProcessed(true);
}
- // Set to the sysex fifo at first.
- ///MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
- // Get the frozen snapshot of the size.
- ///int count = dev->tmpRecordCount(MIDI_CHANNELS);
-
- // Iterate once for sysex fifo (if needed), once for channel fifos.
- ///for(int sei = 0; sei < 2; ++sei)
+ MidiRecFifo& rf = dev->recordEvents(channel);
+ int count = dev->tmpRecordCount(channel);
+ for(int i = 0; i < count; ++i)
{
- // If on first pass, do sysex fifo.
- /*
- if(sei == 0)
- {
- // Ignore any further channel routes on this device if already done here.
- if(dev->sysexFIFOProcessed())
- continue;
- // Go ahead and set this now.
- dev->setSysexFIFOProcessed(true);
- // Allow it to fall through with the sysex fifo and count...
- }
- else
- {
- // We're on the second pass, do channel fifos.
- rf = dev->recordEvents(channel);
- // Get the frozen snapshot of the size.
- count = dev->tmpRecordCount(channel);
- }
- */
-
- MidiRecFifo& rf = dev->recordEvents(channel);
- int count = dev->tmpRecordCount(channel);
-
- //for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
- for(int i = 0; i < count; ++i)
- {
- MidiPlayEvent event(rf.peek(i));
-
- //int channel = ie->channel();
- ///int channel = event.channel();
-
- int defaultPort = devport;
- ///if (!(channelMask & (1 << channel)))
- ///{
- /// continue;
- ///}
-
- //MidiPlayEvent event(*ie);
- int drumRecPitch=0; //prevent compiler warning: variable used without initialization
- MidiController *mc = 0;
- int ctl = 0;
-
- //Hmmm, hehhh...
- // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
- // But not before 0.7 (ml)
-
- int prePitch = 0, preVelo = 0;
-
- event.setChannel(track->outChannel());
-
- if (event.isNote() || event.isNoteOff())
+ MidiPlayEvent event(rf.peek(i));
+ int defaultPort = devport;
+ int drumRecPitch=0; //prevent compiler warning: variable used without initialization
+ MidiController *mc = 0;
+ int ctl = 0;
+
+ //Hmmm, hehhh...
+ // TODO: Clean up a bit around here when it comes to separate events for rec & for playback.
+ // But not before 0.7 (ml)
+
+ int prePitch = 0, preVelo = 0;
+
+ event.setChannel(track->outChannel());
+
+ if (event.isNote() || event.isNoteOff())
+ {
+ //
+ // apply track values
+ //
+
+ //Apply drum inkey:
+ if (track->type() == Track::DRUM)
+ {
+ int pitch = event.dataA();
+ //Map note that is played according to drumInmap
+ drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote;
+ devport = drumMap[(unsigned int)drumInmap[pitch]].port;
+ event.setPort(devport);
+ channel = drumMap[(unsigned int)drumInmap[pitch]].channel;
+ event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote);
+ event.setChannel(channel);
+ }
+ else
+ { //Track transpose if non-drum
+ prePitch = event.dataA();
+ int pitch = prePitch + track->transposition;
+ if (pitch > 127)
+ pitch = 127;
+ if (pitch < 0)
+ pitch = 0;
+ event.setA(pitch);
+ }
+
+ if (!event.isNoteOff())
+ {
+ preVelo = event.dataB();
+ int velo = preVelo + track->velocity;
+ velo = (velo * track->compression) / 100;
+ if (velo > 127)
+ velo = 127;
+ if (velo < 1)
+ velo = 1;
+ event.setB(velo);
+ }
+ }
+ else
+ if(event.type() == ME_CONTROLLER)
+ {
+ if(track->type() == Track::DRUM)
{
- //
- // apply track values
- //
-
- //Apply drum inkey:
- if (track->type() == Track::DRUM)
- {
- int pitch = event.dataA();
- //Map note that is played according to drumInmap
- drumRecPitch = drumMap[(unsigned int)drumInmap[pitch]].enote;
- devport = drumMap[(unsigned int)drumInmap[pitch]].port;
- event.setPort(devport);
- channel = drumMap[(unsigned int)drumInmap[pitch]].channel;
- event.setA(drumMap[(unsigned int)drumInmap[pitch]].anote);
- event.setChannel(channel);
- }
- else
- { //Track transpose if non-drum
- prePitch = event.dataA();
- int pitch = prePitch + track->transposition;
- if (pitch > 127)
- pitch = 127;
- if (pitch < 0)
- pitch = 0;
- event.setA(pitch);
+ ctl = event.dataA();
+ // Regardless of what port the event came from, is it a drum controller event
+ // according to the track port's instrument?
+ mc = tport->drumController(ctl);
+ if(mc)
+ {
+ int pitch = ctl & 0x7f;
+ ctl &= ~0xff;
+ int dmindex = drumInmap[pitch] & 0x7f;
+ //Map note that is played according to drumInmap
+ drumRecPitch = drumMap[dmindex].enote;
+ devport = drumMap[dmindex].port;
+ event.setPort(devport);
+ channel = drumMap[dmindex].channel;
+ event.setA(ctl | drumMap[dmindex].anote);
+ event.setChannel(channel);
+ }
+ }
+ }
+
+ // MusE uses a fixed clocks per quarternote of 24.
+ // At standard 384 ticks per quarternote for example,
+ // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks').
+ // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent(). p3.3.35
+ // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
+
+ // dont't echo controller changes back to software
+ // synthesizer:
+
+ if (!dev->isSynti())
+ {
+ //Check if we're outputting to another port than default:
+ if (devport == defaultPort) {
+ event.setPort(port);
+ if(md && track->recEcho())
+ //playEvents->add(event);
+ md->addScheduledEvent(event);
}
-
- if (!event.isNoteOff())
- {
- preVelo = event.dataB();
- int velo = preVelo + track->velocity;
- velo = (velo * track->compression) / 100;
- if (velo > 127)
- velo = 127;
- if (velo < 1)
- velo = 1;
- event.setB(velo);
+ else {
+ // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
+ MidiDevice* mdAlt = midiPorts[devport].device();
+ if(mdAlt && track->recEcho())
+ //mdAlt->playEvents()->add(event);
+ mdAlt->addScheduledEvent(event);
}
- }
- // Added by T356.
- else
- if(event.type() == ME_CONTROLLER)
- {
- if(track->type() == Track::DRUM)
- {
- ctl = event.dataA();
- // Regardless of what port the event came from, is it a drum controller event
- // according to the track port's instrument?
- mc = tport->drumController(ctl);
- if(mc)
+ // 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(tempomap.frame2tick(event.time())); // set tick time
+
+ // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
+ if (recording)
+ {
+ // In these next steps, it is essential to set the recorded event's port
+ // to the track port so buildMidiEventList will accept it. Even though
+ // the port may have no device "<none>".
+ //
+ if (track->type() == Track::DRUM)
{
- int pitch = ctl & 0x7f;
- ctl &= ~0xff;
- int dmindex = drumInmap[pitch] & 0x7f;
- //Map note that is played according to drumInmap
- drumRecPitch = drumMap[dmindex].enote;
- devport = drumMap[dmindex].port;
- event.setPort(devport);
- channel = drumMap[dmindex].channel;
- event.setA(ctl | drumMap[dmindex].anote);
- event.setChannel(channel);
- }
- }
- }
-
- // p3.3.25
- // MusE uses a fixed clocks per quarternote of 24.
- // At standard 384 ticks per quarternote for example,
- // 384/24=16 for a division of 16 sub-frames (16 MusE 'ticks').
- // That is what we'll use if syncing externally.
- //unsigned time = event.time() + segmentSize*(segmentCount-1);
- //unsigned time = event.time() + (extsync ? MusEConfig::config.division/24 : segmentSize*(segmentCount-1));
- // p3.3.34
- // Oops, use the current tick.
- //unsigned time = extsync ? curTickPos : (event.time() + segmentSize*(segmentCount-1));
- //event.setTime(time);
- // p3.3.35
- // If ext sync, events are now time-stamped with last tick in MidiDevice::recordEvent().
- // TODO: Tested, but record resolution not so good. Switch to wall clock based separate list in MidiDevice.
- // p3.3.36
- //if(!extsync)
- // event.setTime(event.time() + segmentSize*(segmentCount-1));
-
- // dont't echo controller changes back to software
- // synthesizer:
-
- if (!dev->isSynti())
- {
- //Check if we're outputting to another port than default:
- if (devport == defaultPort) {
- event.setPort(port);
- if(md && track->recEcho())
- playEvents->add(event);
- }
- else {
- // Hmm, this appears to work, but... Will this induce trouble with md->setNextPlayEvent??
- MidiDevice* mdAlt = midiPorts[devport].device();
- if(mdAlt && track->recEcho())
- mdAlt->playEvents()->add(event);
- }
- // Shall we activate meters even while rec echo is off? Sure, why not...
- if(event.isNote() && event.dataB() > track->activity())
- track->setActivity(event.dataB());
- }
-
- // p3.3.25
- // If syncing externally the event time is already in units of ticks, set above.
- if(!extsync)
- {
- // p3.3.35
- //time = tempomap.frame2tick(event.time());
- //event.setTime(time); // set tick time
- event.setTime(tempomap.frame2tick(event.time())); // set tick time
- }
-
- // Special handling of events stored in rec-lists. a bit hACKish. TODO: Clean up (after 0.7)! :-/ (ml)
- if (recording)
- {
- // In these next steps, it is essential to set the recorded event's port
- // to the track port so buildMidiEventList will accept it. Even though
- // the port may have no device "<none>".
- //
- if (track->type() == Track::DRUM)
- {
- // Is it a drum controller event?
- if(mc)
- {
- MidiPlayEvent drumRecEvent = event;
- drumRecEvent.setA(ctl | drumRecPitch);
- // In this case, preVelo is simply the controller value.
- drumRecEvent.setB(preVelo);
- drumRecEvent.setPort(port); //rec-event to current port
- drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
- rl->add(drumRecEvent);
- }
- else
- {
-
- MidiPlayEvent drumRecEvent = event;
- drumRecEvent.setA(drumRecPitch);
- drumRecEvent.setB(preVelo);
- // Changed by T356.
- // Tested: Events were not being recorded for a drum map entry pointing to a
- // different port. This must have been wrong - buildMidiEventList would ignore this.
- //drumRecEvent.setPort(devport);
- drumRecEvent.setPort(port); //rec-event to current port
-
- drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
- rl->add(drumRecEvent);
- }
+ // Is it a drum controller event?
+ if(mc)
+ {
+ MidiPlayEvent drumRecEvent = event;
+ drumRecEvent.setA(ctl | drumRecPitch);
+ // In this case, preVelo is simply the controller value.
+ drumRecEvent.setB(preVelo);
+ drumRecEvent.setPort(port); //rec-event to current port
+ drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
+ rl->add(drumRecEvent);
}
- else
+ else
{
- // Restore record-pitch to non-transposed value since we don't want the note transposed twice next
- MidiPlayEvent recEvent = event;
- if (prePitch)
- recEvent.setA(prePitch);
- if (preVelo)
- recEvent.setB(preVelo);
- recEvent.setPort(port);
- recEvent.setChannel(track->outChannel());
-
- rl->add(recEvent);
- }
- }
+ MidiPlayEvent drumRecEvent = event;
+ drumRecEvent.setA(drumRecPitch);
+ drumRecEvent.setB(preVelo);
+ // Tested: Events were not being recorded for a drum map entry pointing to a
+ // different port. This must have been wrong - buildMidiEventList would ignore this. Tim.
+ //drumRecEvent.setPort(devport);
+ drumRecEvent.setPort(port); //rec-event to current port
+
+ drumRecEvent.setChannel(track->outChannel()); //rec-event to current channel
+ rl->add(drumRecEvent);
+ }
+ }
+ else
+ {
+ // Restore record-pitch to non-transposed value since we don't want the note transposed twice next
+ MidiPlayEvent recEvent = event;
+ if (prePitch)
+ recEvent.setA(prePitch);
+ if (preVelo)
+ recEvent.setB(preVelo);
+ recEvent.setPort(port);
+ recEvent.setChannel(track->outChannel());
+
+ rl->add(recEvent);
+ }
+ }
}
- }
}
}
}
- // Added by Tim. p3.3.8
- // Removed p4.0.15
- ///if(md)
- /// md->setNextPlayEvent(playEvents->begin());
- //if(md)
- //{
- // if(md->nextPlayEvent() != playEvents->begin())
- // printf("Audio::processMidi md->nextPlayEvent() != playEvents->begin()\n");
- //}
}
- //
- // clear all recorded events in midiDevices
- // process stuck notes
- //
- for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
- MidiDevice* md = *id;
-
- ///md->recordEvents()->clear();
- // By T356. Done processing this rec buffer, now flip to the other one.
- ///md->flipRecBuffer();
- // We are done with the 'frozen' recording fifos, remove the events.
- md->afterProcess();
-
- MPEventList* stuckNotes = md->stuckNotes();
- MPEventList* playEvents = md->playEvents();
-
- iMPEvent k;
- for (k = stuckNotes->begin(); k != stuckNotes->end(); ++k) {
- if (k->time() >= nextTickPos)
- break;
- MidiPlayEvent ev(*k);
-
- // p3.3.25
- //int frame = tempomap.tick2frame(k->time()) + frameOffset;
- if(extsync)
- {
- ev.setTime(k->time());
- }
- else
- {
- int frame = tempomap.tick2frame(k->time()) + frameOffset;
- ev.setTime(frame);
- }
-
- // p3.3.25
- //ev.setTime(frame);
-
- playEvents->add(ev);
- }
- stuckNotes->erase(stuckNotes->begin(), k);
- // Removed p4.0.15 Tim.
- ///md->setNextPlayEvent(playEvents->begin());
- //if(md->nextPlayEvent() != playEvents->begin())
- // printf("Audio::processMidi clear notes: md->nextPlayEvent() != playEvents->begin()\n");
- }
-
//---------------------------------------------------
// insert metronome clicks
//---------------------------------------------------
@@ -1366,35 +1127,21 @@ void Audio::processMidi()
if (MusEGlobal::midiClickFlag)
md = midiPorts[MusEGlobal::clickPort].device();
if (song->click() && (isPlaying() || state == PRECOUNT)) {
- MPEventList* playEvents = 0;
- MPEventList* stuckNotes = 0;
- if (md) {
- playEvents = md->playEvents();
- stuckNotes = md->stuckNotes();
- }
int bar, beat;
unsigned tick;
bool isMeasure = false;
while (midiClick < nextTickPos) {
if (isPlaying()) {
- ///sigmap.tickValues(midiClick, &bar, &beat, &tick);
AL::sigmap.tickValues(midiClick, &bar, &beat, &tick);
isMeasure = beat == 0;
}
else if (state == PRECOUNT) {
isMeasure = (clickno % clicksMeasure) == 0;
}
- // p3.3.25
//int frame = tempomap.tick2frame(midiClick) + frameOffset;
- int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset;
+ int evtime = extsync ? midiClick : tempomap.tick2frame(midiClick) + frameOffset; // p3.3.25
- // p3.3.25
- //MidiPlayEvent ev(frame, MusEGlobal::clickPort, MusEGlobal::clickChan, ME_NOTEON,
- MidiPlayEvent ev(evtime, MusEGlobal::clickPort, MusEGlobal::clickChan, ME_NOTEON,
- MusEGlobal::beatClickNote, MusEGlobal::beatClickVelo);
-
if (md) {
- // p3.3.25
//MidiPlayEvent ev(frame, MusEGlobal::clickPort, MusEGlobal::clickChan, ME_NOTEON,
MidiPlayEvent ev(evtime, MusEGlobal::clickPort, MusEGlobal::clickChan, ME_NOTEON,
MusEGlobal::beatClickNote, MusEGlobal::beatClickVelo);
@@ -1403,32 +1150,20 @@ void Audio::processMidi()
ev.setA(MusEGlobal::measureClickNote);
ev.setB(MusEGlobal::measureClickVelo);
}
- playEvents->add(ev);
- }
- if (MusEGlobal::audioClickFlag) {
- // p3.3.25
- //MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0);
- MidiPlayEvent ev1(evtime, 0, 0, ME_NOTEON, 0, 0);
+ md->addScheduledEvent(ev);
- ev1.setA(isMeasure ? 0 : 1);
- metronome->playEvents()->add(ev1);
- }
- if (md) {
ev.setB(0);
- // p3.3.25
- // Removed. Why was this here?
- //frame = tempomap.tick2frame(midiClick+20) + frameOffset;
- //
- // Does it mean this should be changed too?
- // No, stuck notes are in units of ticks, not frames like (normal, non-external) play events...
ev.setTime(midiClick+10);
-
- if (md)
- stuckNotes->add(ev);
+ md->addStuckNote(ev);
+ }
+ if (MusEGlobal::audioClickFlag) {
+ //MidiPlayEvent ev1(frame, 0, 0, ME_NOTEON, 0, 0);
+ MidiPlayEvent ev(evtime, 0, 0, ME_NOTEON, 0, 0);
+ ev.setA(isMeasure ? 0 : 1);
+ metronome->addScheduledEvent(ev);
+ // Built-in metronome synth does not use stuck notes...
}
-
if (isPlaying())
- ///midiClick = sigmap.bar2tick(bar, beat+1, 0);
midiClick = AL::sigmap.bar2tick(bar, beat+1, 0);
else if (state == PRECOUNT) {
midiClick += ticksBeat;
@@ -1438,94 +1173,21 @@ void Audio::processMidi()
state = START_PLAY;
}
}
- // Removed p4.0.15 Tim.
- ///if (md)
- /// md->setNextPlayEvent(playEvents->begin());
- //if(md)
- //{
- // if(md->nextPlayEvent() != playEvents->begin())
- // printf("Audio::processMidi metronome: md->nextPlayEvent() != playEvents->begin()\n");
- //}
-
- // Removed p4.0.15 Tim.
- ///if (MusEGlobal::audioClickFlag)
- /// metronome->setNextPlayEvent(metronome->playEvents()->begin());
- //if(MusEGlobal::audioClickFlag)
- //{
- // if(metronome->nextPlayEvent() != metronome->playEvents()->begin())
- // printf("Audio::processMidi metronome: metronome->nextPlayEvent() != metronome->playEvents->begin()\n");
- //}
-
- }
-
- if (state == STOP) {
- //---------------------------------------------------
- // end all notes
- //---------------------------------------------------
-
- for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) {
- MidiDevice* md = *imd;
- MPEventList* playEvents = md->playEvents();
- MPEventList* stuckNotes = md->stuckNotes();
- for (iMPEvent k = stuckNotes->begin(); k != stuckNotes->end(); ++k) {
- MidiPlayEvent ev(*k);
- ev.setTime(0); // play now
- playEvents->add(ev);
- }
- stuckNotes->clear();
- }
}
-
-
- // p3.3.36
- //int tickpos = audio->tickPos();
- //bool extsync = extSyncFlag.value();
+
//
- // Special for Jack midi devices: Play all Jack midi events up to curFrame.
+ // Play all midi events up to curFrame.
//
for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
{
- //MidiDevice* md = *id;
- // Is it a Jack midi device?
- //MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
- //if(!mjd)
- // continue;
- //mjd->processMidi();
- (*id)->processMidi();
+ // We are done with the 'frozen' recording fifos, remove the events.
+ (*id)->afterProcess(); // p4.0.34
- /*
- int port = md->midiPort();
- MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
- MPEventList* el = md->playEvents();
- if (el->empty())
- continue;
- iMPEvent i = md->nextPlayEvent();
- for(; i != el->end(); ++i)
- {
- // If syncing to external midi sync, we cannot use the tempo map.
- // Therefore we cannot get sub-tick resolution. Just use ticks instead of frames.
- //if(i->time() > curFrame)
- if(i->time() > (extsync ? tickpos : curFrame))
- {
- //printf(" curT %d frame %d\n", i->time(), curFrame);
- break; // skip this event
- }
-
- if(mp)
- {
- if(mp->sendEvent(*i))
- break;
- }
- else
- {
- if(md->putEvent(*i))
- break;
- }
- }
- md->setNextPlayEvent(i);
- */
+ // ALSA devices handled by another thread.
+ if((*id)->deviceType() != MidiDevice::ALSA_MIDI)
+ //if((*id)->deviceType() == MidiDevice::JACK_MIDI)
+ (*id)->processMidi();
}
-
midiBusy=false;
}