summaryrefslogtreecommitdiff
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
parentad72332d2cbd0d22e5d49d9fd60c985e563b17d0 (diff)
Mostly engine fixes/corrections. Please see ChangeLog.
-rw-r--r--muse2/ChangeLog16
-rw-r--r--muse2/README.effects-rack11
-rw-r--r--muse2/muse/audio.cpp542
-rw-r--r--muse2/muse/audio.h8
-rw-r--r--muse2/muse/driver/alsamidi.cpp369
-rw-r--r--muse2/muse/driver/alsamidi.h20
-rw-r--r--muse2/muse/driver/jackmidi.cpp851
-rw-r--r--muse2/muse/driver/jackmidi.h89
-rw-r--r--muse2/muse/instruments/minstrument.cpp1
-rw-r--r--muse2/muse/midi.cpp756
-rw-r--r--muse2/muse/midi.h2
-rw-r--r--muse2/muse/mididev.cpp29
-rw-r--r--muse2/muse/mididev.h22
-rw-r--r--muse2/muse/midiseq.cpp84
-rw-r--r--muse2/muse/midiseq.h8
-rw-r--r--muse2/muse/mpevent.h4
-rw-r--r--muse2/muse/song.cpp22
-rw-r--r--muse2/muse/synth.cpp28
-rw-r--r--muse2/muse/synth.h1
19 files changed, 719 insertions, 2144 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index bdc4cb57..b0bc5121 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,3 +1,19 @@
+09.09.2011:
+ - Removed sending of SEQM_ADD_TRACK, SEQM_REMOVE_TRACK, SEQM_CHANGE_TRACK, SEQM_REMOVE_PART, and
+ SEQM_CHANGE_PART to ALSA midi thread (which waits) from inside Audio::processMsg.
+ Replaced with hand-offs to Song::processMsg. TODO: SEQM_SET_TRACK_OUT_CHAN etc. (Tim)
+ - MidiDevice play and stuck event lists no longer directly accessible from outside -
+ replaced with ::addScheduledEvent and ::addStuckNote. (Tim)
+ - Installed a ring buffer for ALSA MidiDevice play/stuck notes event lists, filled by ::addScheduledEvent
+ and ::addStuckNote, because ALSA midi is processed in a thread other than audio. (Tim)
+ TODO: processMidi could do stuck notes better by bypassing their insertion in the play event list,
+ also applies to seek/stop handler block, but I'm not sure about the time comparisons.
+ - Some more separation of ALSA and Jack Midi, one step closer to configurable choice of either/or. (Tim)
+ - Massive cleanup of audio, midi, mididev, alsamidi, jackmidi modules. Moved some stuff from Audio::processMidi
+ into MidiDevice. (Tim)
+ - Test OK here so far, with stress files and complete pre-existing songs, ALSA, Jack, and Synth midi. (Tim)
+ TODO: Restoration of sustain upon play seems broken for a while - try putEvent instead of addScheduledEvent
+ in Audio::startRolling().
08.09.2011:
- Finished namespace MusEWidget. Added namespaces MusEUtil, MusEDialog. (Orcan)
07.09.2011:
diff --git a/muse2/README.effects-rack b/muse2/README.effects-rack
index 823ae74c..071ba08e 100644
--- a/muse2/README.effects-rack
+++ b/muse2/README.effects-rack
@@ -1,4 +1,4 @@
-May 6, 2010 v0.0.2 by Tim.
+Sept 1, 2011 v0.0.3 by Tim.
Understanding the Effects Rack
------------------------------
@@ -48,15 +48,12 @@ These same rules apply to inter-plugin audio when more than one plugin
is in the rack chain. Extra audio outputs of one plugin may be ignored
by the next plugin if not used.
-Currently plugins with no audio outputs are not really useful in MusE,
- chiefly because plugin control outputs are not used or displayed.
-Nor are specialized plugins with many inputs and/or outputs.
+Currently specialized plugins with many inputs and/or outputs are not
+ really useful in MusE.
Nor are so-called 'realtime' control plugins which use audio inputs
and outputs for control signals.
-<<<
- Loud noise alert! Beware of using such plugins in an audio effects rack.
->>>
+Loud noise alert! Beware of using such plugins in an audio effects rack.
Example: Consider a stereo Audio Input track with these effect rack
diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp
index a82fbe13..60eb5c73 100644
--- a/muse2/muse/audio.cpp
+++ b/muse2/muse/audio.cpp
@@ -4,6 +4,7 @@
// $Id: audio.cpp,v 1.59.2.30 2009/12/20 05:00:35 terminator356 Exp $
//
// (C) Copyright 2001-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
@@ -30,10 +31,8 @@
#include "song.h"
#include "node.h"
#include "audiodev.h"
-//#include "driver/audiodev.h" // p4.0.2
#include "mididev.h"
#include "alsamidi.h"
-//#include "driver/alsamidi.h" // p4.0.2
#include "synth.h"
#include "audioprefetch.h"
#include "plugin.h"
@@ -55,8 +54,7 @@ extern double curTime();
Audio* audio;
AudioDevice* audioDevice; // current audio device in use
-// p3.3.25
-extern unsigned int volatile midiExtSyncTicks;
+extern unsigned int volatile midiExtSyncTicks; // p3.3.25
//static const unsigned char mmcDeferredPlayMsg[] = { 0x7f, 0x7f, 0x06, 0x03 };
@@ -126,7 +124,7 @@ Audio::Audio()
_pos.setType(Pos::FRAMES);
_pos.setFrame(0);
- curTickPos = 0;
+ nextTickPos = curTickPos = 0;
midiClick = 0;
clickno = 0;
@@ -140,10 +138,9 @@ Audio::Audio()
state = STOP;
msg = 0;
- // Changed by Tim. p3.3.8
//startRecordPos.setType(Pos::TICKS);
//endRecordPos.setType(Pos::TICKS);
- startRecordPos.setType(Pos::FRAMES);
+ startRecordPos.setType(Pos::FRAMES); // Tim
endRecordPos.setType(Pos::FRAMES);
_audioMonitor = 0;
@@ -187,16 +184,12 @@ bool Audio::start()
_loopCount = 0;
MusEGlobal::muse->setHeartBeat();
if (audioDevice) {
- // Added by Tim. p3.3.6
//_running = true;
-
//audioDevice->start();
}
else {
if(false == initJackAudio()) {
- // Added by Tim. p3.3.6
//_running = true;
-
InputList* itl = song->inputs();
for (iAudioInput i = itl->begin(); i != itl->end(); ++i) {
//printf("reconnecting input %s\n", (*i)->name().ascii());
@@ -253,25 +246,6 @@ void Audio::stop(bool)
bool Audio::sync(int jackState, unsigned frame)
{
-
-// Changed by Tim. p3.3.24
-/*
- bool done = true;
- if (state == LOOP1)
- state = LOOP2;
- else {
- if (_pos.frame() != frame) {
- Pos p(frame, false);
- seek(p);
- }
- state = State(jackState);
- if (!_freewheel)
- //done = audioPrefetch->seekDone;
- done = audioPrefetch->seekDone();
- }
-
- return done;
-*/
bool done = true;
if (state == LOOP1)
state = LOOP2;
@@ -283,8 +257,6 @@ bool Audio::sync(int jackState, unsigned frame)
// PLAY -> START_PLAY seek in play state
if (state != START_PLAY) {
- //Pos p(frame, AL::FRAMES);
- // seek(p);
Pos p(frame, false);
seek(p);
if (!_freewheel)
@@ -293,10 +265,8 @@ bool Audio::sync(int jackState, unsigned frame)
state = START_PLAY;
}
else {
- //if (frame != _seqTime.pos.frame()) {
if (frame != _pos.frame()) {
// seek during seek
- //seek(Pos(frame, AL::FRAMES));
seek(Pos(frame, false));
}
done = audioPrefetch->seekDone();
@@ -335,9 +305,8 @@ void Audio::shutdown()
void Audio::process(unsigned frames)
{
- // Disabled by Tim. p3.3.22
// extern int watchAudio;
-// ++watchAudio; // make a simple watchdog happy
+// ++watchAudio; // make a simple watchdog happy. Disabled.
if (!MusEGlobal::checkAudioDevice()) return;
if (msg) {
@@ -377,8 +346,8 @@ void Audio::process(unsigned frames)
startRolling();
}
else if (isPlaying() && jackState == STOP) {
- // p3.3.43 Make sure to stop bounce and freewheel mode, for example if user presses stop
- // in QJackCtl before right-hand marker is reached (which is handled below).
+ // Make sure to stop bounce and freewheel mode, for example if user presses stop
+ // in QJackCtl before right-hand marker is reached (which is handled below). p3.3.43
//printf("Audio::process isPlaying() && jackState == STOP\n");
//if (_bounce)
//{
@@ -485,15 +454,11 @@ void Audio::process(unsigned frames)
//audioDevice->seekTransport(_loopFrame);
Pos lp(_loopFrame, false);
audioDevice->seekTransport(lp);
-
-
// printf(" process: seek to %d, end %d\n", _loopFrame, loop.frame());
}
}
-
- // p3.3.25
- if(extSyncFlag.value())
+ if(extSyncFlag.value()) // p3.3.25
{
nextTickPos = curTickPos + midiExtSyncTicks;
// Probably not good - interfere with midi thread.
@@ -549,7 +514,6 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)
continue;
track = (AudioTrack*)(*it);
- // Added by T356.
// For audio track types, synths etc. which need some kind of non-audio
// (but possibly audio-affecting) processing always, even if their output path
// is ultimately unconnected.
@@ -560,23 +524,10 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)
// It should be used for things like midi events, gui events etc. - things which need to
// be done BEFORE all the AudioOutput::process() are called below. That does NOT include
// audio processing, because THAT is done at the very end of this routine.
- // This will also reset the track's processed flag.
+ // This will also reset the track's processed flag. Tim.
track->preProcessAlways();
-
- // Removed by T356
- /*
- if (track->noOutRoute() && !track->noInRoute() &&
- track->type() != Track::AUDIO_AUX && track->type() != Track::AUDIO_OUTPUT) {
- channels = track->channels();
- float* buffer[channels];
- float data[frames * channels];
- for (int i = 0; i < channels; ++i)
- buffer[i] = data + i * frames;
- track->copyData(samplePos, channels, frames, buffer);
- }
- */
-
}
+
// Pre-process the metronome.
((AudioTrack*)metronome)->preProcessAlways();
@@ -584,29 +535,12 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)
for (ciAudioOutput i = ol->begin(); i != ol->end(); ++i)
(*i)->process(samplePos, offset, frames);
- // Removed by T356
- /*
- AuxList* auxl = song->auxs();
- for (ciAudioAux ia = auxl->begin(); ia != auxl->end(); ++ia) {
- track = (AudioTrack*)(*ia);
- if (track->noOutRoute()) {
- channels = track->channels();
- float* buffer[channels];
- float data[frames * channels];
- for (int i = 0; i < channels; ++i)
- buffer[i] = data + i * frames;
- track->copyData(samplePos, channels, frames, buffer);
- }
- }
- */
-
- // Added by T356.
// Were ANY tracks unprocessed as a result of processing all the AudioOutputs, above?
// Not just unconnected ones, as previously done, but ones whose output path ultimately leads nowhere.
// Those tracks were missed, until this fix.
// Do them now. This will animate meters, and 'quietly' process some audio which needs to be done -
- // for example synths really need to be processed, 'quietly' or not, otherwise the next time
- // processing is 'turned on', if there was a backlog of events while it was off, then they all happen at once.
+ // for example synths really need to be processed, 'quietly' or not, otherwise the next time processing
+ // is 'turned on', if there was a backlog of events while it was off, then they all happen at once. Tim.
for(ciTrack it = tl->begin(); it != tl->end(); ++it)
{
if((*it)->isMidiTrack())
@@ -623,9 +557,6 @@ void Audio::process1(unsigned samplePos, unsigned offset, unsigned frames)
for (int i = 0; i < channels; ++i)
buffer[i] = data + i * frames;
//printf("Audio::process1 calling track->copyData for track:%s\n", track->name().toLatin1());
-
- // p3.3.38
- //track->copyData(samplePos, channels, frames, buffer);
track->copyData(samplePos, channels, -1, -1, frames, buffer);
}
}
@@ -647,7 +578,7 @@ void Audio::processMsg(AudioMsg* msg)
case AUDIO_ROUTEREMOVE:
removeRoute(msg->sroute, msg->droute);
break;
- case AUDIO_REMOVEROUTES: // p3.3.55
+ case AUDIO_REMOVEROUTES:
removeAllRoutes(msg->sroute, msg->droute);
break;
//case AUDIO_VOL:
@@ -670,7 +601,6 @@ void Audio::processMsg(AudioMsg* msg)
break;
//case AUDIO_SET_PLUGIN_CTRL_VAL:
//msg->plugin->track()->setPluginCtrlVal(msg->ival, msg->dval);
- // p3.3.43
// msg->snode->setPluginCtrlVal(msg->ival, msg->dval);
// break;
case AUDIO_SWAP_CONTROLLER_IDX:
@@ -721,8 +651,8 @@ void Audio::processMsg(AudioMsg* msg)
//printf("Audio::processMsg SEQM_RESET_DEVICES\n");
for (int i = 0; i < MIDI_PORTS; ++i)
{
- if(!midiPorts[i].device()) continue; // p4.0.15
- midiPorts[i].instrument()->reset(i, song->mtype());
+ if(midiPorts[i].device())
+ midiPorts[i].instrument()->reset(i, song->mtype());
}
break;
case SEQM_INIT_DEVICES:
@@ -759,7 +689,7 @@ void Audio::processMsg(AudioMsg* msg)
case MIDI_SHOW_INSTR_GUI:
midiSeq->msgUpdatePollFd();
break;
- case MIDI_SHOW_INSTR_NATIVE_GUI: // p4.0.20
+ case MIDI_SHOW_INSTR_NATIVE_GUI:
midiSeq->msgUpdatePollFd();
break;
case SEQM_ADD_TEMPO:
@@ -776,12 +706,12 @@ void Audio::processMsg(AudioMsg* msg)
frameOffset = syncFrame - samplePos;
}
break;
- case SEQM_ADD_TRACK:
- case SEQM_REMOVE_TRACK:
- case SEQM_CHANGE_TRACK:
- case SEQM_ADD_PART:
- case SEQM_REMOVE_PART:
- case SEQM_CHANGE_PART:
+ //case SEQM_ADD_TRACK:
+ //case SEQM_REMOVE_TRACK:
+ //case SEQM_CHANGE_TRACK:
+ //case SEQM_ADD_PART:
+ //case SEQM_REMOVE_PART:
+ //case SEQM_CHANGE_PART:
case SEQM_SET_TRACK_OUT_CHAN:
case SEQM_SET_TRACK_OUT_PORT:
case SEQM_REMAP_PORT_DRUM_CTL_EVS:
@@ -813,143 +743,26 @@ void Audio::seek(const Pos& p)
printf("Audio::seek already there\n");
return;
}
-
- // p3.3.23
- //printf("Audio::seek frame:%d\n", p.frame());
+ //printf("Audio::seek frame:%d\n", p.frame());
_pos = p;
if (!MusEGlobal::checkAudioDevice()) return;
syncFrame = audioDevice->framePos();
frameOffset = syncFrame - _pos.frame();
curTickPos = _pos.tick();
- // p4.0.22
- // Tell midi thread to tell ALSA devices to handle seek.
- midiSeq->msgSeek();
- // We are in the audio thread. Directly seek Jack midi devices.
+ if (curTickPos == 0 && !song->record())
+ audio->initDevices();
+
for(iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
- {
- MidiDevice* md = *i;
- if(md->deviceType() == MidiDevice::JACK_MIDI)
- md->handleSeek();
- }
-
- // Moved into MidiDevice::handleSeek
- #if 0
- // p3.3.31
- // Don't send if external sync is on. The master, and our sync routing system will take care of that.
- if(!extSyncFlag.value())
- {
-
- for(int port = 0; port < MIDI_PORTS; ++port)
- {
- MidiPort* mp = &midiPorts[port];
- MidiDevice* dev = mp->device();
- //if(!dev || !mp->syncInfo().MCOut())
- if(!dev || !mp->syncInfo().MRTOut())
- continue;
-
- // Added by T356: Shall we check for device write open flag to see if it's ok to send?...
- // This means obey what the user has chosen for read/write in the midi port config dialog,
- // which already takes into account whether the device is writable or not.
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
-
- //int port = dev->midiPort();
-
- // By checking for no port here (-1), (and out of bounds), it means
- // the device must be assigned to a port for these MMC commands to be sent.
- // Without this check, interesting sync things can be done by the user without ever
- // assigning any devices to ports !
- //if(port < 0 || port > MIDI_PORTS)
- //if(port < -1 || port > MIDI_PORTS)
- // continue;
-
- int beat = (curTickPos * 4) / MusEConfig::config.division;
-
- bool isPlaying=false;
- if(state == PLAY)
- isPlaying = true;
-
- mp->sendStop();
- mp->sendSongpos(beat);
- if(isPlaying)
- mp->sendContinue();
- }
- }
- #endif
-
- /*
- if(genMCSync)
- {
- for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
- {
- MidiDevice* dev = (*imd);
- if(!dev->syncInfo().MCOut())
- continue;
-
- // Added by T356: Shall we check for device write open flag to see if it's ok to send?...
- // This means obey what the user has chosen for read/write in the midi port config dialog,
- // which already takes into account whether the device is writable or not.
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
-
- int port = dev->midiPort();
-
- // By checking for no port here (-1), (and out of bounds), it means
- // the device must be assigned to a port for these MMC commands to be sent.
- // Without this check, interesting sync things can be done by the user without ever
- // assigning any devices to ports !
- //if(port < 0 || port > MIDI_PORTS)
- if(port < -1 || port > MIDI_PORTS)
- continue;
-
- int beat = (curTickPos * 4) / MusEConfig::config.division;
-
- bool isPlaying=false;
- if(state == PLAY)
- isPlaying = true;
-
- if(port == -1)
- // Send straight to the device... Copied from MidiPort.
- {
- MidiPlayEvent event(0, 0, 0, ME_STOP, 0, 0);
- dev->putEvent(event);
-
- event.setType(ME_SONGPOS);
- event.setA(beat);
- dev->putEvent(event);
-
- if(isPlaying)
- {
- event.setType(ME_CONTINUE);
- event.setA(0);
- dev->putEvent(event);
- }
- }
- else
- // Go through the port...
- {
- MidiPort* mp = &midiPorts[port];
-
- mp->sendStop();
- mp->sendSongpos(beat);
- if(isPlaying)
- mp->sendContinue();
- }
- }
- }
- */
+ (*i)->handleSeek();
//loopPassed = true; // for record loop mode
if (state != LOOP2 && !freewheel())
{
- // Changed by T356 08/17/08. We need to force prefetch to update,
- // to ensure the most recent data. Things can happen to a part
- // before play is pressed - such as part muting, part moving etc.
- // Without a force, the wrong data was being played.
//audioPrefetch->msgSeek(_pos.frame());
+ // We need to force prefetch to update, to ensure the most recent data.
+ // Things can happen to a part before play is pressed - such as part muting,
+ // part moving etc. Without a force, the wrong data was being played. Tim 08/17/08
audioPrefetch->msgSeek(_pos.frame(), true);
}
@@ -984,8 +797,6 @@ void Audio::writeTick()
void Audio::startRolling()
{
- // Changed by Tim. p3.3.8
- //startRecordPos = _pos;
if (MusEGlobal::debugMsg)
printf("startRolling - loopCount=%d, _pos=%d\n", _loopCount, _pos.tick());
@@ -1005,20 +816,9 @@ void Audio::startRolling()
state = PLAY;
write(sigFd, "1", 1); // Play
- // p3.3.31
// Don't send if external sync is on. The master, and our sync routing system will take care of that.
if(!extSyncFlag.value())
{
-
- // Changed by Tim. p3.3.6
- //if (genMMC)
- // midiPorts[txSyncPort].sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
- //if (genMCSync) {
- // if (curTickPos)
- // midiPorts[txSyncPort].sendContinue();
- // else
- // midiPorts[txSyncPort].sendStart();
- // }
for(int port = 0; port < MIDI_PORTS; ++port)
{
MidiPort* mp = &midiPorts[port];
@@ -1033,13 +833,9 @@ void Audio::startRolling()
MidiSyncInfo& si = mp->syncInfo();
- //if(genMMC && si.MMCOut())
if(si.MMCOut())
- //mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
mp->sendMMCDeferredPlay();
- //if(genMCSync && si.MCOut())
- //if(si.MCOut())
if(si.MRTOut())
{
if(curTickPos)
@@ -1050,68 +846,6 @@ void Audio::startRolling()
}
}
- /*
- for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
- {
- MidiDevice* dev = (*imd);
-
- // Shall we check open flags?
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
-
- int port = dev->midiPort();
-
- // Without this -1 check, interesting sync things can be done by the user without ever
- // assigning any devices to ports !
- //if(port < 0 || port > MIDI_PORTS)
- if(port < -1 || port > MIDI_PORTS)
- continue;
-
- MidiSyncInfo& si = dev->syncInfo();
-
- if(port == -1)
- // Send straight to the device... Copied from MidiPort.
- {
- if(genMMC && si.MMCOut())
- {
- MidiPlayEvent event(0, 0, ME_SYSEX, mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
- dev->putEvent(event);
- }
-
- if(genMCSync && si.MCOut())
- {
- if(curTickPos)
- {
- MidiPlayEvent event(0, 0, 0, ME_CONTINUE, 0, 0);
- dev->putEvent(event);
- }
- else
- {
- MidiPlayEvent event(0, 0, 0, ME_START, 0, 0);
- dev->putEvent(event);
- }
- }
- }
- else
- // Go through the port...
- {
- MidiPort* mp = &midiPorts[port];
-
- if(genMMC && si.MMCOut())
- mp->sendSysex(mmcDeferredPlayMsg, sizeof(mmcDeferredPlayMsg));
-
- if(genMCSync && si.MCOut())
- {
- if(curTickPos)
- mp->sendContinue();
- else
- mp->sendStart();
- }
- }
- }
- */
-
if (MusEGlobal::precountEnableFlag
&& song->click()
&& !extSyncFlag.value()
@@ -1150,9 +884,7 @@ void Audio::startRolling()
if(mp->device() != NULL) {
//printf("send enable sustain!!!!!!!! port %d ch %d\n", i,ch);
MidiPlayEvent ev(0, i, ch, ME_CONTROLLER, CTRL_SUSTAIN, 127);
-
- // may cause problems, called from audio thread
- mp->device()->playEvents()->add(ev);
+ mp->device()->addScheduledEvent(ev); // TODO: Not working? Try putEvent
}
}
}
@@ -1172,220 +904,14 @@ void Audio::stopRolling()
state = STOP;
- //playStateExt = false; // not playing // Moved here from MidiSeq::processStop() p4.0.22
-
- // p4.0.22
- // Tell midi thread to clear ALSA device notes and stop stuck notes.
- midiSeq->msgStop();
- // We are in the audio thread. Directly clear Jack midi device notes and stop stuck notes.
+ midiSeq->setExternalPlayState(false); // not playing Moved here from MidiSeq::processStop() p4.0.34
+
for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
{
MidiDevice* md = *id;
- if(md->deviceType() == MidiDevice::JACK_MIDI)
- md->handleStop();
+ md->handleStop();
}
- // Moved into MidiDevice::handleStop() // p4.0.22
- #if 0 //TODO
- //---------------------------------------------------
- // reset sustain
- //---------------------------------------------------
-
-
- // clear sustain
- for (int i = 0; i < MIDI_PORTS; ++i) {
- MidiPort* mp = &midiPorts[i];
- for (int ch = 0; ch < MIDI_CHANNELS; ++ch) {
- if (mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127) {
- if(mp->device()!=NULL) {
- //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
- MidiPlayEvent ev(0, i, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
- // may cause problems, called from audio thread
- mp->device()->putEvent(ev);
- }
- }
- }
- }
- #endif
-
- // Moved into MidiDevice::handleStop() // p4.0.22
- #if 0
- // p3.3.31
- // Don't send if external sync is on. The master, and our sync routing system will take care of that.
- if(!extSyncFlag.value())
- {
-
- // Changed by Tim. p3.3.6
- //MidiPort* syncPort = &midiPorts[txSyncPort];
- //if (genMMC) {
- // unsigned char mmcPos[] = {
- // 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01,
- // 0, 0, 0, 0, 0
- // };
- // int frame = tempomap.tick2frame(curTickPos);
- // MTC mtc(double(frame) / double(MusEGlobal::sampleRate));
- // mmcPos[6] = mtc.h() | (mtcType << 5);
- // mmcPos[7] = mtc.m();
- // mmcPos[8] = mtc.s();
- // mmcPos[9] = mtc.f();
- // mmcPos[10] = mtc.sf();
- // syncPort->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
- // syncPort->sendSysex(mmcPos, sizeof(mmcPos));
- // }
- //if (genMCSync) { // Midi Clock
- // send STOP and
- // "set song position pointer"
- // syncPort->sendStop();
- // syncPort->sendSongpos(curTickPos * 4 / MusEConfig::config.division);
- // }
- for(int port = 0; port < MIDI_PORTS; ++port)
- {
- MidiPort* mp = &midiPorts[port];
- MidiDevice* dev = mp->device();
- if(!dev)
- continue;
-
- // Shall we check open flags?
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
-
- MidiSyncInfo& si = mp->syncInfo();
-
- //if(genMMC && si.MMCOut())
- if(si.MMCOut())
- {
- //unsigned char mmcPos[] = {
- // 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01,
- // 0, 0, 0, 0, 0
- // };
-
- // p3.3.31
- /*
- int frame = tempomap.tick2frame(curTickPos);
- MTC mtc(double(frame) / double(MusEGlobal::sampleRate));
- */
-
- //mmcPos[6] = mtc.h() | (mtcType << 5);
- //mmcPos[7] = mtc.m();
- //mmcPos[8] = mtc.s();
- //mmcPos[9] = mtc.f();
- //mmcPos[10] = mtc.sf();
-
- //mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
- mp->sendMMCStop();
- //mp->sendSysex(mmcPos, sizeof(mmcPos));
-
- // p3.3.31
- // Added check of option send continue not start.
- // Hmm, is this required? Seems to make other devices unhappy.
- /*
- if(!si.sendContNotStart())
- mp->sendMMCLocate(mtc.h() | (mtcType << 5),
- mtc.m(), mtc.s(), mtc.f(), mtc.sf());
- */
-
- }
-
- //if(genMCSync && si.MCOut()) // Midi Clock
- //if(si.MCOut()) // Midi Clock
- if(si.MRTOut()) //
- {
- // send STOP and
- // "set song position pointer"
- mp->sendStop();
-
- // p3.3.31
- // Added check of option send continue not start.
- // Hmm, is this required? Seems to make other devices unhappy.
- /*
- if(!si.sendContNotStart())
- mp->sendSongpos(curTickPos * 4 / MusEConfig::config.division);
- */
-
- }
- }
- }
- #endif
-
- /*
- for(iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd)
- {
- MidiDevice* dev = (*imd);
-
- // Shall we check open flags?
- //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
- //if(!(dev->openFlags() & 1))
- // continue;
-
- int port = dev->midiPort();
-
- // Without this -1 check, interesting sync things can be done by the user without ever
- // assigning any devices to ports !
- //if(port < 0 || port > MIDI_PORTS)
- if(port < -1 || port > MIDI_PORTS)
- continue;
-
- MidiSyncInfo& si = dev->syncInfo();
-
- MidiPort* mp = 0;
- if(port != -1)
- mp = &midiPorts[port];
-
- if(genMMC && si.MMCOut())
- {
- unsigned char mmcPos[] = {
- 0x7f, 0x7f, 0x06, 0x44, 0x06, 0x01,
- 0, 0, 0, 0, 0
- };
- int frame = tempomap.tick2frame(curTickPos);
- MTC mtc(double(frame) / double(MusEGlobal::sampleRate));
- mmcPos[6] = mtc.h() | (mtcType << 5);
- mmcPos[7] = mtc.m();
- mmcPos[8] = mtc.s();
- mmcPos[9] = mtc.f();
- mmcPos[10] = mtc.sf();
-
- if(mp)
- // Go through the port...
- {
- mp->sendSysex(mmcStopMsg, sizeof(mmcStopMsg));
- mp->sendSysex(mmcPos, sizeof(mmcPos));
- }
- else
- // Send straight to the device... Copied from MidiPort.
- {
- MidiPlayEvent event(0, 0, ME_SYSEX, mmcStopMsg, sizeof(mmcStopMsg));
- dev->putEvent(event);
-
- event.setData(mmcPos, sizeof(mmcPos));
- dev->putEvent(event);
- }
- }
-
- if(genMCSync && si.MCOut()) // Midi Clock
- {
- // send STOP and
- // "set song position pointer"
- if(mp)
- // Go through the port...
- {
- mp->sendStop();
- mp->sendSongpos(curTickPos * 4 / MusEConfig::config.division);
- }
- else
- // Send straight to the device... Copied from MidiPort.
- {
- MidiPlayEvent event(0, 0, 0, ME_STOP, 0, 0);
- dev->putEvent(event);
- event.setType(ME_SONGPOS);
- event.setA(curTickPos * 4 / MusEConfig::config.division);
- dev->putEvent(event);
- }
- }
- }
- */
-
WaveTrackList* tracks = song->waves();
for (iWaveTrack i = tracks->begin(); i != tracks->end(); ++i) {
WaveTrack* track = *i;
diff --git a/muse2/muse/audio.h b/muse2/muse/audio.h
index 86f38004..03e48e23 100644
--- a/muse2/muse/audio.h
+++ b/muse2/muse/audio.h
@@ -4,6 +4,7 @@
// $Id: audio.h,v 1.25.2.13 2009/12/20 05:00:35 terminator356 Exp $
//
// (C) Copyright 2001 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
@@ -239,8 +240,8 @@ class Audio {
bool sendMessage(AudioMsg* m, bool doUndo);
void msgRemoveRoute(Route, Route);
void msgRemoveRoute1(Route, Route);
- void msgRemoveRoutes(Route, Route); // p3.3.55
- void msgRemoveRoutes1(Route, Route); // p3.3.55
+ void msgRemoveRoutes(Route, Route);
+ void msgRemoveRoutes1(Route, Route);
void msgAddRoute(Route, Route);
void msgAddRoute1(Route, Route);
void msgAddPlugin(AudioTrack*, int idx, PluginI* plugin);
@@ -290,7 +291,8 @@ class Audio {
int loopCount() { return _loopCount; } // Number of times we have looped so far
unsigned loopFrame() { return _loopFrame; }
- int tickPos() const { return curTickPos; }
+ unsigned tickPos() const { return curTickPos; }
+ unsigned nextTick() const { return nextTickPos; }
int timestamp() const;
void processMidi();
unsigned curFrame() const;
diff --git a/muse2/muse/driver/alsamidi.cpp b/muse2/muse/driver/alsamidi.cpp
index 07688a33..9a62dbdd 100644
--- a/muse2/muse/driver/alsamidi.cpp
+++ b/muse2/muse/driver/alsamidi.cpp
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: alsamidi.cpp,v 1.8.2.7 2009/11/19 04:20:33 terminator356 Exp $
// (C) Copyright 2000-2001 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
@@ -25,16 +26,18 @@
#include "alsamidi.h"
#include "globals.h"
#include "midi.h"
-#include "mididev.h"
+//#include "mididev.h"
#include "../midiport.h"
#include "../midiseq.h"
#include "../midictrl.h"
#include "../audio.h"
-#include "mpevent.h"
+//#include "mpevent.h"
//#include "sync.h"
#include "utils.h"
#include "audiodev.h"
#include "xml.h"
+#include "part.h"
+#include "gconfig.h"
static int alsaSeqFdi = -1;
static int alsaSeqFdo = -1;
@@ -50,6 +53,8 @@ MidiAlsaDevice::MidiAlsaDevice(const snd_seq_addr_t& a, const QString& n)
: MidiDevice(n)
{
adr = a;
+ stopPending = false;
+ seekPending = false;
init();
}
@@ -132,7 +137,7 @@ void MidiAlsaDevice::close()
// Allocated on stack, no need to call snd_seq_port_subscribe_free() later.
snd_seq_port_subscribe_alloca(&subs);
- // Changed by T356. This function appears to be called only by MidiPort::setMidiDevice(),
+ // This function appears to be called only by MidiPort::setMidiDevice(),
// which closes then opens the device.
// Because the open flags are set BEFORE setMidiDevice() is called, we must ignore the flags.
//
@@ -146,7 +151,7 @@ void MidiAlsaDevice::close()
// dst 16:0
// only sometimes (not when playing notes), but with jack midi turned on,
// we don't get the messages. With jack stopped we get the messages
- // no matter if jack midi is turned on or not.
+ // no matter if jack midi is turned on or not. Tim.
//if (_openFlags & 1) {
//if (!(_openFlags & 1))
@@ -191,95 +196,27 @@ void MidiAlsaDevice::close()
void MidiAlsaDevice::writeRouting(int level, Xml& xml) const
{
- // p3.3.45
// If this device is not actually in use by the song, do not write any routes.
- // This prevents bogus routes from being saved and propagated in the med file.
+ // This prevents bogus routes from being saved and propagated in the med file. Tim.
if(midiPort() == -1)
return;
QString s;
- /*
- //if(rwFlags() & 2) // Readable
- {
- //RouteList* rl = _inRoutes;
- //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
- for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
- {
- // Since an ALSA midi device supports read + write, this is the only way we can tell if this route is using the device as input.
- if(r->type == Route::TRACK_ROUTE)
- continue;
-
- if(!r->name().isEmpty())
- {
- xml.tag(level++, "Route");
-
- //xml.strTag(level, "srcNode", r->name());
- xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData());
-
- //xml.strTag(level, "dstNode", name());
- xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().toLatin1().constData());
-
- xml.etag(level--, "Route");
- }
- }
- }
- */
-
for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
{
- //if(r->type != Route::TRACK_ROUTE)
- //{
- // printf("MidiAlsaDevice::writeRouting Warning out route is not TRACK_ROUTE type\n");
- // continue;
- //}
-
if(!r->name().isEmpty())
{
- //xml.tag(level++, "Route");
-
s = QT_TRANSLATE_NOOP("@default", "Route");
if(r->channel != -1)
s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel);
xml.tag(level++, s.toLatin1().constData());
-
- /*
- //xml.strTag(level, "srcNode", name());
- if(r->channel != -1)
- //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, r->channel, name().toLatin1().constData());
- //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().toLatin1().constData());
- xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, r->channel, name().toLatin1().constData());
- else
- //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::ALSA_MIDI_ROUTE, name().toLatin1().constData());
- //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData());
- */
- //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, name().toLatin1().constData());
- xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData());
-
- /*
- //xml.strTag(level, "dstNode", r->name());
- if(r->channel != -1)
- {
- if(r->type == Route::MIDI_DEVICE_ROUTE)
- xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().toLatin1().constData());
- else
- xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().toLatin1().constData());
- }
- else
- {
- if(r->type == Route::MIDI_DEVICE_ROUTE)
- xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().toLatin1().constData());
- else
- xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData());
- }
- */
-
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData());
s = QT_TRANSLATE_NOOP("@default", "dest");
if(r->type == Route::MIDI_DEVICE_ROUTE)
s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType());
else
if(r->type != Route::TRACK_ROUTE)
s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type);
- //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());
s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));
xml.tag(level, s.toLatin1().constData());
@@ -326,12 +263,9 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
int a = e.dataA();
int b = e.dataB();
int chn = e.channel();
- // p3.3.37
- //if (a < 0x1000) { // 7 Bit Controller
if (a < CTRL_14_OFFSET) { // 7 Bit Controller
snd_seq_ev_set_controller(&event, chn, a, b);
}
- //else if (a < 0x20000) { // 14 bit high resolution controller
else if (a < CTRL_RPN_OFFSET) { // 14 bit high resolution controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
@@ -339,7 +273,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
snd_seq_ev_set_controller(&event, chn, a, b);
event.type = SND_SEQ_EVENT_CONTROL14;
}
- //else if (a < 0x30000) { // RPN 7-Bit Controller
else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
@@ -348,7 +281,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
snd_seq_ev_set_controller(&event, chn, a, b);
event.type = SND_SEQ_EVENT_REGPARAM;
}
- //else if (a < 0x40000) { // NRPN 7-Bit Controller
else if (a < CTRL_INTERNAL_OFFSET) { // NRPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
@@ -357,7 +289,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
snd_seq_ev_set_controller(&event, chn, a, b);
event.type = SND_SEQ_EVENT_NONREGPARAM;
}
- //else if (a < 0x60000) { // RPN14 Controller
else if (a < CTRL_NRPN14_OFFSET) { // RPN14 Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
@@ -365,7 +296,6 @@ bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e)
snd_seq_ev_set_controller(&event, chn, a, b);
event.type = SND_SEQ_EVENT_REGPARAM;
}
- //else if (a < 0x70000) { // NRPN14 Controller
else if (a < CTRL_NONE_OFFSET) { // NRPN14 Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
@@ -466,6 +396,250 @@ bool MidiAlsaDevice::putEvent(snd_seq_event_t* event)
}
//---------------------------------------------------------
+// processMidi
+// Called from ALSA midi sequencer thread only.
+//---------------------------------------------------------
+
+void MidiAlsaDevice::processMidi()
+{
+ bool stop = stopPending; // Snapshots
+ bool seek = seekPending; //
+ seekPending = stopPending = false;
+ // Transfer the stuck notes FIFO to the play events list.
+ // FIXME It would be faster to have MidiAlsaDevice automatically add the stuck note so that only
+ // one FIFO would be needed. But that requires passing an extra 'tick' and 'off velocity' in
+ // addScheduledEvent, which felt too weird.
+ while(!stuckNotesFifo.isEmpty())
+ _stuckNotes.add(stuckNotesFifo.get());
+
+ bool extsync = extSyncFlag.value();
+ //int frameOffset = getFrameOffset();
+ //int nextTick = audio->nextTick();
+
+ // We're in the ALSA midi thread. audio->isPlaying() might not be true during seek right now.
+ //if(stop || (seek && audio->isPlaying()))
+ if(stop || seek)
+ {
+ //---------------------------------------------------
+ // Clear all notes and handle stuck notes
+ //---------------------------------------------------
+ playEventFifo.clear();
+ _playEvents.clear();
+ //printf("transferring stuck notes\n");
+ for(iMPEvent i = _stuckNotes.begin(); i != _stuckNotes.end(); ++i)
+ {
+ //printf(" stuck note\n");
+ MidiPlayEvent ev = *i;
+ ev.setTime(0);
+ _playEvents.add(ev);
+ }
+ _stuckNotes.clear();
+ }
+ else
+ {
+ // Transfer the play events FIFO to the play events list.
+ while(!playEventFifo.isEmpty())
+ _playEvents.add(playEventFifo.get());
+
+ /* TODO Handle these more directly than putting them into play events list.
+ //if(audio->isPlaying())
+ {
+ iMPEvent k;
+ for (k = _stuckNotes.begin(); k != _stuckNotes.end(); ++k) {
+ if (k->time() >= nextTick)
+ break;
+ MidiPlayEvent ev(*k);
+ if(extsync) // p3.3.25
+ ev.setTime(k->time());
+ else
+ ev.setTime(tempomap.tick2frame(k->time()) + frameOffset);
+ _playEvents.add(ev);
+ }
+ _stuckNotes.erase(_stuckNotes.begin(), k);
+ }
+ */
+ processStuckNotes();
+ }
+
+ /* Instead, done immediately in handleStop and handleSeek using putEvent.
+ if(stop)
+ {
+ // reset sustain...
+ MidiPort* mp = &midiPorts[_port];
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ {
+ //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
+ MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
+ _playEvents.add(ev);
+ }
+ }
+ }
+ if(seek)
+ {
+ // Send new contoller values...
+ for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
+ {
+ MidiCtrlValList* vl = ivl->second;
+ iMidiCtrlVal imcv = vl->iValue(pos);
+ if(imcv != vl->end()) {
+ Part* p = imcv->second.part;
+ unsigned t = (unsigned)imcv->first;
+ // Do not add values that are outside of the part.
+ if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
+ _playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+ }
+ }
+ } */
+
+ if (_playEvents.empty())
+ return;
+
+ int port = midiPort();
+ MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
+ unsigned curFrame = audio->curFrame();
+ int tickpos = audio->tickPos();
+
+ // Play all events up to current frame.
+ iMPEvent i = _playEvents.begin();
+ for (; i != _playEvents.end(); ++i) {
+ if (i->time() > (extsync ? tickpos : curFrame)) // p3.3.25 Check: Should be nextTickPos? p4.0.34
+ break;
+ if(mp){
+ if (mp->sendEvent(*i))
+ break;
+ }
+ else
+ if(putMidiEvent(*i))
+ break;
+ }
+ _playEvents.erase(_playEvents.begin(), i);
+}
+
+//---------------------------------------------------------
+// handleStop
+//---------------------------------------------------------
+
+void MidiAlsaDevice::handleStop()
+{
+ // If the device is not in use by a port, don't bother it.
+ if(_port == -1)
+ return;
+
+ stopPending = true; // Trigger stop handling in processMidi.
+
+ //---------------------------------------------------
+ // reset sustain
+ //---------------------------------------------------
+
+ MidiPort* mp = &midiPorts[_port];
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ if(mp->hwCtrlState(ch, CTRL_SUSTAIN) == 127)
+ {
+ //printf("send clear sustain!!!!!!!! port %d ch %d\n", i,ch);
+ MidiPlayEvent ev(0, _port, ch, ME_CONTROLLER, CTRL_SUSTAIN, 0);
+ putMidiEvent(ev);
+ }
+ }
+
+ //---------------------------------------------------
+ // send midi stop
+ //---------------------------------------------------
+
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that.
+ if(!extSyncFlag.value())
+ {
+ // Shall we check open flags?
+ //if(!(dev->rwFlags() & 0x1) || !(dev->openFlags() & 1))
+ //if(!(dev->openFlags() & 1))
+ // return;
+
+ MidiSyncInfo& si = mp->syncInfo();
+ if(si.MMCOut())
+ mp->sendMMCStop();
+
+ if(si.MRTOut())
+ {
+ // Send STOP
+ mp->sendStop();
+
+ // Added check of option send continue not start. p3.3.31
+ // Hmm, is this required? Seems to make other devices unhappy.
+ // (Could try now that this is in MidiDevice. p4.0.22 )
+ //if(!si.sendContNotStart())
+ // mp->sendSongpos(audio->tickPos() * 4 / config.division);
+ }
+ }
+}
+
+//---------------------------------------------------------
+// handleSeek
+//---------------------------------------------------------
+
+void MidiAlsaDevice::handleSeek()
+{
+ // If the device is not in use by a port, don't bother it.
+ if(_port == -1)
+ return;
+
+ seekPending = true; // Trigger seek handling in processMidi.
+
+ MidiPort* mp = &midiPorts[_port];
+ MidiCtrlValListList* cll = mp->controller();
+ int pos = audio->tickPos();
+
+ //---------------------------------------------------
+ // Send new contoller values
+ //---------------------------------------------------
+
+ for(iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl)
+ {
+ MidiCtrlValList* vl = ivl->second;
+ iMidiCtrlVal imcv = vl->iValue(pos);
+ if(imcv != vl->end())
+ {
+ Part* p = imcv->second.part;
+ unsigned t = (unsigned)imcv->first;
+ // Do not add values that are outside of the part.
+ if(p && t >= p->tick() && t < (p->tick() + p->lenTick()) )
+ //_playEvents.add(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+ // Hmm, play event list for immediate playback? Try putEvent instead. p4.0.34
+ putMidiEvent(MidiPlayEvent(0, _port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
+ }
+ }
+
+ //---------------------------------------------------
+ // Send STOP and "set song position pointer"
+ //---------------------------------------------------
+
+ // Don't send if external sync is on. The master, and our sync routing system will take care of that. p3.3.31
+ if(!extSyncFlag.value())
+ {
+ if(mp->syncInfo().MRTOut())
+ {
+ // Shall we check for device write open flag to see if it's ok to send?...
+ // This means obey what the user has chosen for read/write in the midi port config dialog,
+ // which already takes into account whether the device is writable or not.
+ //if(!(rwFlags() & 0x1) || !(openFlags() & 1))
+ //if(!(openFlags() & 1))
+ // continue;
+
+ int beat = (pos * 4) / MusEConfig::config.division;
+
+ //bool isPlaying = (state == PLAY);
+ bool isPlaying = audio->isPlaying(); // TODO Check this it includes LOOP1 and LOOP2 besides PLAY. p4.0.22
+
+ mp->sendStop();
+ mp->sendSongpos(beat);
+ if(isPlaying)
+ mp->sendContinue();
+ }
+ }
+}
+
+//---------------------------------------------------------
// initMidiAlsa
// return true on error
//---------------------------------------------------------
@@ -539,7 +713,6 @@ bool initMidiAlsa()
}
}
- // p3.3.38
//snd_seq_set_client_name(alsaSeq, "MusE Sequencer");
snd_seq_set_client_name(alsaSeq, audioDevice->clientName());
@@ -773,31 +946,6 @@ void alsaProcessMidiInput()
return;
}
- /*
- if(curPort == -1)
- {
- if(mdev == 0)
- {
- if (MusEGlobal::debugMsg)
- {
- fprintf(stderr, "no port %d:%d found for received alsa event\n",
- ev->source.client, ev->source.port);
- }
- }
- else
- {
- // Allow the sync detect mechanisms to work, even if device is not assigned to a port.
- if(ev->type == SND_SEQ_EVENT_CLOCK)
- mdev->syncInfo().trigMCSyncDetect();
- else
- if(ev->type == SND_SEQ_EVENT_TICK)
- mdev->syncInfo().trigTickDetect();
- }
- snd_seq_free_event(ev);
- return;
- }
- */
-
event.setType(0); // mark as unused
event.setPort(curPort);
event.setB(0);
@@ -867,7 +1015,6 @@ void alsaProcessMidiInput()
break;
case SND_SEQ_EVENT_SYSEX:
-
// TODO: Deal with large sysex, which are broken up into chunks!
// For now, do not accept if the first byte is not SYSEX or the last byte is not EOX,
// meaning it's a chunk, possibly with more chunks to follow.
@@ -916,13 +1063,7 @@ void alsaProcessMidiInput()
break;
}
if(event.type())
- {
mdev->recordEvent(event);
- // p3.3.26 1/23/10 Moved to MidiDevice now. Anticipating Jack midi support, so don't make it ALSA specific. Tim.
- //if(ev->type != SND_SEQ_EVENT_SYSEX)
- // Trigger general activity indicator detector. Sysex has no channel, don't trigger.
- // midiPorts[curPort].syncInfo().trigActDetect(event.channel());
- }
snd_seq_free_event(ev);
if (rv == 0)
diff --git a/muse2/muse/driver/alsamidi.h b/muse2/muse/driver/alsamidi.h
index 01894f8c..13e07ca4 100644
--- a/muse2/muse/driver/alsamidi.h
+++ b/muse2/muse/driver/alsamidi.h
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: alsamidi.h,v 1.2 2004/01/14 09:06:43 wschweer Exp $
// (C) Copyright 2001 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
@@ -26,6 +27,7 @@
#include <config.h>
#include <alsa/asoundlib.h>
+#include "mpevent.h"
#include "mididev.h"
class Xml;
@@ -39,6 +41,13 @@ class MidiAlsaDevice : public MidiDevice {
snd_seq_addr_t adr;
private:
+ // Special for ALSA midi device: Play event list is processed in the ALSA midi sequencer thread.
+ // Need this FIFO, to decouple from audio thread which adds events to the list.
+ MidiFifo playEventFifo;
+ MidiFifo stuckNotesFifo;
+ volatile bool stopPending;
+ volatile bool seekPending;
+
virtual QString open();
virtual void close();
virtual void processInput() {}
@@ -49,17 +58,22 @@ class MidiAlsaDevice : public MidiDevice {
virtual bool putMidiEvent(const MidiPlayEvent&);
public:
- //MidiAlsaDevice() {} // p3.3.55 Removed
MidiAlsaDevice(const snd_seq_addr_t&, const QString& name);
virtual ~MidiAlsaDevice() {}
- //virtual void* clientPort() { return (void*)&adr; }
- // p3.3.55
virtual void* inClientPort() { return (void*)&adr; } // For ALSA midi, in/out client ports are the same.
virtual void* outClientPort() { return (void*)&adr; } // That is, ALSA midi client ports can be both r/w.
virtual void writeRouting(int, Xml&) const;
virtual inline int deviceType() const { return ALSA_MIDI; }
+ // Schedule an event for playback. Returns false if event cannot be delivered.
+ virtual bool addScheduledEvent(const MidiPlayEvent& ev) { return !playEventFifo.put(ev); }
+ // Add a stuck note. Returns false if event cannot be delivered.
+ virtual bool addStuckNote(const MidiPlayEvent& ev) { return !stuckNotesFifo.put(ev); }
+ // Play all events up to current frame.
+ virtual void processMidi();
+ virtual void handleStop();
+ virtual void handleSeek();
};
extern bool initMidiAlsa();
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index 2e790a10..a4577f0b 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: jackmidi.cpp,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $
// (C) Copyright 1999-2010 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
@@ -48,128 +49,16 @@
extern unsigned int volatile lastExtMidiSyncTick;
-///int jackmidi_pi[2];
-///int jackmidi_po[2];
-
-//extern muse_jack_midi_buffer jack_midi_out_data[JACK_MIDI_CHANNELS];
-//extern muse_jack_midi_buffer jack_midi_in_data[JACK_MIDI_CHANNELS];
-///extern jack_port_t *midi_port_in[JACK_MIDI_CHANNELS];
-///extern jack_port_t *midi_port_out[JACK_MIDI_CHANNELS];
-
-///MidiJackDevice* gmdev = NULL;
-
-///int* jackSeq;
-//static snd_seq_addr_t musePort;
-
-//int MidiJackDevice::_nextOutIdNum = 0;
-//int MidiJackDevice::_nextInIdNum = 0;
-
-//int JackMidiPortList::_nextOutIdNum = 0;
-//int JackMidiPortList::_nextInIdNum = 0;
-
-//JackMidiPortList jackMidiClientPorts;
-
-
-/*
-//---------------------------------------------------------
-// JackMidiPortList
-//---------------------------------------------------------
-
-JackMidiPortList::JackMidiPortList()
-{
-
-}
-
-JackMidiPortList::~JackMidiPortList()
-{
-
-}
-
-iJackMidiPort JackMidiPortList::createClientPort(int flags) // 1 = writable, 2 = readable - do not mix
-{
- if(flags & 1)
- {
- char buf[80];
- snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
- jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
- if(_client_jackport == NULL)
- {
- fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-out\n");
- //return QString("Could not register jack-midi-out client port");
- return end();
- }
- else
- {
- JackMidiPort jmp(_client_jackport, QString(buf), flags);
- _nextOutIdNum++;
- return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
- }
- }
- else
- if(flags & 2)
- {
- char buf[80];
- snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
- jack_port_t* _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
- if(_client_jackport == NULL)
- {
- fprintf(stderr, "JackMidiPortList::createClientPort failed to register jack-midi-in\n");
- return end();
- }
- else
- {
- JackMidiPort jmp(_client_jackport, QString(buf), flags);
- _nextInIdNum++;
- return insert(begin(), std::pair<jack_port_t*, JackMidiPort>(_client_jackport, jmp));
- }
- }
- return end();
-}
-
-// Return true if removed.
-bool JackMidiPortList::removeClientPort(jack_port_t* port)
-{
- iJackMidiPort ijp = find(port);
- if(ijp == end())
- return false;
-
- // Is output?
- if(ijp->second._flags & 1)
- _nextOutIdNum--;
- // Is input?
- if(ijp->second._flags & 2)
- _nextInIdNum--;
-
- erase(ijp);
-
- audioDevice->unregisterPort(port);
-
- return true;
-}
-*/
-
//---------------------------------------------------------
// MidiJackDevice
// in_jack_port or out_jack_port can be null
//---------------------------------------------------------
-//MidiJackDevice::MidiJackDevice(const int& a, const QString& n)
-//MidiJackDevice::MidiJackDevice(jack_port_t* jack_port, const QString& n)
-// p3.3.55
-//MidiJackDevice::MidiJackDevice(jack_port_t* in_jack_port, jack_port_t* out_jack_port, const QString& n)
MidiJackDevice::MidiJackDevice(const QString& n)
: MidiDevice(n)
{
- //_client_jackport = 0;
-
- //_client_jackport = jack_port;
- // p3.3.55
- //_in_client_jackport = in_jack_port;
- //_out_client_jackport = out_jack_port;
_in_client_jackport = NULL;
_out_client_jackport = NULL;
-
- //adr = a;
init();
}
@@ -179,10 +68,6 @@ MidiJackDevice::~MidiJackDevice()
printf("MidiJackDevice::~MidiJackDevice()\n");
#endif
- //if(_client_jackport)
- // audioDevice->unregisterPort(_client_jackport);
- // p3.3.55
-
if(audioDevice)
{
if(_in_client_jackport)
@@ -194,69 +79,13 @@ MidiJackDevice::~MidiJackDevice()
//close();
}
-/*
-//---------------------------------------------------------
-// select[RW]fd
-//---------------------------------------------------------
-
-int MidiJackDevice::selectRfd()
-{
- return jackmidi_pi[0];
-}
-
-int MidiJackDevice::selectWfd()
-{
- return jackmidi_po[0];
-}
-*/
-
//---------------------------------------------------------
// createJackMidiDevice
// If name parameter is blank, creates a new (locally) unique one.
//---------------------------------------------------------
-//QString MidiJackDevice::createJackMidiDevice(int rwflags) // 1:Writable 2: Readable. Do not mix.
-//MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable. Do not mix.
-MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // p3.3.55 1:Writable 2: Readable 3: Writable + Readable
+MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // 1:Writable 2: Readable 3: Writable + Readable
{
-/// _openFlags &= _rwFlags; // restrict to available bits
-
-/// #ifdef JACK_MIDI_DEBUG
-/// printf("MidiJackDevice::open %s\n", name.toLatin1().constData());
-/// #endif
-
- //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData());
-/// jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData());
-
-/// if(!jp)
-/// {
-/// printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().toLatin1().constData());
-/// _writeEnable = false;
-/// _readEnable = false;
-/// return QString("Jack midi port not found");
-/// }
-
-/// int pf = jack_port_flags(jp);
-
- //if(!name.isEmpty())
- //{
- // Does not work.
- // if(audioDevice->findPort(name.toLatin1().constData()))
- // {
- // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Given port name %s already exists!\n", name.toLatin1().constData());
- // return 0;
- // }
- //}
-
- //jack_port_t* client_jackport = NULL;
- // p3.3.55
- ///jack_port_t* in_client_jackport = NULL;
- ///jack_port_t* out_client_jackport = NULL;
-
- //char buf[80];
-
-
- // p3.3.55
int ni = 0;
if(name.isEmpty())
{
@@ -273,188 +102,7 @@ MidiDevice* MidiJackDevice::createJackMidiDevice(QString name, int rwflags) // p
return 0;
}
- // If Jack port can receive data from us and we actually want to...
- //if((pf & JackPortIsInput) && (_openFlags & 1))
- ///if(rwflags & 1)
- ///{
- /* p3.3.55 Removed.
- if(name.isEmpty())
- {
- //snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
- for(int i = 0; ; ++i)
- {
- //snprintf(buf, 80, "midi-out-%d", i);
- name.sprintf("midi-out-%d", i);
-
- if(!midiDevices.find(name))
- {
- // Does not work.
- //if(!audioDevice->findPort(buf))
- // break;
- //client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
- if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
- {
- //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true);
- out_client_jackport = (jack_port_t*)audioDevice->registerOutPort((name + QString("_out")).toLatin1().constData(), true); // p3.3.55
- //if(client_jackport)
- if(out_client_jackport) // p3.3.55
- break;
- }
- else
- break;
- }
-
- if(i == 65535)
- {
- fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
- return 0;
- }
- }
- //name = QString(buf);
- }
- else
- */
-
- /*
- {
- if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
- {
- //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true);
- out_client_jackport = (jack_port_t*)audioDevice->registerOutPort((name + QString(JACK_MIDI_OUT_PORT_SUFFIX)).toLatin1().constData(), true); // p3.3.55
- //if(!client_jackport)
- if(!out_client_jackport) // p3.3.55
- {
- //fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating output port name %s\n", name.toLatin1().constData());
- fprintf(stderr, "MusE: createJackMidiDevice failed creating output port name %s\n", (name + QString(JACK_MIDI_OUT_PORT_SUFFIX)).toLatin1().constData()); // p3.3.55
-
- //return 0;
- rwflags &= ~1; // p3.3.55 Remove the output r/w flag, but continue on...
- }
- }
- }
- */
-
- /*
- else
- {
- client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true);
- if(!client_jackport)
- {
- for(int i = 0; ; ++i)
- {
- snprintf(buf, 80, "midi-out-%d", i);
- // Does not work!
- //if(!audioDevice->findPort(buf))
- // break;
- client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
- if(client_jackport)
- break;
-
- if(i == 65535)
- {
- fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused output port name!\n");
- return 0;
- }
- }
- name = QString(buf);
- }
- }
- */
-
- //client_jackport = (jack_port_t*)audioDevice->registerOutPort(name.toLatin1().constData(), true);
- //if(client_jackport == NULL)
- //{
- // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client output port %s\n", name.toLatin1().constData());
- // return 0;
- //}
- //else
- // _nextOutIdNum++;
-
- ///}
- //else // Note docs say it can't be both input and output. // p3.3.55 Removed
-
- // If Jack port can send data to us and we actually want it...
- //if((pf & JackPortIsOutput) && (_openFlags & 2))
- ///if(rwflags & 2)
- ///{
- /* p3.3.55 Removed.
- if(name.isEmpty())
- {
- //snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
- for(int i = 0; ; ++i)
- {
- //snprintf(buf, 80, "midi-in-%d", i);
- name.sprintf("midi-in-%d", i);
-
- if(!midiDevices.find(name))
- {
- // Does not work.
- //if(!audioDevice->findPort(buf))
- // break;
- //client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
- if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
- {
- //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true);
- in_client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true); // p3.3.55
- //if(client_jackport)
- if(in_client_jackport) // p3.3.55
- break;
- }
- else
- break;
- }
-
- if(i == 65535)
- {
- fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed! Can't find unused input port name!\n");
- return 0;
- }
- }
- //name = QString(buf);
- }
- else
- */
-
- /*
- {
- if(audioDevice->deviceType() == AudioDevice::JACK_AUDIO) // p3.3.52
- {
- //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true);
- in_client_jackport = (jack_port_t*)audioDevice->registerInPort((name + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData(), true); // p3.3.55
- //if(!client_jackport)
- if(!in_client_jackport) // p3.3.55
- {
- //fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed creating input port name %s\n", name.toLatin1().constData());
- fprintf(stderr, "MusE: createJackMidiDevice failed creating input port name %s\n", (name + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData());
-
- //return 0;
- rwflags &= ~2; // p3.3.55 Remove the input r/w flag, but continue on...
- }
- }
- }
- */
-
- //client_jackport = (jack_port_t*)audioDevice->registerInPort(name.toLatin1().constData(), true);
-
- //if(client_jackport == NULL)
- //{
- // fprintf(stderr, "MidiJackDevice::createJackMidiDevice failed to register jack midi client input port %s\n", name.toLatin1().constData());
- //_readEnable = false;
- //return QString("Could not register jack-midi-in client port");
- // return 0;
- //}
- //else
- // _nextInIdNum++;
-
- ///}
-
- //if(client_jackport == NULL) // p3.3.52 Removed. Allow the device to be created even if Jack isn't running.
- // return 0;
-
- //MidiJackDevice* dev = new MidiJackDevice(client_jackport, name);
- //MidiJackDevice* dev = new MidiJackDevice(in_client_jackport, out_client_jackport, name); // p3.3.55
- //MidiJackDevice* dev = new MidiJackDevice(NULL, NULL, name); // p3.3.55
- MidiJackDevice* dev = new MidiJackDevice(name); // p3.3.55
+ MidiJackDevice* dev = new MidiJackDevice(name);
dev->setrwFlags(rwflags);
midiDevices.add(dev);
return dev;
@@ -471,9 +119,6 @@ void MidiJackDevice::setName(const QString& s)
#endif
_name = s;
- //if(clientPort()) // p3.3.52 Added check.
- // audioDevice->setPortName(clientPort(), s.toLatin1().constData());
- // p3.3.55
if(inClientPort())
audioDevice->setPortName(inClientPort(), (s + QString(JACK_MIDI_IN_PORT_SUFFIX)).toLatin1().constData());
if(outClientPort())
@@ -492,65 +137,7 @@ QString MidiJackDevice::open()
printf("MidiJackDevice::open %s\n", name().toLatin1().constData());
#endif
- /*
- //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData());
- jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData());
-
- if(!jp)
- {
- printf("MidiJackDevice::open: Jack midi port %s not found!\n", name().toLatin1().constData());
- _writeEnable = false;
- _readEnable = false;
- return QString("Jack midi port not found");
- }
-
- int pf = jack_port_flags(jp);
-
- // If Jack port can receive data from us and we actually want to...
- if((pf & JackPortIsInput) && (_openFlags & 1))
- {
- char buf[80];
- snprintf(buf, 80, "muse-jack-midi-out-%d", _nextOutIdNum);
- _client_jackport = (jack_port_t*)audioDevice->registerOutPort(buf, true);
- if(_client_jackport == NULL)
- {
- fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-out\n");
- _writeEnable = false;
- return QString("Could not register jack-midi-out client port");
- }
- else
- {
- _nextOutIdNum++;
- // src, dest
- ///audioDevice->connect(_client_jackport, jp);
- _writeEnable = true;
- }
- }
- else // Note docs say it can't be both input and output.
- // If Jack port can send data to us and we actually want it...
- if((pf & JackPortIsOutput) && (_openFlags & 2))
- {
- char buf[80];
- snprintf(buf, 80, "muse-jack-midi-in-%d", _nextInIdNum);
- _client_jackport = (jack_port_t*)audioDevice->registerInPort(buf, true);
- if(_client_jackport == NULL)
- {
- fprintf(stderr, "MidiJackDevice::open failed to register jack-midi-in\n");
- _readEnable = false;
- return QString("Could not register jack-midi-in client port");
- }
- else
- {
- _nextInIdNum++;
- ///audioDevice->connect(jp, _client_jackport);
- _readEnable = true;
- }
- }
- */
-
-
QString s;
- // p3.3.55 Moved from createJackMidiDevice()
if(_openFlags & 1)
{
if(!_out_client_jackport)
@@ -623,9 +210,6 @@ QString MidiJackDevice::open()
_in_client_jackport = NULL;
}
- //if(client_jackport == NULL) // p3.3.52 Removed. Allow the device to be created even if Jack isn't running.
- // return 0;
-
_writeEnable = bool(_openFlags & 1);
_readEnable = bool(_openFlags & 2);
@@ -642,10 +226,10 @@ void MidiJackDevice::close()
printf("MidiJackDevice::close %s\n", name().toLatin1().constData());
#endif
- // p3.3.55 TODO: I don't really want to unregister the
+ // TODO: I don't really want to unregister the
// Jack midi ports because then we lose the connections
// to Jack every time we click the read/write lights
- // or change a port's device.
+ // or change a port's device. p3.3.55
/*
if(_client_jackport)
@@ -667,38 +251,6 @@ void MidiJackDevice::close()
_writeEnable = false;
_readEnable = false;
-
- /*
- //jack_port_t* jp = jack_port_by_name(_client, name().toLatin1().constData());
- jack_port_t* jp = (jack_port_t*)audioDevice->findPort(name().toLatin1().constData());
-
- if(!jp)
- {
- printf("MidiJackDevice::close: Jack midi port %s not found!\n", name().toLatin1().constData());
- _writeEnable = false;
- _readEnable = false;
- return;
- }
-
- //int pf = jack_port_flags(jp);
-
- // If Jack port can receive data from us and we actually want to...
- //if((pf & JackPortIsInput) && (_openFlags & 1))
- if(jack_port_connected_to(midi_port_out[0], name().toLatin1().constData()))
- {
- // src, dest
-/// audioDevice->disconnect(midi_port_out[0], jp);
- _writeEnable = false;
- }
- else // Note docs say it can't be both input and output.
- // If Jack port can send data to us and we actually want it...
- //if((pf & JackPortIsOutput) && (_openFlags & 2))
- if(jack_port_connected_to(midi_port_in[0], name().toLatin1().constData()))
- {
-/// audioDevice->disconnect(jp, midi_port_in[0]);
- _readEnable = false;
- }
- */
}
//---------------------------------------------------------
@@ -707,7 +259,6 @@ void MidiJackDevice::close()
void MidiJackDevice::writeRouting(int level, Xml& xml) const
{
- // p3.3.45
// If this device is not actually in use by the song, do not write any routes.
// This prevents bogus routes from being saved and propagated in the med file.
if(midiPort() == -1)
@@ -716,30 +267,17 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const
QString s;
if(rwFlags() & 2) // Readable
{
- //RouteList* rl = _inRoutes;
- //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
for (ciRoute r = _inRoutes.begin(); r != _inRoutes.end(); ++r)
{
if(!r->name().isEmpty())
{
xml.tag(level++, "Route");
-
- //xml.strTag(level, "srcNode", r->name());
- //xml.tag(level, "source type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData());
s = QT_TRANSLATE_NOOP("@default", "source");
if(r->type != Route::TRACK_ROUTE)
s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type);
-
- //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());
s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));
xml.tag(level, s.toLatin1().constData());
-
- //xml.strTag(level, "dstNode", name());
- //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData());
- //xml.tag(level, "dest type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData());
- //xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().toLatin1().constData());
xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());
-
xml.etag(level--, "Route");
}
}
@@ -752,49 +290,14 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const
s = QT_TRANSLATE_NOOP("@default", "Route");
if(r->channel != -1)
s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel);
-
- //xml.tag(level++, "Route");
xml.tag(level++, s.toLatin1().constData());
-
- /*
- //xml.strTag(level, "srcNode", name());
- if(r->channel != -1)
- //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, r->channel, name().toLatin1().constData());
- //xml.tag(level, "source type=\"%d\" channel=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, r->channel, name().toLatin1().constData());
- xml.tag(level, "source devtype=\"%d\" channel=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, r->channel, name().toLatin1().constData());
- else
- //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData());
- //xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::MIDI_DEVICE_ROUTE, name().toLatin1().constData());
- */
- //xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, name().toLatin1().constData());
- xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());
-
- /*
- //xml.strTag(level, "dstNode", r->name());
- if(r->channel != -1)
- {
- if(r->type == Route::MIDI_DEVICE_ROUTE)
- xml.tag(level, "dest devtype=\"%d\" channel=\"%d\" name=\"%s\"/", r->device->deviceType(), r->channel, r->name().toLatin1().constData());
- else
- xml.tag(level, "dest type=\"%d\" channel=\"%d\" name=\"%s\"/", r->type, r->channel, r->name().toLatin1().constData());
- }
- else
- {
- if(r->type == Route::MIDI_DEVICE_ROUTE)
- xml.tag(level, "dest devtype=\"%d\" name=\"%s\"/", r->device->deviceType(), r->name().toLatin1().constData());
- else
- xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData());
- }
- */
-
+ xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::JACK_MIDI, Xml::xmlString(name()).toLatin1().constData());
s = QT_TRANSLATE_NOOP("@default", "dest");
if(r->type == Route::MIDI_DEVICE_ROUTE)
s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType());
else
if(r->type != Route::TRACK_ROUTE)
s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type);
-
- //s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(r->name());
s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name()));
xml.tag(level, s.toLatin1().constData());
@@ -802,33 +305,6 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const
xml.etag(level--, "Route");
}
}
-
- /*
- else
- if(rwFlags() & 1) // Writable
- {
- //RouteList* rl = _outRoutes;
- //for (ciRoute r = rl->begin(); r != rl->end(); ++r)
- for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r)
- {
- if(!r->name().isEmpty())
- {
- xml.tag(level++, "Route");
-
- //xml.strTag(level, "srcNode", name());
- //if(r->channel != -1)
- // xml.tag(level, "srcNode type=\"%d\" channel=\"%d\" name=\"%s\"", Route::JACK_MIDI_ROUTE, r->channel, name().toLatin1().constData());
- //else
- xml.tag(level, "source type=\"%d\" name=\"%s\"/", Route::JACK_MIDI_ROUTE, name().toLatin1().constData());
-
- //xml.strTag(level, "dstNode", r->name());
- xml.tag(level, "dest type=\"%d\" name=\"%s\"/", r->type, r->name().toLatin1().constData());
-
- xml.etag(level--, "Route");
- }
- }
- }
- */
}
//---------------------------------------------------------
@@ -841,80 +317,8 @@ void MidiJackDevice::writeRouting(int level, Xml& xml) const
*/
bool MidiJackDevice::putMidiEvent(const MidiPlayEvent& /*event*/)
{
- /*
- int give, channel = event.channel();
- int x;
-
- if(channel >= JACK_MIDI_CHANNELS) return false;
-
- // buffer up events, because jack eats them in chunks, if
- // the buffer is full, there isn't so much to do, than
- // drop the event
-
- give = jack_midi_out_data[channel].give;
- if(jack_midi_out_data[channel].buffer[give*4+3]){
- fprintf(stderr, "WARNING: muse-to-jack midi-buffer is full, channel=%u\n", channel);
- return false;
- }
- // copy event(note-on etc..), pitch and volume
- // see http://www.midi.org/techspecs/midimessages.php
- switch(event.type()){
- case ME_NOTEOFF:
- jack_midi_out_data[channel].buffer[give*4+0] = 0x80;
- jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
- jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
- break;
- case ME_NOTEON:
- jack_midi_out_data[channel].buffer[give*4+0] = 0x90;
- jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
- jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
- break;
- case ME_CONTROLLER:
- jack_midi_out_data[channel].buffer[give*4+0] = 0xb0;
- jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
- jack_midi_out_data[channel].buffer[give*4+2] = event.dataB() & 0x7f;
- break;
- case ME_PROGRAM:
- jack_midi_out_data[channel].buffer[give*4+0] = 0xc0;
- jack_midi_out_data[channel].buffer[give*4+1] = event.dataA() & 0x7f;
- jack_midi_out_data[channel].buffer[give*4+2] = 0;
- break;
- case ME_PITCHBEND:
- jack_midi_out_data[channel].buffer[give*4+0] = 0xE0;
- // convert muse pitch-bend to midi standard
- x = 0x2000 + event.dataA();
- jack_midi_out_data[channel].buffer[give*4+1] = x & 0x7f;
- jack_midi_out_data[channel].buffer[give*4+2] = (x >> 8) & 0x7f;
- break;
- default:
- fprintf(stderr, "jack-midi-out %u WARNING: unknown event %x\n", channel, event.type());
- return false;
- }
- jack_midi_out_data[channel].buffer[give*4+3] = 1; // mark state of this slot
- // finally increase give position
- give++;
- if(give >= JACK_MIDI_BUFFER_SIZE){
- give = 0;
- }
- jack_midi_out_data[channel].give = give;
- return false;
- */
-
- return false;
-}
-
-/*
-//---------------------------------------------------------
-// putEvent
-// return false if event is delivered
-//---------------------------------------------------------
-
-bool MidiJackDevice::putEvent(int* event)
-{
- int *y; y = event;
return false;
}
-*/
//---------------------------------------------------------
// recordEvent
@@ -1004,9 +408,8 @@ void MidiJackDevice::recordEvent(MidiRecordEvent& event)
//if(_recordFifo.put(MidiPlayEvent(event)))
// printf("MidiJackDevice::recordEvent: fifo overflow\n");
- // p3.3.38
// Do not bother recording if it is NOT actually being used by a port.
- // Because from this point on, process handles things, by selected port.
+ // Because from this point on, process handles things, by selected port. p3.3.38
if(_port == -1)
return;
@@ -1025,7 +428,7 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
MidiRecordEvent event;
event.setB(0);
- // NOTE: From MusE-2. Not done here in Muse-1 (yet).
+ // NOTE: From muse_qt4_evolution. Not done here in Muse-2 (yet).
// move all events 2*MusEGlobal::segmentSize into the future to get
// jitterfree playback
//
@@ -1034,15 +437,11 @@ void MidiJackDevice::eventReceived(jack_midi_event_t* ev)
// ^ ^ ^
// catch process play
//
-// const SeqTime* st = audio->seqTime();
-
- //unsigned curFrame = st->startFrame() + MusEGlobal::segmentSize;
-// unsigned curFrame = st->lastFrameTime;
+
//int frameOffset = audio->getFrameOffset();
unsigned pos = audio->pos().frame();
- //event.setTime(pos + ev->time);
- event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time));
+ event.setTime(extSyncFlag.value() ? lastExtMidiSyncTick : (pos + ev->time)); // p3.3.25
event.setChannel(*(ev->buffer) & 0xf);
int type = *(ev->buffer) & 0xf0;
@@ -1144,13 +543,10 @@ void MidiJackDevice::collectMidiEvents()
if(!_readEnable)
return;
- //if(!_client_jackport)
- if(!_in_client_jackport) // p3.3.55
+ if(!_in_client_jackport)
return;
- //void* port_buf = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize);
- void* port_buf = jack_port_get_buffer(_in_client_jackport, MusEGlobal::segmentSize); // p3.3.55
-
+ void* port_buf = jack_port_get_buffer(_in_client_jackport, MusEGlobal::segmentSize);
jack_midi_event_t event;
jack_nframes_t eventCount = jack_midi_get_event_count(port_buf);
for (jack_nframes_t i = 0; i < eventCount; ++i)
@@ -1172,9 +568,7 @@ void MidiJackDevice::collectMidiEvents()
bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)
{
- //if(!_writeEnable)
- if(!_writeEnable || !_out_client_jackport) // p4.0.15
- //return true;
+ if(!_writeEnable || !_out_client_jackport)
return false;
#ifdef JACK_MIDI_DEBUG
@@ -1193,9 +587,7 @@ bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)
// return true if successful
//---------------------------------------------------------
-//void JackAudioDevice::putEvent(Port port, const MidiEvent& e)
bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
-//bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
{
// Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
// No big deal if not. Not used for now.
@@ -1212,11 +604,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
//if(MusEGlobal::debugMsg)
// printf("MidiJackDevice::queueEvent\n");
- //if(!_client_jackport)
- if(!_out_client_jackport) // p3.3.55
+ if(!_out_client_jackport)
return false;
- //void* pb = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize);
- void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize); // p3.3.55
+ void* pb = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);
//unsigned frameCounter = ->frameTime();
int frameOffset = audio->getFrameOffset();
@@ -1340,7 +730,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
// Just do this 'standard midi 64T timing thing' for now until we figure out more precise external timings.
// Does require relatively short audio buffers, in order to catch the resolution, but buffer <= 256 should be OK...
// Tested OK so far with 128.
- ///if(extSyncFlag.value())
+ //if(extSyncFlag.value())
// p4.0.15 Or, is the event marked to be played immediately?
// Nothing to do but stamp the event to be queued for frame 0+.
if(t == 0 || extSyncFlag.value())
@@ -1377,17 +767,13 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
if(event.type() == ME_PITCHBEND)
{
int v = a + 8192;
- // p3.3.44
//printf("MidiJackDevice::processEvent ME_PITCHBEND v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
-
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))
return false;
}
else
if(event.type() == ME_CONTROLLER)
{
- //int a = event.dataA();
- //int b = event.dataB();
// Perhaps we can find use for this value later, together with the Jack midi MusE port(s).
// No big deal if not. Not used for now.
//int port = event.port();
@@ -1407,9 +793,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
if(a == CTRL_PITCH)
{
int v = b + 8192;
- // p3.3.44
//printf("MidiJackDevice::processEvent CTRL_PITCH v:%d time:%d type:%d ch:%d A:%d B:%d\n", v, event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
-
if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))
return false;
}
@@ -1420,8 +804,6 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
int hb = (b >> 16) & 0xff;
int lb = (b >> 8) & 0xff;
int pr = b & 0x7f;
-
- // p3.3.44
//printf("MidiJackDevice::processEvent CTRL_PROGRAM time:%d type:%d ch:%d A:%d B:%d hb:%d lb:%d pr:%d\n",
// event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
@@ -1440,7 +822,7 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
// }
}
- else if (a == CTRL_MASTER_VOLUME) // Enabled p4.0.15 Tim.
+ else if (a == CTRL_MASTER_VOLUME)
{
unsigned char sysex[] = {
0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00
@@ -1596,19 +978,16 @@ bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
}
//---------------------------------------------------------
-// processMidi called from audio process only.
+// processMidi
+// Called from audio thread only.
//---------------------------------------------------------
void MidiJackDevice::processMidi()
{
- //if(!_client_jackport)
- //if(!_out_client_jackport) // p3.3.55
- // return;
+ processStuckNotes();
- //void* port_buf = jack_port_get_buffer(_client_jackport, MusEGlobal::segmentSize);
- //void* port_buf = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize); // p3.3.55
void* port_buf = 0;
- if(_out_client_jackport && _writeEnable) // p4.0.15
+ if(_out_client_jackport && _writeEnable)
{
port_buf = jack_port_get_buffer(_out_client_jackport, MusEGlobal::segmentSize);
jack_midi_clear_buffer(port_buf);
@@ -1616,45 +995,24 @@ void MidiJackDevice::processMidi()
while(!eventFifo.isEmpty())
{
- ///MidiPlayEvent e(eventFifo.get());
- MidiPlayEvent e(eventFifo.peek()); // p4.0.15
-
- ///int evTime = e.time();
- // Is event marked to be played immediately? p4.0.15 Moved into processEvent().
- ///if(evTime == 0)
- ///{
- // Nothing to do but stamp the event to be queued for frame 0+.
- //e.setTime(frameOffset + pos);
- /// e.setTime(audio->getFrameOffset() + audio->pos().frame());
- ///}
-
- //#ifdef JACK_MIDI_DEBUG
- //printf("MidiJackDevice::processMidi eventFifo time:%d type:%d ch:%d A:%d B:%d\n", e.time(), e.type(), e.channel(), e.dataA(), e.dataB());
- //#endif
-
- //el->insert(eventFifo.get());
- //el->insert(e);
- ///processEvent(e);
- // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events.
+ MidiPlayEvent e(eventFifo.peek());
+ // Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. p4.0.15
if(port_buf && !processEvent(e))
return; // Give up. The Jack buffer is full. Nothing left to do.
eventFifo.remove(); // Successfully processed event. Remove it from FIFO.
}
- MPEventList* el = playEvents();
- if(el->empty())
+ if(_playEvents.empty())
{
//printf("MidiJackDevice::processMidi play events empty\n");
return;
}
- //printf("MidiJackDevice::processMidi play events:\n");
- ///iMPEvent i = nextPlayEvent();
- iMPEvent i = el->begin(); // p4.0.15
- for(; i != el->end(); ++i)
+ iMPEvent i = _playEvents.begin();
+ for(; i != _playEvents.end(); ++i)
{
//printf("MidiJackDevice::processMidi playEvent time:%d type:%d ch:%d A:%d B:%d\n", i->time(), i->type(), i->channel(), i->dataA(), i->dataB());
- // p3.3.39 Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
+ // Update hardware state so knobs and boxes are updated. Optimize to avoid re-setting existing values.
// Same code as in MidiPort::sendEvent()
if(_port != -1)
{
@@ -1672,12 +1030,10 @@ void MidiJackDevice::processMidi()
if(i->type() == ME_PITCHBEND)
{
//printf("MidiJackDevice::processMidi playEvents ME_PITCHBEND time:%d type:%d ch:%d A:%d B:%d\n", (*i).time(), (*i).type(), (*i).channel(), (*i).dataA(), (*i).dataB());
-
int da = mp->limitValToInstrCtlRange(CTRL_PITCH, i->dataA());
if(!mp->setHwCtrlState(i->channel(), CTRL_PITCH, da))
continue;
//mp->setHwCtrlState(i->channel(), CTRL_PITCH, da);
-
//(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
}
else
@@ -1689,25 +1045,11 @@ void MidiJackDevice::processMidi()
}
}
- ///processEvent(*i);
- // p4.0.15 Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events.
- if(port_buf && !processEvent(*i))
- {
- //setNextPlayEvent(i);
- //return;
+ // Try to process only until full, keep rest for next cycle. If no out client port or no write enable, eat up events. p4.0.15
+ if(port_buf && !processEvent(*i))
break;
- }
}
-
- ///setNextPlayEvent(i);
- // p4.0.15 We are done with these events. Let us erase them here instead of Audio::processMidi.
- // That way we can simply set the next play event to the beginning.
- // This also allows other events to be inserted without the problems caused by the next play event
- // being at the 'end' iterator and not being *easily* set to some new place beginning of the newer insertions.
- // The way that MPEventList sorts made it difficult to predict where the iterator of the first newly inserted items was.
- // The erasure in Audio::processMidi was missing some events because of that.
- el->erase(el->begin(), i);
- // setNextPlayEvent(el->begin()); // Removed p4.0.15 Tim.
+ _playEvents.erase(_playEvents.begin(), i);
}
@@ -1718,139 +1060,6 @@ void MidiJackDevice::processMidi()
bool initMidiJack()
{
- /*
- int adr = 0;
-
- memset(jack_midi_out_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
- memset(jack_midi_in_data, 0, JACK_MIDI_CHANNELS * sizeof(muse_jack_midi_buffer));
-
- MidiJackDevice* dev = new MidiJackDevice(adr, QString("jack-midi"));
- dev->setrwFlags(3); // set read and write flags
-
- if(pipe(jackmidi_pi) < 0){
- fprintf(stderr, "cant create midi-jack input pipe\n");
- }
- if(pipe(jackmidi_po) < 0){
- fprintf(stderr, "cant create midi-jack output pipe\n");
- }
-
- midiDevices.add(dev);
-
- gmdev = dev; // proclaim the global jack-midi instance
-
- //jackScanMidiPorts();
- */
-
return false;
}
-/*
-struct JackPort {
- int adr;
- //char* name;
- QString name;
- int flags;
- //JackPort(int a, const char* s, int f) {
- JackPort(int a, const QString& s, int f) {
- adr = a;
- //name = strdup(s);
- name = QString(s);
- flags = f;
- }
- };
-
-
-static std::list<JackPort> portList;
-
-//---------------------------------------------------------
-// jackScanMidiPorts
-//---------------------------------------------------------
-
-void jackScanMidiPorts()
-{
- int adr;
- const char* name;
-
- portList.clear();
- adr = 0;
- name = strdup("namex");
- portList.push_back(JackPort(adr, name, 0));
- //
- // check for devices to add
- //
- for (std::list<JackPort>::iterator k = portList.begin(); k != portList.end(); ++k) {
- iMidiDevice i = midiDevices.begin();
- for (;i != midiDevices.end(); ++i) {
- //MidiJackDevice* d = dynamic_cast<MidiJackDevice*>(*i);
- break;
- //if (d == 0) continue;
- //if ((k->adr.client == d->adr.client) && (k->adr.port == d->adr.port)) {
- // break;
- //}
- }
- if (i == midiDevices.end()) {
- // add device
- MidiJackDevice* dev = new MidiJackDevice(k->adr, QString(k->name));
- dev->setrwFlags(k->flags);
- midiDevices.add(dev);
- }
- }
-}
-*/
-
-/*
-//---------------------------------------------------------
-// processInput
-//---------------------------------------------------------
-static void handle_jack_midi_in(int channel)
-{
- MidiRecordEvent event;
- int t,n,v;
- t = jack_midi_in_data[channel].buffer[0];
- n = jack_midi_in_data[channel].buffer[1];
- v = jack_midi_in_data[channel].buffer[2];
-
- event.setType(0); // mark as unused
- event.setPort(gmdev->midiPort());
- event.setB(0);
-
- if(t == 0x90){ // note on
- fprintf(stderr, "jackProcessMidiInput note-on\n");
- event.setChannel(channel);
- event.setType(ME_NOTEON);
- event.setA(n);
- event.setB(v);
- }else if (t == 0x80){ // note off
- fprintf(stderr, "jackProcessMidiInput note-off\n");
- event.setChannel(channel);
- event.setType(ME_NOTEOFF);
- event.setA(n);
- event.setB(v);
- }else{
- fprintf(stderr, "WARNING: unknown midi-in on channel %d: %x,%x,%x\n",
- channel, t, n, v);
- return;
- }
- if(event.type()){
- gmdev->recordEvent(event);
- midiPorts[gmdev->midiPort()].syncInfo().trigActDetect(event.channel());
- }
-}
-
-void MidiJackDevice::processInput()
-{
- char buf;
- int i,s;
- read(gmdev->selectRfd(), &buf, 1);
-
- s = 1;
- for(i = 0; i < JACK_MIDI_CHANNELS; i++){
- if(jack_midi_in_data[i].buffer[3]){
- s = 0;
- handle_jack_midi_in(i);
- jack_midi_in_data[i].buffer[3] = 0;
- }
- }
-}
-
-*/
diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h
index 2c027c00..e79e9288 100644
--- a/muse2/muse/driver/jackmidi.h
+++ b/muse2/muse/driver/jackmidi.h
@@ -3,6 +3,7 @@
// Linux Music Editor
// $Id: jackmidi.h,v 1.1.1.1 2010/01/27 09:06:43 terminator356 Exp $
// (C) Copyright 1999-2010 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
@@ -40,81 +41,17 @@ class MidiPlayEvent;
//class RouteList;
class Xml;
-// Turn on to show multiple devices, work in progress,
-// not working fully yet, can't seem to connect...
-//#define JACK_MIDI_SHOW_MULTIPLE_DEVICES
-
// It appears one client port per remote port will be necessary.
// Jack doesn't seem to like manipulation of non-local ports buffers.
//#define JACK_MIDI_USE_MULTIPLE_CLIENT_PORTS
-/* jack-midi channels */
-//#define JACK_MIDI_CHANNELS 32
-
-/* jack-midi buffer size */
-//#define JACK_MIDI_BUFFER_SIZE 32
-
-/*
-typedef struct {
- int give;
- int take;
- // 32 parallel midi events, where each event contains three
- // midi-bytes and one busy-byte
- char buffer[4 * JACK_MIDI_BUFFER_SIZE];
-} muse_jack_midi_buffer;
-*/
-
-/*
-struct JackMidiPort
-{
- jack_port_t* _jackPort;
- QString _name;
- int _flags; // 1 = writable, 2 = readable - do not mix
- JackMidiPort(jack_port_t* jp, const QString& s, int f)
- {
- _jackPort = jp;
- _name = QString(s);
- _flags = f;
- }
-};
-
-typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::iterator iJackMidiPort;
-typedef std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >::const_iterator ciJackMidiPort;
-
-class JackMidiPortList : public std::map<jack_port_t*, JackMidiPort, std::less<jack_port_t*> >
-{
- private:
- static int _nextOutIdNum;
- static int _nextInIdNum;
-
- public:
- JackMidiPortList();
- ~JackMidiPortList();
- iJackMidiPort createClientPort(int flags);
- bool removeClientPort(jack_port_t* port);
-};
-
-extern JackMidiPortList jackMidiClientPorts;
-*/
-
//---------------------------------------------------------
// MidiJackDevice
//---------------------------------------------------------
class MidiJackDevice : public MidiDevice {
- public:
- //int adr;
-
private:
- // fifo for midi events sent from gui
- // direct to midi port:
- //MidiFifo eventFifo; // Moved into MidiDevice p4.0.15
-
- //static int _nextOutIdNum;
- //static int _nextInIdNum;
- //jack_port_t* _client_jackport;
- // p3.3.55
jack_port_t* _in_client_jackport;
jack_port_t* _out_client_jackport;
@@ -134,49 +71,27 @@ class MidiJackDevice : public MidiDevice {
void eventReceived(jack_midi_event_t*);
public:
- //MidiJackDevice() {} // p3.3.55 Removed.
- //MidiJackDevice(const int&, const QString& name);
-
- //MidiJackDevice(jack_port_t* jack_port, const QString& name);
- //MidiJackDevice(jack_port_t* in_jack_port, jack_port_t* out_jack_port, const QString& name); // p3.3.55 In or out port can be null.
MidiJackDevice(const QString& name);
- //static MidiDevice* createJackMidiDevice(QString /*name*/, int /*rwflags*/); // 1:Writable 2: Readable. Do not mix.
- static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // p3.3.55 1:Writable 2: Readable 3: Writable + Readable
-
+ static MidiDevice* createJackMidiDevice(QString name = "", int rwflags = 3); // 1:Writable 2: Readable 3: Writable + Readable
virtual inline int deviceType() const { return JACK_MIDI; }
-
virtual void setName(const QString&);
virtual void processMidi();
virtual ~MidiJackDevice();
- //virtual int selectRfd();
- //virtual int selectWfd();
- //virtual void processInput();
virtual void recordEvent(MidiRecordEvent&);
virtual bool putEvent(const MidiPlayEvent&);
virtual void collectMidiEvents();
- //virtual jack_port_t* jackPort() { return _jackport; }
- //virtual jack_port_t* clientJackPort() { return _client_jackport; }
-
- //virtual void* clientPort() { return (void*)_client_jackport; }
- // p3.3.55
virtual void* inClientPort() { return (void*) _in_client_jackport; }
virtual void* outClientPort() { return (void*) _out_client_jackport; }
- //RouteList* routes() { return &_routes; }
- //bool noRoute() const { return _routes.empty(); }
virtual void writeRouting(int, Xml&) const;
};
extern bool initMidiJack();
-//extern int jackSelectRfd();
-//extern int jackSelectWfd();
-//extern void jackProcessMidiInput();
-//extern void jackScanMidiPorts();
#endif
diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp
index dfdf94c6..20bee129 100644
--- a/muse2/muse/instruments/minstrument.cpp
+++ b/muse2/muse/instruments/minstrument.cpp
@@ -559,6 +559,7 @@ void MidiInstrument::reset(int portNo, MType)
// These loops send 2048 events, which is more than our FIFO (or Jack buffer) can handle! p4.0.15 Tim.
// Nope, instead, increased FIFO sizes to accommodate.
//port->device()->playEvents()->add(ev);
+ //port->device()->addScheduledEvent(ev);
}
}
}
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;
}
diff --git a/muse2/muse/midi.h b/muse2/muse/midi.h
index 2bfe695b..f137d7e5 100644
--- a/muse2/muse/midi.h
+++ b/muse2/muse/midi.h
@@ -4,6 +4,7 @@
// $Id: midi.h,v 1.4.2.2 2009/11/09 20:28:28 terminator356 Exp $
//
// (C) Copyright 1999/2000 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
@@ -86,7 +87,6 @@ QString midiMetaName(int);
class EventList;
class MPEventList;
class MidiTrack;
-//extern void buildMidiEventList(EventList* mel, const MPEventList* el, MidiTrack* track, int division, bool);
extern void buildMidiEventList(EventList* mel, const MPEventList* el, MidiTrack* track, int division, bool /*addSysexMeta*/, bool /*doLoops*/);
// extern bool checkSysex(MidiTrack* track, unsigned int len, unsigned char* buf);
diff --git a/muse2/muse/mididev.cpp b/muse2/muse/mididev.cpp
index a97ac1fb..a06303e1 100644
--- a/muse2/muse/mididev.cpp
+++ b/muse2/muse/mididev.cpp
@@ -4,6 +4,7 @@
// $Id: mididev.cpp,v 1.10.2.6 2009/11/05 03:14:35 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
@@ -596,6 +597,34 @@ bool MidiDevice::putEvent(const MidiPlayEvent& ev)
}
//---------------------------------------------------------
+// processStuckNotes
+//---------------------------------------------------------
+
+void MidiDevice::processStuckNotes()
+{
+ // Must be playing for valid nextTickPos, right? But wasn't checked in Audio::processMidi().
+ // audio->isPlaying() might not be true during seek right now.
+ //if(audio->isPlaying())
+ {
+ bool extsync = extSyncFlag.value();
+ int frameOffset = audio->getFrameOffset();
+ unsigned nextTick = audio->nextTick();
+ iMPEvent k;
+ for (k = _stuckNotes.begin(); k != _stuckNotes.end(); ++k) {
+ if (k->time() >= nextTick)
+ break;
+ MidiPlayEvent ev(*k);
+ if(extsync) // p3.3.25
+ ev.setTime(k->time());
+ else
+ ev.setTime(tempomap.tick2frame(k->time()) + frameOffset);
+ _playEvents.add(ev);
+ }
+ _stuckNotes.erase(_stuckNotes.begin(), k);
+ }
+}
+
+//---------------------------------------------------------
// handleStop
//---------------------------------------------------------
diff --git a/muse2/muse/mididev.h b/muse2/muse/mididev.h
index 00e4ab65..cdb69ea2 100644
--- a/muse2/muse/mididev.h
+++ b/muse2/muse/mididev.h
@@ -4,6 +4,7 @@
// $Id: mididev.h,v 1.3.2.4 2009/04/04 01:49:50 terminator356 Exp $
//
// (C) Copyright 2000 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
@@ -41,8 +42,8 @@ class Xml;
//---------------------------------------------------------
class MidiDevice {
- MPEventList _stuckNotes;
- MPEventList _playEvents;
+ //MPEventList _stuckNotes;
+ //MPEventList _playEvents;
// Removed p4.0.15 Tim.
//iMPEvent _nextPlayEvent;
@@ -71,6 +72,9 @@ class MidiDevice {
//bool _sysexWritingChunks;
bool _sysexReadingChunks;
+ MPEventList _stuckNotes;
+ MPEventList _playEvents;
+
// Fifo for midi events sent from gui direct to midi port:
MidiFifo eventFifo; // p4.0.15
@@ -84,6 +88,7 @@ class MidiDevice {
void init();
virtual bool putMidiEvent(const MidiPlayEvent&) = 0;
+ virtual void processStuckNotes();
public:
enum { ALSA_MIDI=0, JACK_MIDI=1, SYNTH_MIDI=2 };
@@ -130,21 +135,24 @@ class MidiDevice {
virtual void recordEvent(MidiRecordEvent&);
+ // Schedule an event for playback. Returns false if event cannot be delivered.
+ virtual bool addScheduledEvent(const MidiPlayEvent& ev) { _playEvents.add(ev); return true; }
+ // Add a stuck note. Returns false if event cannot be delivered.
+ virtual bool addStuckNote(const MidiPlayEvent& ev) { _stuckNotes.add(ev); return true; }
+ // Put an event for immediate playback.
virtual bool putEvent(const MidiPlayEvent&);
// This method will try to putEvent 'tries' times, waiting 'delayUs' microseconds between tries.
// Since it waits, it should not be used in RT or other time-sensitive threads. p4.0.15
bool putEventWithRetry(const MidiPlayEvent&, int /*tries*/ = 2, long /*delayUs*/ = 50000); // 2 tries, 50 mS by default.
- // p4.0.22
- virtual void handleStop();
+ virtual void handleStop(); // p4.0.22
virtual void handleSeek();
- // For Jack-based devices - called in Jack audio process callback
virtual void collectMidiEvents() {}
virtual void processMidi() {}
- MPEventList* stuckNotes() { return &_stuckNotes; }
- MPEventList* playEvents() { return &_playEvents; }
+ //MPEventList* stuckNotes() { return &_stuckNotes; }
+ //MPEventList* playEvents() { return &_playEvents; }
///MREventList* recordEvents();
///void flipRecBuffer() { _recBufFlipped = _recBufFlipped ? false : true; }
diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp
index c2f3c7bd..2f1174cd 100644
--- a/muse2/muse/midiseq.cpp
+++ b/muse2/muse/midiseq.cpp
@@ -74,12 +74,15 @@ void MidiSeq::processMsg(const ThreadMsg* m)
//case MS_PROCESS:
// audio->processMidi();
// break;
- case SEQM_SEEK:
- processSeek();
- break;
- case MS_STOP:
- processStop();
- break;
+
+ // Removed p4.0.34
+ //case SEQM_SEEK:
+ // processSeek();
+ // break;
+ //case MS_STOP:
+ // processStop();
+ // break;
+
case MS_SET_RTC:
MusEGlobal::doSetuid();
setRtcTicks();
@@ -88,6 +91,8 @@ void MidiSeq::processMsg(const ThreadMsg* m)
case MS_UPDATE_POLL_FD:
updatePollFd();
break;
+ // Moved into Song::processMsg p4.0.34
+ /*
case SEQM_ADD_TRACK:
song->insertTrack2(msg->track, msg->ival);
updatePollFd();
@@ -110,6 +115,7 @@ void MidiSeq::processMsg(const ThreadMsg* m)
//song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2);
song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2, msg->a, msg->b);
break;
+ */
case SEQM_SET_TRACK_OUT_CHAN:
{
MidiTrack* track = (MidiTrack*)(msg->p1);
@@ -141,6 +147,8 @@ void MidiSeq::processMsg(const ThreadMsg* m)
}
}
+#if 0
+// Removed p4.0.34
//---------------------------------------------------------
// processStop
//---------------------------------------------------------
@@ -148,8 +156,8 @@ void MidiSeq::processMsg(const ThreadMsg* m)
void MidiSeq::processStop()
{
// p3.3.28
- // TODO Try to move this into Audio::stopRolling(). p4.0.22
- playStateExt = false; // not playing
+ // TODO Try to move this into Audio::stopRolling(). p4.0.22 // Done p4.0.34
+ //playStateExt = false; // not playing
//
// clear Alsa midi device notes and stop stuck notes
@@ -157,10 +165,10 @@ void MidiSeq::processStop()
//
for(iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id)
{
- MidiDevice* md = *id;
- if(md->deviceType() == MidiDevice::JACK_MIDI) // p4.0.22
- continue;
- md->handleStop(); // p4.0.22
+ //MidiDevice* md = *id;
+ // Only ALSA devices are handled by this thread.
+ if((*id)->deviceType() == MidiDevice::ALSA_MIDI) // p4.0.22
+ (*id)->handleStop(); // p4.0.22
/*
if (md->midiPort() == -1)
continue;
@@ -178,18 +186,20 @@ void MidiSeq::processStop()
*/
}
}
+#endif
+#if 0
+// Removed p4.0.34
//---------------------------------------------------------
// processSeek
//---------------------------------------------------------
void MidiSeq::processSeek()
{
- int pos = audio->tickPos();
-
- // TODO Try to move this into audio::seek(). p4.0.22
- if (pos == 0 && !song->record())
- audio->initDevices();
+ //int pos = audio->tickPos();
+ // TODO Try to move this into audio::seek(). p4.0.22 Done p4.0.34
+ //if (pos == 0 && !song->record())
+ // audio->initDevices();
//---------------------------------------------------
// set all controller
@@ -197,13 +207,10 @@ void MidiSeq::processSeek()
for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i)
{
- MidiDevice* md = *i;
- //
- // Jack midi devices are handled in Audio::seek()
- //
- if(md->deviceType() == MidiDevice::JACK_MIDI) // p4.0.22
- continue;
- md->handleSeek(); // p4.0.22
+ //MidiDevice* md = *i;
+ // Only ALSA devices are handled by this thread.
+ if((*i)->deviceType() == MidiDevice::ALSA_MIDI) // p4.0.22
+ (*i)->handleSeek(); // p4.0.22
/*
int port = md->midiPort();
if (port == -1)
@@ -254,6 +261,7 @@ void MidiSeq::processSeek()
*/
}
}
+#endif
//---------------------------------------------------------
// MidiSeq
@@ -427,7 +435,7 @@ void MidiSeq::updatePollFd()
for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) {
MidiDevice* dev = *imd;
int port = dev->midiPort();
- const QString name = dev->name();
+ //const QString name = dev->name();
if (port == -1)
continue;
if ((dev->rwFlags() & 0x2) || (extSyncFlag.value()
@@ -725,20 +733,26 @@ void MidiSeq::processTimerTick()
// }
// p3.3.25
- int tickpos = audio->tickPos();
- bool extsync = extSyncFlag.value();
+ //int tickpos = audio->tickPos();
+ //bool extsync = extSyncFlag.value();
//
// play all events upto curFrame
//
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
- MidiDevice* md = *id;
+ //MidiDevice* md = *id;
// Is it a Jack midi device? They are iterated in Audio::processMidi. p3.3.36
//MidiJackDevice* mjd = dynamic_cast<MidiJackDevice*>(md);
//if(mjd)
- if(md->deviceType() == MidiDevice::JACK_MIDI)
- continue;
- if(md->isSynti()) // syntis are handled by audio thread
- continue;
+ //if(md->deviceType() == MidiDevice::JACK_MIDI)
+ // continue;
+ //if(md->isSynti()) // syntis are handled by audio thread
+ // continue;
+ // Only ALSA midi devices are handled by this thread.
+ if((*id)->deviceType() == MidiDevice::ALSA_MIDI)
+ (*id)->processMidi();
+
+ // Moved into MidiAlsaDevice. p4.0.34
+ /*
int port = md->midiPort();
MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
MPEventList* el = md->playEvents();
@@ -776,6 +790,8 @@ void MidiSeq::processTimerTick()
// The erasure in Audio::processMidi was missing some events because of that.
el->erase(el->begin(), i);
//md->setNextPlayEvent(el->begin()); // Removed p4.0.15
+ */
+
}
}
@@ -813,8 +829,8 @@ void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device)
// This does not appear to be used anymore. Was called in Audio::process1, now Audio::processMidi is called directly. p4.0.15 Tim.
//void MidiSeq::msgProcess() { msgMsg(MS_PROCESS); }
-void MidiSeq::msgSeek() { msgMsg(SEQM_SEEK); }
-void MidiSeq::msgStop() { msgMsg(MS_STOP); }
+//void MidiSeq::msgSeek() { msgMsg(SEQM_SEEK); } // Removed p4.0.34
+//void MidiSeq::msgStop() { msgMsg(MS_STOP); } //
void MidiSeq::msgSetRtc() { msgMsg(MS_SET_RTC); }
void MidiSeq::msgUpdatePollFd() { msgMsg(MS_UPDATE_POLL_FD); }
diff --git a/muse2/muse/midiseq.h b/muse2/muse/midiseq.h
index 0cf85114..1e6ebf2a 100644
--- a/muse2/muse/midiseq.h
+++ b/muse2/muse/midiseq.h
@@ -91,6 +91,8 @@ class MidiSeq : public Thread {
virtual void threadStop();
virtual void threadStart(void*);
+ bool externalPlayState() const { return playStateExt; }
+ void setExternalPlayState(bool v) { playStateExt = v; }
void realtimeSystemInput(int, int);
void mtcInputQuarter(int, unsigned char);
void setSongPosition(int, int);
@@ -101,9 +103,9 @@ class MidiSeq : public Thread {
void nonRealtimeSystemSysex(int, const unsigned char*, int);
void msgMsg(int id);
- void msgProcess();
- void msgSeek();
- void msgStop();
+ //void msgProcess();
+ //void msgSeek();
+ //void msgStop();
void msgSetRtc();
void msgUpdatePollFd();
void msgAddSynthI(SynthI* synth);
diff --git a/muse2/muse/mpevent.h b/muse2/muse/mpevent.h
index 6e9a1f90..4d957adf 100644
--- a/muse2/muse/mpevent.h
+++ b/muse2/muse/mpevent.h
@@ -154,8 +154,8 @@ class MidiPlayEvent : public MEvent {
typedef std::multiset<MidiPlayEvent, std::less<MidiPlayEvent>, audioRTalloc<MidiPlayEvent> > MPEL;
struct MPEventList : public MPEL {
- //void add(const MidiPlayEvent& ev) { MPEL::insert(ev); }
- iterator add(const MidiPlayEvent& ev) { return MPEL::insert(ev); } // p4.0.15 We need the iterator.
+ void add(const MidiPlayEvent& ev) { MPEL::insert(ev); }
+ //iterator add(const MidiPlayEvent& ev) { return MPEL::insert(ev); } // p4.0.15 We need the iterator.
};
typedef MPEventList::iterator iMPEvent;
diff --git a/muse2/muse/song.cpp b/muse2/muse/song.cpp
index 65bfec13..bec5aabc 100644
--- a/muse2/muse/song.cpp
+++ b/muse2/muse/song.cpp
@@ -1982,6 +1982,28 @@ void Song::processMsg(AudioMsg* msg)
updateFlags = SC_EVENT_MODIFIED;
break;
+ // Moved here from MidiSeq::processMsg p4.0.34
+ case SEQM_ADD_TRACK:
+ insertTrack2(msg->track, msg->ival);
+ break;
+ case SEQM_REMOVE_TRACK:
+ //removeTrack2(msg->track);
+ cmdRemoveTrack(msg->track);
+ break;
+ case SEQM_CHANGE_TRACK:
+ changeTrack((Track*)(msg->p1), (Track*)(msg->p2));
+ break;
+ case SEQM_ADD_PART:
+ cmdAddPart((Part*)msg->p1);
+ break;
+ case SEQM_REMOVE_PART:
+ cmdRemovePart((Part*)msg->p1);
+ break;
+ case SEQM_CHANGE_PART:
+ //cmdChangePart((Part*)msg->p1, (Part*)msg->p2);
+ cmdChangePart((Part*)msg->p1, (Part*)msg->p2, msg->a, msg->b);
+ break;
+
case SEQM_ADD_TEMPO:
//printf("processMsg (SEQM_ADD_TEMPO) UndoOp::AddTempo. adding tempo at: %d with tempo=%d\n", msg->a, msg->b);
addUndo(UndoOp(UndoOp::AddTempo, msg->a, msg->b));
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index 5435f8ce..ae54cd15 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -323,6 +323,15 @@ bool SynthI::putEvent(const MidiPlayEvent& ev)
}
//---------------------------------------------------------
+// processMidi
+//---------------------------------------------------------
+
+void SynthI::processMidi()
+{
+ processStuckNotes();
+}
+
+//---------------------------------------------------------
// setName
//---------------------------------------------------------
@@ -962,12 +971,13 @@ void SynthI::preProcessAlways()
if(off())
{
// Clear any accumulated play events.
- playEvents()->clear();
+ //playEvents()->clear();
+ _playEvents.clear();
// Eat up any fifo events.
//while(!eventFifo.isEmpty())
// eventFifo.get();
- eventFifo.clear(); // p4.0.21 Duh, clear is the same but faster AND safer, right?
- }
+ eventFifo.clear(); // Clear is the same but faster AND safer, right?
+ }
}
void MessSynthIF::preProcessAlways()
@@ -987,12 +997,15 @@ bool SynthI::getData(unsigned pos, int ports, unsigned n, float** buffer)
int p = midiPort();
MidiPort* mp = (p != -1) ? &midiPorts[p] : 0;
- MPEventList* el = playEvents();
+ //MPEventList* el = playEvents();
///iMPEvent ie = nextPlayEvent();
- iMPEvent ie = el->begin(); // p4.0.15 Tim.
+ //iMPEvent ie = el->begin(); // p4.0.15 Tim.
+ iMPEvent ie = _playEvents.begin();
+
- ie = _sif->getData(mp, el, ie, pos, ports, n, buffer);
+ //ie = _sif->getData(mp, el, ie, pos, ports, n, buffer);
+ ie = _sif->getData(mp, &_playEvents, ie, pos, ports, n, buffer);
///setNextPlayEvent(ie);
// p4.0.15 We are done with these events. Let us erase them here instead of Audio::processMidi.
@@ -1001,7 +1014,8 @@ bool SynthI::getData(unsigned pos, int ports, unsigned n, float** buffer)
// being at the 'end' iterator and not being *easily* set to some new place beginning of the newer insertions.
// The way that MPEventList sorts made it difficult to predict where the iterator of the first newly inserted items was.
// The erasure in Audio::processMidi was missing some events because of that.
- el->erase(el->begin(), ie);
+ //el->erase(el->begin(), ie);
+ _playEvents.erase(_playEvents.begin(), ie);
// setNextPlayEvent(el->begin()); // Removed p4.0.15
return true;
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index a76d798d..fc442027 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -292,6 +292,7 @@ class SynthI : public AudioTrack, public MidiDevice,
}
bool putEvent(const MidiPlayEvent& ev);
+ virtual void processMidi();
MidiPlayEvent receiveEvent() { return _sif->receiveEvent(); }
int eventsPending() const { return _sif->eventsPending(); }