• 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
46MidiPlayer::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
59MidiPlayer::~MidiPlayer()
60{
61 removeSpecialEvents();
62 removeSong();
63}
64
65void 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
89int 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
113void 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
126void 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
246void 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
259void 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/*
444NoteArray *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
531void 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
795void 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
915void 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
927void MidiPlayer::setParseSong(bool b)
928{
929 parsesong=b;
930}
931
932void MidiPlayer::setGenerateBeats(bool b)
933{
934 generatebeats=b;
935}
936
937void 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.4
This website is maintained by Timothy Pearson.