~ubuntu-branches/ubuntu/breezy/muse/breezy

« back to all changes in this revision

Viewing changes to mrecord.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2004-02-07 15:18:22 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040207151822-es27xxkzbcxkebjm
Tags: 0.6.3-1
* New upstream version.
* Added patches:
  + [10_alsa_init_fix] New, from upstream CVS.
    Initialize direction variable when setting Alsa parameters.
  + [10_canvas_translation_fix] New, from upstream CVS.
    Do not translate tooltips twice in canvas popup.
  + [10_checkbox_fix] New, from upstream CVS.
    Use proper set/test methods on metronome checkboxes.
  + [10_html_doc_cleanup] New.
    Fix links and HTML errors in documentation.
  + [20_allow_system_timer] New.
    The new upstream version fails by default if the real-time clock
    could not be accessed (usually the case when not running suid-root).
    This patch reverts the old behaviour of falling back to the more
    inaccurate system timer.
* Updated patches:
  + [11_PIC_fixes_fixup] Rediffed.
* Removed patches:
  + [20_no_atomic_asm] Merged upstream.
* debian/compat: Splice out debhelper compatibility level from rules file.
* debian/control: Build-depend on latest jack release by default.
  Closes: #228788
* debian/control: Bump standards version.
* debian/control: Use auto-generated debconf dependency via misc:Depends.
* debian/control: Minor tweaks to the long description.
* debian/control: Tighten fluidsynth build dependency to sane version.
* debian/muse.doc-base: New. Register HTML documentation with doc-base.
* debian/templates: Tiny rewording, and typo fix.
* debian/templates, debian/po/*: Switch to po-debconf for translations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
//=========================================================
2
2
//  MusE
3
3
//  Linux Music Editor
4
 
//  $Id: mrecord.cpp,v 1.2 2002/02/07 08:14:48 muse Exp $
 
4
//  $Id: mrecord.cpp,v 1.2 2003/11/18 18:43:00 lunar_shuttle Exp $
5
5
//
6
 
//  (C) Copyright 1999-2001 Werner Schweer (ws@seh.de)
 
6
//  (C) Copyright 1999-2003 Werner Schweer (ws@seh.de)
7
7
//=========================================================
8
8
 
9
9
#include <unistd.h>
 
10
#include <cmath>
10
11
 
11
 
#include "midithreadp.h"
 
12
#include "sync.h"
12
13
#include "mtc.h"
13
14
#include "event.h"
14
15
#include "song.h"
19
20
#include "mididev.h"
20
21
#include "midiitransform.h"
21
22
#include "utils.h"
22
 
 
23
 
extern void processMidiInputTransformPlugins(MidiEvent*);
24
 
 
25
 
static MTC mtcCurTime;
26
 
static int mtcState;    // 0-7 next expected quarter message
27
 
static bool mtcValid;
28
 
static int mtcLost;
29
 
static bool mtcSync;
30
 
 
31
 
static bool mcStart = false;
32
 
static int mcStartTick;
 
23
#include "drummap.h"
 
24
 
 
25
extern void processMidiInputTransformPlugins(MidiPlayEvent*);
33
26
 
34
27
//---------------------------------------------------------
35
28
//   eventReceived
37
30
 
38
31
void MidiThread::eventReceived(int port, unsigned char channel, unsigned char c1, unsigned c2)
39
32
      {
40
 
      MidiEvent* event = new MidiEvent(
41
 
         port, channel & 0xf,
42
 
         0, MidiEvent::EventType(0), c1, c2, 0, 0);
43
 
      switch(channel & 0xf0) {
44
 
            case 0x80:
45
 
                  event->setType(MidiEvent::NoteOff);
46
 
                  break;
47
 
            case 0x90:
48
 
                  event->setType(c2 == 0 ? MidiEvent::NoteOff : MidiEvent::Note);
49
 
                  break;
50
 
            case 0xa0:
51
 
                  event->setType(MidiEvent::PAfter);  // Poly Pressure
52
 
                  break;
53
 
            case 0xb0:
54
 
                  event->setType(MidiEvent::Ctrl7);
55
 
                  break;
56
 
            case 0xc0:
57
 
                  event->setType(MidiEvent::Program);
58
 
                  break;
59
 
            case 0xd0:                            // After Touch
60
 
                  event->setType(MidiEvent::CAfter);
61
 
                  break;
62
 
            case 0xe0:                            // Pitch Bender
63
 
                  event->setType(MidiEvent::Pitch);
64
 
                  break;
65
 
            case 0xf0:
66
 
                  break;
67
 
            }
 
33
      MidiPlayEvent* event = new MidiPlayEvent(port, channel & 0xf,
 
34
         channel & 0xf0, c1, c2);
68
35
      eventReceived(event);
69
36
      }
70
37
 
73
40
//    return true if event filtered
74
41
//---------------------------------------------------------
75
42
 
76
 
bool MidiThread::filterEvent(const MidiEvent* event, int type, bool thru)
 
43
bool MidiThread::filterEvent(const MidiPlayEvent* event, int type, bool thru)
77
44
      {
78
45
      switch(event->type()) {
79
 
            case MidiEvent::Note:
80
 
            case MidiEvent::NoteOff:
 
46
            case 0x90:
 
47
            case 0x80:
81
48
                  if (type & MIDI_FILTER_NOTEON)
82
49
                        return true;
83
50
                  break;
84
 
            case MidiEvent::PAfter:
 
51
            case 0xa0:
85
52
                  if (type & MIDI_FILTER_POLYP)
86
53
                        return true;
87
54
                  break;
88
 
            case MidiEvent::Ctrl7:
 
55
            case 0xb0:
89
56
                  if (type & MIDI_FILTER_CTRL)
90
57
                        return true;
91
58
                  if (!thru && (midiFilterCtrl1 == event->dataA()
95
62
                        return true;
96
63
                        }
97
64
                  break;
98
 
            case MidiEvent::Program:
 
65
            case 0xc0:
99
66
                  if (type & MIDI_FILTER_PROGRAM)
100
67
                        return true;
101
68
                  break;
102
 
            case MidiEvent::CAfter:
 
69
            case 0xd0:
103
70
                  if (type & MIDI_FILTER_AT)
104
71
                        return true;
105
72
                  break;
106
 
            case MidiEvent::Pitch:
 
73
            case 0xe0:
107
74
                  if (type & MIDI_FILTER_PITCH)
108
75
                        return true;
109
76
                  break;
110
 
            case MidiEvent::Sysex:
 
77
            case 0xf0:
111
78
                  if (type & MIDI_FILTER_SYSEX)
112
79
                        return true;
113
80
                  break;
121
88
//   Sequencer::eventReceived
122
89
//---------------------------------------------------------
123
90
 
124
 
void MidiThread::eventReceived(MidiEvent* event)
 
91
void MidiThread::eventReceived(MidiPlayEvent* event)
125
92
      {
126
 
      if (midiInputTrace)
 
93
      int tick = recTimeStamp();
 
94
 
 
95
      if (midiInputTrace) {
 
96
            printf("MidiInput: ");
127
97
            event->dump();
128
 
 
 
98
            }
129
99
      //
130
100
      //  special handling for software synthesizer events
131
101
      //
132
102
      int port = event->port();           // hack
133
 
      bool isSynth = (port & 0x100) == 0x100;
134
 
      if (!isSynth) {
 
103
      bool fromSynthGui = (port & 0x80) == 0x80;
 
104
      if (!fromSynthGui) {
135
105
            for (iSynthI i = synthiInstances.begin(); i != synthiInstances.end(); ++i) {
136
106
                  SynthI* si = *i;
137
107
                  MidiDevice* dev = si->mdev();
138
108
                  if (dev && (dev->port() == port)) {
139
109
                        (*i)->writeToGui(event);
140
 
                        isSynth = true;
 
110
                        fromSynthGui = true;
141
111
                        break;
142
112
                        }
143
113
                  }
145
115
      port &= 0xff;
146
116
      event->setPort(port);
147
117
 
148
 
      if (event->type() == MidiEvent::Sysex) {
 
118
      int typ = event->type();
 
119
 
 
120
      if (typ == 0xf0) {
149
121
            const unsigned char* p = event->data();
150
 
            int n = event->dataLen();
 
122
            int n = event->len();
151
123
            if (n >= 4) {
152
124
                  if ((p[0] == 0x7f)
153
 
                     && ((p[1] == 0x7f) || (p[1] == deviceId))) {
 
125
                     && ((p[1] == 0x7f) || (p[1] == rxDeviceId))) {
154
126
                        if (p[2] == 0x06) {
155
127
                              mmcInput(p, n);
156
128
                              delete event;
169
141
                        }
170
142
                  }
171
143
            }
172
 
      int tick = recTimeStamp();
173
 
      event->setPosTick(tick);
174
144
 
175
145
      //
176
146
      // filter midi remote control events
177
147
      //
178
148
      int c1 = event->dataA();
179
 
      if (rcEnable && (event->isNote() || event->isNoteOff())) {
 
149
      if (rcEnable && (typ == 0x90 || typ == 0x80)) {
180
150
            if (c1 == rcStopNote) {
181
 
                  if (event->isNote()) {
182
 
                        write(data->sigFd, "0", 1);
 
151
                  if (typ == 0x90) {
 
152
                        write(sigFd, "0", 1);
183
153
                        }
184
154
                  delete event;
185
155
                  return;
186
156
                  }
187
157
            else if (c1 == rcRecordNote) {
188
 
                  if (event->isNote()) {
189
 
                        write(data->sigFd, "2", 1);
 
158
                  if (typ == 0x90) {
 
159
                        write(sigFd, "2", 1);
190
160
                        }
191
161
                  delete event;
192
162
                  return;
193
163
                  }
194
164
            else if (c1 == rcGotoLeftMarkNote) {
195
 
                  if (event->isNote()) {
196
 
                        write(data->sigFd, "3", 1);
 
165
                  if (typ == 0x90) {
 
166
                        write(sigFd, "3", 1);
197
167
                        }
198
168
                  delete event;
199
169
                  return;
200
170
                  }
201
171
            else if (c1 == rcPlayNote) {
202
 
                  if (event->isNote()) {
203
 
                        write(data->sigFd, "1", 1);
 
172
                  if (typ == 0x90) {
 
173
                        write(sigFd, "1", 1);
204
174
                        }
205
175
                  delete event;
206
176
                  return;
213
183
            delete event;
214
184
            return;
215
185
            }
216
 
 
217
186
      if (!applyMidiInputTransformation(event)) {
218
187
            if (midiInputTrace)
219
188
                  printf("   midi input transformation: event filtered\n");
221
190
            return;
222
191
            }
223
192
 
224
 
      if (event->type() == MidiEvent::Note) {
225
 
            data->curPitch = event->pitch();
226
 
            data->curVelo  = event->velo();
227
 
            write(data->sigFd, "I", 1);
 
193
      if ((event->type() == 0x90) && (noteFifoSize < REC_NOTE_FIFO_SIZE)) {
 
194
            int pv = ((event->dataA() & 0xff)<<8) + (event->dataB() & 0xff);
 
195
            recNoteFifo[noteFifoWindex] = pv;
 
196
            noteFifoWindex = (noteFifoWindex + 1) % REC_NOTE_FIFO_SIZE;
 
197
            ++noteFifoSize;
228
198
            }
229
199
 
230
200
      TrackList* tl = song->tracks();
232
202
            MidiTrack* mt = dynamic_cast<MidiTrack*>(*it);
233
203
            if (mt == 0 || !mt->recordFlag())
234
204
                  continue;
235
 
            event->setPort(mt->outPort());
236
 
            event->setChannel(mt->outChannel());
237
205
            if ((mt->inPortMask() & (1 << event->port())) && (mt->inChannelMask() & (1 << event->channel()))) {
238
 
                  if (data->state == PLAY && song->record()) {
239
 
                        if (data->loopPassed) {
 
206
                  //
 
207
                  // Add recorded events to track
 
208
                  //
 
209
                  if (state == PLAY && song->record()) {
 
210
                        if (loopPassed) {
240
211
                              // this is the first event in a new loop
241
212
                              //   - erase all events from previous loop
242
213
                              mt->events()->clear();
243
214
                              }
244
 
                        MidiEvent* ev = new MidiEvent(*event);
 
215
                        MidiEvent* ev = new MidiEvent(event);
 
216
                        ev->setPosTick(tick);
 
217
 
 
218
                        if (mt->type() == Track::DRUM) {
 
219
                                    int pitch = drumInmap[ev->dataA()]; //Point to the drummap-value for this in-note
 
220
                                    ev->setPitch(pitch);
 
221
                                    }
 
222
 
245
223
                        mt->events()->add(ev);
246
224
                        }
247
225
 
248
226
                  // echo event to current track output
249
227
                  // (if not from synth gui)
250
228
 
251
 
                  MidiPort* mport = &midiPorts[event->port()];
252
 
                  if (!isSynth && mt->midiThruFlag() && !filterEvent(event, midiThruType, true)) {
 
229
                  MidiPort* mport = &midiPorts[mt->outPort()];
 
230
                  if (!fromSynthGui && mt->midiThruFlag() && !filterEvent(event, midiThruType, true)) {
 
231
                        // event->setPort(mt->outPort());
 
232
                        event->setChannel(mt->outChannel());
253
233
                        if (event->isNote() || event->isNoteOff()) {
254
 
                              MidiEvent e(*event);
255
 
                              int pitch = e.pitch() + mt->transposition;
 
234
                              MidiPlayEvent e(*event);
 
235
                              int pitch;
 
236
                              if (mt->type() == Track::DRUM) {
 
237
                                    int instr = drumInmap[e.dataA()];
 
238
                                    pitch = drumMap[instr].anote; //Map to output note for this key, since this is goes straight out to the midi port
 
239
                                    e.setChannel(drumMap[instr].channel);
 
240
                                    mport = &midiPorts[drumMap[instr].port];
 
241
                                    //printf("Drum-track, event pitch: %d chan: %d port: %d\n",pitch, drumMap[instr].channel, drumMap[instr].port);
 
242
                                    }
 
243
                              else
 
244
                                    pitch = e.dataA() + mt->transposition;
 
245
 
256
246
                              if (pitch > 127)
257
247
                                    pitch = 127;
258
248
                              if (pitch < 0)
259
249
                                    pitch = 0;
260
 
                              e.setPitch(pitch);
 
250
                              e.setA(pitch);
261
251
 
262
252
                              //
263
253
                              // apply track values
264
254
                              //
265
255
                              if (!e.isNoteOff()) {
266
 
                                    int velo = e.velo() + mt->velocity;
 
256
                                    int velo = e.dataB() + mt->velocity;
267
257
                                    velo = (velo * mt->compression) / 100;
268
258
                                    if (velo > 127)
269
259
                                          velo = 127;
270
260
                                    if (velo < 1)
271
261
                                          velo = 1;
272
 
                                    e.setVelo(velo);
 
262
                                    e.setB(velo);
273
263
                                    }
274
264
                              mport->putEvent(&e);
275
265
                              }
276
 
                        else
 
266
                        else {
277
267
                              mport->putEvent(event);
278
 
                        }
279
 
                  }
280
 
            }
281
 
      data->loopPassed = false;
282
 
      }
283
 
 
284
 
//---------------------------------------------------------
285
 
//  mmcInput
286
 
//    Midi Machine Control Input received
287
 
//---------------------------------------------------------
288
 
 
289
 
void MidiThread::mmcInput(const unsigned char* /*p*/, int /*n*/)
290
 
      {
291
 
#if 0
292
 
      if (!extSyncFlag.value())
293
 
            return;
294
 
//      printf("mmcInput: %x -- %02x %d %02x %02x %02x\n",
295
 
//         this, n, p[2], p[3], p[4]);
296
 
 
297
 
      switch(p[3]) {
298
 
            case 1:
299
 
                  printf("MMC: STOP\n");
300
 
                  if (_state == SSTATE_PLAY || _state == SSTATE_START_PLAY)
301
 
                        _state = SSTATE_STOP;
302
 
                  break;
303
 
            case 2:
304
 
                  printf("MMC: PLAY\n");
305
 
//                  break;
306
 
            case 3:
307
 
                  printf("MMC: DEFERRED PLAY\n");
308
 
                  mtcState = 0;
309
 
                  mtcValid = false;
310
 
                  mtcLost  = 0;
311
 
                  mtcSync  = false;
312
 
                  break;
313
 
 
314
 
            case 4:  printf("FF\n"); break;
315
 
            case 5:  printf("REWIND\n"); break;
316
 
            case 6:  printf("REC STROBE\n"); break;
317
 
            case 7:  printf("REC EXIT\n"); break;
318
 
            case 0xd:  printf("RESET\n"); break;
319
 
            case 0x44:
320
 
                  if (p[5] == 0) {
321
 
                        printf("LOCATE IF\n");
322
 
                        break;
323
 
                        }
324
 
                  else if (p[5] == 1) {
325
 
                        MTC mtc(p[6] & 0x1f, p[7], p[8], p[9], p[10]);
326
 
                        mmcPos = tempomap.time2tick(mtc.time());
327
 
 
328
 
                        printf("MMC: seek ");
329
 
                        mtc.print();
330
 
                        printf("\n");
331
 
 
332
 
                        write(data->sigFd, "G", 1);
333
 
                        break;
334
 
                        }
335
 
                  // fall through
336
 
            default:
337
 
                  printf("MMC %x %x\n", p[3], p[4]); break;
338
 
            }
339
 
#endif
340
 
      }
341
 
 
342
 
//---------------------------------------------------------
343
 
//   mtcInputQuarter
344
 
//    process Quarter Frame Message
345
 
//---------------------------------------------------------
346
 
 
347
 
void MidiThread::mtcInputQuarter(int, unsigned char c)
348
 
      {
349
 
      static int hour, min, sec, frame;
350
 
 
351
 
      if (!extSyncFlag.value())
352
 
            return;
353
 
 
354
 
      int valL = c & 0xf;
355
 
      int valH = valL << 4;
356
 
 
357
 
      int _state = (c & 0x70) >> 4;
358
 
      if (mtcState != _state)
359
 
            mtcLost += _state - mtcState;
360
 
      mtcState = _state + 1;
361
 
 
362
 
      switch(_state) {
363
 
            case 7:
364
 
                  hour  = (hour  & 0x0f) | valH;
365
 
                  break;
366
 
            case 6:
367
 
                  hour  = (hour  & 0xf0) | valL;
368
 
                  break;
369
 
            case 5:
370
 
                  min   = (min   & 0x0f) | valH;
371
 
                  break;
372
 
            case 4:
373
 
                  min   = (min   & 0xf0) | valL;
374
 
                  break;
375
 
            case 3:
376
 
                  sec   = (sec   & 0x0f) | valH;
377
 
                  break;
378
 
            case 2:
379
 
                  sec   = (sec   & 0xf0) | valL;
380
 
                  break;
381
 
            case 1:
382
 
                  frame = (frame & 0x0f) | valH;
383
 
                  break;
384
 
            case 0:  frame = (frame & 0xf0) | valL;
385
 
                  break;
386
 
            }
387
 
      frame &= 0x1f;    // 0-29
388
 
      sec   &= 0x3f;    // 0-59
389
 
      min   &= 0x3f;    // 0-59
390
 
      hour  &= 0x1f;
391
 
 
392
 
      if (mtcState == 8) {
393
 
            mtcValid = (mtcLost == 0);
394
 
            mtcState = 0;
395
 
            mtcLost  = 0;
396
 
            if (mtcValid) {
397
 
                  mtcCurTime.set(hour, min, sec, frame);
398
 
                  mtcSyncMsg(mtcCurTime, !mtcSync);
399
 
                  mtcSync = true;
400
 
                  }
401
 
            }
402
 
      else if (mtcValid && (mtcLost == 0)) {
403
 
            mtcCurTime.incQuarter();
404
 
            mtcSyncMsg(mtcCurTime, false);
405
 
            }
406
 
      }
407
 
 
408
 
//---------------------------------------------------------
409
 
//   mtcInputFull
410
 
//    process Frame Message
411
 
//---------------------------------------------------------
412
 
 
413
 
void MidiThread::mtcInputFull(const unsigned char* p, int n)
414
 
      {
415
 
      if (!extSyncFlag.value())
416
 
            return;
417
 
 
418
 
      if (p[3] != 1) {
419
 
            if (p[3] != 2) {   // silently ignore user bits
420
 
                  printf("unknown mtc msg subtype 0x%02x\n", p[3]);
421
 
                  dump(p, n);
422
 
                  }
423
 
            return;
424
 
            }
425
 
      int hour  = p[4];
426
 
      int min   = p[5];
427
 
      int sec   = p[6];
428
 
      int frame = p[7];
429
 
 
430
 
      frame &= 0x1f;    // 0-29
431
 
      sec   &= 0x3f;    // 0-59
432
 
      min   &= 0x3f;    // 0-59
433
 
//      int type = (hour >> 5) & 3;
434
 
      hour &= 0x1f;
435
 
 
436
 
      mtcCurTime.set(hour, min, sec, frame);
437
 
      mtcState = 0;
438
 
      mtcValid = true;
439
 
      mtcLost = 0;
440
 
 
441
 
//      printf("MTC Full ");
442
 
//      mtcCurTime.print();
443
 
//      printf("\n");
444
 
      }
445
 
 
446
 
//---------------------------------------------------------
447
 
//   nonRealtimeSystemSysex
448
 
//---------------------------------------------------------
449
 
 
450
 
void MidiThread::nonRealtimeSystemSysex(const unsigned char* p, int/* n*/)
451
 
      {
452
 
//      int chan = p[2];
453
 
      switch(p[3]) {
454
 
            case 4:
455
 
                  printf("NRT Setup\n");
456
 
                  break;
457
 
            default:
458
 
//                  printf("unknown NRT Msg 0x%02x\n", p[3]);
459
 
//                  dump(p, n);
460
 
                  break;
461
 
           }
462
 
      }
463
 
 
464
 
//---------------------------------------------------------
465
 
//   mtcSyncMsg
466
 
//    process received mtc Sync
467
 
//---------------------------------------------------------
468
 
 
469
 
void MidiThread::mtcSyncMsg(const MTC& /*mtc*/, bool /*seekFlag*/)
470
 
      {
471
 
#if 0
472
 
      double time = mtc.time();
473
 
      if (seekFlag && data->state == IDLE) {
474
 
            int tick = tempomap.time2tick(mtc.time());
475
 
            start(tick);
476
 
            data->state = PLAY;
477
 
            write(data->sigFd, "1", 1);
478
 
            return;
479
 
            }
480
 
      double curT = curTime();
481
 
 
482
 
      int newTempoSN;
483
 
      double cposTime = tempomap.tick2time(curTickPos, &newTempoSN);
484
 
      if (tempoSN != newTempoSN) {
485
 
            tempoSN   = newTempoSN;
486
 
            startTime = curT - cposTime;
487
 
            }
488
 
 
489
 
      //
490
 
      // diff is the time in sec MusE is out of sync
491
 
      //
492
 
      double diff = time - (curT - startTime);
493
 
      if (debugSync)
494
 
            printf("%d %f\n", mtcState, diff);
495
 
#endif
496
 
      }
497
 
 
498
 
//---------------------------------------------------------
499
 
//   setSongPosition
500
 
//    MidiBeat is a 14 Bit value. Each MidiBeat spans
501
 
//    6 MIDI Clocks. Inother words, each MIDI Beat is a
502
 
//    16th note (since there are 24 MIDI Clocks in a
503
 
//    quarter note).
504
 
//---------------------------------------------------------
505
 
 
506
 
void MidiThread::setSongPosition(int port, int midiBeat)
507
 
      {
508
 
      if (midiInputTrace)
509
 
            printf("set song position port:%d %d\n", port, midiBeat);
510
 
      if (!extSyncFlag.value())
511
 
            return;
512
 
      data->playTickPos = data->midiClick = (division * midiBeat) / 4;
513
 
      write(data->sigFd, "G", 1);
514
 
      }
515
 
 
516
 
//---------------------------------------------------------
517
 
//   realtimeSystemInput
518
 
//    real time message received
519
 
//---------------------------------------------------------
520
 
 
521
 
void MidiThread::realtimeSystemInput(int port, int c)
522
 
      {
523
 
      data->realtimeSystemInput(port, c);
524
 
      }
525
 
 
526
 
void MidiThreadPrivate::realtimeSystemInput(int port, int c)
527
 
      {
528
 
      if (midiInputTrace)
529
 
            printf("realtimeSystemInput port:%d 0x%x\n", port+1, c);
530
 
 
531
 
      if (midiInputTrace && (extSyncPort != port)) {
532
 
//            printf("extSyncPort %d != received sync port %d\n",
533
 
//               extSyncPort, port);
534
 
            return;
535
 
            }
536
 
      if (!extSyncFlag.value())
537
 
            return;
538
 
      switch(c) {
539
 
            case 0xf8:  // midi clock (24 ticks / quarter note)
540
 
                  {
541
 
                  double mclock0 = curTime();
542
 
                  processMidiTick();
543
 
                  if (state == PLAY) {
544
 
                        recTick  += division / 24;
545
 
                        int diff  = recTick - midiTick;
546
 
                        int tempo = tempomap.tempo(0);
547
 
                        tempo    -= diff*5;
548
 
                        tempomap.setTempo(0, tempo);
549
 
                        midiTick = recTick;  // brutal
550
 
                        break;
551
 
                        }
552
 
                  double tdiff0   = mclock0 - mclock1;
553
 
                  double tdiff1   = mclock1 - mclock2;
554
 
                  if (mclock1 == 0.0)
555
 
                        midiPorts[port].device()->discardInput();
556
 
                  if ((mclock2 != 0.0) && (tdiff0 > 0.0)) {
557
 
                        int tempo0 = int(24000000.0 * tdiff0 + .5);
558
 
                        int tempo1 = int(24000000.0 * tdiff1 + .5);
559
 
                        int tempo = tempomap.tempo(0);
560
 
 
561
 
                        int diff0 = tempo0 - tempo;
562
 
                        int diff1 = tempo1 - tempo0;
563
 
                        if (diff0) {
564
 
                              int newTempo = tempo + diff0/8 + diff1/16;
565
 
//                              printf("new tempo %d -> %d (%d + %d + %d)\n",
566
 
//                                tempo, tempo0,
567
 
//                                tempo, diff0/4, diff1/8);
568
 
                              tempomap.setTempo(0, newTempo);
569
268
                              }
570
269
                        }
571
 
                  mclock2 = mclock1;
572
 
                  mclock1 = mclock0;
573
270
                  }
574
 
                  break;
575
 
            case 0xf9:  // midi tick  (every 10 msec)
576
 
                  if (mcStart) {
577
 
                        song->setPos(0, mcStartTick);
578
 
                        mcStart = false;
579
 
                        return;
580
 
                        }
581
 
                  break;
582
 
            case 0xfa:  // start
583
 
printf("start\n");
584
 
                  if (state == IDLE) {
585
 
                        seek(0);
586
 
                        startPlay();
587
 
                        }
588
 
                  break;
589
 
            case 0xfb:  // continue
590
 
printf("continue\n");
591
 
                  if (state == IDLE) {
592
 
                        startPlay();
593
 
                        }
594
 
                  break;
595
 
            case 0xfc:  // stop
596
 
printf("stop\n");
597
 
                  if (state == PLAY)
598
 
                        stopPlay();
599
 
                  break;
600
 
            case 0xfd:  // unknown
601
 
            case 0xfe:  // active sensing
602
 
            case 0xff:  // system reset
603
 
                  break;
604
271
            }
 
272
      loopPassed = false;
605
273
      }
606
274
 
607