40#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)
42#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L))
44#define REMOVEDUPSTRINGS
61 removeSpecialEvents();
67 if ((songLoaded)&&(tracks!=NULL))
70 printf(
"Removing song from memory\n");
73 while (i<info->ntracks)
75 if (tracks[i]!=NULL)
delete tracks[i];
93 printf(
"Loading Song : %s\n",filename);
97 tracks=readMidiFile(filename,info,ok);
99 if (tracks==NULL)
return -4;
101 parseInfoData(info,tracks,ctl->ratioTempo);
105 parseSpecialEvents();
106 if (generatebeats) generateBeats();
113void MidiPlayer::insertBeat(
SpecialEvent *ev,ulong ms,
int num,
int den)
126void MidiPlayer::generateBeats(
void)
129 printf(
"player::Generating Beats...\n");
132 if (spev==NULL)
return;
133 SpecialEvent *ev=spev;
134 SpecialEvent *nextev=ev->
next;
135 ulong tempo=(ulong)(500000 * ctl->ratioTempo);
141 double ticksleft=(((double)info->ticksPerCuarterNote*4)/den);
143 double beatstep=T2MS(ticksleft);
162 ticksleft=MS2T(nextbeatms-lastbeatms);
164 nextbeatms=lastbeatms+T2MS(ticksleft);
167 beatstep=T2MS(((
static_cast<double>(info->ticksPerCuarterNote)*4)/den));
177 beatstep=T2MS((((
double)info->ticksPerCuarterNote*4)/den));
187 measurems=nextbeatms;
189 insertBeat(ev,
static_cast<unsigned long>(nextbeatms), i++, num);
193 lastbeatms=nextbeatms;
194 nextbeatms+=beatstep;
197 ticksleft = ( (
static_cast<double>(info->ticksPerCuarterNote)*4) / den);
218 while (nextbeatms<info->millisecsTotal)
221 if (i==1) measurems=nextbeatms;
222 insertBeat(ev,
static_cast<unsigned long>(nextbeatms), i++, num);
224 nextbeatms+=beatstep;
241 printf(
"player::Beats Generated\n");
246void MidiPlayer::removeSpecialEvents(
void)
248 SpecialEvent * ev=spev;
259void MidiPlayer::parseSpecialEvents(
void)
262 printf(
"player::Parsing...\n");
264 removeSpecialEvents();
265 spev=
new SpecialEvent;
266 if (spev==NULL)
return;
267 SpecialEvent *pspev=spev;
272 if (!na) {
delete spev; spev=0L;
return; };
277 ulong tempo=(ulong)(500000 * (ctl->ratioTempo));
279 for (
int i=0;i<info->ntracks;i++)
282 tracks[i]->changeTempo(tempo);
284 MidiEvent *ev=
new MidiEvent;
290#ifdef REMOVEDUPSTRINGS
292 ulong lasttexttime=0;
301 maxTime=minTime + 2 * 60000L;
304 while (trk<info->ntracks)
306 if (tracks[trk]->absMsOfNextEvent()<minTime)
309 minTime=tracks[minTrk]->absMsOfNextEvent();
319 printf(
"END of parsing\n");
326 while (trk<info->ntracks)
328 tracks[trk]->currentMs(minTime);
333 tracks[trk]->readEvent(ev);
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);
340 case (MIDI_NOTEOFF) :
341 na->add((ulong)minTime,ev->
chn,0, ev->
note);
343 case (MIDI_PGM_CHANGE) :
344 na->add((ulong)minTime,ev->
chn, 2,ev->
patch);
346 case (MIDI_SYSTEM_PREFIX) :
361 printf(
"ev->length %ld\n",ev->
length);
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;
368 printf(
"(%s)(%s)\n",pspev->
text,lasttext);
370#ifdef REMOVEDUPSTRINGS
374 lasttexttype=pspev->
type;
375 strncpy(lasttext, pspev->
text, 1024);
376 lasttext[
sizeof(lasttext)-1] = 0;
378 pspev->
next=
new SpecialEvent;
380 if (pspev->
next==NULL) printf(
"pspev->next=NULL\n");
383#ifdef REMOVEDUPSTRINGS
389 case (ME_SET_TEMPO) :
396 tempo=(ulong)(((ev->
data[0]<<16)|(ev->
data[1]<<8)|(ev->
data[2])) * ctl->ratioTempo);
398 if (firsttempo==0) firsttempo=tempo;
399 for (j=0;j<info->ntracks;j++)
401 tracks[j]->changeTempo(tempo);
403 pspev->
next=
new SpecialEvent;
408 case (ME_TIME_SIGNATURE) :
417 pspev->
next=
new SpecialEvent;
433 if (firsttempo==0) firsttempo=tempo;
434 ctl->
tempo=firsttempo;
437 for (
int i=0;i<info->ntracks;i++)
534 printf(
"Playing...\n");
537 if (midi->midiPorts()+midi->synthDevices()==0)
539 fprintf(stderr,
"Player :: There are no midi ports !\n");
547 fprintf(stderr,
"Player :: Couldn't play !\n");
551 midi->setVolumePercentage(ctl->volumepercentage);
554 midi->setPatchesToUse(info->patchesUsed);
561 ulong tempo=(ulong)(500000 * ctl->ratioTempo);
562 for (i=0;i<info->ntracks;i++)
565 tracks[i]->changeTempo(tempo);
568 midi->tmrStart(info->ticksPerCuarterNote);
571 ctl->ticksTotal=info->ticksTotal;
575 double absTimeAtChangeTempo=0;
588 if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS))
591 ctl->message&=~PLAYER_SETPOS;
596 setPos(ctl->gotomsec,midistat);
597 minTime=ctl->gotomsec;
598 prevms=(ulong)minTime;
600 midi->tmrStart(info->ticksPerCuarterNote);
601 diffTime=ctl->gotomsec;
604 midi->setPatchesToUse(info->patchesUsed);
609 if (ctl->forcepgm[i])
611 midi->chnPatchChange(i, ctl->pgm[i]);
616 gettimeofday(&begintv, NULL);
617 ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000;
619 ctl->playing=playing=1;
679 maxTime=minTime + 120000L ;
682 while (trk<info->ntracks)
684 if (tracks[trk]->absMsOfNextEvent()<minTime)
687 minTime=tracks[minTrk]->absMsOfNextEvent();
693 printf(
"minTime %g\n",minTime);
700 printf(
"END of playing\n");
707 while (trk<info->ntracks)
709 tracks[trk]->currentMs(minTime);
712 midi->wait(minTime-diffTime);
715 tracks[trk]->readEvent(ev);
719 midi->noteOn(ev->
chn, ev->
note, ev->
vel);
break;
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) :
736 if ((ev->
d1==5)||(ev->
d1==1))
740 if (ev->
d1==ME_SET_TEMPO)
742 absTimeAtChangeTempo=absTime;
745 tempo=(ulong)(((ev->
data[0]<<16)|(ev->
data[1]<<8)|(ev->
data[2]))*ctl->ratioTempo);
747 printf(
"Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo);
749 midi->tmrSetTempo((
int)tempoToMetronomeTempo(tempo));
751 for (j=0;j<info->ntracks;j++)
753 tracks[j]->changeTempo(tempo);
756 if (ev->
d1==ME_TIME_SIGNATURE)
775 printf(
"Syncronizing ...\n");
782 printf(
"Closing device ...\n");
798 ulong tempo=(ulong)(500000 * ctl->ratioTempo);
799 double minTime=0,maxTime,prevms=0;
800 int i,j,likeplaying=1;
804 for (i=0;i<info->ntracks;i++)
807 tracks[i]->changeTempo(tempo);
819 maxTime=minTime + 120000L;
821 while (trk<info->ntracks)
823 if (tracks[trk]->absMsOfNextEvent()<minTime)
826 minTime=tracks[minTrk]->absMsOfNextEvent();
830 if (minTime==maxTime)
833#ifdef GENERAL_DEBUG_MESSAGES
834 printf(
"END of likeplaying\n");
839 if (minTime>=gotomsec)
843#ifdef GENERAL_DEBUG_MESSAGES
844 printf(
"Position reached !! \n");
853 while (trk<info->ntracks)
855 tracks[trk]->currentMs(minTime);
863 tracks[trk]->readEvent(ev);
873 case (MIDI_PGM_CHANGE) :
875 case (MIDI_CHN_PRESSURE) :
877 case (MIDI_PITCH_BEND) :
879 case (MIDI_CTL_CHANGE) :
881 case (MIDI_SYSTEM_PREFIX) :
884 if ((ev->
d1==5)||(ev->
d1==1))
888 if (ev->
d1==ME_SET_TEMPO)
891 tempo=(ulong)(((ev->
data[0]<<16)|(ev->
data[1]<<8)|(ev->
data[2]))*ctl->ratioTempo);
893 midistat->
tmrSetTempo((
int)tempoToMetronomeTempo(tempo));
894 for (j=0;j<info->ntracks;j++)
896 tracks[j]->changeTempo(tempo);
899 if (ev->
d1==ME_TIME_SIGNATURE)
915void MidiPlayer::debugSpecialEvents(
void)
918 printf(
"**************************************\n");
919 while ((pspev!=NULL)&&(pspev->
type!=0))
941 ctl->ratioTempo=ratio;
942 parseInfoData(info,tracks,ctl->ratioTempo);
945 parseSpecialEvents();
946 if (generatebeats) generateBeats();
952 ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio);
953 ctl->ratioTempo=ratio;
MIDI Device Manager class .
MidiPlayer(DeviceManager *midi_, PlayerController *pctl)
Constructor .
int loadSong(const char *filename)
Loads a Song, and parses it (it the parse wasn't disabled with setParseSong() ) .
void setPos(ulong gotomsec, class MidiStatus *midistat)
Sets the position in a song.
void play(bool calloutput=false, void output(void)=0)
Plays the song using the DeviceManager object supplied in the constructor.
void setGenerateBeats(bool b=false)
Enables or disables the generation of beats event in a song when loading it.
void setParseSong(bool b=true)
Enables or disables the parsing of the song when loading it.
void setTempoRatio(double ratio)
Changes the speed at which a song is played.
void removeSong(void)
Unloads the current song, so that every internal variable is empty and clean for further usage.
Stores the status of a MIDI device .
void chnPitchBender(uchar chn, uchar lsb, uchar msb)
Stores a new pitch bender value in channel chn.
void chnPressure(uchar chn, uchar vel)
Stores a new channel pressure value in channel chn.
void tmrSetTempo(int v)
Sets the tempo.
void chnController(uchar chn, uchar ctl, uchar v)
Stores a new value for controller ctl in channel chn.
void chnPatchChange(uchar chn, uchar patch)
Stores a new patch in channel chn.
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...
An structure that represents a MIDI event.
ulong length
Length of the generic data variable.
uchar command
MIDI Command.
uchar ctl
Patch (if command was a controller command).
uchar patch
Patch (if command was a change patch command).
uchar * data
The data for commands like text, sysex, etc.
Contains all the information about a MIDI file.
PlayerController is a struct that is used by the MidiPlayer object to tell other parts of the applica...
This struct stores text, lyrics and change tempo events among others.
int ticks
MIDI ticks (from the beginning of the song) at which this event is played.
char text[1024]
Text field .
struct SpecialEvent * next
This struct stores text, lyrics and change tempo events among others.
ulong absmilliseconds
The absolute millisecond (from the beginning of the song) at which this SpecialEvent object is played...
ulong diffmilliseconds
Delta milliseconds from the previous SpecialEvent.
int id
An integer ID, that is assigned in order to each SpecialEvent.