1
//=========================================================
4
// $Id: midiseq.cpp,v 1.30.2.9 2005/07/09 22:01:22 lunar_shuttle Exp $
6
// high priority task for scheduling midi events
8
// (C) Copyright 2003 Werner Schweer (ws@seh.de)
9
//=========================================================
13
#include <sys/ioctl.h>
23
#include "driver/alsamidi.h"
30
int MidiSeq::ticker = 0;
32
//---------------------------------------------------------
34
//---------------------------------------------------------
36
static void readMsg(void* p, void*)
39
MidiSeq* at = (MidiSeq*)p;
43
//---------------------------------------------------------
45
//---------------------------------------------------------
47
void MidiSeq::processMsg(const ThreadMsg* m)
49
AudioMsg* msg = (AudioMsg*)m;
65
case MS_UPDATE_POLL_FD:
69
song->insertTrack2(msg->track, msg->ival);
72
case SEQM_REMOVE_TRACK:
73
song->cmdRemoveTrack(msg->track);
76
case SEQM_CHANGE_TRACK:
77
song->changeTrack((Track*)(msg->p1), (Track*)(msg->p2));
81
song->cmdAddPart((Part*)msg->p1);
83
case SEQM_REMOVE_PART:
84
song->cmdRemovePart((Part*)msg->p1);
86
case SEQM_CHANGE_PART:
87
song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2);
89
case SEQM_SET_MIDI_DEVICE:
90
((MidiPort*)(msg->p1))->setMidiDevice((MidiDevice*)(msg->p2));
97
printf("MidiSeq::processMsg() unknown id %d\n", msg->id);
102
//---------------------------------------------------------
104
//---------------------------------------------------------
106
void MidiSeq::processStop()
111
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
112
MidiDevice* md = *id;
113
if (md->midiPort() == -1)
115
MPEventList* pel = md->playEvents();
116
MPEventList* sel = md->stuckNotes();
118
for (iMPEvent i = sel->begin(); i != sel->end(); ++i) {
119
MidiPlayEvent ev = *i;
124
md->setNextPlayEvent(pel->begin());
128
//---------------------------------------------------------
130
//---------------------------------------------------------
132
void MidiSeq::processSeek()
134
int pos = audio->tickPos();
135
if (pos == 0 && !song->record())
136
audio->initDevices();
138
//---------------------------------------------------
139
// set all controller
140
//---------------------------------------------------
142
for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) {
143
MidiDevice* dev = *i;
144
int port = dev->midiPort();
147
MidiPort* mp = &midiPorts[port];
148
MidiCtrlValListList* cll = mp->controller();
150
MPEventList* el = dev->playEvents();
152
if (audio->isPlaying()) {
155
MPEventList* sel = dev->stuckNotes();
156
for (iMPEvent i = sel->begin(); i != sel->end(); ++i) {
157
MidiPlayEvent ev = *i;
164
el->erase(el->begin(), dev->nextPlayEvent());
165
for (iMidiCtrlValList ivl = cll->begin(); ivl != cll->end(); ++ivl) {
166
MidiCtrlValList* vl = ivl->second;
167
int val = vl->value(pos);
168
if (val != CTRL_VAL_UNKNOWN) {
169
int channel = ivl->first >> 24;
170
el->add(MidiPlayEvent(0, port, channel, ME_CONTROLLER, vl->num(), val));
173
dev->setNextPlayEvent(el->begin());
177
//---------------------------------------------------------
179
//---------------------------------------------------------
181
MidiSeq::MidiSeq(int priority, const char* name)
182
: Thread(priority, name)
189
songtick1 = songtick2 = 0;
194
//---------------------------------------------------------
196
// called from loop()
197
//---------------------------------------------------------
199
void MidiSeq::threadStart(void*)
201
struct sched_param rt_param;
202
memset(&rt_param, 0, sizeof(rt_param));
203
int prio_min = sched_get_priority_min(SCHED_FIFO);
204
int prio_max = sched_get_priority_max(SCHED_FIFO);
206
if (prio < prio_min) prio = prio_min;
207
else if (prio > prio_max) prio = prio_max;
209
rt_param.sched_priority = prio;
210
int rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
212
perror("set realtime scheduler");
215
if ((policy = sched_getscheduler (0)) < 0) {
216
printf("Cannot get current client scheduler: %s\n", strerror(errno));
218
if (policy != SCHED_FIFO)
219
printf("midi thread %d _NOT_ running SCHED_FIFO\n", getpid());
223
//---------------------------------------------------------
225
//---------------------------------------------------------
227
static void alsaMidiRead(void*, void*)
229
// calls itself midiDevice->recordEvent(MidiRecordEvent):
230
alsaProcessMidiInput();
233
//---------------------------------------------------------
235
//---------------------------------------------------------
237
static void midiRead(void*, void* d)
239
MidiDevice* dev = (MidiDevice*) d;
243
//---------------------------------------------------------
245
//---------------------------------------------------------
248
static void synthIRead(void*, void* d)
250
SynthI* syn = (SynthI*) d;
255
//---------------------------------------------------------
257
//---------------------------------------------------------
259
static void midiWrite(void*, void* d)
261
MidiDevice* dev = (MidiDevice*) d;
265
//---------------------------------------------------------
267
//---------------------------------------------------------
269
void MidiSeq::updatePollFd()
275
addPollFd(timerFd, POLLIN, midiTick, this, 0);
278
fprintf(stderr, "updatePollFd: no timer fd\n");
283
addPollFd(toThreadFdr, POLLIN, ::readMsg, this, 0);
285
//---------------------------------------------------
287
//---------------------------------------------------
289
for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) {
290
MidiDevice* dev = *imd;
291
int port = dev->midiPort();
294
if ((dev->rwFlags()&0x2) || (extSyncFlag.value()
295
&& (rxSyncPort == port || rxSyncPort == -1))) {
296
addPollFd(dev->selectRfd(), POLLIN, ::midiRead, this, dev);
298
if (dev->bytesToWrite())
299
addPollFd(dev->selectWfd(), POLLOUT, ::midiWrite, this, dev);
301
// special handling for alsa midi:
302
// (one fd for all devices)
303
// this allows for processing of some alsa events
304
// even if no alsa driver is active (assigned to a port)
306
addPollFd(alsaSelectRfd(), POLLIN, ::alsaMidiRead, this, 0);
309
//---------------------------------------------------------
311
// called from loop()
312
//---------------------------------------------------------
314
void MidiSeq::threadStop()
319
//---------------------------------------------------------
321
// return true on success
322
//---------------------------------------------------------
324
bool MidiSeq::setRtcTicks()
327
timer.setTimerTicks(config.rtcTicks);
329
realRtcTicks = config.rtcTicks;
333
//---------------------------------------------------------
335
// return true on error
336
//---------------------------------------------------------
338
bool MidiSeq::start()
343
timerFd = timer.initTimer();
350
//---------------------------------------------------------
352
//---------------------------------------------------------
354
void MidiSeq::processMidiClock()
357
midiPorts[txSyncPort].sendClock();
359
/* if (state == START_PLAY) {
360
// start play on sync
362
_midiTick = playTickPos;
363
midiClock = playTickPos;
366
sigmap.tickValues(_midiTick, &bar, &beat, &tick);
367
midiClick = sigmap.bar2tick(bar, beat+1, 0);
369
double cpos = tempomap.tick2time(playTickPos);
370
samplePosStart = samplePos - lrint(cpos * sampleRate);
371
rtcTickStart = rtcTick - lrint(cpos * realRtcTicks);
373
endSlice = playTickPos;
374
recTick = playTickPos;
375
lastTickPos = playTickPos;
377
tempoSN = tempomap.tempoSN();
379
startRecordPos.setPosTick(playTickPos);
382
midiClock += config.division/24;
385
//---------------------------------------------------------
387
//---------------------------------------------------------
389
void MidiSeq::midiTick(void* p, void*)
391
MidiSeq* at = (MidiSeq*)p;
392
at->processTimerTick();
395
if(MidiSeq::ticker++ > 100)
403
//---------------------------------------------------------
405
//---------------------------------------------------------
407
void MidiSeq::processTimerTick()
409
extern int watchMidi;
410
++watchMidi; // make a simple watchdog happy
412
//---------------------------------------------------
413
// read elapsed rtc timer ticks
414
//---------------------------------------------------
418
nn = timer.getTimerTicks();
427
unsigned curFrame = audio->curFrame();
429
if (!extSyncFlag.value()) {
430
int curTick = tempomap.frame2tick(curFrame);
431
if ( midiClock > curTick + 100) // reinitialize
433
else if( curTick > midiClock + 100) // reinitialize
436
//printf("curTick=%d >= midiClock=%d\n",curTick,midiClock);
437
if (curTick >= midiClock) {
443
// printf("Midi Time Code Sync generation not impl.\n");
447
// play all events upto curFrame
449
for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
450
MidiDevice* md = *id;
451
int port = md->midiPort();
452
MidiPort* mp = port != -1 ? &midiPorts[port] : 0;
453
if (md->isSynti()) // syntis are handled by audio thread
455
MPEventList* el = md->playEvents();
458
iMPEvent i = md->nextPlayEvent();
459
for (; i != el->end(); ++i) {
460
/* if (i->time() > curFrame) {
461
printf(" curT %d frame %d\n", i->time(), curFrame);
465
// break if event cannot be delivered
467
if (mp->sendEvent(*i))
471
if (md->putEvent(*i))
475
md->setNextPlayEvent(i);
479
//---------------------------------------------------------
481
//---------------------------------------------------------
483
void MidiSeq::msgMsg(int id)
487
Thread::sendMsg(&msg);
490
//---------------------------------------------------------
492
// to avoid timeouts in the RT-thread, setMidiDevice
493
// is done in GUI context after setting the midi thread
495
//---------------------------------------------------------
497
void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device)
502
Thread::sendMsg(&msg);
504
port->setMidiDevice(device);
508
Thread::sendMsg(&msg);
511
void MidiSeq::msgProcess() { msgMsg(MS_PROCESS); }
512
void MidiSeq::msgSeek() { msgMsg(SEQM_SEEK); }
513
void MidiSeq::msgStop() { msgMsg(MS_STOP); }
514
void MidiSeq::msgSetRtc() { msgMsg(MS_SET_RTC); }
515
void MidiSeq::msgUpdatePollFd() { msgMsg(MS_UPDATE_POLL_FD); }