player.cc
/**************************************************************************
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: player.cc 539843 2006-05-11 20:08:40Z mueller $
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
MidiEvent::d2
uchar d2
Data 2.
Definition: track.h:79
MidiStatus::chnController
void chnController(uchar chn, uchar ctl, uchar v)
Stores a new value for controller ctl in channel chn.
Definition: midistat.cc:76
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
MidiFileInfo::ntracks
int ntracks
Number of tracks.
Definition: midfile.h:49
MidiStatus::chnPatchChange
void chnPatchChange(uchar chn, uchar patch)
Stores a new patch in channel chn.
Definition: midistat.cc:61
MidiEvent::patch
uchar patch
Patch (if command was a change patch command)
Definition: track.h:64
PlayerController::ratioTempo
volatile double ratioTempo
Ratio to multiply the tempo to.
Definition: player.h:226
DeviceManager::synthDevices
int synthDevices(void)
Returns the number of internal synthesizers available on the system.
Definition: deviceman.h:515
DeviceManager::noteOn
void noteOn(uchar chn, uchar note, uchar vel)
Sends a Note On MIDI event.
Definition: deviceman.cc:496
DeviceManager::initDev
void initDev(void)
Calls MidiOut::initDev() in turn in each of the available devices.
Definition: deviceman.cc:482
SpecialEvent::id
int id
An integer ID, that is assigned in order to each SpecialEvent.
Definition: player.h:53
MidiEvent::command
uchar command
MIDI Command.
Definition: track.h:44
SpecialEvent::type
int type
Type of event.
Definition: player.h:89
DeviceManager::ok
int ok(void)
Definition: deviceman.cc:169
DeviceManager::chnPressure
void chnPressure(uchar chn, uchar vel)
Changes the Pressure (Aftertouch) on a MIDI channel.
Definition: deviceman.cc:516
DeviceManager::keyPressure
void keyPressure(uchar chn, uchar note, uchar vel)
Sends a Key Pressure (or Aftertouch) MIDI event.
Definition: deviceman.cc:506
DeviceManager::tmrStart
void tmrStart(long int tpcn)
Starts the timer.
Definition: deviceman.cc:565
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.cc:190
MidiPlayer::loadSong
int loadSong(const char *filename)
Loads a Song, and parses it (it the parse wasn't disabled with setParseSong() ) . ...
Definition: player.cc:89
DeviceManager::midiPorts
int midiPorts(void)
Returns the number of MIDI ports available on the system.
Definition: deviceman.h:504
MidiStatus
Stores the status of a MIDI device .
Definition: midistat.h:40
DeviceManager::setVolumePercentage
void setVolumePercentage(int i)
Changes the "master" volume of the played events by altering next volume controller events...
Definition: deviceman.cc:810
SpecialEvent::absmilliseconds
ulong absmilliseconds
The absolute millisecond (from the beginning of the song) at which this SpecialEvent object is played...
Definition: player.h:68
DeviceManager::chnController
void chnController(uchar chn, uchar ctl, uchar v)
Sends a Controller event to a MIDI channel.
Definition: deviceman.cc:526
SpecialEvent::den
int den
Denominator .
Definition: player.h:109
MidiEvent::length
ulong length
Length of the generic data variable.
Definition: track.h:104
MidiEvent
An structure that represents a MIDI event.
Definition: track.h:37
DeviceManager::tmrStop
void tmrStop(void)
Stops the timer.
Definition: deviceman.cc:591
MidiPlayer::setParseSong
void setParseSong(bool b=true)
Enables or disables the parsing of the song when loading it.
Definition: player.cc:927
PlayerController::paused
volatile int paused
When the player is paused, paused is set to 1.
Definition: player.h:167
MidiStatus::chnPressure
void chnPressure(uchar chn, uchar vel)
Stores a new channel pressure value in channel chn.
Definition: midistat.cc:66
SpecialEvent::diffmilliseconds
ulong diffmilliseconds
Delta milliseconds from the previous SpecialEvent.
Definition: player.h:60
MidiEvent::d1
uchar d1
Data 1.
Definition: track.h:74
MidiFileInfo
Contains all the information about a MIDI file.
Definition: midfile.h:39
DeviceManager::chnPatchChange
void chnPatchChange(uchar chn, uchar patch)
Changes the patch (instrument) on a MIDI channel.
Definition: deviceman.cc:511
MidiTrack::changeTempo
void changeTempo(ulong t)
Change the tempo of the song.
Definition: track.cc:544
MidiEvent::d3
uchar d3
Data 3.
Definition: track.h:84
PlayerController::playing
volatile int playing
When the player is playing (or paused), playing is set to 1.
Definition: player.h:162
PlayerController::moving
volatile int moving
When the player seeking the position of the song, moving is set to 1.
Definition: player.h:172
PlayerController
PlayerController is a struct that is used by the MidiPlayer object to tell other parts of the applica...
Definition: player.h:138
PlayerController::forcepgm
volatile bool forcepgm[16]
Activate or disactivate the force to use a patch for a given channel.
Definition: player.h:215
DeviceManager::openDev
void openDev(void)
Open the devices.
Definition: deviceman.cc:398
PlayerController::volumepercentage
volatile int volumepercentage
100 means no change, 50 halfs the volume, 200 doubles it (if possible), etc.
Definition: player.h:209
DeviceManager::noteOff
void noteOff(uchar chn, uchar note, uchar vel)
Sends a Note Off MIDI event.
Definition: deviceman.cc:501
MidiPlayer::setTempoRatio
void setTempoRatio(double ratio)
Changes the speed at which a song is played.
Definition: player.cc:937
DeviceManager::setPatchesToUse
int setPatchesToUse(int *patchesused)
Loads the patches you're going to use .
Definition: deviceman.cc:796
MidiTrack::init
void init(void)
Initializes the iterator.
Definition: track.cc:519
PlayerController::finished
volatile int finished
When the player has finished playing a song, finished is set to 1.
Definition: player.h:177
DeviceManager::allNotesOff
void allNotesOff(void)
Sends an all notes off event.
Definition: deviceman.cc:826
NoteArray
Holds a resizeable array of note on/off and patch change events.
Definition: notearray.h:38
MidiStatus::tmrSetTempo
void tmrSetTempo(int v)
Sets the tempo.
Definition: midistat.cc:84
SpecialEvent::num
int num
Numerator .
Definition: player.h:104
SpecialEvent::tempo
ulong tempo
Tempo field .
Definition: player.h:99
MidiTrack::absMsOfNextEvent
double absMsOfNextEvent(void)
Returns the absolute number of milliseconds of the next event.
Definition: track.h:212
MidiPlayer::setGenerateBeats
void setGenerateBeats(bool b=false)
Enables or disables the generation of beats event in a song when loading it.
Definition: player.cc:932
SpecialEvent::text
char text[1024]
Text field .
Definition: player.h:94
MidiFileInfo::ticksPerCuarterNote
int ticksPerCuarterNote
Ticks per cuarter note.
Definition: midfile.h:54
MidiPlayer::play
void play(bool calloutput=false, void output(void)=0)
Plays the song using the DeviceManager object supplied in the constructor.
Definition: player.cc:531
MidiFileInfo::patchesUsed
int patchesUsed[256]
Patches used in the MIDI file.
Definition: midfile.h:77
MidiEvent::data
uchar * data
The data for commands like text, sysex, etc.
Definition: track.h:109
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
MidiEvent::chn
uchar chn
Channel.
Definition: track.h:49
DeviceManager::wait
void wait(double ms)
Sets the number of milliseconds at which the next event will be sent.
Definition: deviceman.cc:537
NoteArray::add
void add(ulong ms, int chn, int cmd, int note)
Adds a note/patch event at a given millisecond.
Definition: notearray.cc:80
DeviceManager::sync
void sync(bool f=0)
Synchronizes with the MIDI buffer.
Definition: deviceman.cc:632
SpecialEvent
This struct stores text, lyrics and change tempo events among others.
Definition: player.h:48
SpecialEvent::next
struct SpecialEvent * next
This struct stores text, lyrics and change tempo events among others.
Definition: player.h:121
DeviceManager::tmrSetTempo
void tmrSetTempo(int v)
Sets the tempo which will be used to convert between ticks and milliseconds.
Definition: deviceman.cc:553
MidiEvent::vel
uchar vel
Velocity.
Definition: track.h:59
DeviceManager::chnPitchBender
void chnPitchBender(uchar chn, uchar lsb, uchar msb)
Changes the Pitch Bender value on a MIDI channel.
Definition: deviceman.cc:521
MidiFileInfo::ticksTotal
ulong ticksTotal
Total number of MIDI ticks.
Definition: midfile.h:59
PlayerController::error
volatile int error
When error is 1, an error has ocurred (i.e.
Definition: player.h:196
MidiPlayer::~MidiPlayer
~MidiPlayer()
Destructor.
Definition: player.cc:59
MidiPlayer::removeSong
void removeSong(void)
Unloads the current song, so that every internal variable is empty and clean for further usage...
Definition: player.cc:65
MidiPlayer::setPos
void setPos(ulong gotomsec, class MidiStatus *midistat)
Sets the position in a song.
Definition: player.cc:795
MidiTrack::currentMs
int currentMs(double ms)
Returns the current millisecond which the iterator is at.
Definition: track.cc:174
DeviceManager
MIDI Device Manager class .
Definition: deviceman.h:47
MidiStatus::chnPitchBender
void chnPitchBender(uchar chn, uchar lsb, uchar msb)
Stores a new pitch bender value in channel chn.
Definition: midistat.cc:71
MidiEvent::ctl
uchar ctl
Patch (if command was a controller command)
Definition: track.h:69
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.cc:89
SpecialEvent::ticks
int ticks
MIDI ticks (from the beginning of the song) at which this event is played.
Definition: player.h:73
DeviceManager::closeDev
void closeDev(void)
Closes the devices, and /dev/sequencer.
Definition: deviceman.cc:449
PlayerController::pgm
volatile int pgm[16]
Force a given patch in each channel at "this" moment, as determined by forcepgm.
Definition: player.h:221
MidiEvent::note
uchar note
Note.
Definition: track.h:54
MidiPlayer::MidiPlayer
MidiPlayer(DeviceManager *midi_, PlayerController *pctl)
Constructor .
Definition: player.cc:46

KDE Home | KDE Accessibility Home | Description of Access Keys