summaryrefslogtreecommitdiffstats
path: root/libkmid/player.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libkmid/player.cc')
-rw-r--r--libkmid/player.cc959
1 files changed, 959 insertions, 0 deletions
diff --git a/libkmid/player.cc b/libkmid/player.cc
new file mode 100644
index 000000000..a68a9b147
--- /dev/null
+++ b/libkmid/player.cc
@@ -0,0 +1,959 @@
+/**************************************************************************
+
+ player.cc - class MidiPlayer. Plays a set of tracks
+ This file is part of LibKMid 0.9.5
+ Copyright (C) 1997,98,99,2000 Antonio Larrosa Jimenez
+ LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libkmid.html
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ $Id$
+
+ Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
+
+***************************************************************************/
+#include "player.h"
+#include "sndcard.h"
+#include "midispec.h"
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "midistat.h"
+#include "mt32togm.h"
+
+//#define PLAYERDEBUG
+//#define GENERAL_DEBUG_MESSAGES
+
+#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)
+
+#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L))
+
+#define REMOVEDUPSTRINGS
+
+MidiPlayer::MidiPlayer(DeviceManager *midi_,PlayerController *pctl)
+{
+ midi=midi_;
+ info=NULL;
+ tracks=NULL;
+ songLoaded=0;
+ ctl=pctl;
+ spev=NULL;
+ na=NULL;
+ parsesong=true;
+ generatebeats=false;
+}
+
+MidiPlayer::~MidiPlayer()
+{
+ removeSpecialEvents();
+ removeSong();
+}
+
+void MidiPlayer::removeSong(void)
+{
+ if ((songLoaded)&&(tracks!=NULL))
+ {
+#ifdef PLAYERDEBUG
+ printf("Removing song from memory\n");
+#endif
+ int i=0;
+ while (i<info->ntracks)
+ {
+ if (tracks[i]!=NULL) delete tracks[i];
+ i++;
+ }
+ delete tracks;
+ tracks=NULL;
+ if (info!=NULL)
+ {
+ delete info;
+ info=NULL;
+ }
+ }
+ songLoaded=0;
+}
+
+int MidiPlayer::loadSong(const char *filename)
+{
+ removeSong();
+#ifdef PLAYERDEBUG
+ printf("Loading Song : %s\n",filename);
+#endif
+ info=new MidiFileInfo;
+ int ok;
+ tracks=readMidiFile(filename,info,ok);
+ if (ok<0) return ok;
+ if (tracks==NULL) return -4;
+
+ parseInfoData(info,tracks,ctl->ratioTempo);
+
+ if (parsesong)
+ {
+ parseSpecialEvents();
+ if (generatebeats) generateBeats();
+ }
+
+ songLoaded=1;
+ return 0;
+}
+
+void MidiPlayer::insertBeat(SpecialEvent *ev,ulong ms,int num,int den)
+{
+ SpecialEvent *beat=new SpecialEvent;
+ beat->next=ev->next;
+ ev->next=beat;
+ beat->id=1;
+ beat->type=7;
+ beat->absmilliseconds=ms;
+ beat->num=num;
+ beat->den=den;
+}
+
+
+void MidiPlayer::generateBeats(void)
+{
+#ifdef PLAYERDEBUG
+ printf("player::Generating Beats...\n");
+#endif
+
+ if (spev==NULL) return;
+ SpecialEvent *ev=spev;
+ SpecialEvent *nextev=ev->next;
+ ulong tempo=(ulong)(500000 * ctl->ratioTempo);
+ int i=1;
+ int num=4;
+ int den=4;
+ // ulong beatstep=((double)tempo*4/(den*1000));
+ // ulong beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
+ double ticksleft=(((double)info->ticksPerCuarterNote*4)/den);
+
+ double beatstep=T2MS(ticksleft);
+ double nextbeatms=0;
+ double lastbeatms=0;
+ double measurems=0;
+
+ while (nextev!=NULL)
+ {
+ switch (ev->type)
+ {
+ case (0): // End of list
+ {
+ };break;
+ case (1): // Text
+ case (2): // Lyrics
+ {
+ };break;
+ case (3): // Change Tempo
+ {
+ lastbeatms=ev->absmilliseconds;
+ ticksleft=MS2T(nextbeatms-lastbeatms);
+ tempo=ev->tempo;
+ nextbeatms=lastbeatms+T2MS(ticksleft);
+ // printf("Change at %lu to %d\n",ev->absmilliseconds,ev->tempo);
+ // beatstep=((double)tempo*4/(den*1000));
+ beatstep=T2MS(((static_cast<double>(info->ticksPerCuarterNote)*4)/den));
+ };break;
+ case (6): // Change number of beats per measure
+ {
+ num=ev->num;
+ i=1;
+ den=ev->den;
+ // printf("Change at %lu to %d/%d\n",ev->absmilliseconds,num,den);
+ // beatstep=((double)tempo*4/(den*1000));
+ // beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
+ beatstep=T2MS((((double)info->ticksPerCuarterNote*4)/den));
+ nextbeatms=ev->absmilliseconds;
+ };break;
+ };
+ if (nextev->absmilliseconds>nextbeatms)
+ {
+ //printf("Adding %d,%d\n",num,tot);
+ //printf("beat at %g , %d/%d\n",nextbeatms,i,num);
+ //printf(" %ld %d\n",nextev->absmilliseconds,nextev->type);
+ if (i == 1) {
+ measurems=nextbeatms;
+ }
+ insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
+ if (i > num) {
+ i=1;
+ }
+ lastbeatms=nextbeatms;
+ nextbeatms+=beatstep;
+ // nextbeatms=measurems+beatstep*i;
+
+ ticksleft = ( (static_cast<double>(info->ticksPerCuarterNote)*4) / den);
+
+ }
+
+ ev=ev->next;
+ nextev=ev->next;
+ }
+
+ /* ev==NULL doesn't indicate the end of the song, so continue generating beats */
+
+ if (ev!=NULL)
+ {
+ if (ev->type==0)
+ {
+ ev=spev;
+ /* Looking if ev->next is NULL is not needed because
+ we are sure that a ev->type == 0 exists, we just have
+ to assure that the first spev is not the only one */
+ if (ev->next!=NULL)
+ while (ev->next->type!=0) ev=ev->next;
+ }
+ while (nextbeatms<info->millisecsTotal)
+ {
+ // printf("beat2 at %g , %d/%d\n",nextbeatms,i,num);
+ if (i==1) measurems=nextbeatms;
+ insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
+ if (i>num) i=1;
+ nextbeatms+=beatstep;
+ ev=ev->next;
+ }
+ }
+
+ /* Regenerate IDs */
+
+ ev=spev;
+ i=1;
+ while (ev!=NULL)
+ {
+ ev->id=i++;
+ ev=ev->next;
+ }
+
+
+#ifdef PLAYERDEBUG
+ printf("player::Beats Generated\n");
+#endif
+
+}
+
+void MidiPlayer::removeSpecialEvents(void)
+{
+ SpecialEvent * ev=spev;
+ while (spev!=NULL)
+ {
+ ev=spev->next;
+ delete spev;
+ spev=ev;
+ }
+ delete na;
+ na=0;
+}
+
+void MidiPlayer::parseSpecialEvents(void)
+{
+#ifdef PLAYERDEBUG
+ printf("player::Parsing...\n");
+#endif
+ removeSpecialEvents();
+ spev=new SpecialEvent;
+ if (spev==NULL) return;
+ SpecialEvent *pspev=spev;
+ pspev->type=0;
+ pspev->ticks=0;
+ if (na) delete na;
+ na=new NoteArray();
+ if (!na) { delete spev; spev=0L; return; };
+ int trk;
+ int minTrk;
+ double minTime=0;
+ double maxTime;
+ ulong tempo=(ulong)(500000 * (ctl->ratioTempo));
+ ulong firsttempo=0;
+ for (int i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ tracks[i]->changeTempo(tempo);
+ }
+ MidiEvent *ev=new MidiEvent;
+ //ulong mspass;
+ double prevms=0;
+ int spev_id=1;
+ int j;
+ int parsing=1;
+#ifdef REMOVEDUPSTRINGS
+ char lasttext[1024];
+ ulong lasttexttime=0;
+ lasttext[0]=0;
+ int lasttexttype=0;
+#endif
+ while (parsing)
+ {
+ prevms=minTime;
+ trk=0;
+ minTrk=0;
+ maxTime=minTime + 2 * 60000L;
+ minTime=maxTime;
+ parsing=0;
+ while (trk<info->ntracks)
+ {
+ if (tracks[trk]->absMsOfNextEvent()<minTime)
+ {
+ minTrk=trk;
+ minTime=tracks[minTrk]->absMsOfNextEvent();
+ parsing=1;
+ }
+ trk++;
+ }
+ // if ((minTime==maxTime))
+ if (parsing==0)
+ {
+ // parsing=0;
+#ifdef PLAYERDEBUG
+ printf("END of parsing\n");
+#endif
+ }
+ else
+ {
+ // mspass=(ulong)(minTime-prevms);
+ trk=0;
+ while (trk<info->ntracks)
+ {
+ tracks[trk]->currentMs(minTime);
+ trk++;
+ }
+ }
+ trk=minTrk;
+ tracks[trk]->readEvent(ev);
+ switch (ev->command)
+ {
+ case (MIDI_NOTEON) :
+ if (ev->vel==0) na->add((ulong)minTime,ev->chn,0, ev->note);
+ else na->add((ulong)minTime,ev->chn,1,ev->note);
+ break;
+ case (MIDI_NOTEOFF) :
+ na->add((ulong)minTime,ev->chn,0, ev->note);
+ break;
+ case (MIDI_PGM_CHANGE) :
+ na->add((ulong)minTime,ev->chn, 2,ev->patch);
+ break;
+ case (MIDI_SYSTEM_PREFIX) :
+ {
+ if ((ev->command|ev->chn)==META_EVENT)
+ {
+ switch (ev->d1)
+ {
+ case (1) :
+ case (5) :
+ {
+ if (pspev!=NULL)
+ {
+ pspev->absmilliseconds=(ulong)minTime;
+ pspev->type=ev->d1;
+ pspev->id=spev_id++;
+#ifdef PLAYERDEBUG
+ printf("ev->length %ld\n",ev->length);
+
+#endif
+ strncpy(pspev->text,(char *)ev->data,
+ (ev->length>= sizeof(lasttext))? sizeof(lasttext)-1 : (ev->length) );
+ pspev->text[(ev->length>= sizeof(lasttext))? sizeof(lasttext)-1:(ev->length)]=0;
+#ifdef PLAYERDEBUG
+ printf("(%s)(%s)\n",pspev->text,lasttext);
+#endif
+#ifdef REMOVEDUPSTRINGS
+ if ((strcmp(pspev->text,lasttext)!=0)||(pspev->absmilliseconds!=lasttexttime)||(pspev->type!=lasttexttype))
+ {
+ lasttexttime=pspev->absmilliseconds;
+ lasttexttype=pspev->type;
+ strncpy(lasttext, pspev->text, 1024);
+ lasttext[sizeof(lasttext)-1] = 0;
+#endif
+ pspev->next=new SpecialEvent;
+#ifdef PLAYERDEBUG
+ if (pspev->next==NULL) printf("pspev->next=NULL\n");
+#endif
+ pspev=pspev->next;
+#ifdef REMOVEDUPSTRINGS
+ }
+#endif
+ }
+ }
+ break;
+ case (ME_SET_TEMPO) :
+ {
+ if (pspev!=NULL)
+ {
+ pspev->absmilliseconds=(ulong)minTime;
+ pspev->type=3;
+ pspev->id=spev_id++;
+ tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ctl->ratioTempo);
+ pspev->tempo=tempo;
+ if (firsttempo==0) firsttempo=tempo;
+ for (j=0;j<info->ntracks;j++)
+ {
+ tracks[j]->changeTempo(tempo);
+ }
+ pspev->next=new SpecialEvent;
+ pspev=pspev->next;
+ }
+ }
+ break;
+ case (ME_TIME_SIGNATURE) :
+ {
+ if (pspev!=NULL)
+ {
+ pspev->absmilliseconds=(ulong)minTime;
+ pspev->type=6;
+ pspev->id=spev_id++;
+ pspev->num=ev->d2;
+ pspev->den=ev->d3;
+ pspev->next=new SpecialEvent;
+ pspev=pspev->next;
+ }
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ delete ev;
+ pspev->type=0;
+ pspev->absmilliseconds=(ulong)prevms;
+ pspev->next=NULL;
+ if (firsttempo==0) firsttempo=tempo;
+ ctl->tempo=firsttempo;
+
+ //writeSPEV();
+ for (int i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ }
+}
+
+/*
+NoteArray *MidiPlayer::parseNotes(void)
+{
+#ifdef PLAYERDEBUG
+ printf("player::Parsing Notes...\n");
+#endif
+ NoteArray *na=new NoteArray();
+ int trk;
+ int minTrk;
+ double minTime=0;
+ double maxTime;
+ for (int i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ };
+ ulong tempo=1000000;
+ ulong tmp;
+ Midi_event *ev=new Midi_event;
+ //ulong mspass;
+ double prevms=0;
+ int j;
+ int parsing=1;
+ while (parsing)
+ {
+ prevms=minTime;
+ trk=0;
+ minTrk=0;
+ maxTime=minTime + 2 * 60000L;
+ minTime=maxTime;
+ while (trk<info->ntracks)
+ {
+ if (tracks[trk]->absMsOfNextEvent()<minTime)
+ {
+ minTrk=trk;
+ minTime=tracks[minTrk]->absMsOfNextEvent();
+ };
+ trk++;
+ };
+ if ((minTime==maxTime))
+ {
+ parsing=0;
+#ifdef PLAYERDEBUG
+ printf("END of parsing\n");
+#endif
+ }
+ else
+ {
+ // mspass=(ulong)(minTime-prevms);
+ trk=0;
+ while (trk<info->ntracks)
+ {
+ tracks[trk]->currentMs(minTime);
+ trk++;
+ };
+ };
+ trk=minTrk;
+ tracks[trk]->readEvent(ev);
+ if (ev->command==MIDI_NOTEON)
+ {
+ if (ev->vel==0) {printf("note off at %g\n",minTime);na->add((ulong)minTime,ev->chn,0, ev->note);}
+ else {printf("note on at %g\n",minTime);na->add((ulong)minTime,ev->chn,1,ev->note);}
+ }
+ else
+ if (ev->command==MIDI_NOTEOFF) na->add((ulong)minTime,ev->chn,0, ev->note);
+ if (ev->command==MIDI_PGM_CHANGE) na->add((ulong)minTime,ev->chn, 2,ev->patch);
+ if (ev->command==MIDI_SYSTEM_PREFIX)
+ {
+ if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO))
+ {
+ tempo=(ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]);
+ for (j=0;j<info->ntracks;j++)
+ {
+ tracks[j]->changeTempo(tempo);
+ };
+ };
+ };
+
+ };
+
+ delete ev;
+ for (int i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ };
+ return na;
+};
+*/
+
+void MidiPlayer::play(bool calloutput,void output(void))
+{
+#ifdef PLAYERDEBUG
+ printf("Playing...\n");
+#endif
+
+ if (midi->midiPorts()+midi->synthDevices()==0)
+ {
+ fprintf(stderr,"Player :: There are no midi ports !\n");
+ ctl->error=1;
+ return;
+ }
+
+ midi->openDev();
+ if (midi->ok()==0)
+ {
+ fprintf(stderr,"Player :: Couldn't play !\n");
+ ctl->error=1;
+ return;
+ }
+ midi->setVolumePercentage(ctl->volumepercentage);
+ midi->initDev();
+ // parsePatchesUsed(tracks,info,ctl->gm);
+ midi->setPatchesToUse(info->patchesUsed);
+
+ int trk;
+ int minTrk;
+ double minTime=0;
+ double maxTime;
+ int i;
+ ulong tempo=(ulong)(500000 * ctl->ratioTempo);
+ for (i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ tracks[i]->changeTempo(tempo);
+ }
+
+ midi->tmrStart(info->ticksPerCuarterNote);
+ MidiEvent *ev=new MidiEvent;
+ ctl->ev=ev;
+ ctl->ticksTotal=info->ticksTotal;
+ ctl->ticksPlayed=0;
+ //ctl->millisecsPlayed=0;
+ ulong ticksplayed=0;
+ double absTimeAtChangeTempo=0;
+ double absTime=0;
+ double diffTime=0;
+ MidiStatus *midistat;
+ //ulong mspass;
+ double prevms=0;
+ int j;
+ int halt=0;
+ ctl->tempo=tempo;
+ ctl->num=4;
+ ctl->den=4;
+ int playing;
+ ctl->paused=0;
+ if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS))
+ {
+ ctl->moving=1;
+ ctl->message&=~PLAYER_SETPOS;
+ midi->sync(1);
+ midi->tmrStop();
+ midi->closeDev();
+ midistat = new MidiStatus();
+ setPos(ctl->gotomsec,midistat);
+ minTime=ctl->gotomsec;
+ prevms=(ulong)minTime;
+ midi->openDev();
+ midi->tmrStart(info->ticksPerCuarterNote);
+ diffTime=ctl->gotomsec;
+ midistat->sendData(midi,ctl->gm);
+ delete midistat;
+ midi->setPatchesToUse(info->patchesUsed);
+ ctl->moving=0;
+ } else
+ for (i=0;i<16;i++)
+ {
+ if (ctl->forcepgm[i])
+ {
+ midi->chnPatchChange(i, ctl->pgm[i]);
+ }
+ }
+
+ timeval begintv;
+ gettimeofday(&begintv, NULL);
+ ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000;
+ ctl->OK=1;
+ ctl->playing=playing=1;
+
+ while (playing)
+ {
+ /*
+ if (ctl->message!=0)
+ {
+ if (ctl->message & PLAYER_DOPAUSE)
+ {
+ diffTime=minTime;
+ ctl->message&=~PLAYER_DOPAUSE;
+ midi->sync(1);
+ midi->tmrStop();
+ ctl->paused=1;
+ midi->closeDev();
+ while ((ctl->paused)&&(!(ctl->message&PLAYER_DOSTOP))
+ &&(!(ctl->message&PLAYER_HALT))) sleep(1);
+ midi->openDev();
+ midi->tmrStart();
+ ctl->OK=1;
+ printf("Continue playing ... \n");
+ };
+ if (ctl->message & PLAYER_DOSTOP)
+ {
+ ctl->message&=~PLAYER_DOSTOP;
+ playing=0;
+ };
+ if (ctl->message & PLAYER_HALT)
+ {
+ ctl->message&=~PLAYER_HALT;
+ playing=0;
+ halt=1;
+ };
+ if (ctl->message & PLAYER_SETPOS)
+ {
+ ctl->moving=1;
+ ctl->message&=~PLAYER_SETPOS;
+ midi->sync(1);
+ midi->tmrStop();
+ midi->closeDev();
+ midistat = new midiStat();
+ SetPos(ctl->gotomsec,midistat);
+ minTime=ctl->gotomsec;
+ prevms=(ulong)minTime;
+ midi->openDev();
+ midi->tmrStart();
+ diffTime=ctl->gotomsec;
+ ctl->moving=0;
+ midistat->sendData(midi,ctl->gm);
+ delete midistat;
+ ctl->OK=1;
+ while (ctl->OK==1) ;
+ ctl->moving=0;
+ };
+ };
+ */
+ prevms=minTime;
+ // ctl->millisecsPlayed=minTime;
+ trk=0;
+ minTrk=0;
+ maxTime=minTime + 120000L /* milliseconds */;
+ minTime=maxTime;
+ playing=0;
+ while (trk<info->ntracks)
+ {
+ if (tracks[trk]->absMsOfNextEvent()<minTime)
+ {
+ minTrk=trk;
+ minTime=tracks[minTrk]->absMsOfNextEvent();
+ playing=1;
+ }
+ trk++;
+ }
+#ifdef PLAYERDEBUG
+ printf("minTime %g\n",minTime);
+#endif
+ // if ((minTime==maxTime)/* || (minTicks> 60000L)*/)
+ if (playing==0)
+ {
+ // playing=0;
+#ifdef PLAYERDEBUG
+ printf("END of playing\n");
+#endif
+ }
+ else
+ {
+ // mspass=(ulong)(minTime-prevms);
+ trk=0;
+ while (trk<info->ntracks)
+ {
+ tracks[trk]->currentMs(minTime);
+ trk++;
+ }
+ midi->wait(minTime-diffTime);
+ }
+ trk=minTrk;
+ tracks[trk]->readEvent(ev);
+ switch (ev->command)
+ {
+ case (MIDI_NOTEON) :
+ midi->noteOn(ev->chn, ev->note, ev->vel);break;
+ case (MIDI_NOTEOFF):
+ midi->noteOff(ev->chn, ev->note, ev->vel);break;
+ case (MIDI_KEY_PRESSURE) :
+ midi->keyPressure(ev->chn, ev->note,ev->vel);break;
+ case (MIDI_PGM_CHANGE) :
+ if (!ctl->forcepgm[ev->chn])
+ midi->chnPatchChange(ev->chn, (ctl->gm==1)?(ev->patch):(MT32toGM[ev->patch]));break;
+ case (MIDI_CHN_PRESSURE) :
+ midi->chnPressure(ev->chn, ev->vel);break;
+ case (MIDI_PITCH_BEND) :
+ midi->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
+ case (MIDI_CTL_CHANGE) :
+ midi->chnController(ev->chn, ev->ctl,ev->d1);break;
+ case (MIDI_SYSTEM_PREFIX) :
+ if ((ev->command|ev->chn)==META_EVENT)
+ {
+ if ((ev->d1==5)||(ev->d1==1))
+ {
+ ctl->SPEVplayed++;
+ }
+ if (ev->d1==ME_SET_TEMPO)
+ {
+ absTimeAtChangeTempo=absTime;
+ ticksplayed=0;
+ ctl->SPEVplayed++;
+ tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
+#ifdef PLAYERDEBUG
+ printf("Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo);
+#endif
+ midi->tmrSetTempo((int)tempoToMetronomeTempo(tempo));
+ ctl->tempo=tempo;
+ for (j=0;j<info->ntracks;j++)
+ {
+ tracks[j]->changeTempo(tempo);
+ }
+ }
+ if (ev->d1==ME_TIME_SIGNATURE)
+ {
+ ctl->num=ev->d2;
+ ctl->den=ev->d3;
+ ctl->SPEVplayed++;
+ }
+ }
+ break;
+ }
+ if (calloutput)
+ {
+ midi->sync();
+ output();
+ }
+
+ }
+ ctl->ev=NULL;
+ delete ev;
+#ifdef PLAYERDEBUG
+ printf("Syncronizing ...\n");
+#endif
+ if (halt)
+ midi->sync(1);
+ else
+ midi->sync();
+#ifdef PLAYERDEBUG
+ printf("Closing device ...\n");
+#endif
+ midi->allNotesOff();
+ midi->closeDev();
+ ctl->playing=0;
+#ifdef PLAYERDEBUG
+ printf("Bye...\n");
+#endif
+ ctl->OK=1;
+ ctl->finished=1;
+}
+
+
+void MidiPlayer::setPos(ulong gotomsec,MidiStatus *midistat)
+{
+ int trk,minTrk;
+ ulong tempo=(ulong)(500000 * ctl->ratioTempo);
+ double minTime=0,maxTime,prevms=0;
+ int i,j,likeplaying=1;
+
+ MidiEvent *ev=new MidiEvent;
+ ctl->SPEVplayed=0;
+ for (i=0;i<info->ntracks;i++)
+ {
+ tracks[i]->init();
+ tracks[i]->changeTempo(tempo);
+ }
+
+ for (i=0;i<16;i++)
+ {
+ if (ctl->forcepgm[i]) midistat->chnPatchChange(i, ctl->pgm[i]);
+ }
+
+ while (likeplaying)
+ {
+ trk=0;
+ minTrk=0;
+ maxTime=minTime + 120000L; /*milliseconds (2 minutes)*/
+ minTime=maxTime;
+ while (trk<info->ntracks)
+ {
+ if (tracks[trk]->absMsOfNextEvent()<minTime)
+ {
+ minTrk=trk;
+ minTime=tracks[minTrk]->absMsOfNextEvent();
+ }
+ trk++;
+ }
+ if (minTime==maxTime)
+ {
+ likeplaying=0;
+#ifdef GENERAL_DEBUG_MESSAGES
+ printf("END of likeplaying\n");
+#endif
+ }
+ else
+ {
+ if (minTime>=gotomsec)
+ {
+ prevms=gotomsec;
+ likeplaying=0;
+#ifdef GENERAL_DEBUG_MESSAGES
+ printf("Position reached !! \n");
+#endif
+ minTime=gotomsec;
+ }
+ else
+ {
+ prevms=minTime;
+ }
+ trk=0;
+ while (trk<info->ntracks)
+ {
+ tracks[trk]->currentMs(minTime);
+ trk++;
+ }
+ }
+
+ if (likeplaying)
+ {
+ trk=minTrk;
+ tracks[trk]->readEvent(ev);
+ switch (ev->command)
+ {
+ /* case (MIDI_NOTEON) :
+ midistat->noteOn(ev->chn, ev->note, ev->vel);break;
+ case (MIDI_NOTEOFF):
+ midistat->noteOff(ev->chn, ev->note, ev->vel);break;
+ case (MIDI_KEY_PRESSURE) :
+ midistat->keyPressure(ev->chn, ev->note,ev->vel);break;
+ */
+ case (MIDI_PGM_CHANGE) :
+ if (!ctl->forcepgm[ev->chn]) midistat->chnPatchChange(ev->chn, ev->patch);break;
+ case (MIDI_CHN_PRESSURE) :
+ midistat->chnPressure(ev->chn, ev->vel);break;
+ case (MIDI_PITCH_BEND) :
+ midistat->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
+ case (MIDI_CTL_CHANGE) :
+ midistat->chnController(ev->chn, ev->ctl,ev->d1);break;
+ case (MIDI_SYSTEM_PREFIX) :
+ if ((ev->command|ev->chn)==META_EVENT)
+ {
+ if ((ev->d1==5)||(ev->d1==1))
+ {
+ ctl->SPEVplayed++;
+ }
+ if (ev->d1==ME_SET_TEMPO)
+ {
+ ctl->SPEVplayed++;
+ tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
+
+ midistat->tmrSetTempo((int)tempoToMetronomeTempo(tempo));
+ for (j=0;j<info->ntracks;j++)
+ {
+ tracks[j]->changeTempo(tempo);
+ }
+ }
+ if (ev->d1==ME_TIME_SIGNATURE)
+ {
+ ctl->num=ev->d2;
+ ctl->den=ev->d3;
+ ctl->SPEVplayed++;
+ }
+ }
+ break;
+ }
+ }
+ }
+ delete ev;
+ ctl->tempo=tempo;
+}
+
+
+void MidiPlayer::debugSpecialEvents(void)
+{
+ SpecialEvent *pspev=spev;
+ printf("**************************************\n");
+ while ((pspev!=NULL)&&(pspev->type!=0))
+ {
+ 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);
+ pspev=pspev->next;
+ }
+
+}
+
+void MidiPlayer::setParseSong(bool b)
+{
+ parsesong=b;
+}
+
+void MidiPlayer::setGenerateBeats(bool b)
+{
+ generatebeats=b;
+}
+
+void MidiPlayer::setTempoRatio(double ratio)
+{
+ if (songLoaded)
+ {
+ ctl->ratioTempo=ratio;
+ parseInfoData(info,tracks,ctl->ratioTempo);
+ if (parsesong)
+ {
+ parseSpecialEvents();
+ if (generatebeats) generateBeats();
+
+ }
+ }
+ else
+ {
+ ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio);
+ ctl->ratioTempo=ratio;
+ }
+
+}
+
+#undef T2MS
+#undef MS2T