~ubuntu-branches/ubuntu/quantal/muse/quantal

« back to all changes in this revision

Viewing changes to muse/midiseq.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2005-08-23 17:19:39 UTC
  • mto: (4.1.1 breezy) (1.1.9) (10.1.6 sid)
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20050823171939-hd8fgzokb4dbj007
Tags: upstream-0.7.1+0.7.2pre2
ImportĀ upstreamĀ versionĀ 0.7.1+0.7.2pre2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=========================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//  $Id: midiseq.cpp,v 1.30.2.9 2005/07/09 22:01:22 lunar_shuttle Exp $
 
5
//
 
6
//    high priority task for scheduling midi events
 
7
//
 
8
//  (C) Copyright 2003 Werner Schweer (ws@seh.de)
 
9
//=========================================================
 
10
 
 
11
#include <stdio.h>
 
12
#include <fcntl.h>
 
13
#include <sys/ioctl.h>
 
14
#include <poll.h>
 
15
 
 
16
#include "globals.h"
 
17
#include "midi.h"
 
18
#include "midiseq.h"
 
19
#include "midiport.h"
 
20
#include "mididev.h"
 
21
#include "midictrl.h"
 
22
#include "audio.h"
 
23
#include "driver/alsamidi.h"
 
24
#include "sync.h"
 
25
#include "synth.h"
 
26
#include "song.h"
 
27
#include "gconfig.h"
 
28
 
 
29
MidiSeq* midiSeq;
 
30
int MidiSeq::ticker = 0;
 
31
 
 
32
//---------------------------------------------------------
 
33
//   readMsg
 
34
//---------------------------------------------------------
 
35
 
 
36
static void readMsg(void* p, void*)
 
37
      {
 
38
      
 
39
      MidiSeq* at = (MidiSeq*)p;
 
40
      at->readMsg();
 
41
      }
 
42
 
 
43
//---------------------------------------------------------
 
44
//   processMsg
 
45
//---------------------------------------------------------
 
46
 
 
47
void MidiSeq::processMsg(const ThreadMsg* m)
 
48
      {
 
49
      AudioMsg* msg = (AudioMsg*)m;
 
50
      switch(msg->id) {
 
51
            case MS_PROCESS:
 
52
                  audio->processMidi();
 
53
                  break;
 
54
            case SEQM_SEEK:
 
55
                  processSeek();
 
56
                  break;
 
57
            case MS_STOP:
 
58
                  processStop();
 
59
                  break;
 
60
            case MS_SET_RTC:
 
61
                  doSetuid();
 
62
                  setRtcTicks();
 
63
                  undoSetuid();
 
64
                  break;
 
65
            case MS_UPDATE_POLL_FD:
 
66
                  updatePollFd();
 
67
                  break;
 
68
            case SEQM_ADD_TRACK:
 
69
                  song->insertTrack2(msg->track, msg->ival);
 
70
                  updatePollFd();
 
71
                  break;
 
72
            case SEQM_REMOVE_TRACK:
 
73
                  song->cmdRemoveTrack(msg->track);
 
74
                  updatePollFd();
 
75
                  break;
 
76
            case SEQM_CHANGE_TRACK:
 
77
                  song->changeTrack((Track*)(msg->p1), (Track*)(msg->p2));
 
78
                  updatePollFd();
 
79
                  break;
 
80
            case SEQM_ADD_PART:
 
81
                  song->cmdAddPart((Part*)msg->p1);
 
82
                  break;
 
83
            case SEQM_REMOVE_PART:
 
84
                  song->cmdRemovePart((Part*)msg->p1);
 
85
                  break;
 
86
            case SEQM_CHANGE_PART:
 
87
                  song->cmdChangePart((Part*)msg->p1, (Part*)msg->p2);
 
88
                  break;
 
89
            case SEQM_SET_MIDI_DEVICE:
 
90
                  ((MidiPort*)(msg->p1))->setMidiDevice((MidiDevice*)(msg->p2));
 
91
                  updatePollFd();
 
92
                  break;
 
93
            case SEQM_IDLE:
 
94
                  idle = msg->a;
 
95
                  break;
 
96
            default:
 
97
                  printf("MidiSeq::processMsg() unknown id %d\n", msg->id);
 
98
                  break;
 
99
            }
 
100
      }
 
101
 
 
102
//---------------------------------------------------------
 
103
//   processStop
 
104
//---------------------------------------------------------
 
105
 
 
106
void MidiSeq::processStop()
 
107
      {
 
108
      //
 
109
      //    stop stuck notes
 
110
      //
 
111
      for (iMidiDevice id = midiDevices.begin(); id != midiDevices.end(); ++id) {
 
112
            MidiDevice* md = *id;
 
113
            if (md->midiPort() == -1)
 
114
                  continue;
 
115
            MPEventList* pel = md->playEvents();
 
116
            MPEventList* sel = md->stuckNotes();
 
117
            pel->clear();
 
118
            for (iMPEvent i = sel->begin(); i != sel->end(); ++i) {
 
119
                  MidiPlayEvent ev = *i;
 
120
                  ev.setTime(0);
 
121
                  pel->add(ev);
 
122
                  }
 
123
            sel->clear();
 
124
            md->setNextPlayEvent(pel->begin());
 
125
            }
 
126
      }
 
127
 
 
128
//---------------------------------------------------------
 
129
//   processSeek
 
130
//---------------------------------------------------------
 
131
 
 
132
void MidiSeq::processSeek()
 
133
      {
 
134
      int pos = audio->tickPos();
 
135
      if (pos == 0 && !song->record())
 
136
            audio->initDevices();
 
137
 
 
138
      //---------------------------------------------------
 
139
      //    set all controller
 
140
      //---------------------------------------------------
 
141
 
 
142
      for (iMidiDevice i = midiDevices.begin(); i != midiDevices.end(); ++i) {
 
143
            MidiDevice* dev = *i;
 
144
            int port = dev->midiPort();
 
145
            if (port == -1)
 
146
                  continue;
 
147
            MidiPort* mp = &midiPorts[port];
 
148
            MidiCtrlValListList* cll = mp->controller();
 
149
 
 
150
            MPEventList* el = dev->playEvents();
 
151
 
 
152
            if (audio->isPlaying()) {
 
153
                  // stop all notes
 
154
                  el->clear();
 
155
                  MPEventList* sel = dev->stuckNotes();
 
156
                  for (iMPEvent i = sel->begin(); i != sel->end(); ++i) {
 
157
                        MidiPlayEvent ev = *i;
 
158
                        ev.setTime(0);
 
159
                        el->add(ev);
 
160
                        }
 
161
                  sel->clear();
 
162
                  }
 
163
            else
 
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));
 
171
                        }
 
172
                  }
 
173
            dev->setNextPlayEvent(el->begin());
 
174
            }
 
175
      }
 
176
 
 
177
//---------------------------------------------------------
 
178
//   MidiSeq
 
179
//---------------------------------------------------------
 
180
 
 
181
MidiSeq::MidiSeq(int priority, const char* name)
 
182
   : Thread(priority, name)
 
183
      {
 
184
      prio = priority;
 
185
      idle = false;
 
186
      midiClock = 0;
 
187
      mclock1 = 0.0;
 
188
      mclock2 = 0.0;
 
189
      songtick1 = songtick2 = 0;
 
190
      lastTempo = 0;
 
191
      storedtimediffs = 0;
 
192
      }
 
193
 
 
194
//---------------------------------------------------------
 
195
//   threadStart
 
196
//    called from loop()
 
197
//---------------------------------------------------------
 
198
 
 
199
void MidiSeq::threadStart(void*)
 
200
      {
 
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);
 
205
 
 
206
      if (prio < prio_min) prio = prio_min;
 
207
      else if (prio > prio_max) prio = prio_max;
 
208
 
 
209
      rt_param.sched_priority = prio;
 
210
      int rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &rt_param);
 
211
      if (rv != 0)
 
212
            perror("set realtime scheduler");
 
213
 
 
214
      int policy;
 
215
      if ((policy = sched_getscheduler (0)) < 0) {
 
216
            printf("Cannot get current client scheduler: %s\n", strerror(errno));
 
217
            }
 
218
      if (policy != SCHED_FIFO)
 
219
            printf("midi thread %d _NOT_ running SCHED_FIFO\n", getpid());
 
220
      updatePollFd();
 
221
      }
 
222
 
 
223
//---------------------------------------------------------
 
224
//   alsaMidiRead
 
225
//---------------------------------------------------------
 
226
 
 
227
static void alsaMidiRead(void*, void*)
 
228
      {
 
229
      // calls itself midiDevice->recordEvent(MidiRecordEvent):
 
230
      alsaProcessMidiInput();
 
231
      }
 
232
 
 
233
//---------------------------------------------------------
 
234
//   midiRead
 
235
//---------------------------------------------------------
 
236
 
 
237
static void midiRead(void*, void* d)
 
238
      {
 
239
      MidiDevice* dev = (MidiDevice*) d;
 
240
      dev->processInput();
 
241
      }
 
242
 
 
243
//---------------------------------------------------------
 
244
//   synthIRead
 
245
//---------------------------------------------------------
 
246
 
 
247
#if 0
 
248
static void synthIRead(void*, void* d)
 
249
      {
 
250
      SynthI* syn = (SynthI*) d;
 
251
      syn->processInput();
 
252
      }
 
253
#endif
 
254
 
 
255
//---------------------------------------------------------
 
256
//   midiWrite
 
257
//---------------------------------------------------------
 
258
 
 
259
static void midiWrite(void*, void* d)
 
260
      {
 
261
      MidiDevice* dev = (MidiDevice*) d;
 
262
      dev->flush();
 
263
      }
 
264
 
 
265
//---------------------------------------------------------
 
266
//   updatePollFd
 
267
//---------------------------------------------------------
 
268
 
 
269
void MidiSeq::updatePollFd()
 
270
      {
 
271
      if (!isRunning())
 
272
            return;
 
273
 
 
274
      clearPollFd();
 
275
      addPollFd(timerFd, POLLIN, midiTick, this, 0);
 
276
 
 
277
      if (timerFd == -1) {
 
278
            fprintf(stderr, "updatePollFd: no timer fd\n");
 
279
            if (!debugMode)
 
280
                  exit(-1);
 
281
            }
 
282
 
 
283
      addPollFd(toThreadFdr, POLLIN, ::readMsg, this, 0);
 
284
 
 
285
      //---------------------------------------------------
 
286
      //  midi ports
 
287
      //---------------------------------------------------
 
288
 
 
289
      for (iMidiDevice imd = midiDevices.begin(); imd != midiDevices.end(); ++imd) {
 
290
            MidiDevice* dev = *imd;
 
291
            int port = dev->midiPort();
 
292
            if (port == -1)
 
293
                  continue;
 
294
            if ((dev->rwFlags()&0x2) || (extSyncFlag.value()
 
295
               && (rxSyncPort == port || rxSyncPort == -1))) {
 
296
                  addPollFd(dev->selectRfd(), POLLIN, ::midiRead, this, dev);
 
297
                  }
 
298
            if (dev->bytesToWrite())
 
299
                  addPollFd(dev->selectWfd(), POLLOUT, ::midiWrite, this, dev);
 
300
            }
 
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)
 
305
 
 
306
      addPollFd(alsaSelectRfd(), POLLIN, ::alsaMidiRead, this, 0);
 
307
      }
 
308
 
 
309
//---------------------------------------------------------
 
310
//   threadStop
 
311
//    called from loop()
 
312
//---------------------------------------------------------
 
313
 
 
314
void MidiSeq::threadStop()
 
315
      {
 
316
      timer.stopTimer();
 
317
      }
 
318
 
 
319
//---------------------------------------------------------
 
320
//   setRtcTicks
 
321
//    return true on success
 
322
//---------------------------------------------------------
 
323
 
 
324
bool MidiSeq::setRtcTicks()
 
325
      {
 
326
 
 
327
      timer.setTimerTicks(config.rtcTicks);
 
328
      timer.startTimer();
 
329
      realRtcTicks = config.rtcTicks;
 
330
      return true;
 
331
      }
 
332
 
 
333
//---------------------------------------------------------
 
334
//   start
 
335
//    return true on error
 
336
//---------------------------------------------------------
 
337
 
 
338
bool MidiSeq::start()
 
339
      {
 
340
      timerFd = -1;
 
341
 
 
342
      doSetuid();
 
343
      timerFd = timer.initTimer();
 
344
      setRtcTicks();
 
345
      undoSetuid();
 
346
      Thread::start();
 
347
      return false;
 
348
      }
 
349
 
 
350
//---------------------------------------------------------
 
351
//   processMidiClock
 
352
//---------------------------------------------------------
 
353
 
 
354
void MidiSeq::processMidiClock()
 
355
      {
 
356
      if (genMCSync) {
 
357
            midiPorts[txSyncPort].sendClock();
 
358
      }
 
359
/*      if (state == START_PLAY) {
 
360
            // start play on sync
 
361
            state      = PLAY;
 
362
            _midiTick  = playTickPos;
 
363
            midiClock  = playTickPos;
 
364
 
 
365
            int bar, beat, tick;
 
366
            sigmap.tickValues(_midiTick, &bar, &beat, &tick);
 
367
            midiClick      = sigmap.bar2tick(bar, beat+1, 0);
 
368
 
 
369
            double cpos    = tempomap.tick2time(playTickPos);
 
370
            samplePosStart = samplePos - lrint(cpos * sampleRate);
 
371
            rtcTickStart   = rtcTick - lrint(cpos * realRtcTicks);
 
372
 
 
373
            endSlice       = playTickPos;
 
374
            recTick        = playTickPos;
 
375
            lastTickPos    = playTickPos;
 
376
 
 
377
            tempoSN = tempomap.tempoSN();
 
378
 
 
379
            startRecordPos.setPosTick(playTickPos);
 
380
            }
 
381
*/
 
382
      midiClock += config.division/24;
 
383
      }
 
384
 
 
385
//---------------------------------------------------------
 
386
//   midiTick
 
387
//---------------------------------------------------------
 
388
 
 
389
void MidiSeq::midiTick(void* p, void*)
 
390
      {
 
391
      MidiSeq* at = (MidiSeq*)p;
 
392
      at->processTimerTick();
 
393
      if (TIMER_DEBUG)
 
394
      {
 
395
        if(MidiSeq::ticker++ > 100)
 
396
          {
 
397
          printf("tick!\n");
 
398
          MidiSeq::ticker=0;
 
399
          }
 
400
        }
 
401
      }
 
402
 
 
403
//---------------------------------------------------------
 
404
//   processTimerTick
 
405
//---------------------------------------------------------
 
406
 
 
407
void MidiSeq::processTimerTick()
 
408
      {
 
409
      extern int watchMidi;
 
410
      ++watchMidi;      // make a simple watchdog happy
 
411
 
 
412
      //---------------------------------------------------
 
413
      //    read elapsed rtc timer ticks
 
414
      //---------------------------------------------------
 
415
 
 
416
      unsigned long nn;
 
417
      if (timerFd != -1) {
 
418
            nn = timer.getTimerTicks();
 
419
            nn >>= 8;
 
420
            }
 
421
 
 
422
      if (idle) {
 
423
        //printf("IDLE\n");
 
424
            return;
 
425
      }
 
426
 
 
427
      unsigned curFrame = audio->curFrame();
 
428
 
 
429
      if (!extSyncFlag.value()) {
 
430
            int curTick = tempomap.frame2tick(curFrame);
 
431
            if ( midiClock > curTick + 100) // reinitialize
 
432
              midiClock = curTick;
 
433
            else if( curTick > midiClock + 100) // reinitialize
 
434
              midiClock = curTick;
 
435
              
 
436
            //printf("curTick=%d >= midiClock=%d\n",curTick,midiClock);
 
437
            if (curTick >= midiClock)  {
 
438
                  processMidiClock();
 
439
                 }
 
440
            }
 
441
 
 
442
//      if (genMTCSync) {
 
443
            // printf("Midi Time Code Sync generation not impl.\n");
 
444
//            }
 
445
 
 
446
      //
 
447
      // play all events upto curFrame
 
448
      //
 
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
 
454
                  continue;
 
455
            MPEventList* el = md->playEvents();
 
456
            if (el->empty())
 
457
                  continue;
 
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);
 
462
                        break;
 
463
                        }
 
464
 */
 
465
                  // break if event cannot be delivered
 
466
                  if (mp) {
 
467
                        if (mp->sendEvent(*i))
 
468
                              break;
 
469
                        }
 
470
                  else {
 
471
                        if (md->putEvent(*i))
 
472
                              break;
 
473
                        }
 
474
                  }
 
475
            md->setNextPlayEvent(i);
 
476
            }
 
477
      }
 
478
 
 
479
//---------------------------------------------------------
 
480
//   msgMsg
 
481
//---------------------------------------------------------
 
482
 
 
483
void MidiSeq::msgMsg(int id)
 
484
      {
 
485
      AudioMsg msg;
 
486
      msg.id = id;
 
487
      Thread::sendMsg(&msg);
 
488
      }
 
489
 
 
490
//---------------------------------------------------------
 
491
//   msgSetMidiDevice
 
492
//    to avoid timeouts in the RT-thread, setMidiDevice
 
493
//    is done in GUI context after setting the midi thread
 
494
//    into idle mode
 
495
//---------------------------------------------------------
 
496
 
 
497
void MidiSeq::msgSetMidiDevice(MidiPort* port, MidiDevice* device)
 
498
      {
 
499
      AudioMsg msg;
 
500
      msg.id = SEQM_IDLE;
 
501
      msg.a  = true;
 
502
      Thread::sendMsg(&msg);
 
503
 
 
504
      port->setMidiDevice(device);
 
505
 
 
506
      msg.id = SEQM_IDLE;
 
507
      msg.a  = false;
 
508
      Thread::sendMsg(&msg);
 
509
      }
 
510
 
 
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); }
 
516