summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2011-02-09 22:37:27 +0000
committerTim E. Real <termtech@rogers.com>2011-02-09 22:37:27 +0000
commitd7f4820023196bfc7d40ef5fa134bc46a6e55849 (patch)
treefa00ee04c060c2ece1122f9d3fee382b0d5f043c /muse2
parente11f572d97bb761d848fad41991d0ed747bad111 (diff)
Mini MIDI overhaul. Please see ChangeLog.
Diffstat (limited to 'muse2')
-rw-r--r--muse2/ChangeLog20
-rw-r--r--muse2/awl/posedit.cpp14
-rw-r--r--muse2/muse/app.cpp14
-rw-r--r--muse2/muse/appearance.cpp4
-rw-r--r--muse2/muse/arranger/arranger.cpp6
-rw-r--r--muse2/muse/arranger/pcanvas.cpp2
-rw-r--r--muse2/muse/audio.cpp8
-rw-r--r--muse2/muse/driver/jackmidi.cpp242
-rw-r--r--muse2/muse/driver/jackmidi.h6
-rw-r--r--muse2/muse/dssihost.cpp182
-rw-r--r--muse2/muse/instruments/minstrument.cpp34
-rw-r--r--muse2/muse/main.cpp4
-rw-r--r--muse2/muse/midi.cpp75
-rw-r--r--muse2/muse/midictrl.cpp8
-rw-r--r--muse2/muse/midictrl.h2
-rw-r--r--muse2/muse/mididev.cpp27
-rw-r--r--muse2/muse/mididev.h22
-rw-r--r--muse2/muse/midiedit/dcanvas.cpp6
-rw-r--r--muse2/muse/midiedit/ecanvas.cpp2
-rw-r--r--muse2/muse/midiedit/prcanvas.cpp2
-rw-r--r--muse2/muse/midiport.cpp24
-rw-r--r--muse2/muse/midiseq.cpp42
-rw-r--r--muse2/muse/mixer/amixer.cpp10
-rw-r--r--muse2/muse/mixer/astrip.cpp2
-rw-r--r--muse2/muse/mpevent.cpp53
-rw-r--r--muse2/muse/mpevent.h40
-rw-r--r--muse2/muse/osc.cpp1
-rw-r--r--muse2/muse/osc.h2
-rw-r--r--muse2/muse/plugin.cpp4
-rw-r--r--muse2/muse/route.cpp6
-rw-r--r--muse2/muse/sync.cpp7
-rw-r--r--muse2/muse/synth.cpp39
-rw-r--r--muse2/muse/synth.h2
-rw-r--r--muse2/muse/widgets/shortcutcapturedialog.cpp2
34 files changed, 605 insertions, 309 deletions
diff --git a/muse2/ChangeLog b/muse2/ChangeLog
index 081649b8..9928262c 100644
--- a/muse2/ChangeLog
+++ b/muse2/ChangeLog
@@ -1,5 +1,25 @@
09.02.2011:
- fixed regression with Bounce to File and Bounce to Track (rj)
+ [[[ By Tim. Marked as p4.0.15 ...
+ - Removed MidiDevice::nextPlayEvent, and instead of erasing 'already played events' at top of
+ Audio::processMidi(), let each device erase played events immediately after playing them.
+ Still a bit uneasy with this one, but nextPlayEvent was causing some problems.
+ This required forced event erasure, if the track is off, in SynthI::preProcessAlways(),
+ which may need more tweaking for other non-processed circumstances.
+ - Added MidiDevice::putEventWithRetry() which will wait and retry sending an event.
+ So far it is only used in MidiPort::setMidiDevice(), which runs in the GUI thread where
+ it can wait a bit.
+ - Increased playback MidiFifo size from 512 to 2100, to accommodate large block sends,
+ such as in MidiInstrument::reset() which sends 2048 events at once.
+ Created new recording MidiRecFifo with reduced size of 160 instead of previous 512.
+ Replaced SynthI::putFifo and MidiJackDevice::eventFifo with unified MidiDevice::eventFifo.
+ TODO: Allow ALSA devices to also make use of it, in case events cannot be delivered.
+ - Added a timestamp to OscControlFifo events. To be used for better, faster OSC processing - TODO.
+ - Fixed DSSI processing timing in DssiSynthIF::getData(). Should be much better now, tested OK.
+ - Fixed Jack Midi 'lost event' messages due to full buffers. Now it waits until next cycle if buffer is full.
+ Slight mod: SysEx events forced to be lost, since it is most likely that the sysex is too big and Jack Midi
+ could never allocate enough space for it, meaning the event would linger around forever attempting to
+ be sent, tying up other events. ]]]
08.02.2011:
- made muse compilable under gcc-4.6. ptrdiff_t type requires inclusion of cstddef. (Orcan)
31.01.2011:
diff --git a/muse2/awl/posedit.cpp b/muse2/awl/posedit.cpp
index 3d4abaab..e9cddd44 100644
--- a/muse2/awl/posedit.cpp
+++ b/muse2/awl/posedit.cpp
@@ -93,7 +93,7 @@ bool PosEdit::event(QEvent* event)
QKeyEvent* ke = static_cast<QKeyEvent*>(event);
if (ke->key() == Qt::Key_Return)
{
- //printf("key press event Return\n"); // REMOVE Tim.
+ //printf("key press event Return\n");
//enterPressed();
finishEdit();
emit returnPressed();
@@ -103,7 +103,7 @@ bool PosEdit::event(QEvent* event)
if (ke->key() == Qt::Key_Escape)
{
- //printf("key press event Escape\n"); // REMOVE Tim.
+ //printf("key press event Escape\n");
if(lineEdit())
lineEdit()->undo();
// "By default, isAccepted() is set to true, but don't rely on this as subclasses may
@@ -363,8 +363,8 @@ void PosEdit::fixup(QString& input) const
QValidator::State PosEdit::validate(QString& s,int& /*i*/) const
{
- //printf("validate string:%s int:%d\n", s.toLatin1().data(), i); // REMOVE Tim.
- //printf("validate string:%s\n", s.toLatin1().data()); // REMOVE Tim.
+ //printf("validate string:%s int:%d\n", s.toLatin1().data(), i);
+ //printf("validate string:%s\n", s.toLatin1().data());
QStringList sl = s.split(_smpte ? ':' : '.');
QValidator::State state;
@@ -436,7 +436,7 @@ QValidator::State PosEdit::validate(QString& s,int& /*i*/) const
int bm = tm / tb;
validator->setRange(1, 9999);
- //printf("validate substring 0:%s\n", sl[0].toLatin1().data()); // REMOVE Tim.
+ //printf("validate substring 0:%s\n", sl[0].toLatin1().data());
// Special hack because validator says 0000 is intermediate.
if(sl[0] == "0000")
return QValidator::Invalid;
@@ -447,7 +447,7 @@ QValidator::State PosEdit::validate(QString& s,int& /*i*/) const
rv = state;
validator->setRange(1, bm);
- //printf("validate substring 1:%s\n", sl[1].toLatin1().data()); // REMOVE Tim.
+ //printf("validate substring 1:%s\n", sl[1].toLatin1().data());
// Special hack because validator says 00 is intermediate.
if(sl[1] == "00")
return QValidator::Invalid;
@@ -458,7 +458,7 @@ QValidator::State PosEdit::validate(QString& s,int& /*i*/) const
rv = state;
validator->setRange(0, tb-1);
- //printf("validate substring 2:%s\n", sl[2].toLatin1().data()); // REMOVE Tim.
+ //printf("validate substring 2:%s\n", sl[2].toLatin1().data());
state = validator->validate(sl[2], dpos);
if(state == QValidator::Invalid)
return state;
diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp
index c12e5914..2f3d32ed 100644
--- a/muse2/muse/app.cpp
+++ b/muse2/muse/app.cpp
@@ -2231,7 +2231,7 @@ void MusE::updateRouteMenus(Track* track, QObject* master)
imm->second.type == Route::TRACK_ROUTE && imm->second.track->type() == Track::AUDIO_INPUT)
return;
#if 0
- printf("imm route:\n"); // REMOVE Tim.
+ printf("imm route:\n");
imm->second.dump();
if(track->isMidiTrack())
{
@@ -2256,19 +2256,19 @@ void MusE::updateRouteMenus(Track* track, QObject* master)
iRoute ir = mprl->begin();
for(; ir != mprl->end(); ++ir)
{
- printf("mp route:\n"); // REMOVE Tim.
- ir->dump(); // REMOVE Tim.
+ printf("mp route:\n");
+ ir->dump();
///if(aRoute.type == Route::TRACK_ROUTE) // Is the map route a track route?
{
if(ir->type == Route::TRACK_ROUTE && ir->track == aRoute.track) // Is the track route a midi port route?
//&& (ir->channel & chbit) == chbit)
//&& (ir->channel & tchbit)) // Is the exact channel mask bit(s) set?
{
- printf("track matches\n"); // REMOVE Tim.
+ printf("track matches\n");
if(ir->channel & tchbit)
{
found = true;
- printf("found: bit matches\n"); // REMOVE Tim.
+ printf("found: bit matches\n");
}
break;
}
@@ -2286,10 +2286,10 @@ void MusE::updateRouteMenus(Track* track, QObject* master)
//if(pup->isItemChecked(imm->first) != (irl != rl->end()))
// pup->setItemChecked(imm->first, irl != rl->end());
QAction* act = pup->findActionFromData(imm->first);
- //printf("set act checked to:%d\n", ir != mprl->end()); // REMOVE Tim.
+ //printf("set act checked to:%d\n", ir != mprl->end());
//if(act && act->isChecked() != (ir != mprl->end()))
// act->setChecked(ir != mprl->end());
- printf("set act checked to:%d\n", found); // REMOVE Tim.
+ printf("set act checked to:%d\n", found);
if(act && act->isChecked() != found)
act->setChecked(found);
diff --git a/muse2/muse/appearance.cpp b/muse2/muse/appearance.cpp
index 7b0383b5..df81e3b1 100644
--- a/muse2/muse/appearance.cpp
+++ b/muse2/muse/appearance.cpp
@@ -488,8 +488,8 @@ void Appearance::resetValues()
themeComboBox->clear();
QString cs = muse->style()->objectName();
- //printf("Appearance::resetValues style:%s\n", cs.toAscii().data()); // REMOVE Tim
- //printf("Appearance::resetValues App styleSheet:%s\n", qApp->styleSheet().toAscii().data()); // REMOVE Tim
+ //printf("Appearance::resetValues style:%s\n", cs.toAscii().data());
+ //printf("Appearance::resetValues App styleSheet:%s\n", qApp->styleSheet().toAscii().data());
cs = cs.toLower();
themeComboBox->insertItems(0, QStyleFactory::keys());
diff --git a/muse2/muse/arranger/arranger.cpp b/muse2/muse/arranger/arranger.cpp
index 38583d48..9b0de8c8 100644
--- a/muse2/muse/arranger/arranger.cpp
+++ b/muse2/muse/arranger/arranger.cpp
@@ -918,7 +918,7 @@ QSize WidgetStack::minimumSizeHint() const
s = s.expandedTo(ss);
}
}
- //printf("WidgetStack::minimumSizeHint width:%d height:%d\n", s.width(), s.height()); // REMOVE Tim.
+ //printf("WidgetStack::minimumSizeHint width:%d height:%d\n", s.width(), s.height());
return s;
}
@@ -1054,13 +1054,13 @@ void Arranger::switchInfo(int n)
/*
QSize WidgetStack::minimumSize() const
{
- printf("WidgetStack::minimumSize\n"); // REMOVE Tim.
+ printf("WidgetStack::minimumSize\n");
return minimumSizeHint();
}
int WidgetStack::minimumHeight() const
{
- printf("WidgetStack::minimumHeight\n"); // REMOVE Tim.
+ printf("WidgetStack::minimumHeight\n");
return minimumSizeHint().height();
}
*/
diff --git a/muse2/muse/arranger/pcanvas.cpp b/muse2/muse/arranger/pcanvas.cpp
index 9c970c52..5658f7e6 100644
--- a/muse2/muse/arranger/pcanvas.cpp
+++ b/muse2/muse/arranger/pcanvas.cpp
@@ -1731,7 +1731,7 @@ void PartCanvas::drawWavePart(QPainter& p,
//
// combine multi channels into one waveform
//
- //printf("PartCanvas::drawWavePart i:%d ex:%d\n", i, ex); // REMOVE Tim.
+ //printf("PartCanvas::drawWavePart i:%d ex:%d\n", i, ex);
for (; i < ex; i++) {
SampleV sa[channels];
diff --git a/muse2/muse/audio.cpp b/muse2/muse/audio.cpp
index 1b62f15c..f541a10c 100644
--- a/muse2/muse/audio.cpp
+++ b/muse2/muse/audio.cpp
@@ -695,8 +695,12 @@ void Audio::processMsg(AudioMsg* msg)
break;
case SEQM_RESET_DEVICES:
- for (int i = 0; i < MIDI_PORTS; ++i)
- midiPorts[i].instrument()->reset(i, song->mtype());
+ //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());
+ }
break;
case SEQM_INIT_DEVICES:
initDevices();
diff --git a/muse2/muse/driver/jackmidi.cpp b/muse2/muse/driver/jackmidi.cpp
index d401c7e1..c950e096 100644
--- a/muse2/muse/driver/jackmidi.cpp
+++ b/muse2/muse/driver/jackmidi.cpp
@@ -1150,7 +1150,8 @@ void MidiJackDevice::collectMidiEvents()
bool MidiJackDevice::putEvent(const MidiPlayEvent& ev)
{
- if(!_writeEnable)
+ //if(!_writeEnable)
+ if(!_writeEnable || !_out_client_jackport) // p4.0.15
//return true;
return false;
@@ -1225,7 +1226,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
unsigned char* p = jack_midi_event_reserve(pb, ft, 3);
if (p == 0) {
- fprintf(stderr, "MidiJackDevice::queueEvent #1: buffer overflow, event lost\n");
+ #ifdef JACK_MIDI_DEBUG
+ fprintf(stderr, "MidiJackDevice::queueEvent NOTE CTL PAT or PB: buffer overflow, stopping until next cycle\n");
+ #endif
return false;
}
p[0] = e.type() | e.channel();
@@ -1243,7 +1246,9 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
unsigned char* p = jack_midi_event_reserve(pb, ft, 2);
if (p == 0) {
- fprintf(stderr, "MidiJackDevice::queueEvent #2: buffer overflow, event lost\n");
+ #ifdef JACK_MIDI_DEBUG
+ fprintf(stderr, "MidiJackDevice::queueEvent PROG or AT: buffer overflow, stopping until next cycle\n");
+ #endif
return false;
}
p[0] = e.type() | e.channel();
@@ -1260,8 +1265,16 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
int len = e.len();
unsigned char* p = jack_midi_event_reserve(pb, ft, len+2);
if (p == 0) {
- fprintf(stderr, "MidiJackDevice::queueEvent #3: buffer overflow, event lost\n");
- return false;
+ fprintf(stderr, "MidiJackDevice::queueEvent ME_SYSEX: buffer overflow, sysex too big, event lost\n");
+
+ //return false;
+ // Changed to true. Absorb the sysex if it is too big, to avoid attempting
+ // to resend repeatedly. If the sysex is too big, it would just stay in the
+ // list and never be processed, because Jack could never reserve enough space.
+ // Other types of events should be OK since they are small and can be resent
+ // next cycle. p4.0.15 Tim.
+ // FIXME: We really need to chunk sysex events properly. It's tough. Investigating...
+ return true;
}
p[0] = 0xf0;
p[len+1] = 0xf7;
@@ -1273,8 +1286,10 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
case ME_START:
case ME_CONTINUE:
case ME_STOP:
- printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
- return false;
+ if(debugMsg)
+ printf("MidiJackDevice::queueEvent: event type %x not supported\n", e.type());
+ //return false;
+ return true; // Absorb the event. Don't want it hanging around in the list. FIXME: Support these? p4.0.15 Tim.
break;
}
@@ -1283,9 +1298,10 @@ bool MidiJackDevice::queueEvent(const MidiPlayEvent& e)
//---------------------------------------------------------
// processEvent
+// return true if successful
//---------------------------------------------------------
-void MidiJackDevice::processEvent(const MidiPlayEvent& event)
+bool MidiJackDevice::processEvent(const MidiPlayEvent& event)
{
//int frameOffset = audio->getFrameOffset();
//unsigned pos = audio->pos().frame();
@@ -1302,12 +1318,15 @@ void 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())
t = audio->getFrameOffset() + audio->pos().frame();
//t = frameOffset + pos;
#ifdef JACK_MIDI_DEBUG
- printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", event.time(), event.type(), event.channel(), event.dataA(), event.dataB());
+ //printf("MidiJackDevice::processEvent time:%d type:%d ch:%d A:%d B:%d\n", t, event.type(), chn, a, b);
#endif
if(event.type() == ME_PROGRAM)
@@ -1318,15 +1337,18 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
int lb = (a >> 8) & 0xff;
int pr = a & 0x7f;
- // p3.3.44
//printf("MidiJackDevice::processEvent ME_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);
if (hb != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))
+ return false; // p4.0.15 Inform that processing the event in general failed. Ditto all below...
if (lb != 0xff)
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0));
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)))
+ return false;
+
// }
}
else
@@ -1336,7 +1358,8 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
// 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());
- queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))
+ return false;
}
else
if(event.type() == ME_CONTROLLER)
@@ -1365,7 +1388,8 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
// 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());
- queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_PITCHBEND, v & 0x7f, (v >> 7) & 0x7f)))
+ return false;
}
else if (a == CTRL_PROGRAM)
{
@@ -1380,28 +1404,36 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
// event.time(), event.type(), event.channel(), event.dataA(), event.dataB(), hb, lb, pr);
if (hb != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb));
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HBANK, hb)))
+ return false;
+ }
if (lb != 0xff)
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0));
+ {
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LBANK, lb)))
+ return false;
+ }
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_PROGRAM, pr, 0)))
+ return false;
+
// }
}
- /*
- else if (a == CTRL_MASTER_VOLUME)
+ else if (a == CTRL_MASTER_VOLUME) // Enabled p4.0.15 Tim.
{
unsigned char sysex[] = {
0x7f, 0x7f, 0x04, 0x01, 0x00, 0x00
};
- sysex[1] = deviceId();
+ //sysex[1] = deviceId(); TODO FIXME p4.0.15 Grab the ID from midi port sync info.
sysex[4] = b & 0x7f;
sysex[5] = (b >> 7) & 0x7f;
- queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6));
+ if(!queueEvent(MidiPlayEvent(t, port, ME_SYSEX, sysex, 6)))
+ return false;
}
- */
else if (a < CTRL_14_OFFSET)
{ // 7 Bit Controller
- queueEvent(event);
//queueEvent(museport, MidiPlayEvent(t, port, chn, event));
+ if(!queueEvent(event))
+ return false;
}
else if (a < CTRL_RPN_OFFSET)
{ // 14 bit high resolution controller
@@ -1409,46 +1441,62 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH));
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, ctrlH, dataH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, ctrlL, dataL)))
+ return false;
}
else if (a < CTRL_NRPN_OFFSET)
{ // RPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
+ return false;
t += 3;
// Select null parameters so that subsequent data controller events do not upset the last *RPN controller.
//sendNullRPNParams(chn, false);
if(nvh != 0xff)
{
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))
+ return false;
t += 1;
}
if(nvl != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f)))
+ return false;
+ }
}
//else if (a < CTRL_RPN14_OFFSET)
else if (a < CTRL_INTERNAL_OFFSET)
{ // NRPN 7-Bit Controller
int ctrlH = (a >> 8) & 0x7f;
int ctrlL = a & 0x7f;
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, b)))
+ return false;
t += 3;
//sendNullRPNParams(chn, true);
if(nvh != 0xff)
{
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))
+ return false;
t += 1;
}
if(nvl != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f)))
+ return false;
+ }
}
else if (a < CTRL_NRPN14_OFFSET)
{ // RPN14 Controller
@@ -1456,20 +1504,28 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH));
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
- queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, ctrlH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LRPN, ctrlL)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
+ return false;
t += 4;
//sendNullRPNParams(chn, false);
if(nvh != 0xff)
{
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HRPN, nvh & 0x7f)))
+ return false;
t += 1;
}
if(nvl != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f));
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LRPN, nvl & 0x7f)))
+ return false;
+ }
}
else if (a < CTRL_NONE_OFFSET)
{ // NRPN14 Controller
@@ -1477,31 +1533,44 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
int ctrlL = a & 0x7f;
int dataH = (b >> 7) & 0x7f;
int dataL = b & 0x7f;
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH));
- queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL));
- queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH));
- queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, ctrlH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+1, port, chn, ME_CONTROLLER, CTRL_LNRPN, ctrlL)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+2, port, chn, ME_CONTROLLER, CTRL_HDATA, dataH)))
+ return false;
+ if(!queueEvent(MidiPlayEvent(t+3, port, chn, ME_CONTROLLER, CTRL_LDATA, dataL)))
+ return false;
t += 4;
//sendNullRPNParams(chn, true);
if(nvh != 0xff)
{
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f));
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_HNRPN, nvh & 0x7f)))
+ return false;
t += 1;
}
if(nvl != 0xff)
- queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f));
+ {
+ if(!queueEvent(MidiPlayEvent(t, port, chn, ME_CONTROLLER, CTRL_LNRPN, nvl & 0x7f)))
+ return false;
+ }
}
else
{
- printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a);
+ if(debugMsg)
+ printf("MidiJackDevice::processEvent: unknown controller type 0x%x\n", a);
+ //return false; // Just ignore it.
}
}
else
{
- queueEvent(event);
//queueEvent(MidiPlayEvent(t, port, chn, event));
+ if(!queueEvent(event))
+ return false;
}
+
+ return true;
}
//---------------------------------------------------------
@@ -1511,40 +1580,58 @@ void MidiJackDevice::processEvent(const MidiPlayEvent& event)
void MidiJackDevice::processMidi()
{
//if(!_client_jackport)
- if(!_out_client_jackport) // p3.3.55
- return;
+ //if(!_out_client_jackport) // p3.3.55
+ // return;
+
//void* port_buf = jack_port_get_buffer(_client_jackport, segmentSize);
- void* port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55
- jack_midi_clear_buffer(port_buf);
+ //void* port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize); // p3.3.55
+ void* port_buf = 0;
+ if(_out_client_jackport && _writeEnable) // p4.0.15
+ {
+ port_buf = jack_port_get_buffer(_out_client_jackport, segmentSize);
+ jack_midi_clear_buffer(port_buf);
+ }
while(!eventFifo.isEmpty())
{
- MidiPlayEvent e(eventFifo.get());
- int evTime = e.time();
- // Is event marked to be played immediately?
- if(evTime == 0)
- {
+ ///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());
- }
+ /// 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
+ //#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);
+ ///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.
+ 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())
+ {
+ //printf("MidiJackDevice::processMidi play events empty\n");
return;
+ }
- iMPEvent i = nextPlayEvent();
+ //printf("MidiJackDevice::processMidi play events:\n");
+ ///iMPEvent i = nextPlayEvent();
+ iMPEvent i = el->begin(); // p4.0.15
for(; i != el->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.
// Same code as in MidiPort::sendEvent()
if(_port != -1)
@@ -1562,7 +1649,6 @@ void MidiJackDevice::processMidi()
else
if(i->type() == ME_PITCHBEND)
{
- // p3.3.44
//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());
@@ -1581,10 +1667,26 @@ void MidiJackDevice::processMidi()
}
}
- processEvent(*i);
+ ///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;
+ break;
+ }
}
- setNextPlayEvent(i);
+ ///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.
+
}
//---------------------------------------------------------
diff --git a/muse2/muse/driver/jackmidi.h b/muse2/muse/driver/jackmidi.h
index f7b5eb94..842cbc2d 100644
--- a/muse2/muse/driver/jackmidi.h
+++ b/muse2/muse/driver/jackmidi.h
@@ -19,7 +19,7 @@
#include "route.h"
class QString;
-class MidiFifo;
+//class MidiFifo;
class MidiRecordEvent;
class MidiPlayEvent;
//class RouteList;
@@ -93,7 +93,7 @@ class MidiJackDevice : public MidiDevice {
private:
// fifo for midi events sent from gui
// direct to midi port:
- MidiFifo eventFifo;
+ //MidiFifo eventFifo; // Moved into MidiDevice p4.0.15
//static int _nextOutIdNum;
//static int _nextInIdNum;
@@ -109,7 +109,7 @@ class MidiJackDevice : public MidiDevice {
virtual void close();
//bool putEvent(int*);
- void processEvent(const MidiPlayEvent&);
+ bool processEvent(const MidiPlayEvent&);
// Port is not midi port, it is the port(s) created for MusE.
bool queueEvent(const MidiPlayEvent&);
diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp
index 986abea1..d1d599f7 100644
--- a/muse2/muse/dssihost.cpp
+++ b/muse2/muse/dssihost.cpp
@@ -1728,83 +1728,6 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
// Since we absorbed the message as a ladspa control change, return false - the event is not filled.
return false;
//}
-
- // p3.3.39 Removed.
- // "Hosts should not deliver through run_synth any MIDI controller events that have already
- // been mapped to control port values."
- // D'oh! My mistake, did not understand that the mapping is only a *request* that the app map MIDI
- // controller events to a LADSPA port, and must do the conversion, not to actually *send* them via MIDI...
- /*
- else
- {
- switch(midiControllerType(a))
- {
- case MidiController::Controller7:
- #ifdef DSSI_DEBUG
- //fprintf(stderr, "DssiSynthIF::processEvent midi event is Controller7. Changing to DSSI_CC type. Current dataA:%d\n", a);
- fprintf(stderr, "DssiSynthIF::processEvent midi event is Controller7. Current dataA:%d\n", a);
- #endif
- //a = DSSI_CC(a);
- a &= 0x7f;
- ctlnum = DSSI_CC_NUMBER(ctlnum);
- break;
- case MidiController::NRPN14:
- #ifdef DSSI_DEBUG
- // fprintf(stderr, "DssiSynthIF::processEvent midi event is NRPN. Changing to DSSI_NRPN type. Current dataA:%d\n", a);
- fprintf(stderr, "DssiSynthIF::processEvent midi event is NRPN. Current dataA:%d\n", a);
- #endif
- //a = DSSI_NRPN(a - CTRL_NRPN14_OFFSET);
- a &= 0x3fff;
- ctlnum = DSSI_NRPN_NUMBER(ctlnum);
- break;
- case MidiController::Controller14:
- a &= 0x7f;
- break;
- case MidiController::Pitch:
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is Pitch. DataA:%d\n", a);
- #endif
- a &= 0x3fff;
- break;
- case MidiController::Program:
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is Program. DataA:%d\n", a);
- #endif
- a &= 0x3fff;
- break;
- case MidiController::RPN:
- case MidiController::RPN14:
- case MidiController::NRPN:
- default:
- #ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::processEvent midi event is RPN, RPN14, or NRPN type. DataA:%d\n", a);
- #endif
- break;
- }
-
- // Verify it's the same number.
- if(ctlnum != a)
- {
- #ifdef DSSI_DEBUG
- printf("DssiSynthIF::processEvent Error! ctlnum:%d != event dataA:%d\n", ctlnum, a);
- #endif
- // Event not filled. Return false.
-
- // TEMP: TODO: Turn on later
- //return false;
- }
-
- // Fill the event.
- // FIXME: Darn! We get to this point, but no change in sound (later). Nothing happens, at least with LTS -
- // which is the only one I found so far with midi controllers.
- // Tried with/without converting to DSSI_CC and DSSI_NRPN. What could be wrong here?
- #ifdef DSSI_DEBUG
- printf("DssiSynthIF::processEvent filling event chn:%d dataA:%d dataB:%d\n", chn, a, b);
- #endif
- snd_seq_ev_set_controller(event, chn, a, b);
- }
- */
-
}
break;
case ME_PITCHBEND:
@@ -1910,7 +1833,7 @@ bool DssiSynthIF::processEvent(const MidiPlayEvent& e, snd_seq_event_t* event)
//---------------------------------------------------------
//void DssiSynthIF::getData(MidiEventList* el, unsigned pos, int ch, unsigned samples, float** data)
-iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/, unsigned pos, int ports, unsigned n, float** buffer)
+iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent i, unsigned pos, int ports, unsigned n, float** buffer)
{
//#ifdef DSSI_DEBUG
// fprintf(stderr, "DssiSynthIF::getData elsize:%d pos:%d ports:%d samples:%d processed already?:%d\n", el->size(), pos, ports, n, synti->processed());
@@ -1920,11 +1843,11 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
// FIXME: Add 10(?) for good luck in case volatile size changes (increments) while we're processing.
//unsigned long nevents = el->size();
- unsigned long nevents = el->size() + synti->putFifo.getSize() + 10;
+ unsigned long nevents = el->size() + synti->eventFifo.getSize() + 10;
/*
- while (!synti->putFifo.isEmpty()) {
- MidiEvent event = synti->putFifo.get();
+ while (!synti->eventFifo.isEmpty()) {
+ MidiEvent event = synti->eventFifo.get();
printf("Dssi: FIFO\n");
}
*/
@@ -1933,21 +1856,14 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
memset(events, 0, sizeof(events));
nevents = 0;
- //int curPos = pos;
- //unsigned endPos = pos + samples;
unsigned endPos = pos + n;
- //int off = pos;
int frameOffset = audio->getFrameOffset();
- //iMidiEvent i = el->begin();
- iMPEvent i = el->begin();
+ //iMPEvent i = el->begin(); // Removed p4.0.15
// Process event list events...
for(; i != el->end(); ++i)
{
- //if(i->time() >= endPos) // Doesn't work, at least here in muse-1. The event times are all
- // just slightly after the endPos, EVEN IF transport is stopped.
- // So it misses all the notes.
if(i->time() >= (endPos + frameOffset)) // NOTE: frameOffset? Tested, examined printouts of times: Seems OK for playback.
break;
@@ -1987,23 +1903,56 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
}
if(processEvent(*i, &events[nevents]))
+ {
+ // Time-stamp the event. p4.0.15 Tim.
+ int ft = i->time() - frameOffset - pos;
+ if(ft < 0)
+ ft = 0;
+ if (ft >= (int)segmentSize)
+ {
+ printf("DssiSynthIF::getData: eventlist event time:%d out of range. pos:%d offset:%d ft:%d (seg=%d)\n", i->time(), pos, frameOffset, ft, segmentSize);
+ ///if (ft > (int)segmentSize)
+ ft = segmentSize - 1;
+ }
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
++nevents;
+ }
}
// Now process putEvent events...
- while(!synti->putFifo.isEmpty())
+ while(!synti->eventFifo.isEmpty())
{
- MidiPlayEvent e = synti->putFifo.get();
+ MidiPlayEvent e = synti->eventFifo.get();
#ifdef DSSI_DEBUG
- fprintf(stderr, "DssiSynthIF::getData putFifo event time:%d\n", e.time());
+ fprintf(stderr, "DssiSynthIF::getData eventFifo event time:%d\n", e.time());
#endif
- // Set to the current time.
- // FIXME: FIXME: Wrong - we should be setting some kind of linear realtime wallclock here, not song pos.
- e.setTime(pos);
+ // Maybe TODO:
+ //if(e.time() >= (endPos + frameOffset))
+ // break;
+
if(processEvent(e, &events[nevents]))
+ {
+ // Time-stamp the event. p4.0.15 Tim.
+ int ft = e.time() - frameOffset - pos;
+ if(ft < 0)
+ ft = 0;
+ if (ft >= (int)segmentSize)
+ {
+ printf("DssiSynthIF::getData: eventFifo event time:%d out of range. pos:%d offset:%d ft:%d (seg=%d)\n", e.time(), pos, frameOffset, ft, segmentSize);
+ ///if (ft > (int)segmentSize)
+ ft = segmentSize - 1;
+ }
+ // "Each event is timestamped relative to the start of the block, (mis)using the ALSA "tick time" field as a frame count.
+ // The host is responsible for ensuring that events with differing timestamps are already ordered by time." - From dssi.h
+ events[nevents].time.tick = ft;
+
++nevents;
+ }
}
// Now process OSC gui input control fifo events.
@@ -2018,6 +1967,8 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
continue;
// If there are 'events' in the fifo, get exactly one 'event' per control per process cycle...
+ // TODO: The OSC events are now time-stamped. Split up the processing below between parameter changes
+ // and get rid of this slooow control processing! p4.0.15
if(!cfifo->isEmpty())
{
OscControlValue v = cfifo->get();
@@ -2041,40 +1992,9 @@ iMPEvent DssiSynthIF::getData(MidiPort* /*mp*/, MPEventList* el, iMPEvent /*i*/,
}
}
#endif
-
-/* // This is from MESS... Tried this here, didn't work, need to re-adapt, try again.
- int evTime = i->time();
- if(evTime == 0)
- {
- printf("DssiSynthIF::getData - time is 0!\n");
- //continue;
- evTime=frameOffset; // will cause frame to be zero, problem?
- }
-
- int frame = evTime - frameOffset;
-
- if(frame >= endPos)
- {
- printf("DssiSynthIF::getData frame > endPos!! frame = %d >= endPos %d, i->time() %d, frameOffset %d curPos=%d\n", frame, endPos, i->time(), frameOffset,curPos);
- continue;
- }
-
- if(frame > curPos)
- {
- if(frame < pos)
- printf("DssiSynthIF::getData should not happen: missed event %d\n", pos -frame);
- else
- {
-*/
-
-/*
- }
- curPos = frame;
- }
-*/
-// }
- el->erase(el->begin(), i);
+ ///el->erase(el->begin(), i); // Removed p4.0.15 Let SynthI::getData() do this.
+
//END: Process midi events
//BEGIN: Run the synth
@@ -2197,7 +2117,7 @@ bool DssiSynthIF::putEvent(const MidiPlayEvent& ev)
if (midiOutputTrace)
ev.dump();
- return synti->putFifo.put(ev);
+ return synti->eventFifo.put(ev);
//return false;
}
@@ -2599,6 +2519,10 @@ int DssiSynthIF::oscControl(unsigned long port, float value)
OscControlValue cv;
//cv.idx = cport;
cv.value = value;
+ // Time-stamp the event. Looks like no choice but to use the (possibly slow) call to gettimeofday via timestamp(),
+ // because these are asynchronous events arriving from OSC. timestamp() is more or less an estimate of the
+ // current frame. (This is exactly how ALSA events are treated when they arrive in our ALSA driver.) p4.0.15 Tim.
+ cv.frame = audio->timestamp();
if(cfifo->put(cv))
{
fprintf(stderr, "DssiSynthIF::oscControl: fifo overflow: in control number:%ld\n", cport);
diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp
index e39ee996..9e52498f 100644
--- a/muse2/muse/instruments/minstrument.cpp
+++ b/muse2/muse/instruments/minstrument.cpp
@@ -16,6 +16,9 @@
#include "minstrument.h"
#include "midiport.h"
+#include "mididev.h" // p4.0.15
+#include "audio.h" // p4.0.15
+#include "midi.h" // p4.0.15
#include "globals.h"
#include "xml.h"
#include "event.h"
@@ -508,22 +511,39 @@ MidiInstrument& MidiInstrument::assign(const MidiInstrument& ins)
//---------------------------------------------------------
void MidiInstrument::reset(int portNo, MType)
+{
+ MidiPort* port = &midiPorts[portNo];
+ //if (port == 0)
+ // return;
+ if(port->device() == 0) // p4.0.15
{
+ //printf("MidiInstrument::reset port device is 0\n");
+ return;
+ }
MidiPlayEvent ev;
ev.setType(0x90);
- MidiPort* port = &midiPorts[portNo];
- if (port == 0)
- return;
ev.setPort(portNo);
- for (int chan = 0; chan < MIDI_CHANNELS; ++chan) {
+ ev.setTime(0); // p4.0.15
+ //ev.setTime(audio->getFrameOffset() + audio->pos().frame());
+
+ for (int chan = 0; chan < MIDI_CHANNELS; ++chan)
+ {
ev.setChannel(chan);
- for (int pitch = 0; pitch < 128; ++pitch) {
+ for (int pitch = 0; pitch < 128; ++pitch)
+ {
ev.setA(pitch);
ev.setB(0);
+ //printf("MidiInstrument::reset adding event channel:%d pitch:%d\n", chan, pitch);
+ //ev.dump();
+
port->sendEvent(ev);
- }
+ // Changed to use play events list instead of putEvent FIFO.
+ // 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);
}
}
+}
//---------------------------------------------------------
// readPatchGroup
@@ -770,7 +790,7 @@ void MidiInstrument::write(int level, Xml& xml)
xml.put(">");
// -------------
- // What about Init, Reset, State, and InitScript ?
+ // TODO: What about Init, Reset, State, and InitScript ?
// -------------
//std::vector<PatchGroup>* pg = groups();
diff --git a/muse2/muse/main.cpp b/muse2/muse/main.cpp
index 936a8aa3..fccf801d 100644
--- a/muse2/muse/main.cpp
+++ b/muse2/muse/main.cpp
@@ -107,10 +107,10 @@ class MuseApplication : public QApplication {
bool notify(QObject* receiver, QEvent* event) {
//if (event->type() == QEvent::KeyPress)
- // printf("notify key press before app::notify accepted:%d\n", event->isAccepted()); // REMOVE Tim
+ // printf("notify key press before app::notify accepted:%d\n", event->isAccepted());
bool flag = QApplication::notify(receiver, event);
if (event->type() == QEvent::KeyPress) {
- //printf("notify key press after app::notify accepted:%d\n", event->isAccepted()); // REMOVE Tim
+ //printf("notify key press after app::notify accepted:%d\n", event->isAccepted());
QKeyEvent* ke = (QKeyEvent*)event;
///globalKeyState = ke->stateAfter();
globalKeyState = ke->modifiers();
diff --git a/muse2/muse/midi.cpp b/muse2/muse/midi.cpp
index 87e9ff32..7087b342 100644
--- a/muse2/muse/midi.cpp
+++ b/muse2/muse/midi.cpp
@@ -945,12 +945,29 @@ void Audio::processMidi()
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
MidiDevice* md = *id;
- MPEventList* playEvents = md->playEvents();
//
// erase already played events:
//
- iMPEvent nextPlayEvent = md->nextPlayEvent();
- playEvents->erase(playEvents->begin(), nextPlayEvent);
+ ///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())
@@ -974,9 +991,11 @@ void Audio::processMidi()
md->beforeProcess();
}
- MPEventList* playEvents = metronome->playEvents();
- iMPEvent nextPlayEvent = metronome->nextPlayEvent();
- playEvents->erase(playEvents->begin(), nextPlayEvent);
+ // 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();
@@ -1075,7 +1094,7 @@ void Audio::processMidi()
if(!dev->sysexFIFOProcessed())
{
// Set to the sysex fifo at first.
- MidiFifo& rf = dev->recordEvents(MIDI_CHANNELS);
+ MidiRecFifo& rf = dev->recordEvents(MIDI_CHANNELS);
// Get the frozen snapshot of the size.
int count = dev->tmpRecordCount(MIDI_CHANNELS);
@@ -1140,7 +1159,7 @@ void Audio::processMidi()
}
*/
- MidiFifo& rf = dev->recordEvents(channel);
+ MidiRecFifo& rf = dev->recordEvents(channel);
int count = dev->tmpRecordCount(channel);
//for (iMREvent ie = el->begin(); ie != el->end(); ++ie)
@@ -1343,11 +1362,14 @@ void Audio::processMidi()
}
}
// Added by Tim. p3.3.8
- if(md)
- {
-
- md->setNextPlayEvent(playEvents->begin());
- }
+ // 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");
+ //}
}
//
@@ -1390,7 +1412,10 @@ void Audio::processMidi()
playEvents->add(ev);
}
stuckNotes->erase(stuckNotes->begin(), k);
- md->setNextPlayEvent(playEvents->begin());
+ // Removed p4.0.15 Tim.
+ ///md->setNextPlayEvent(playEvents->begin());
+ //if(md->nextPlayEvent() != playEvents->begin())
+ // printf("Audio::processMidi clear notes: md->nextPlayEvent() != playEvents->begin()\n");
}
//---------------------------------------------------
@@ -1473,10 +1498,24 @@ void Audio::processMidi()
state = START_PLAY;
}
}
- if (md)
- md->setNextPlayEvent(playEvents->begin());
- if (audioClickFlag)
- metronome->setNextPlayEvent(metronome->playEvents()->begin());
+ // 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 (audioClickFlag)
+ /// metronome->setNextPlayEvent(metronome->playEvents()->begin());
+ //if(audioClickFlag)
+ //{
+ // if(metronome->nextPlayEvent() != metronome->playEvents()->begin())
+ // printf("Audio::processMidi metronome: metronome->nextPlayEvent() != metronome->playEvents->begin()\n");
+ //}
+
}
if (state == STOP) {
diff --git a/muse2/muse/midictrl.cpp b/muse2/muse/midictrl.cpp
index b96fcda6..66f8d87e 100644
--- a/muse2/muse/midictrl.cpp
+++ b/muse2/muse/midictrl.cpp
@@ -68,8 +68,8 @@ MidiControllerList defaultMidiController;
MidiController veloCtrl("Velocity", CTRL_VELOCITY, 0, 127, 0);
static MidiController pitchCtrl("PitchBend", CTRL_PITCH, -8192, +8191, 0);
static MidiController programCtrl("Program", CTRL_PROGRAM, 0, 0xffffff, 0);
-// Removed p3.3.37
-//static MidiController mastervolCtrl("MasterVolume", CTRL_MASTER_VOLUME, 0, 0x3fff, 0x3000);
+// Removed p3.3.37 Re-added p4.0.15
+static MidiController mastervolCtrl("MasterVolume", CTRL_MASTER_VOLUME, 0, 0x3fff, 0x3000);
static MidiController volumeCtrl("MainVolume", CTRL_VOLUME, 0, 127, 100);
static MidiController panCtrl("Pan", CTRL_PANPOT, -64, 63, 0);
@@ -132,8 +132,8 @@ void initMidiController()
defaultMidiController.add(&veloCtrl);
defaultMidiController.add(&pitchCtrl);
defaultMidiController.add(&programCtrl);
- // Removed p3.3.37
- //defaultMidiController.add(&mastervolCtrl);
+ // Removed p3.3.37 Re-added p4.0.15
+ defaultMidiController.add(&mastervolCtrl);
defaultMidiController.add(&volumeCtrl);
defaultMidiController.add(&panCtrl);
}
diff --git a/muse2/muse/midictrl.h b/muse2/muse/midictrl.h
index 4c08fbe0..27f8e7be 100644
--- a/muse2/muse/midictrl.h
+++ b/muse2/muse/midictrl.h
@@ -68,7 +68,7 @@ const int CTRL_INTERNAL_OFFSET = 0x40000;
const int CTRL_PITCH = CTRL_INTERNAL_OFFSET;
const int CTRL_PROGRAM = CTRL_INTERNAL_OFFSET + 1;
const int CTRL_VELOCITY = CTRL_INTERNAL_OFFSET + 2;
-//const int CTRL_MASTER_VOLUME = CTRL_INTERNAL_OFFSET + 3;
+const int CTRL_MASTER_VOLUME = CTRL_INTERNAL_OFFSET + 3;
const int CTRL_VAL_UNKNOWN = 0x10000000; // used as unknown hwVal
diff --git a/muse2/muse/mididev.cpp b/muse2/muse/mididev.cpp
index 0aab9a71..10be79ef 100644
--- a/muse2/muse/mididev.cpp
+++ b/muse2/muse/mididev.cpp
@@ -73,7 +73,7 @@ void MidiDevice::init()
_rwFlags = 3;
_openFlags = 3;
_port = -1;
- _nextPlayEvent = _playEvents.begin();
+ // _nextPlayEvent = _playEvents.begin(); // Removed p4.0.15 Tim.
}
//---------------------------------------------------------
@@ -443,9 +443,34 @@ bool MidiDevice::sendNullRPNParams(int chn, bool nrpn)
}
//---------------------------------------------------------
+// putEventWithRetry
+// return true if event cannot be delivered
+// This method will try to putEvent 'tries' times, waiting 'delayUs' microseconds between tries.
+// NOTE: Since it waits, it should not be used in RT or other time-sensitive threads. p4.0.15 Tim.
+//---------------------------------------------------------
+
+bool MidiDevice::putEventWithRetry(const MidiPlayEvent& ev, int tries, long delayUs)
+{
+ // TODO: Er, probably not the best way to do this.
+ // Maybe try to correlate with actual audio buffer size instead of blind time delay.
+ for( ; tries > 0; --tries)
+ {
+ if(!putEvent(ev)) // Returns true if event cannot be delivered.
+ return false;
+
+ bool sleepOk = -1;
+ while(sleepOk == -1)
+ sleepOk = usleep(delayUs); // FIXME: usleep is supposed to be depricated!
+ }
+ return true;
+}
+
+//---------------------------------------------------------
// putEvent
// return true if event cannot be delivered
// TODO: retry on controller putMidiEvent
+// (Note: Since putEvent is virtual and there are different versions,
+// a retry facility is now found in putEventWithRetry. p4.0.15 Tim)
//---------------------------------------------------------
bool MidiDevice::putEvent(const MidiPlayEvent& ev)
diff --git a/muse2/muse/mididev.h b/muse2/muse/mididev.h
index 16e834f2..6ac93729 100644
--- a/muse2/muse/mididev.h
+++ b/muse2/muse/mididev.h
@@ -28,7 +28,10 @@ class Xml;
class MidiDevice {
MPEventList _stuckNotes;
MPEventList _playEvents;
- iMPEvent _nextPlayEvent;
+
+ // Removed p4.0.15 Tim.
+ //iMPEvent _nextPlayEvent;
+
///MREventList _recordEvents;
///MREventList _recordEvents2;
@@ -53,10 +56,14 @@ class MidiDevice {
//bool _sysexWritingChunks;
bool _sysexReadingChunks;
+ // Fifo for midi events sent from gui direct to midi port:
+ MidiFifo eventFifo; // p4.0.15
+
// Recording fifo.
//MidiFifo _recordFifo;
// Recording fifos. To speed up processing, one per channel plus one special system 'channel' for channel-less events like sysex.
- MidiFifo _recordFifo[MIDI_CHANNELS + 1];
+ //MidiFifo _recordFifo[MIDI_CHANNELS + 1];
+ MidiRecFifo _recordFifo[MIDI_CHANNELS + 1]; // p4.0.15
RouteList _inRoutes, _outRoutes;
@@ -109,6 +116,9 @@ class MidiDevice {
virtual void recordEvent(MidiRecordEvent&);
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.
// For Jack-based devices - called in Jack audio process callback
virtual void collectMidiEvents() {}
@@ -125,7 +135,7 @@ class MidiDevice {
//int tmpRecordCount() { return _tmpRecordCount; }
int tmpRecordCount(const unsigned int ch) { return _tmpRecordCount[ch]; }
//MidiFifo& recordEvents() { return _recordFifo; }
- MidiFifo& recordEvents(const unsigned int ch) { return _recordFifo[ch]; }
+ MidiRecFifo& recordEvents(const unsigned int ch) { return _recordFifo[ch]; }
bool sysexFIFOProcessed() { return _sysexFIFOProcessed; }
void setSysexFIFOProcessed(bool v) { _sysexFIFOProcessed = v; }
//bool sysexWritingChunks() { return _sysexWritingChunks; }
@@ -134,8 +144,10 @@ class MidiDevice {
void setSysexReadingChunks(bool v) { _sysexReadingChunks = v; }
//virtual void getEvents(unsigned /*from*/, unsigned /*to*/, int /*channel*/, MPEventList* /*dst*/);
- iMPEvent nextPlayEvent() { return _nextPlayEvent; }
- void setNextPlayEvent(iMPEvent i) { _nextPlayEvent = i; }
+ // Removed p4.0.15 Tim.
+ //iMPEvent nextPlayEvent() { return _nextPlayEvent; }
+ //void setNextPlayEvent(iMPEvent i) { _nextPlayEvent = i; }
+
bool sendNullRPNParams(int, bool);
};
diff --git a/muse2/muse/midiedit/dcanvas.cpp b/muse2/muse/midiedit/dcanvas.cpp
index fa89b8ad..623a2734 100644
--- a/muse2/muse/midiedit/dcanvas.cpp
+++ b/muse2/muse/midiedit/dcanvas.cpp
@@ -1050,7 +1050,7 @@ void DrumCanvas::dragEnterEvent(QDragEnterEvent* event)
void DrumCanvas::dragMoveEvent(QDragMoveEvent*)
{
- //printf("drag move %x\n", this); // REMOVE Tim
+ //printf("drag move %x\n", this);
//event->acceptProposedAction();
}
@@ -1060,7 +1060,7 @@ void DrumCanvas::dragMoveEvent(QDragMoveEvent*)
void DrumCanvas::dragLeaveEvent(QDragLeaveEvent*)
{
- //printf("drag leave\n"); // REMOVE Tim
+ //printf("drag leave\n");
//event->acceptProposedAction();
}
@@ -1073,7 +1073,7 @@ void DrumCanvas::viewDropEvent(QDropEvent* event)
{
QString text;
if (event->source() == this) {
- printf("local DROP\n"); // REMOVE Tim
+ printf("local DROP\n");
//event->acceptProposedAction();
//event->ignore(); // TODO CHECK Tim.
return;
diff --git a/muse2/muse/midiedit/ecanvas.cpp b/muse2/muse/midiedit/ecanvas.cpp
index 889657aa..c8ee91ef 100644
--- a/muse2/muse/midiedit/ecanvas.cpp
+++ b/muse2/muse/midiedit/ecanvas.cpp
@@ -518,7 +518,7 @@ void EventCanvas::viewDropEvent(QDropEvent* event)
{
QString text;
if (event->source() == this) {
- printf("local DROP\n"); // REMOVE Tim
+ printf("local DROP\n");
//event->acceptProposedAction();
//event->ignore(); // TODO CHECK Tim.
return;
diff --git a/muse2/muse/midiedit/prcanvas.cpp b/muse2/muse/midiedit/prcanvas.cpp
index 4b280a16..a0ffdcaf 100644
--- a/muse2/muse/midiedit/prcanvas.cpp
+++ b/muse2/muse/midiedit/prcanvas.cpp
@@ -1584,7 +1584,7 @@ void PianoCanvas::viewDropEvent(QDropEvent* event)
{
QString text;
if (event->source() == this) {
- printf("local DROP\n"); // REMOVE Tim
+ printf("local DROP\n");
//event->acceptProposedAction();
//event->ignore(); // TODO CHECK Tim.
return;
diff --git a/muse2/muse/midiport.cpp b/muse2/muse/midiport.cpp
index 66da871a..0220a353 100644
--- a/muse2/muse/midiport.cpp
+++ b/muse2/muse/midiport.cpp
@@ -181,8 +181,15 @@ void MidiPort::setMidiDevice(MidiDevice* dev)
///{
///#endif
// Note the addition of bias!
- _device->putEvent(MidiPlayEvent(0, portno(), chan,
+ //_device->putEvent(MidiPlayEvent(0, portno(), chan,
+ // ME_CONTROLLER, ctl, mc->initVal() + mc->bias()));
+ // Retry added. Use default attempts and delay. p4.0.15
+ _device->putEventWithRetry(MidiPlayEvent(0, portno(), chan,
ME_CONTROLLER, ctl, mc->initVal() + mc->bias()));
+ //if(_device->putEventWithRetry(MidiPlayEvent(0, portno(), chan,
+ // ME_CONTROLLER, ctl, mc->initVal() + mc->bias())))
+ // return;
+
///#ifdef DSSI_SUPPORT
///}
///#endif
@@ -214,8 +221,15 @@ void MidiPort::setMidiDevice(MidiDevice* dev)
///if(!_device->isSynti() || (dynamic_cast<DssiSynthIF*>(((SynthI*)_device)->sif()) == 0))
///{
///#endif
- _device->putEvent(MidiPlayEvent(0, portno(), channel,
- ME_CONTROLLER, cntrl, val));
+ //_device->putEvent(MidiPlayEvent(0, portno(), channel,
+ // ME_CONTROLLER, cntrl, val));
+ // Retry added. Use default attempts and delay. p4.0.15
+ _device->putEventWithRetry(MidiPlayEvent(0, portno(), channel,
+ ME_CONTROLLER, cntrl, val));
+ //if(_device->putEventWithRetry(MidiPlayEvent(0, portno(), channel,
+ // ME_CONTROLLER, cntrl, val)))
+ // return;
+
///#ifdef DSSI_SUPPORT
///}
///#endif
@@ -320,6 +334,8 @@ void MidiPort::tryCtrlInitVal(int chan, int ctl, int val)
//MidiPlayEvent ev(song->cpos(), portno(), chan, ME_CONTROLLER, ctl, initval + mc->bias());
MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, initval + mc->bias());
_device->putEvent(ev);
+ // Retry added. Use default attempts and delay. p4.0.15
+ //_device->putEventWithRetry(ev);
}
// Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
//setHwCtrlState(chan, ctl, initval + mc->bias());
@@ -337,6 +353,8 @@ void MidiPort::tryCtrlInitVal(int chan, int ctl, int val)
//MidiPlayEvent ev(song->cpos(), portno(), chan, ME_CONTROLLER, ctl, val);
MidiPlayEvent ev(0, portno(), chan, ME_CONTROLLER, ctl, val);
_device->putEvent(ev);
+ // Retry added. Use default attempts and delay. p4.0.15
+ //_device->putEventWithRetry(ev);
}
// Set it once so the 'last HW value' is set, and control knobs are positioned at the value...
//setHwCtrlState(chan, ctl, val);
diff --git a/muse2/muse/midiseq.cpp b/muse2/muse/midiseq.cpp
index 8aabcbbb..5e42d547 100644
--- a/muse2/muse/midiseq.cpp
+++ b/muse2/muse/midiseq.cpp
@@ -54,9 +54,11 @@ void MidiSeq::processMsg(const ThreadMsg* m)
{
AudioMsg* msg = (AudioMsg*)m;
switch(msg->id) {
- case MS_PROCESS:
- audio->processMidi();
- break;
+ // This does not appear to be used anymore. Was sent in Audio::process1,
+ // now Audio::processMidi is called directly. p4.0.15 Tim.
+ //case MS_PROCESS:
+ // audio->processMidi();
+ // break;
case SEQM_SEEK:
processSeek();
break;
@@ -149,7 +151,7 @@ void MidiSeq::processStop()
pel->add(ev);
}
sel->clear();
- md->setNextPlayEvent(pel->begin());
+ //md->setNextPlayEvent(pel->begin()); // Removed p4.0.15
}
}
@@ -188,8 +190,11 @@ void MidiSeq::processSeek()
}
sel->clear();
}
- else
- el->erase(el->begin(), dev->nextPlayEvent());
+ //else
+ // Removed p4.0.15 Device now leaves beginning pointing at next event,
+ // immediately after playing some notes.
+ // NOTE: This removal needs testing. I'm not sure about this.
+ // el->erase(el->begin(), dev->nextPlayEvent());
for (iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl) {
MidiCtrlValList* vl = ivl->second;
@@ -208,7 +213,7 @@ void MidiSeq::processSeek()
el->add(MidiPlayEvent(0, port, ivl->first >> 24, ME_CONTROLLER, vl->num(), imcv->second.val));
}
}
- dev->setNextPlayEvent(el->begin());
+ //dev->setNextPlayEvent(el->begin()); // Removed p4.0.15
}
}
@@ -543,7 +548,7 @@ void MidiSeq::processTimerTick()
return;
}
if (midiBusy) {
- // we hit audio: midiSeq->msgProcess
+ // we hit audio: midiSeq->msgProcess (actually this has been audio->processMidi for some time now - Tim)
// miss this timer tick
return;
}
@@ -650,7 +655,6 @@ void MidiSeq::processTimerTick()
printf("Dropped %d midi out clock(s). curTick:%d midiClock:%d div:%d\n", perr, curTick, midiClock, div);
//}
- // Keeping in mind how (receiving end) Phase Locked Loops (usually) operate...
// Increment as if we had caught the timer exactly on the mark, even if the timer
// has passed beyond the mark, or even beyond 2 * div.
// If we missed some chances to send clock, resume the count where it would have been,
@@ -690,7 +694,7 @@ void MidiSeq::processTimerTick()
//
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
MidiDevice* md = *id;
- // Is it a Jack midi device? p3.3.36
+ // 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)
@@ -702,7 +706,10 @@ void MidiSeq::processTimerTick()
MPEventList* el = md->playEvents();
if (el->empty())
continue;
- iMPEvent i = md->nextPlayEvent();
+
+ ///iMPEvent i = md->nextPlayEvent();
+ iMPEvent i = el->begin(); // p4.0.15 Tim.
+
for (; i != el->end(); ++i) {
// p3.3.25
// If syncing to external midi sync, we cannot use the tempo map.
@@ -722,7 +729,15 @@ void MidiSeq::processTimerTick()
break;
}
}
- md->setNextPlayEvent(i);
+ ///md->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);
+ //md->setNextPlayEvent(el->begin()); // Removed p4.0.15
}
}
@@ -758,7 +773,8 @@ void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device)
Thread::sendMsg(&msg);
}
-void MidiSeq::msgProcess() { msgMsg(MS_PROCESS); }
+// 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::msgSetRtc() { msgMsg(MS_SET_RTC); }
diff --git a/muse2/muse/mixer/amixer.cpp b/muse2/muse/mixer/amixer.cpp
index e4a82ce8..f59a2187 100644
--- a/muse2/muse/mixer/amixer.cpp
+++ b/muse2/muse/mixer/amixer.cpp
@@ -226,7 +226,7 @@ AudioMixerApp::AudioMixerApp(QWidget* parent, MixerConfig* c)
/*
bool AudioMixerApp::event(QEvent* event)
{
- printf("AudioMixerApp::event type:%d\n", event->type()); // REMOVE Tim.
+ printf("AudioMixerApp::event type:%d\n", event->type());
// Let it do the layout now, before we emit.
QMainWindow::event(event);
@@ -246,7 +246,7 @@ void AudioMixerApp::setSizing()
{
//w += (*si)->frameGeometry().width();
//Strip* s = *si;
- //printf("AudioMixerApp::setSizing width:%d frame width:%d\n", s->width(), s->frameWidth()); // REMOVE Tim
+ //printf("AudioMixerApp::setSizing width:%d frame width:%d\n", s->width(), s->frameWidth());
//w += s->width() + 2 * (s->frameWidth() + s->lineWidth() + s->midLineWidth());
//w += s->width() + 2 * s->frameWidth();
w += (*si)->width();
@@ -359,7 +359,7 @@ void AudioMixerApp::updateMixer(UpdateAction action)
stripList.erase(ssi);
}
- //printf("AudioMixerApp::updateMixer STRIP_REMOVED\n"); // REMOVE Tim
+ //printf("AudioMixerApp::updateMixer STRIP_REMOVED\n");
//setMaximumWidth(STRIP_WIDTH * stripList.size() + __WIDTH_COMPENSATION);
/// int w = computeWidth();
@@ -410,7 +410,7 @@ void AudioMixerApp::updateMixer(UpdateAction action)
addStrip(*i, idx++);
}
- //printf("AudioMixerApp::updateMixer UPDATE_MIDI\n"); // REMOVE Tim
+ //printf("AudioMixerApp::updateMixer UPDATE_MIDI\n");
//setMaximumWidth(STRIP_WIDTH * stripList.size() + __WIDTH_COMPENSATION);
/// int w = computeWidth();
@@ -500,7 +500,7 @@ void AudioMixerApp::updateMixer(UpdateAction action)
addStrip(*i, idx++);
}
- //printf("AudioMixerApp::updateMixer other\n"); // REMOVE Tim
+ //printf("AudioMixerApp::updateMixer other\n");
//setMaximumWidth(STRIP_WIDTH * idx + __WIDTH_COMPENSATION);
/// int w = computeWidth();
diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp
index b6a89ada..62695823 100644
--- a/muse2/muse/mixer/astrip.cpp
+++ b/muse2/muse/mixer/astrip.cpp
@@ -831,7 +831,7 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)
pan = addKnob(0, 0, &panl);
pan->setValue(t->pan());
-
+
//---------------------------------------------------
// mute, solo, record
//---------------------------------------------------
diff --git a/muse2/muse/mpevent.cpp b/muse2/muse/mpevent.cpp
index 9988c12b..5b4fc4cb 100644
--- a/muse2/muse/mpevent.cpp
+++ b/muse2/muse/mpevent.cpp
@@ -105,7 +105,6 @@ bool MEvent::operator<(const MEvent& e) const
return map[channel()] < map[e.channel()];
}
-
//---------------------------------------------------------
// put
// return true on fifo overflow
@@ -158,3 +157,55 @@ void MidiFifo::remove()
}
+//---------------------------------------------------------
+// put
+// return true on fifo overflow
+//---------------------------------------------------------
+
+bool MidiRecFifo::put(const MidiPlayEvent& event)
+ {
+ if (size < MIDI_REC_FIFO_SIZE) {
+ fifo[wIndex] = event;
+ wIndex = (wIndex + 1) % MIDI_REC_FIFO_SIZE;
+ // q_atomic_increment(&size);
+ ++size;
+ return false;
+ }
+ return true;
+ }
+
+//---------------------------------------------------------
+// get
+//---------------------------------------------------------
+
+MidiPlayEvent MidiRecFifo::get()
+ {
+ MidiPlayEvent event(fifo[rIndex]);
+ rIndex = (rIndex + 1) % MIDI_REC_FIFO_SIZE;
+ // q_atomic_decrement(&size);
+ --size;
+ return event;
+ }
+
+//---------------------------------------------------------
+// peek
+//---------------------------------------------------------
+
+const MidiPlayEvent& MidiRecFifo::peek(int n)
+ {
+ int idx = (rIndex + n) % MIDI_REC_FIFO_SIZE;
+ return fifo[idx];
+ }
+
+//---------------------------------------------------------
+// remove
+//---------------------------------------------------------
+
+void MidiRecFifo::remove()
+ {
+ rIndex = (rIndex + 1) % MIDI_REC_FIFO_SIZE;
+ // q_atomic_decrement(&size);
+ --size;
+ }
+
+
diff --git a/muse2/muse/mpevent.h b/muse2/muse/mpevent.h
index 6df7b0c0..b9b21e08 100644
--- a/muse2/muse/mpevent.h
+++ b/muse2/muse/mpevent.h
@@ -14,7 +14,14 @@
#include "evdata.h"
#include "memory.h"
-#define MIDI_FIFO_SIZE 512
+// Play events ring buffer size
+//#define MIDI_FIFO_SIZE 512
+// Increased. FE/6/11 p4.0.15 Tim.
+#define MIDI_FIFO_SIZE 2100
+
+// Record events ring buffer size
+//#define MIDI_REC_FIFO_SIZE 512
+#define MIDI_REC_FIFO_SIZE 160
class Event;
class EvData;
@@ -132,8 +139,9 @@ 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); }
- };
+ //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;
typedef MPEventList::const_iterator ciMPEvent;
@@ -170,9 +178,31 @@ class MidiFifo {
public:
MidiFifo() { clear(); }
- bool put(const MidiPlayEvent& event); // returns true on fifo overflow
+ bool put(const MidiPlayEvent& /*event*/); // returns true on fifo overflow
+ MidiPlayEvent get();
+ const MidiPlayEvent& peek(int = 0);
+ void remove();
+ bool isEmpty() const { return size == 0; }
+ void clear() { size = 0, wIndex = 0, rIndex = 0; }
+ int getSize() const { return size; }
+ };
+
+//---------------------------------------------------------
+// MidiRecFifo
+// (Same as MidiFifo, but with a smaller size.)
+//---------------------------------------------------------
+
+class MidiRecFifo {
+ MidiPlayEvent fifo[MIDI_REC_FIFO_SIZE];
+ volatile int size;
+ int wIndex;
+ int rIndex;
+
+ public:
+ MidiRecFifo() { clear(); }
+ bool put(const MidiPlayEvent& /*event*/); // returns true on fifo overflow
MidiPlayEvent get();
- const MidiPlayEvent& peek(int n = 0);
+ const MidiPlayEvent& peek(int = 0);
void remove();
bool isEmpty() const { return size == 0; }
void clear() { size = 0, wIndex = 0, rIndex = 0; }
diff --git a/muse2/muse/osc.cpp b/muse2/muse/osc.cpp
index 26cd3a8a..c5ff182d 100644
--- a/muse2/muse/osc.cpp
+++ b/muse2/muse/osc.cpp
@@ -184,6 +184,7 @@ int oscMessageHandler(const char* path, const char* types, lo_arg** argv,
continue;
//DssiSynthIF* instance = (DssiSynthIF*)synti->sif();
+ // TODO: Fix this dynamic cast - it may be a slowdown.
DssiSynthIF* instance = dynamic_cast<DssiSynthIF*>(synti->sif());
if(!instance)
break;
diff --git a/muse2/muse/osc.h b/muse2/muse/osc.h
index 8e093e2c..7d9afa92 100644
--- a/muse2/muse/osc.h
+++ b/muse2/muse/osc.h
@@ -48,7 +48,7 @@ struct OscControlValue
{
//int idx;
float value;
- // maybe timestamp, too ?
+ int frame; // Added p4.0.15
};
//---------------------------------------------------------
diff --git a/muse2/muse/plugin.cpp b/muse2/muse/plugin.cpp
index 5bacf092..179708ea 100644
--- a/muse2/muse/plugin.cpp
+++ b/muse2/muse/plugin.cpp
@@ -2454,6 +2454,10 @@ int PluginI::oscControl(unsigned long port, float value)
OscControlValue cv;
//cv.idx = cport;
cv.value = value;
+ // Time-stamp the event. Looks like no choice but to use the (possibly slow) call to gettimeofday via timestamp(),
+ // because these are asynchronous events arriving from OSC. timestamp() is more or less an estimate of the
+ // current frame. (This is exactly how ALSA events are treated when they arrive in our ALSA driver.) p4.0.15 Tim.
+ cv.frame = audio->timestamp();
if(cfifo->put(cv))
{
fprintf(stderr, "PluginI::oscControl: fifo overflow: in control number:%ld\n", cport);
diff --git a/muse2/muse/route.cpp b/muse2/muse/route.cpp
index 92c32317..05d25eee 100644
--- a/muse2/muse/route.cpp
+++ b/muse2/muse/route.cpp
@@ -366,12 +366,12 @@ void addRoute(Route src, Route dst)
for ( ; ir != outRoutes->end(); ++ir)
{
//if (*i == dst) // route already there
- ir->dump(); // REMOVE Tim.
+ ir->dump();
if (ir->type == Route::TRACK_ROUTE && ir->track == dst.track) // Does a route to the track exist?
{
//#ifdef ROUTE_DEBUG
fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s out route already exists. ir->channel:%d |= dst.channel:%d\n",
- src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, dst.channel); // REMOVE Tim.
+ src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, dst.channel);
//#endif
ir->channel |= dst.channel; // Bitwise OR the desired channel bit with the existing bit mask.
break;
@@ -389,7 +389,7 @@ void addRoute(Route src, Route dst)
if (ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == src.midiPort) // Does a route to the midi port exist?
{
fprintf(stderr, "addRoute: src midi port:%d dst audio in track:%s in route already exists. ir->channel:%d |= src.channel:%d\n",
- src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, src.channel); // REMOVE Tim.
+ src.midiPort, dst.track->name().toLatin1().constData(), ir->channel, src.channel);
ir->channel |= src.channel; // Bitwise OR the desired channel bit with the existing bit mask.
break;
}
diff --git a/muse2/muse/sync.cpp b/muse2/muse/sync.cpp
index 9fe5f4d3..22117536 100644
--- a/muse2/muse/sync.cpp
+++ b/muse2/muse/sync.cpp
@@ -28,7 +28,7 @@
//MidiSyncPort midiSyncPorts[MIDI_PORTS];
int volatile curMidiSyncInPort = -1;
-bool debugSync = true;
+bool debugSync = false;
int mtcType = 1;
MTC mtcOffset;
@@ -637,7 +637,6 @@ void MidiSeq::mtcInputQuarter(int port, unsigned char c)
{
static int hour, min, sec, frame;
- // p3.3.28
//printf("MidiSeq::mtcInputQuarter c:%h\n", c);
int valL = c & 0xf;
@@ -924,7 +923,6 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if(port != curMidiSyncInPort)
break;
- // p3.3.31
//printf("midi clock:%f\n", curTime());
// Re-transmit clock to other devices if clock out turned on.
@@ -1235,7 +1233,6 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if (debugSync)
printf(" start\n");
- // p3.3.31
//printf("midi start:%f\n", curTime());
if (1 /* !audio->isPlaying()*/ /*state == IDLE*/) {
@@ -1285,7 +1282,6 @@ void MidiSeq::realtimeSystemInput(int port, int c)
if (debugSync)
printf("realtimeSystemInput continue\n");
- // p3.3.31
//printf("continue:%f\n", curTime());
if (1 /* !audio->isPlaying() */ /*state == IDLE */) {
@@ -1321,7 +1317,6 @@ void MidiSeq::realtimeSystemInput(int port, int c)
//lastStoppedBeat = (audio->tickPos() * 4) / config.division;
//curExtMidiSyncTick = (config.division * lastStoppedBeat) / 4;
- // p3.3.31
//printf("stop:%f\n", curTime());
if (audio->isPlaying() /*state == PLAY*/) {
diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp
index defcd02e..f8d21d41 100644
--- a/muse2/muse/synth.cpp
+++ b/muse2/muse/synth.cpp
@@ -851,6 +851,31 @@ void SynthI::preProcessAlways()
if(_sif)
_sif->preProcessAlways();
_processed = false;
+
+ // TODO: p4.0.15 Tim. Erasure of already-played events was moved from Audio::processMidi()
+ // to each of the midi devices - ALSA, Jack, or Synth in SynthI::getData() below.
+ // If a synth track is 'off', AudioTrack::copyData() does not call our getData().
+ // So there is no processing of midi play events, or putEvent FIFOs.
+ // Hence the play events list and putEvent FIFOs will then accumulate events, sometimes
+ // thousands. Only when the Synth track is turned on again, are all these events
+ // processed. Whether or not we want this is a question.
+ //
+ // If we DON'T want the events to accumulate, we NEED this following piece of code.
+ // Without this code: When a song is loaded, if a Synth track is off, various controller init events
+ // can remain queued up so that when the Synth track is turned on, those initializations
+ // will be processed. Otherwise we, or the user, will have to init every time the track is turned on.
+ // Con: Thousands of events can accumulate. For example selecting "midi -> Reset Instr." sends a flood
+ // of 2048 note-off events, one for each note in each channel! Each time, the 2048, 4096, 8192 etc.
+ // events remain in the list.
+ // Variation: Maybe allow certain types, or groups, of events through, especially bulk init or note offs.
+ if(off())
+ {
+ // Clear any accumulated play events.
+ playEvents()->clear();
+ // Eat up any fifo events.
+ while(!eventFifo.isEmpty())
+ eventFifo.get();
+ }
}
void MessSynthIF::preProcessAlways()
@@ -872,11 +897,21 @@ bool SynthI::getData(unsigned pos, int ports, unsigned n, float** buffer)
MidiPort* mp = (p != -1) ? &midiPorts[p] : 0;
MPEventList* el = playEvents();
- iMPEvent ie = nextPlayEvent();
+ ///iMPEvent ie = nextPlayEvent();
+ iMPEvent ie = el->begin(); // p4.0.15 Tim.
ie = _sif->getData(mp, el, ie, pos, ports, n, buffer);
- setNextPlayEvent(ie);
+ ///setNextPlayEvent(ie);
+ // 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(), ie);
+ // setNextPlayEvent(el->begin()); // Removed p4.0.15
+
return true;
}
diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h
index de400423..1e06682c 100644
--- a/muse2/muse/synth.h
+++ b/muse2/muse/synth.h
@@ -157,7 +157,7 @@ class SynthI : public AudioTrack, public MidiDevice,
protected:
Synth* synthesizer;
- MidiFifo putFifo;
+ // MidiFifo putFifo; // Moved into MidiDevice p4.0.15
// List of initial floating point parameters, for synths which use them.
// Used once upon song reload, then discarded.
diff --git a/muse2/muse/widgets/shortcutcapturedialog.cpp b/muse2/muse/widgets/shortcutcapturedialog.cpp
index ca627661..73534811 100644
--- a/muse2/muse/widgets/shortcutcapturedialog.cpp
+++ b/muse2/muse/widgets/shortcutcapturedialog.cpp
@@ -53,7 +53,7 @@ void ShortcutCaptureDialog::keyPressEvent(QKeyEvent* e)
bool ispunct = keychar.isPunct();
bool issymbol = keychar.isSymbol();
//printf("Key:%x, alt:%d, ctrl:%d shift:%d ispunct:%d issymbol:%d text:%s\n",
- // e->key(), alt, ctrl, shift, ispunct, issymbol, e->text().toLatin1().constData()); // REMOVE Tim.
+ // e->key(), alt, ctrl, shift, ispunct, issymbol, e->text().toLatin1().constData());
temp_key += (shift ? (int)Qt::SHIFT : 0); // (int) Tim
temp_key += (ctrl ? (int)Qt::CTRL : 0); //