1
//=========================================================
4
// $Id: sync.cpp,v 1.1.1.1 2003/10/29 10:05:10 wschweer Exp $
6
// (C) Copyright 2003 Werner Schweer (ws@seh.de)
7
//=========================================================
10
#include "midithread.h"
18
int rxSyncPort = -1; // receive from all ports
20
int rxDeviceId = 0x7f; // �any� device
21
int txDeviceId = 0x7f; // �any� device
23
bool debugSync = false;
26
BValue extSyncFlag(0, "extSync"); // false - MASTER, true - SLAVE
27
bool genMTCSync = false; // output MTC Sync
28
bool genMCSync = false; // output MidiClock Sync
29
bool genMMC = false; // output Midi Machine Control
30
bool acceptMTC = false;
32
bool acceptMMC = true;
34
static MTC mtcCurTime;
35
static int mtcState; // 0-7 next expected quarter message
38
static bool mtcSync; // receive complete mtc frame?
40
static bool mcStart = false;
41
static int mcStartTick;
43
//---------------------------------------------------------
45
// Midi Machine Control Input received
46
//---------------------------------------------------------
48
void MidiThread::mmcInput(const unsigned char* p, int n)
51
printf("mmcInput: n:%d %02x %02x %02x %02x\n",
52
n, p[2], p[3], p[4], p[5]);
53
if (!(extSyncFlag.value() && acceptMMC))
59
printf(" MMC: STOP\n");
60
if ((state == PLAY || state == PRECOUNT))
65
printf(" MMC: PLAY\n");
68
printf(" MMC: DEFERRED PLAY\n");
73
startPlay(song->cpos());
77
printf("MMC: FF not implemented\n");
80
printf("MMC: REWIND not implemented\n");
83
printf("MMC: REC STROBE not implemented\n");
86
printf("MMC: REC EXIT not implemented\n");
89
printf("MMC: RESET not implemented\n");
93
printf("MMC: LOCATE IF not implemented\n");
97
MTC mtc(p[6] & 0x1f, p[7], p[8], p[9], p[10]);
98
int mmcPos = tempomap.time2tick(mtc.time());
102
printf("MMC: %f %d seek ",
107
write(sigFd, "G", 1);
112
printf("MMC %x %x, unknown\n", p[3], p[4]); break;
116
//---------------------------------------------------------
118
// process Quarter Frame Message
119
//---------------------------------------------------------
121
void MidiThread::mtcInputQuarter(int, unsigned char c)
123
static int hour, min, sec, frame;
125
if (!extSyncFlag.value())
129
int valH = valL << 4;
131
int _state = (c & 0x70) >> 4;
132
if (mtcState != _state)
133
mtcLost += _state - mtcState;
134
mtcState = _state + 1;
138
hour = (hour & 0x0f) | valH;
141
hour = (hour & 0xf0) | valL;
144
min = (min & 0x0f) | valH;
147
min = (min & 0xf0) | valL;
150
sec = (sec & 0x0f) | valH;
153
sec = (sec & 0xf0) | valL;
156
frame = (frame & 0x0f) | valH;
158
case 0: frame = (frame & 0xf0) | valL;
161
frame &= 0x1f; // 0-29
167
mtcValid = (mtcLost == 0);
171
mtcCurTime.set(hour, min, sec, frame);
172
mtcSyncMsg(mtcCurTime, !mtcSync);
176
else if (mtcValid && (mtcLost == 0)) {
177
mtcCurTime.incQuarter();
178
mtcSyncMsg(mtcCurTime, false);
182
//---------------------------------------------------------
184
// process Frame Message
185
//---------------------------------------------------------
187
void MidiThread::mtcInputFull(const unsigned char* p, int n)
190
printf("mtcInputFull\n");
191
if (!extSyncFlag.value())
195
if (p[3] != 2) { // silently ignore user bits
196
printf("unknown mtc msg subtype 0x%02x\n", p[3]);
206
frame &= 0x1f; // 0-29
209
// int type = (hour >> 5) & 3;
212
mtcCurTime.set(hour, min, sec, frame);
218
//---------------------------------------------------------
219
// nonRealtimeSystemSysex
220
//---------------------------------------------------------
222
void MidiThread::nonRealtimeSystemSysex(const unsigned char* p, int n)
227
printf("NRT Setup\n");
230
printf("unknown NRT Msg 0x%02x\n", p[3]);
236
//---------------------------------------------------------
238
// MidiBeat is a 14 Bit value. Each MidiBeat spans
239
// 6 MIDI Clocks. Inother words, each MIDI Beat is a
240
// 16th note (since there are 24 MIDI Clocks in a
242
//---------------------------------------------------------
244
void MidiThread::setSongPosition(int port, int midiBeat)
247
printf("set song position port:%d %d\n", port, midiBeat);
248
if (!extSyncFlag.value())
250
playTickPos = midiClick = (division * midiBeat) / 4;
252
printf("setSongPosition %d\n", playTickPos);
253
write(sigFd, "G", 1);
256
//---------------------------------------------------------
257
// realtimeSystemInput
258
// real time message received
259
//---------------------------------------------------------
261
void MidiThread::realtimeSystemInput(int port, int c)
264
printf("realtimeSystemInput port:%d 0x%x\n", port+1, c);
266
if (midiInputTrace && (rxSyncPort != port) && rxSyncPort != -1) {
268
printf("rxSyncPort configured as %d; received sync from port %d\n",
272
if (!extSyncFlag.value())
275
case 0xf8: // midi clock (24 ticks / quarter note)
277
double mclock0 = curTime();
280
recTick += division / 24;
281
int diff = recTick - _midiTick;
282
int tempo = tempomap.tempo(0);
284
tempomap.setTempo(0, tempo);
285
_midiTick = recTick; // brutal
288
double tdiff0 = mclock0 - mclock1;
289
double tdiff1 = mclock1 - mclock2;
291
midiPorts[port].device()->discardInput();
292
if ((mclock2 != 0.0) && (tdiff0 > 0.0)) {
293
int tempo0 = int(24000000.0 * tdiff0 + .5);
294
int tempo1 = int(24000000.0 * tdiff1 + .5);
295
int tempo = tempomap.tempo(0);
297
int diff0 = tempo0 - tempo;
298
int diff1 = tempo1 - tempo0;
300
int newTempo = tempo + diff0/8 + diff1/16;
301
tempomap.setTempo(0, newTempo);
308
case 0xf9: // midi tick (every 10 msec)
310
song->setPos(0, mcStartTick);
320
startPlay(song->cpos());
323
case 0xfb: // continue
325
printf(" continue\n");
327
startPlay(song->cpos());
336
case 0xfd: // unknown
337
case 0xfe: // active sensing
338
case 0xff: // system reset
343
//---------------------------------------------------------
345
// process received mtc Sync
346
// seekFlag - first complete mtc frame received after
348
//---------------------------------------------------------
350
void MidiThread::mtcSyncMsg(const MTC& mtc, bool seekFlag)
352
double time = mtc.time();
354
printf("mtcSyncMsg: time %f\n", time);
356
if (seekFlag && state == START_PLAY) {
357
// int tick = tempomap.time2tick(time);
359
write(sigFd, "1", 1); // say PLAY to gui
362
// double curT = curTime();
364
if (tempoSN != tempomap.tempoSN()) {
365
double cpos = tempomap.tick2time(_midiTick, 0);
366
samplePosStart = samplePos - lrint(cpos * sampleRate);
367
rtcTickStart = rtcTick - lrint(cpos * realRtcTicks);
368
tempoSN = tempomap.tempoSN();
372
// diff is the time in sec MusE is out of sync
374
double diff = time - (double(samplePosStart)/double(sampleRate));
376
printf(" state %d diff %f\n", mtcState, diff);