• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • libtdemid
 

libtdemid

  • libtdemid
player.cpp
1 /**************************************************************************
2 
3  player.cpp - class MidiPlayer. Plays a set of tracks
4  This file is part of LibKMid 0.9.5
5  Copyright (C) 1997,98,99,2000 Antonio Larrosa Jimenez
6  LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 
23  $Id$
24 
25  Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
26 
27 ***************************************************************************/
28 #include "player.h"
29 #include "sndcard.h"
30 #include "midispec.h"
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/time.h>
34 #include "midistat.h"
35 #include "mt32togm.h"
36 
37 //#define PLAYERDEBUG
38 //#define GENERAL_DEBUG_MESSAGES
39 
40 #define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)
41 
42 #define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L))
43 
44 #define REMOVEDUPSTRINGS
45 
46 MidiPlayer::MidiPlayer(DeviceManager *midi_,PlayerController *pctl)
47 {
48  midi=midi_;
49  info=NULL;
50  tracks=NULL;
51  songLoaded=0;
52  ctl=pctl;
53  spev=NULL;
54  na=NULL;
55  parsesong=true;
56  generatebeats=false;
57 }
58 
59 MidiPlayer::~MidiPlayer()
60 {
61  removeSpecialEvents();
62  removeSong();
63 }
64 
65 void MidiPlayer::removeSong(void)
66 {
67  if ((songLoaded)&&(tracks!=NULL))
68  {
69 #ifdef PLAYERDEBUG
70  printf("Removing song from memory\n");
71 #endif
72  int i=0;
73  while (i<info->ntracks)
74  {
75  if (tracks[i]!=NULL) delete tracks[i];
76  i++;
77  }
78  delete tracks;
79  tracks=NULL;
80  if (info!=NULL)
81  {
82  delete info;
83  info=NULL;
84  }
85  }
86  songLoaded=0;
87 }
88 
89 int MidiPlayer::loadSong(const char *filename)
90 {
91  removeSong();
92 #ifdef PLAYERDEBUG
93  printf("Loading Song : %s\n",filename);
94 #endif
95  info=new MidiFileInfo;
96  int ok;
97  tracks=readMidiFile(filename,info,ok);
98  if (ok<0) return ok;
99  if (tracks==NULL) return -4;
100 
101  parseInfoData(info,tracks,ctl->ratioTempo);
102 
103  if (parsesong)
104  {
105  parseSpecialEvents();
106  if (generatebeats) generateBeats();
107  }
108 
109  songLoaded=1;
110  return 0;
111 }
112 
113 void MidiPlayer::insertBeat(SpecialEvent *ev,ulong ms,int num,int den)
114 {
115  SpecialEvent *beat=new SpecialEvent;
116  beat->next=ev->next;
117  ev->next=beat;
118  beat->id=1;
119  beat->type=7;
120  beat->absmilliseconds=ms;
121  beat->num=num;
122  beat->den=den;
123 }
124 
125 
126 void MidiPlayer::generateBeats(void)
127 {
128 #ifdef PLAYERDEBUG
129  printf("player::Generating Beats...\n");
130 #endif
131 
132  if (spev==NULL) return;
133  SpecialEvent *ev=spev;
134  SpecialEvent *nextev=ev->next;
135  ulong tempo=(ulong)(500000 * ctl->ratioTempo);
136  int i=1;
137  int num=4;
138  int den=4;
139  // ulong beatstep=((double)tempo*4/(den*1000));
140  // ulong beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
141  double ticksleft=(((double)info->ticksPerCuarterNote*4)/den);
142 
143  double beatstep=T2MS(ticksleft);
144  double nextbeatms=0;
145  double lastbeatms=0;
146  double measurems=0;
147 
148  while (nextev!=NULL)
149  {
150  switch (ev->type)
151  {
152  case (0): // End of list
153  {
154  };break;
155  case (1): // Text
156  case (2): // Lyrics
157  {
158  };break;
159  case (3): // Change Tempo
160  {
161  lastbeatms=ev->absmilliseconds;
162  ticksleft=MS2T(nextbeatms-lastbeatms);
163  tempo=ev->tempo;
164  nextbeatms=lastbeatms+T2MS(ticksleft);
165  // printf("Change at %lu to %d\n",ev->absmilliseconds,ev->tempo);
166  // beatstep=((double)tempo*4/(den*1000));
167  beatstep=T2MS(((static_cast<double>(info->ticksPerCuarterNote)*4)/den));
168  };break;
169  case (6): // Change number of beats per measure
170  {
171  num=ev->num;
172  i=1;
173  den=ev->den;
174  // printf("Change at %lu to %d/%d\n",ev->absmilliseconds,num,den);
175  // beatstep=((double)tempo*4/(den*1000));
176  // beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
177  beatstep=T2MS((((double)info->ticksPerCuarterNote*4)/den));
178  nextbeatms=ev->absmilliseconds;
179  };break;
180  };
181  if (nextev->absmilliseconds>nextbeatms)
182  {
183  //printf("Adding %d,%d\n",num,tot);
184  //printf("beat at %g , %d/%d\n",nextbeatms,i,num);
185  //printf(" %ld %d\n",nextev->absmilliseconds,nextev->type);
186  if (i == 1) {
187  measurems=nextbeatms;
188  }
189  insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
190  if (i > num) {
191  i=1;
192  }
193  lastbeatms=nextbeatms;
194  nextbeatms+=beatstep;
195  // nextbeatms=measurems+beatstep*i;
196 
197  ticksleft = ( (static_cast<double>(info->ticksPerCuarterNote)*4) / den);
198 
199  }
200 
201  ev=ev->next;
202  nextev=ev->next;
203  }
204 
205  /* ev==NULL doesn't indicate the end of the song, so continue generating beats */
206 
207  if (ev!=NULL)
208  {
209  if (ev->type==0)
210  {
211  ev=spev;
212  /* Looking if ev->next is NULL is not needed because
213  we are sure that a ev->type == 0 exists, we just have
214  to assure that the first spev is not the only one */
215  if (ev->next!=NULL)
216  while (ev->next->type!=0) ev=ev->next;
217  }
218  while (nextbeatms<info->millisecsTotal)
219  {
220  // printf("beat2 at %g , %d/%d\n",nextbeatms,i,num);
221  if (i==1) measurems=nextbeatms;
222  insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
223  if (i>num) i=1;
224  nextbeatms+=beatstep;
225  ev=ev->next;
226  }
227  }
228 
229  /* Regenerate IDs */
230 
231  ev=spev;
232  i=1;
233  while (ev!=NULL)
234  {
235  ev->id=i++;
236  ev=ev->next;
237  }
238 
239 
240 #ifdef PLAYERDEBUG
241  printf("player::Beats Generated\n");
242 #endif
243 
244 }
245 
246 void MidiPlayer::removeSpecialEvents(void)
247 {
248  SpecialEvent * ev=spev;
249  while (spev!=NULL)
250  {
251  ev=spev->next;
252  delete spev;
253  spev=ev;
254  }
255  delete na;
256  na=0;
257 }
258 
259 void MidiPlayer::parseSpecialEvents(void)
260 {
261 #ifdef PLAYERDEBUG
262  printf("player::Parsing...\n");
263 #endif
264  removeSpecialEvents();
265  spev=new SpecialEvent;
266  if (spev==NULL) return;
267  SpecialEvent *pspev=spev;
268  pspev->type=0;
269  pspev->ticks=0;
270  if (na) delete na;
271  na=new NoteArray();
272  if (!na) { delete spev; spev=0L; return; };
273  int trk;
274  int minTrk;
275  double minTime=0;
276  double maxTime;
277  ulong tempo=(ulong)(500000 * (ctl->ratioTempo));
278  ulong firsttempo=0;
279  for (int i=0;i<info->ntracks;i++)
280  {
281  tracks[i]->init();
282  tracks[i]->changeTempo(tempo);
283  }
284  MidiEvent *ev=new MidiEvent;
285  //ulong mspass;
286  double prevms=0;
287  int spev_id=1;
288  int j;
289  int parsing=1;
290 #ifdef REMOVEDUPSTRINGS
291  char lasttext[1024];
292  ulong lasttexttime=0;
293  lasttext[0]=0;
294  int lasttexttype=0;
295 #endif
296  while (parsing)
297  {
298  prevms=minTime;
299  trk=0;
300  minTrk=0;
301  maxTime=minTime + 2 * 60000L;
302  minTime=maxTime;
303  parsing=0;
304  while (trk<info->ntracks)
305  {
306  if (tracks[trk]->absMsOfNextEvent()<minTime)
307  {
308  minTrk=trk;
309  minTime=tracks[minTrk]->absMsOfNextEvent();
310  parsing=1;
311  }
312  trk++;
313  }
314  // if ((minTime==maxTime))
315  if (parsing==0)
316  {
317  // parsing=0;
318 #ifdef PLAYERDEBUG
319  printf("END of parsing\n");
320 #endif
321  }
322  else
323  {
324  // mspass=(ulong)(minTime-prevms);
325  trk=0;
326  while (trk<info->ntracks)
327  {
328  tracks[trk]->currentMs(minTime);
329  trk++;
330  }
331  }
332  trk=minTrk;
333  tracks[trk]->readEvent(ev);
334  switch (ev->command)
335  {
336  case (MIDI_NOTEON) :
337  if (ev->vel==0) na->add((ulong)minTime,ev->chn,0, ev->note);
338  else na->add((ulong)minTime,ev->chn,1,ev->note);
339  break;
340  case (MIDI_NOTEOFF) :
341  na->add((ulong)minTime,ev->chn,0, ev->note);
342  break;
343  case (MIDI_PGM_CHANGE) :
344  na->add((ulong)minTime,ev->chn, 2,ev->patch);
345  break;
346  case (MIDI_SYSTEM_PREFIX) :
347  {
348  if ((ev->command|ev->chn)==META_EVENT)
349  {
350  switch (ev->d1)
351  {
352  case (1) :
353  case (5) :
354  {
355  if (pspev!=NULL)
356  {
357  pspev->absmilliseconds=(ulong)minTime;
358  pspev->type=ev->d1;
359  pspev->id=spev_id++;
360 #ifdef PLAYERDEBUG
361  printf("ev->length %ld\n",ev->length);
362 
363 #endif
364  strncpy(pspev->text,(char *)ev->data,
365  (ev->length>= sizeof(lasttext))? sizeof(lasttext)-1 : (ev->length) );
366  pspev->text[(ev->length>= sizeof(lasttext))? sizeof(lasttext)-1:(ev->length)]=0;
367 #ifdef PLAYERDEBUG
368  printf("(%s)(%s)\n",pspev->text,lasttext);
369 #endif
370 #ifdef REMOVEDUPSTRINGS
371  if ((strcmp(pspev->text,lasttext)!=0)||(pspev->absmilliseconds!=lasttexttime)||(pspev->type!=lasttexttype))
372  {
373  lasttexttime=pspev->absmilliseconds;
374  lasttexttype=pspev->type;
375  strncpy(lasttext, pspev->text, 1024);
376  lasttext[sizeof(lasttext)-1] = 0;
377 #endif
378  pspev->next=new SpecialEvent;
379 #ifdef PLAYERDEBUG
380  if (pspev->next==NULL) printf("pspev->next=NULL\n");
381 #endif
382  pspev=pspev->next;
383 #ifdef REMOVEDUPSTRINGS
384  }
385 #endif
386  }
387  }
388  break;
389  case (ME_SET_TEMPO) :
390  {
391  if (pspev!=NULL)
392  {
393  pspev->absmilliseconds=(ulong)minTime;
394  pspev->type=3;
395  pspev->id=spev_id++;
396  tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ctl->ratioTempo);
397  pspev->tempo=tempo;
398  if (firsttempo==0) firsttempo=tempo;
399  for (j=0;j<info->ntracks;j++)
400  {
401  tracks[j]->changeTempo(tempo);
402  }
403  pspev->next=new SpecialEvent;
404  pspev=pspev->next;
405  }
406  }
407  break;
408  case (ME_TIME_SIGNATURE) :
409  {
410  if (pspev!=NULL)
411  {
412  pspev->absmilliseconds=(ulong)minTime;
413  pspev->type=6;
414  pspev->id=spev_id++;
415  pspev->num=ev->d2;
416  pspev->den=ev->d3;
417  pspev->next=new SpecialEvent;
418  pspev=pspev->next;
419  }
420  }
421  break;
422  }
423  }
424  }
425  break;
426  }
427  }
428 
429  delete ev;
430  pspev->type=0;
431  pspev->absmilliseconds=(ulong)prevms;
432  pspev->next=NULL;
433  if (firsttempo==0) firsttempo=tempo;
434  ctl->tempo=firsttempo;
435 
436  //writeSPEV();
437  for (int i=0;i<info->ntracks;i++)
438  {
439  tracks[i]->init();
440  }
441 }
442 
443 /*
444 NoteArray *MidiPlayer::parseNotes(void)
445 {
446 #ifdef PLAYERDEBUG
447  printf("player::Parsing Notes...\n");
448 #endif
449  NoteArray *na=new NoteArray();
450  int trk;
451  int minTrk;
452  double minTime=0;
453  double maxTime;
454  for (int i=0;i<info->ntracks;i++)
455  {
456  tracks[i]->init();
457  };
458  ulong tempo=1000000;
459  ulong tmp;
460  Midi_event *ev=new Midi_event;
461  //ulong mspass;
462  double prevms=0;
463  int j;
464  int parsing=1;
465  while (parsing)
466  {
467  prevms=minTime;
468  trk=0;
469  minTrk=0;
470  maxTime=minTime + 2 * 60000L;
471  minTime=maxTime;
472  while (trk<info->ntracks)
473  {
474  if (tracks[trk]->absMsOfNextEvent()<minTime)
475  {
476  minTrk=trk;
477  minTime=tracks[minTrk]->absMsOfNextEvent();
478  };
479  trk++;
480  };
481  if ((minTime==maxTime))
482  {
483  parsing=0;
484 #ifdef PLAYERDEBUG
485  printf("END of parsing\n");
486 #endif
487  }
488  else
489  {
490  // mspass=(ulong)(minTime-prevms);
491  trk=0;
492  while (trk<info->ntracks)
493  {
494  tracks[trk]->currentMs(minTime);
495  trk++;
496  };
497  };
498  trk=minTrk;
499  tracks[trk]->readEvent(ev);
500  if (ev->command==MIDI_NOTEON)
501  {
502  if (ev->vel==0) {printf("note off at %g\n",minTime);na->add((ulong)minTime,ev->chn,0, ev->note);}
503  else {printf("note on at %g\n",minTime);na->add((ulong)minTime,ev->chn,1,ev->note);}
504  }
505  else
506  if (ev->command==MIDI_NOTEOFF) na->add((ulong)minTime,ev->chn,0, ev->note);
507  if (ev->command==MIDI_PGM_CHANGE) na->add((ulong)minTime,ev->chn, 2,ev->patch);
508  if (ev->command==MIDI_SYSTEM_PREFIX)
509  {
510  if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO))
511  {
512  tempo=(ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]);
513  for (j=0;j<info->ntracks;j++)
514  {
515  tracks[j]->changeTempo(tempo);
516  };
517  };
518  };
519 
520  };
521 
522  delete ev;
523  for (int i=0;i<info->ntracks;i++)
524  {
525  tracks[i]->init();
526  };
527  return na;
528 };
529 */
530 
531 void MidiPlayer::play(bool calloutput,void output(void))
532 {
533 #ifdef PLAYERDEBUG
534  printf("Playing...\n");
535 #endif
536 
537  if (midi->midiPorts()+midi->synthDevices()==0)
538  {
539  fprintf(stderr,"Player :: There are no midi ports !\n");
540  ctl->error=1;
541  return;
542  }
543 
544  midi->openDev();
545  if (midi->ok()==0)
546  {
547  fprintf(stderr,"Player :: Couldn't play !\n");
548  ctl->error=1;
549  return;
550  }
551  midi->setVolumePercentage(ctl->volumepercentage);
552  midi->initDev();
553  // parsePatchesUsed(tracks,info,ctl->gm);
554  midi->setPatchesToUse(info->patchesUsed);
555 
556  int trk;
557  int minTrk;
558  double minTime=0;
559  double maxTime;
560  int i;
561  ulong tempo=(ulong)(500000 * ctl->ratioTempo);
562  for (i=0;i<info->ntracks;i++)
563  {
564  tracks[i]->init();
565  tracks[i]->changeTempo(tempo);
566  }
567 
568  midi->tmrStart(info->ticksPerCuarterNote);
569  MidiEvent *ev=new MidiEvent;
570  ctl->ev=ev;
571  ctl->ticksTotal=info->ticksTotal;
572  ctl->ticksPlayed=0;
573  //ctl->millisecsPlayed=0;
574  ulong ticksplayed=0;
575  double absTimeAtChangeTempo=0;
576  double absTime=0;
577  double diffTime=0;
578  MidiStatus *midistat;
579  //ulong mspass;
580  double prevms=0;
581  int j;
582  int halt=0;
583  ctl->tempo=tempo;
584  ctl->num=4;
585  ctl->den=4;
586  int playing;
587  ctl->paused=0;
588  if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS))
589  {
590  ctl->moving=1;
591  ctl->message&=~PLAYER_SETPOS;
592  midi->sync(1);
593  midi->tmrStop();
594  midi->closeDev();
595  midistat = new MidiStatus();
596  setPos(ctl->gotomsec,midistat);
597  minTime=ctl->gotomsec;
598  prevms=(ulong)minTime;
599  midi->openDev();
600  midi->tmrStart(info->ticksPerCuarterNote);
601  diffTime=ctl->gotomsec;
602  midistat->sendData(midi,ctl->gm);
603  delete midistat;
604  midi->setPatchesToUse(info->patchesUsed);
605  ctl->moving=0;
606  } else
607  for (i=0;i<16;i++)
608  {
609  if (ctl->forcepgm[i])
610  {
611  midi->chnPatchChange(i, ctl->pgm[i]);
612  }
613  }
614 
615  timeval begintv;
616  gettimeofday(&begintv, NULL);
617  ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000;
618  ctl->OK=1;
619  ctl->playing=playing=1;
620 
621  while (playing)
622  {
623  /*
624  if (ctl->message!=0)
625  {
626  if (ctl->message & PLAYER_DOPAUSE)
627  {
628  diffTime=minTime;
629  ctl->message&=~PLAYER_DOPAUSE;
630  midi->sync(1);
631  midi->tmrStop();
632  ctl->paused=1;
633  midi->closeDev();
634  while ((ctl->paused)&&(!(ctl->message&PLAYER_DOSTOP))
635  &&(!(ctl->message&PLAYER_HALT))) sleep(1);
636  midi->openDev();
637  midi->tmrStart();
638  ctl->OK=1;
639  printf("Continue playing ... \n");
640  };
641  if (ctl->message & PLAYER_DOSTOP)
642  {
643  ctl->message&=~PLAYER_DOSTOP;
644  playing=0;
645  };
646  if (ctl->message & PLAYER_HALT)
647  {
648  ctl->message&=~PLAYER_HALT;
649  playing=0;
650  halt=1;
651  };
652  if (ctl->message & PLAYER_SETPOS)
653  {
654  ctl->moving=1;
655  ctl->message&=~PLAYER_SETPOS;
656  midi->sync(1);
657  midi->tmrStop();
658  midi->closeDev();
659  midistat = new midiStat();
660  SetPos(ctl->gotomsec,midistat);
661  minTime=ctl->gotomsec;
662  prevms=(ulong)minTime;
663  midi->openDev();
664  midi->tmrStart();
665  diffTime=ctl->gotomsec;
666  ctl->moving=0;
667  midistat->sendData(midi,ctl->gm);
668  delete midistat;
669  ctl->OK=1;
670  while (ctl->OK==1) ;
671  ctl->moving=0;
672  };
673  };
674  */
675  prevms=minTime;
676  // ctl->millisecsPlayed=minTime;
677  trk=0;
678  minTrk=0;
679  maxTime=minTime + 120000L /* milliseconds */;
680  minTime=maxTime;
681  playing=0;
682  while (trk<info->ntracks)
683  {
684  if (tracks[trk]->absMsOfNextEvent()<minTime)
685  {
686  minTrk=trk;
687  minTime=tracks[minTrk]->absMsOfNextEvent();
688  playing=1;
689  }
690  trk++;
691  }
692 #ifdef PLAYERDEBUG
693  printf("minTime %g\n",minTime);
694 #endif
695  // if ((minTime==maxTime)/* || (minTicks> 60000L)*/)
696  if (playing==0)
697  {
698  // playing=0;
699 #ifdef PLAYERDEBUG
700  printf("END of playing\n");
701 #endif
702  }
703  else
704  {
705  // mspass=(ulong)(minTime-prevms);
706  trk=0;
707  while (trk<info->ntracks)
708  {
709  tracks[trk]->currentMs(minTime);
710  trk++;
711  }
712  midi->wait(minTime-diffTime);
713  }
714  trk=minTrk;
715  tracks[trk]->readEvent(ev);
716  switch (ev->command)
717  {
718  case (MIDI_NOTEON) :
719  midi->noteOn(ev->chn, ev->note, ev->vel);break;
720  case (MIDI_NOTEOFF):
721  midi->noteOff(ev->chn, ev->note, ev->vel);break;
722  case (MIDI_KEY_PRESSURE) :
723  midi->keyPressure(ev->chn, ev->note,ev->vel);break;
724  case (MIDI_PGM_CHANGE) :
725  if (!ctl->forcepgm[ev->chn])
726  midi->chnPatchChange(ev->chn, (ctl->gm==1)?(ev->patch):(MT32toGM[ev->patch]));break;
727  case (MIDI_CHN_PRESSURE) :
728  midi->chnPressure(ev->chn, ev->vel);break;
729  case (MIDI_PITCH_BEND) :
730  midi->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
731  case (MIDI_CTL_CHANGE) :
732  midi->chnController(ev->chn, ev->ctl,ev->d1);break;
733  case (MIDI_SYSTEM_PREFIX) :
734  if ((ev->command|ev->chn)==META_EVENT)
735  {
736  if ((ev->d1==5)||(ev->d1==1))
737  {
738  ctl->SPEVplayed++;
739  }
740  if (ev->d1==ME_SET_TEMPO)
741  {
742  absTimeAtChangeTempo=absTime;
743  ticksplayed=0;
744  ctl->SPEVplayed++;
745  tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
746 #ifdef PLAYERDEBUG
747  printf("Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo);
748 #endif
749  midi->tmrSetTempo((int)tempoToMetronomeTempo(tempo));
750  ctl->tempo=tempo;
751  for (j=0;j<info->ntracks;j++)
752  {
753  tracks[j]->changeTempo(tempo);
754  }
755  }
756  if (ev->d1==ME_TIME_SIGNATURE)
757  {
758  ctl->num=ev->d2;
759  ctl->den=ev->d3;
760  ctl->SPEVplayed++;
761  }
762  }
763  break;
764  }
765  if (calloutput)
766  {
767  midi->sync();
768  output();
769  }
770 
771  }
772  ctl->ev=NULL;
773  delete ev;
774 #ifdef PLAYERDEBUG
775  printf("Syncronizing ...\n");
776 #endif
777  if (halt)
778  midi->sync(1);
779  else
780  midi->sync();
781 #ifdef PLAYERDEBUG
782  printf("Closing device ...\n");
783 #endif
784  midi->allNotesOff();
785  midi->closeDev();
786  ctl->playing=0;
787 #ifdef PLAYERDEBUG
788  printf("Bye...\n");
789 #endif
790  ctl->OK=1;
791  ctl->finished=1;
792 }
793 
794 
795 void MidiPlayer::setPos(ulong gotomsec,MidiStatus *midistat)
796 {
797  int trk,minTrk;
798  ulong tempo=(ulong)(500000 * ctl->ratioTempo);
799  double minTime=0,maxTime,prevms=0;
800  int i,j,likeplaying=1;
801 
802  MidiEvent *ev=new MidiEvent;
803  ctl->SPEVplayed=0;
804  for (i=0;i<info->ntracks;i++)
805  {
806  tracks[i]->init();
807  tracks[i]->changeTempo(tempo);
808  }
809 
810  for (i=0;i<16;i++)
811  {
812  if (ctl->forcepgm[i]) midistat->chnPatchChange(i, ctl->pgm[i]);
813  }
814 
815  while (likeplaying)
816  {
817  trk=0;
818  minTrk=0;
819  maxTime=minTime + 120000L; /*milliseconds (2 minutes)*/
820  minTime=maxTime;
821  while (trk<info->ntracks)
822  {
823  if (tracks[trk]->absMsOfNextEvent()<minTime)
824  {
825  minTrk=trk;
826  minTime=tracks[minTrk]->absMsOfNextEvent();
827  }
828  trk++;
829  }
830  if (minTime==maxTime)
831  {
832  likeplaying=0;
833 #ifdef GENERAL_DEBUG_MESSAGES
834  printf("END of likeplaying\n");
835 #endif
836  }
837  else
838  {
839  if (minTime>=gotomsec)
840  {
841  prevms=gotomsec;
842  likeplaying=0;
843 #ifdef GENERAL_DEBUG_MESSAGES
844  printf("Position reached !! \n");
845 #endif
846  minTime=gotomsec;
847  }
848  else
849  {
850  prevms=minTime;
851  }
852  trk=0;
853  while (trk<info->ntracks)
854  {
855  tracks[trk]->currentMs(minTime);
856  trk++;
857  }
858  }
859 
860  if (likeplaying)
861  {
862  trk=minTrk;
863  tracks[trk]->readEvent(ev);
864  switch (ev->command)
865  {
866  /* case (MIDI_NOTEON) :
867  midistat->noteOn(ev->chn, ev->note, ev->vel);break;
868  case (MIDI_NOTEOFF):
869  midistat->noteOff(ev->chn, ev->note, ev->vel);break;
870  case (MIDI_KEY_PRESSURE) :
871  midistat->keyPressure(ev->chn, ev->note,ev->vel);break;
872  */
873  case (MIDI_PGM_CHANGE) :
874  if (!ctl->forcepgm[ev->chn]) midistat->chnPatchChange(ev->chn, ev->patch);break;
875  case (MIDI_CHN_PRESSURE) :
876  midistat->chnPressure(ev->chn, ev->vel);break;
877  case (MIDI_PITCH_BEND) :
878  midistat->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
879  case (MIDI_CTL_CHANGE) :
880  midistat->chnController(ev->chn, ev->ctl,ev->d1);break;
881  case (MIDI_SYSTEM_PREFIX) :
882  if ((ev->command|ev->chn)==META_EVENT)
883  {
884  if ((ev->d1==5)||(ev->d1==1))
885  {
886  ctl->SPEVplayed++;
887  }
888  if (ev->d1==ME_SET_TEMPO)
889  {
890  ctl->SPEVplayed++;
891  tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
892 
893  midistat->tmrSetTempo((int)tempoToMetronomeTempo(tempo));
894  for (j=0;j<info->ntracks;j++)
895  {
896  tracks[j]->changeTempo(tempo);
897  }
898  }
899  if (ev->d1==ME_TIME_SIGNATURE)
900  {
901  ctl->num=ev->d2;
902  ctl->den=ev->d3;
903  ctl->SPEVplayed++;
904  }
905  }
906  break;
907  }
908  }
909  }
910  delete ev;
911  ctl->tempo=tempo;
912 }
913 
914 
915 void MidiPlayer::debugSpecialEvents(void)
916 {
917  SpecialEvent *pspev=spev;
918  printf("**************************************\n");
919  while ((pspev!=NULL)&&(pspev->type!=0))
920  {
921  printf("t:%d ticks:%d diff:%ld abs:%ld s:%s tempo:%ld\n",pspev->type,pspev->ticks,pspev->diffmilliseconds,pspev->absmilliseconds,pspev->text,pspev->tempo);
922  pspev=pspev->next;
923  }
924 
925 }
926 
927 void MidiPlayer::setParseSong(bool b)
928 {
929  parsesong=b;
930 }
931 
932 void MidiPlayer::setGenerateBeats(bool b)
933 {
934  generatebeats=b;
935 }
936 
937 void MidiPlayer::setTempoRatio(double ratio)
938 {
939  if (songLoaded)
940  {
941  ctl->ratioTempo=ratio;
942  parseInfoData(info,tracks,ctl->ratioTempo);
943  if (parsesong)
944  {
945  parseSpecialEvents();
946  if (generatebeats) generateBeats();
947 
948  }
949  }
950  else
951  {
952  ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio);
953  ctl->ratioTempo=ratio;
954  }
955 
956 }
957 
958 #undef T2MS
959 #undef MS2T
DeviceManager
MIDI Device Manager class .
Definition: deviceman.h:48
DeviceManager::noteOn
void noteOn(uchar chn, uchar note, uchar vel)
Sends a Note On MIDI event.
Definition: deviceman.cpp:496
DeviceManager::chnPitchBender
void chnPitchBender(uchar chn, uchar lsb, uchar msb)
Changes the Pitch Bender value on a MIDI channel.
Definition: deviceman.cpp:521
DeviceManager::wait
void wait(double ms)
Sets the number of milliseconds at which the next event will be sent.
Definition: deviceman.cpp:537
DeviceManager::chnPatchChange
void chnPatchChange(uchar chn, uchar patch)
Changes the patch (instrument) on a MIDI channel.
Definition: deviceman.cpp:511
DeviceManager::midiPorts
int midiPorts(void)
Returns the number of MIDI ports available on the system.
Definition: deviceman.h:504
DeviceManager::setPatchesToUse
int setPatchesToUse(int *patchesused)
Loads the patches you're going to use .
Definition: deviceman.cpp:794
DeviceManager::chnController
void chnController(uchar chn, uchar ctl, uchar v)
Sends a Controller event to a MIDI channel.
Definition: deviceman.cpp:526
DeviceManager::initDev
void initDev(void)
Calls MidiOut::initDev() in turn in each of the available devices.
Definition: deviceman.cpp:482
DeviceManager::tmrStart
void tmrStart(long int tpcn)
Starts the timer.
Definition: deviceman.cpp:565
DeviceManager::setVolumePercentage
void setVolumePercentage(int i)
Changes the "master" volume of the played events by altering next volume controller events.
Definition: deviceman.cpp:808
DeviceManager::ok
int ok(void)
Definition: deviceman.cpp:169
DeviceManager::chnPressure
void chnPressure(uchar chn, uchar vel)
Changes the Pressure (Aftertouch) on a MIDI channel.
Definition: deviceman.cpp:516
DeviceManager::tmrStop
void tmrStop(void)
Stops the timer.
Definition: deviceman.cpp:591
DeviceManager::sync
void sync(bool f=0)
Synchronizes with the MIDI buffer.
Definition: deviceman.cpp:632
DeviceManager::noteOff
void noteOff(uchar chn, uchar note, uchar vel)
Sends a Note Off MIDI event.
Definition: deviceman.cpp:501
DeviceManager::keyPressure
void keyPressure(uchar chn, uchar note, uchar vel)
Sends a Key Pressure (or Aftertouch) MIDI event.
Definition: deviceman.cpp:506
DeviceManager::closeDev
void closeDev(void)
Closes the devices, and /dev/sequencer.
Definition: deviceman.cpp:449
DeviceManager::tmrSetTempo
void tmrSetTempo(int v)
Sets the tempo which will be used to convert between ticks and milliseconds.
Definition: deviceman.cpp:553
DeviceManager::openDev
void openDev(void)
Open the devices.
Definition: deviceman.cpp:398
DeviceManager::allNotesOff
void allNotesOff(void)
Sends an all notes off event.
Definition: deviceman.cpp:824
DeviceManager::synthDevices
int synthDevices(void)
Returns the number of internal synthesizers available on the system.
Definition: deviceman.h:515
MidiPlayer::MidiPlayer
MidiPlayer(DeviceManager *midi_, PlayerController *pctl)
Constructor .
Definition: player.cpp:46
MidiPlayer::loadSong
int loadSong(const char *filename)
Loads a Song, and parses it (it the parse wasn't disabled with setParseSong() ) .
Definition: player.cpp:89
MidiPlayer::~MidiPlayer
~MidiPlayer()
Destructor.
Definition: player.cpp:59
MidiPlayer::setPos
void setPos(ulong gotomsec, class MidiStatus *midistat)
Sets the position in a song.
Definition: player.cpp:795
MidiPlayer::play
void play(bool calloutput=false, void output(void)=0)
Plays the song using the DeviceManager object supplied in the constructor.
Definition: player.cpp:531
MidiPlayer::setGenerateBeats
void setGenerateBeats(bool b=false)
Enables or disables the generation of beats event in a song when loading it.
Definition: player.cpp:932
MidiPlayer::setParseSong
void setParseSong(bool b=true)
Enables or disables the parsing of the song when loading it.
Definition: player.cpp:927
MidiPlayer::setTempoRatio
void setTempoRatio(double ratio)
Changes the speed at which a song is played.
Definition: player.cpp:937
MidiPlayer::removeSong
void removeSong(void)
Unloads the current song, so that every internal variable is empty and clean for further usage.
Definition: player.cpp:65
MidiStatus
Stores the status of a MIDI device .
Definition: midistat.h:41
MidiStatus::chnPitchBender
void chnPitchBender(uchar chn, uchar lsb, uchar msb)
Stores a new pitch bender value in channel chn.
Definition: midistat.cpp:71
MidiStatus::chnPressure
void chnPressure(uchar chn, uchar vel)
Stores a new channel pressure value in channel chn.
Definition: midistat.cpp:66
MidiStatus::tmrSetTempo
void tmrSetTempo(int v)
Sets the tempo.
Definition: midistat.cpp:84
MidiStatus::chnController
void chnController(uchar chn, uchar ctl, uchar v)
Stores a new value for controller ctl in channel chn.
Definition: midistat.cpp:76
MidiStatus::chnPatchChange
void chnPatchChange(uchar chn, uchar patch)
Stores a new patch in channel chn.
Definition: midistat.cpp:61
MidiStatus::sendData
void sendData(class DeviceManager *midi, int gm=1)
Sends the current MIDI state to the DeviceManager object used as parameter (you should have already s...
Definition: midistat.cpp:89
MidiTrack::readEvent
void readEvent(MidiEvent *ev)
Reads the event at the iterator position, and puts it on the structure pointed to by ev.
Definition: track.cpp:190
MidiTrack::init
void init(void)
Initializes the iterator.
Definition: track.cpp:519
MidiTrack::currentMs
int currentMs(double ms)
Returns the current millisecond which the iterator is at.
Definition: track.cpp:174
MidiTrack::changeTempo
void changeTempo(ulong t)
Change the tempo of the song.
Definition: track.cpp:544
MidiTrack::absMsOfNextEvent
double absMsOfNextEvent(void)
Returns the absolute number of milliseconds of the next event.
Definition: track.h:212
NoteArray
Holds a resizeable array of note on/off and patch change events.
Definition: notearray.h:39
NoteArray::add
void add(ulong ms, int chn, int cmd, int note)
Adds a note/patch event at a given millisecond.
Definition: notearray.cpp:80
MidiEvent
An structure that represents a MIDI event.
Definition: track.h:38
MidiEvent::length
ulong length
Length of the generic data variable.
Definition: track.h:104
MidiEvent::command
uchar command
MIDI Command.
Definition: track.h:44
MidiEvent::ctl
uchar ctl
Patch (if command was a controller command)
Definition: track.h:69
MidiEvent::chn
uchar chn
Channel.
Definition: track.h:49
MidiEvent::note
uchar note
Note.
Definition: track.h:54
MidiEvent::d3
uchar d3
Data 3.
Definition: track.h:84
MidiEvent::d2
uchar d2
Data 2.
Definition: track.h:79
MidiEvent::patch
uchar patch
Patch (if command was a change patch command)
Definition: track.h:64
MidiEvent::d1
uchar d1
Data 1.
Definition: track.h:74
MidiEvent::vel
uchar vel
Velocity.
Definition: track.h:59
MidiEvent::data
uchar * data
The data for commands like text, sysex, etc.
Definition: track.h:109
MidiFileInfo
Contains all the information about a MIDI file.
Definition: midfile.h:40
MidiFileInfo::ticksTotal
ulong ticksTotal
Total number of MIDI ticks.
Definition: midfile.h:59
MidiFileInfo::ntracks
int ntracks
Number of tracks.
Definition: midfile.h:49
MidiFileInfo::patchesUsed
int patchesUsed[256]
Patches used in the MIDI file.
Definition: midfile.h:77
MidiFileInfo::ticksPerCuarterNote
int ticksPerCuarterNote
Ticks per cuarter note.
Definition: midfile.h:54
PlayerController
PlayerController is a struct that is used by the MidiPlayer object to tell other parts of the applica...
Definition: player.h:139
PlayerController::OK
volatile int OK
When pause is released, if the caller must know when the player has opened the devices and is playing...
Definition: player.h:157
PlayerController::ratioTempo
volatile double ratioTempo
Ratio to multiply the tempo to.
Definition: player.h:226
PlayerController::paused
volatile int paused
When the player is paused, paused is set to 1.
Definition: player.h:167
PlayerController::playing
volatile int playing
When the player is playing (or paused), playing is set to 1.
Definition: player.h:162
PlayerController::pgm
volatile int pgm[16]
Force a given patch in each channel at "this" moment, as determined by forcepgm.
Definition: player.h:221
PlayerController::gm
volatile int gm
If gm is 1, the song follows the General Midi standard, if gm is 0, the song is in MT 32 format.
Definition: player.h:202
PlayerController::moving
volatile int moving
When the player seeking the position of the song, moving is set to 1.
Definition: player.h:172
PlayerController::volumepercentage
volatile int volumepercentage
100 means no change, 50 halfs the volume, 200 doubles it (if possible), etc.
Definition: player.h:209
PlayerController::error
volatile int error
When error is 1, an error has ocurred (i.e.
Definition: player.h:196
PlayerController::finished
volatile int finished
When the player has finished playing a song, finished is set to 1.
Definition: player.h:177
PlayerController::forcepgm
volatile bool forcepgm[16]
Activate or disactivate the force to use a patch for a given channel.
Definition: player.h:215
SpecialEvent
This struct stores text, lyrics and change tempo events among others.
Definition: player.h:49
SpecialEvent::ticks
int ticks
MIDI ticks (from the beginning of the song) at which this event is played.
Definition: player.h:73
SpecialEvent::tempo
ulong tempo
Tempo field .
Definition: player.h:99
SpecialEvent::text
char text[1024]
Text field .
Definition: player.h:94
SpecialEvent::num
int num
Numerator .
Definition: player.h:104
SpecialEvent::next
struct SpecialEvent * next
This struct stores text, lyrics and change tempo events among others.
Definition: player.h:121
SpecialEvent::den
int den
Denominator .
Definition: player.h:109
SpecialEvent::absmilliseconds
ulong absmilliseconds
The absolute millisecond (from the beginning of the song) at which this SpecialEvent object is played...
Definition: player.h:68
SpecialEvent::diffmilliseconds
ulong diffmilliseconds
Delta milliseconds from the previous SpecialEvent.
Definition: player.h:60
SpecialEvent::type
int type
Type of event.
Definition: player.h:89
SpecialEvent::id
int id
An integer ID, that is assigned in order to each SpecialEvent.
Definition: player.h:53

libtdemid

Skip menu "libtdemid"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

libtdemid

Skip menu "libtdemid"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for libtdemid by doxygen 1.9.1
This website is maintained by Timothy Pearson.