player.cc

00001 /**************************************************************************
00002 
00003     player.cc  - class MidiPlayer. Plays a set of tracks
00004     This file is part of LibKMid 0.9.5
00005     Copyright (C) 1997,98,99,2000  Antonio Larrosa Jimenez
00006     LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libkmid.html            
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Library General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012  
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Library General Public License for more details.
00017  
00018     You should have received a copy of the GNU Library General Public License
00019     along with this library; see the file COPYING.LIB.  If not, write to
00020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA 02110-1301, USA.
00022 
00023     $Id: player.cc 539843 2006-05-11 20:08:40Z mueller $
00024 
00025     Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
00026 
00027 ***************************************************************************/
00028 #include "player.h"
00029 #include "sndcard.h"
00030 #include "midispec.h"
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <sys/time.h>
00034 #include "midistat.h"
00035 #include "mt32togm.h"
00036 
00037 //#define PLAYERDEBUG
00038 //#define GENERAL_DEBUG_MESSAGES
00039 
00040 #define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)
00041 
00042 #define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L))
00043 
00044 #define REMOVEDUPSTRINGS
00045 
00046 MidiPlayer::MidiPlayer(DeviceManager *midi_,PlayerController *pctl)
00047 {
00048   midi=midi_;
00049   info=NULL;
00050   tracks=NULL;
00051   songLoaded=0;
00052   ctl=pctl;
00053   spev=NULL;
00054   na=NULL;
00055   parsesong=true;
00056   generatebeats=false;
00057 }
00058 
00059 MidiPlayer::~MidiPlayer()
00060 {
00061   removeSpecialEvents();
00062   removeSong();
00063 }
00064 
00065 void MidiPlayer::removeSong(void)
00066 {
00067   if ((songLoaded)&&(tracks!=NULL))
00068   {
00069 #ifdef PLAYERDEBUG
00070     printf("Removing song from memory\n");
00071 #endif
00072     int i=0;
00073     while (i<info->ntracks)
00074     {
00075       if (tracks[i]!=NULL) delete tracks[i];
00076       i++;
00077     }
00078     delete tracks;
00079     tracks=NULL;
00080     if (info!=NULL)
00081     {
00082       delete info;
00083       info=NULL;
00084     }
00085   }
00086   songLoaded=0;
00087 }
00088 
00089 int MidiPlayer::loadSong(const char *filename)
00090 {
00091   removeSong();
00092 #ifdef PLAYERDEBUG
00093   printf("Loading Song : %s\n",filename);
00094 #endif
00095   info=new MidiFileInfo;
00096   int ok;
00097   tracks=readMidiFile(filename,info,ok);
00098   if (ok<0) return ok;
00099   if (tracks==NULL) return -4;
00100 
00101   parseInfoData(info,tracks,ctl->ratioTempo);
00102 
00103   if (parsesong)
00104   {
00105     parseSpecialEvents();
00106     if (generatebeats) generateBeats();
00107   }
00108 
00109   songLoaded=1;
00110   return 0;
00111 }
00112 
00113 void MidiPlayer::insertBeat(SpecialEvent *ev,ulong ms,int num,int den)
00114 {
00115   SpecialEvent *beat=new SpecialEvent;
00116   beat->next=ev->next;
00117   ev->next=beat;
00118   beat->id=1;
00119   beat->type=7;
00120   beat->absmilliseconds=ms;
00121   beat->num=num;
00122   beat->den=den;
00123 }
00124 
00125 
00126 void MidiPlayer::generateBeats(void)
00127 {
00128 #ifdef PLAYERDEBUG
00129   printf("player::Generating Beats...\n");
00130 #endif
00131 
00132   if (spev==NULL) return;
00133   SpecialEvent *ev=spev;
00134   SpecialEvent *nextev=ev->next;
00135   ulong tempo=(ulong)(500000 * ctl->ratioTempo);
00136   int i=1;
00137   int num=4;
00138   int den=4;
00139   //    ulong beatstep=((double)tempo*4/(den*1000));
00140   //    ulong beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
00141   double ticksleft=(((double)info->ticksPerCuarterNote*4)/den);
00142 
00143   double beatstep=T2MS(ticksleft);
00144   double nextbeatms=0;
00145   double lastbeatms=0;
00146   double measurems=0;
00147 
00148   while (nextev!=NULL)
00149   {
00150     switch (ev->type)
00151     {
00152       case (0): // End of list
00153     {
00154     };break;
00155       case (1): // Text
00156       case (2): // Lyrics
00157     {
00158     };break;
00159       case (3): // Change Tempo
00160     {
00161       lastbeatms=ev->absmilliseconds;
00162       ticksleft=MS2T(nextbeatms-lastbeatms);
00163       tempo=ev->tempo;
00164       nextbeatms=lastbeatms+T2MS(ticksleft);
00165       // printf("Change at %lu to %d\n",ev->absmilliseconds,ev->tempo);
00166       // beatstep=((double)tempo*4/(den*1000));
00167       beatstep=T2MS(((static_cast<double>(info->ticksPerCuarterNote)*4)/den));
00168     };break;
00169       case (6): // Change number of beats per measure
00170     {
00171       num=ev->num;
00172       i=1;
00173       den=ev->den;
00174       // printf("Change at %lu to %d/%d\n",ev->absmilliseconds,num,den);
00175       // beatstep=((double)tempo*4/(den*1000));
00176       // beatstep=T2MS(info->ticksPerCuarterNote*(4/den));
00177       beatstep=T2MS((((double)info->ticksPerCuarterNote*4)/den));
00178       nextbeatms=ev->absmilliseconds;
00179     };break;
00180     };
00181     if (nextev->absmilliseconds>nextbeatms)
00182     {
00183       //printf("Adding %d,%d\n",num,tot);
00184       //printf("beat at %g , %d/%d\n",nextbeatms,i,num);
00185       //printf("  %ld %d\n",nextev->absmilliseconds,nextev->type);
00186       if (i == 1) {
00187           measurems=nextbeatms;
00188       }
00189       insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
00190       if (i > num) {
00191           i=1;
00192       }
00193       lastbeatms=nextbeatms;
00194       nextbeatms+=beatstep;
00195       // nextbeatms=measurems+beatstep*i;
00196 
00197       ticksleft = ( (static_cast<double>(info->ticksPerCuarterNote)*4) / den);
00198 
00199     }
00200 
00201     ev=ev->next;
00202     nextev=ev->next;
00203   }
00204 
00205   /* ev==NULL doesn't indicate the end of the song, so continue generating beats */
00206 
00207   if (ev!=NULL)
00208   {
00209     if (ev->type==0)
00210     {
00211       ev=spev;
00212       /* Looking if ev->next is NULL is not needed because
00213      we are sure that a ev->type == 0 exists, we just have
00214      to assure that the first spev is not the only one */
00215       if (ev->next!=NULL)
00216     while (ev->next->type!=0) ev=ev->next;
00217     }
00218     while (nextbeatms<info->millisecsTotal)
00219     {
00220       //            printf("beat2 at %g , %d/%d\n",nextbeatms,i,num);
00221       if (i==1) measurems=nextbeatms;
00222       insertBeat(ev, static_cast<unsigned long>(nextbeatms), i++, num);
00223       if (i>num) i=1;
00224       nextbeatms+=beatstep;
00225       ev=ev->next;
00226     }
00227   }
00228 
00229   /* Regenerate IDs */
00230 
00231   ev=spev;
00232   i=1;
00233   while (ev!=NULL)
00234   {
00235     ev->id=i++;
00236     ev=ev->next;
00237   }
00238 
00239 
00240 #ifdef PLAYERDEBUG
00241   printf("player::Beats Generated\n");
00242 #endif
00243 
00244 }
00245 
00246 void MidiPlayer::removeSpecialEvents(void)
00247 {
00248   SpecialEvent * ev=spev;
00249   while (spev!=NULL)
00250   {
00251     ev=spev->next;
00252     delete spev;
00253     spev=ev;
00254   }
00255   delete na;
00256   na=0;
00257 }
00258 
00259 void MidiPlayer::parseSpecialEvents(void)
00260 {
00261 #ifdef PLAYERDEBUG
00262   printf("player::Parsing...\n");
00263 #endif
00264   removeSpecialEvents();
00265   spev=new SpecialEvent;
00266   if (spev==NULL) return;
00267   SpecialEvent *pspev=spev;
00268   pspev->type=0;
00269   pspev->ticks=0;
00270   if (na) delete na;
00271   na=new NoteArray();
00272   if (!na) { delete spev; spev=0L; return; };
00273   int trk;
00274   int minTrk;
00275   double minTime=0;
00276   double maxTime;
00277   ulong tempo=(ulong)(500000 * (ctl->ratioTempo));
00278   ulong firsttempo=0;
00279   for (int i=0;i<info->ntracks;i++)
00280   {
00281     tracks[i]->init();
00282     tracks[i]->changeTempo(tempo);
00283   }
00284   MidiEvent *ev=new MidiEvent;
00285   //ulong mspass;
00286   double prevms=0;
00287   int spev_id=1;
00288   int j;
00289   int parsing=1;
00290 #ifdef REMOVEDUPSTRINGS
00291   char lasttext[1024];
00292   ulong lasttexttime=0;
00293   lasttext[0]=0;
00294   int lasttexttype=0;
00295 #endif
00296   while (parsing)
00297   {
00298     prevms=minTime;
00299     trk=0;
00300     minTrk=0;
00301     maxTime=minTime + 2 * 60000L;
00302     minTime=maxTime;
00303     parsing=0;
00304     while (trk<info->ntracks)
00305     {
00306       if (tracks[trk]->absMsOfNextEvent()<minTime)
00307       {
00308         minTrk=trk;
00309         minTime=tracks[minTrk]->absMsOfNextEvent();
00310         parsing=1;
00311       }
00312       trk++;
00313     }
00314     //  if ((minTime==maxTime))
00315     if (parsing==0)
00316     {
00317       // parsing=0;
00318 #ifdef PLAYERDEBUG
00319       printf("END of parsing\n");
00320 #endif
00321     }
00322     else
00323     {
00324       // mspass=(ulong)(minTime-prevms);
00325       trk=0;
00326       while (trk<info->ntracks)
00327       {
00328         tracks[trk]->currentMs(minTime);
00329         trk++;
00330       }     
00331     }
00332     trk=minTrk;
00333     tracks[trk]->readEvent(ev);
00334     switch (ev->command)
00335     {
00336       case (MIDI_NOTEON) :
00337         if (ev->vel==0) na->add((ulong)minTime,ev->chn,0, ev->note);
00338         else na->add((ulong)minTime,ev->chn,1,ev->note);
00339         break;
00340       case (MIDI_NOTEOFF) :
00341         na->add((ulong)minTime,ev->chn,0, ev->note);
00342         break;
00343       case (MIDI_PGM_CHANGE) :
00344         na->add((ulong)minTime,ev->chn, 2,ev->patch);
00345         break;
00346       case (MIDI_SYSTEM_PREFIX) :
00347         {
00348           if ((ev->command|ev->chn)==META_EVENT)
00349           {
00350             switch (ev->d1)
00351             {
00352               case (1) :
00353               case (5) :
00354                 {
00355                   if (pspev!=NULL)
00356                   {
00357                     pspev->absmilliseconds=(ulong)minTime;
00358                     pspev->type=ev->d1;
00359                     pspev->id=spev_id++;
00360 #ifdef PLAYERDEBUG
00361                     printf("ev->length %ld\n",ev->length);
00362  
00363 #endif
00364                     strncpy(pspev->text,(char *)ev->data,
00365                         (ev->length>= sizeof(lasttext))? sizeof(lasttext)-1 : (ev->length) );
00366                     pspev->text[(ev->length>= sizeof(lasttext))? sizeof(lasttext)-1:(ev->length)]=0;
00367 #ifdef PLAYERDEBUG
00368                     printf("(%s)(%s)\n",pspev->text,lasttext);
00369 #endif
00370 #ifdef REMOVEDUPSTRINGS
00371                     if ((strcmp(pspev->text,lasttext)!=0)||(pspev->absmilliseconds!=lasttexttime)||(pspev->type!=lasttexttype))
00372                     {
00373                       lasttexttime=pspev->absmilliseconds;
00374                       lasttexttype=pspev->type;
00375                       strncpy(lasttext, pspev->text, 1024);
00376                       lasttext[sizeof(lasttext)-1] = 0;
00377 #endif
00378                       pspev->next=new SpecialEvent;
00379 #ifdef PLAYERDEBUG
00380                       if (pspev->next==NULL) printf("pspev->next=NULL\n");
00381 #endif
00382                       pspev=pspev->next;
00383 #ifdef REMOVEDUPSTRINGS
00384                     }
00385 #endif
00386                   }
00387                 }
00388                 break;
00389               case (ME_SET_TEMPO) :
00390                 {
00391                   if (pspev!=NULL)
00392                   {
00393                     pspev->absmilliseconds=(ulong)minTime;
00394                     pspev->type=3;
00395                     pspev->id=spev_id++;
00396                     tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ctl->ratioTempo);
00397                     pspev->tempo=tempo;
00398                     if (firsttempo==0) firsttempo=tempo;
00399                     for (j=0;j<info->ntracks;j++)
00400                     {
00401                       tracks[j]->changeTempo(tempo);
00402                     }
00403                     pspev->next=new SpecialEvent;
00404                     pspev=pspev->next;
00405                   }
00406                 }
00407                 break;
00408               case (ME_TIME_SIGNATURE) :
00409                 {
00410                   if (pspev!=NULL)
00411                   {
00412                     pspev->absmilliseconds=(ulong)minTime;
00413                     pspev->type=6;
00414                     pspev->id=spev_id++;
00415                     pspev->num=ev->d2;
00416                     pspev->den=ev->d3;
00417                     pspev->next=new SpecialEvent;
00418                     pspev=pspev->next;
00419                   }
00420                 }
00421                 break;
00422             }
00423           }
00424         }
00425         break;
00426     }
00427   }
00428  
00429   delete ev;
00430   pspev->type=0;
00431   pspev->absmilliseconds=(ulong)prevms;
00432   pspev->next=NULL;
00433   if (firsttempo==0) firsttempo=tempo;
00434   ctl->tempo=firsttempo;
00435  
00436   //writeSPEV();
00437   for (int i=0;i<info->ntracks;i++)
00438   {
00439     tracks[i]->init();
00440   }
00441 }
00442 
00443 /*
00444 NoteArray *MidiPlayer::parseNotes(void)
00445 {
00446 #ifdef PLAYERDEBUG
00447   printf("player::Parsing Notes...\n");
00448 #endif
00449   NoteArray *na=new NoteArray();
00450   int trk;
00451   int minTrk;
00452   double minTime=0;
00453   double maxTime;
00454   for (int i=0;i<info->ntracks;i++)
00455   {
00456     tracks[i]->init();
00457   }; 
00458   ulong tempo=1000000;
00459   ulong tmp;
00460   Midi_event *ev=new Midi_event;
00461   //ulong mspass;
00462   double prevms=0;
00463   int j;
00464   int parsing=1;
00465   while (parsing)
00466   {
00467     prevms=minTime;
00468     trk=0;
00469     minTrk=0;
00470     maxTime=minTime + 2 * 60000L;
00471     minTime=maxTime;
00472     while (trk<info->ntracks)
00473     {
00474       if (tracks[trk]->absMsOfNextEvent()<minTime)
00475       {
00476     minTrk=trk;
00477     minTime=tracks[minTrk]->absMsOfNextEvent();
00478       };
00479       trk++;
00480     };
00481     if ((minTime==maxTime))
00482     {
00483       parsing=0;
00484 #ifdef PLAYERDEBUG
00485       printf("END of parsing\n");
00486 #endif
00487     }
00488     else
00489     {   
00490       //    mspass=(ulong)(minTime-prevms);
00491       trk=0;
00492       while (trk<info->ntracks)
00493       {
00494     tracks[trk]->currentMs(minTime);
00495     trk++;
00496       };
00497     };
00498     trk=minTrk;
00499     tracks[trk]->readEvent(ev);
00500     if (ev->command==MIDI_NOTEON)
00501     {
00502       if (ev->vel==0) {printf("note off at %g\n",minTime);na->add((ulong)minTime,ev->chn,0, ev->note);}
00503       else {printf("note on at %g\n",minTime);na->add((ulong)minTime,ev->chn,1,ev->note);}
00504     }
00505     else
00506       if (ev->command==MIDI_NOTEOFF) na->add((ulong)minTime,ev->chn,0, ev->note);
00507     if (ev->command==MIDI_PGM_CHANGE) na->add((ulong)minTime,ev->chn, 2,ev->patch);
00508     if (ev->command==MIDI_SYSTEM_PREFIX)
00509     {
00510       if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO))
00511       {
00512     tempo=(ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]);
00513     for (j=0;j<info->ntracks;j++)
00514     {
00515       tracks[j]->changeTempo(tempo);
00516     };
00517       };
00518     };
00519 
00520   };
00521 
00522   delete ev;
00523   for (int i=0;i<info->ntracks;i++)
00524   {
00525     tracks[i]->init();
00526   };
00527   return na;
00528 };
00529 */
00530 
00531 void MidiPlayer::play(bool calloutput,void output(void))
00532 {       
00533 #ifdef PLAYERDEBUG
00534   printf("Playing...\n");
00535 #endif
00536   
00537   if (midi->midiPorts()+midi->synthDevices()==0) 
00538   {
00539     fprintf(stderr,"Player :: There are no midi ports !\n");
00540     ctl->error=1;
00541     return;
00542   }
00543 
00544   midi->openDev();
00545   if (midi->ok()==0) 
00546   {
00547     fprintf(stderr,"Player :: Couldn't play !\n");
00548     ctl->error=1;
00549     return;
00550   }
00551   midi->setVolumePercentage(ctl->volumepercentage);
00552   midi->initDev();
00553   //    parsePatchesUsed(tracks,info,ctl->gm);
00554   midi->setPatchesToUse(info->patchesUsed);
00555 
00556   int trk;
00557   int minTrk;
00558   double minTime=0;
00559   double maxTime;
00560   int i;
00561   ulong tempo=(ulong)(500000 * ctl->ratioTempo);
00562   for (i=0;i<info->ntracks;i++)
00563   {
00564     tracks[i]->init();
00565     tracks[i]->changeTempo(tempo);
00566   }
00567 
00568   midi->tmrStart(info->ticksPerCuarterNote);
00569   MidiEvent *ev=new MidiEvent;
00570   ctl->ev=ev;
00571   ctl->ticksTotal=info->ticksTotal;
00572   ctl->ticksPlayed=0;
00573   //ctl->millisecsPlayed=0;
00574   ulong ticksplayed=0;
00575   double absTimeAtChangeTempo=0;
00576   double absTime=0;
00577   double diffTime=0;
00578   MidiStatus *midistat;
00579   //ulong mspass;
00580   double prevms=0;
00581   int j;
00582   int halt=0;
00583   ctl->tempo=tempo;
00584   ctl->num=4;
00585   ctl->den=4;
00586   int playing;
00587   ctl->paused=0;
00588   if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS))
00589   {
00590     ctl->moving=1;
00591     ctl->message&=~PLAYER_SETPOS;
00592     midi->sync(1);
00593     midi->tmrStop();
00594     midi->closeDev();
00595     midistat = new MidiStatus();
00596     setPos(ctl->gotomsec,midistat);
00597     minTime=ctl->gotomsec;
00598     prevms=(ulong)minTime;
00599     midi->openDev();
00600     midi->tmrStart(info->ticksPerCuarterNote);
00601     diffTime=ctl->gotomsec;
00602     midistat->sendData(midi,ctl->gm);
00603     delete midistat;
00604     midi->setPatchesToUse(info->patchesUsed);
00605     ctl->moving=0;
00606   } else
00607     for (i=0;i<16;i++)
00608     {
00609       if (ctl->forcepgm[i])
00610       {
00611     midi->chnPatchChange(i, ctl->pgm[i]);
00612       }
00613     }
00614 
00615   timeval begintv;
00616   gettimeofday(&begintv, NULL);
00617   ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000;
00618   ctl->OK=1;
00619   ctl->playing=playing=1;
00620 
00621   while (playing)
00622     {
00623       /*
00624       if (ctl->message!=0)
00625       {
00626     if (ctl->message & PLAYER_DOPAUSE)
00627     {
00628       diffTime=minTime;
00629       ctl->message&=~PLAYER_DOPAUSE;
00630       midi->sync(1);
00631       midi->tmrStop();
00632       ctl->paused=1; 
00633       midi->closeDev();
00634       while ((ctl->paused)&&(!(ctl->message&PLAYER_DOSTOP))
00635           &&(!(ctl->message&PLAYER_HALT))) sleep(1);
00636       midi->openDev();
00637       midi->tmrStart();
00638       ctl->OK=1;
00639       printf("Continue playing ... \n");
00640     };
00641     if (ctl->message & PLAYER_DOSTOP)
00642     {
00643       ctl->message&=~PLAYER_DOSTOP;
00644       playing=0;
00645     };
00646     if (ctl->message & PLAYER_HALT)
00647     {
00648       ctl->message&=~PLAYER_HALT;
00649       playing=0;
00650       halt=1;
00651     };
00652     if (ctl->message & PLAYER_SETPOS)
00653     {
00654       ctl->moving=1;
00655       ctl->message&=~PLAYER_SETPOS;
00656       midi->sync(1);
00657       midi->tmrStop();
00658       midi->closeDev();
00659       midistat = new midiStat();
00660       SetPos(ctl->gotomsec,midistat);
00661       minTime=ctl->gotomsec;
00662       prevms=(ulong)minTime;
00663       midi->openDev();
00664       midi->tmrStart();
00665       diffTime=ctl->gotomsec;
00666       ctl->moving=0;
00667       midistat->sendData(midi,ctl->gm);
00668       delete midistat;
00669       ctl->OK=1;
00670       while (ctl->OK==1) ;
00671       ctl->moving=0;
00672     };
00673       };
00674       */
00675     prevms=minTime;
00676       //    ctl->millisecsPlayed=minTime;
00677       trk=0;
00678       minTrk=0;
00679       maxTime=minTime + 120000L /* milliseconds */;
00680     minTime=maxTime;
00681       playing=0;
00682       while (trk<info->ntracks)
00683       {
00684     if (tracks[trk]->absMsOfNextEvent()<minTime)
00685     {
00686       minTrk=trk;
00687       minTime=tracks[minTrk]->absMsOfNextEvent();
00688       playing=1;
00689     }
00690     trk++;
00691       }
00692 #ifdef PLAYERDEBUG
00693       printf("minTime %g\n",minTime);
00694 #endif
00695       // if ((minTime==maxTime)/* || (minTicks> 60000L)*/)
00696       if (playing==0)
00697       {
00698     // playing=0;
00699 #ifdef PLAYERDEBUG
00700     printf("END of playing\n");
00701 #endif
00702       }
00703       else
00704       { 
00705     // mspass=(ulong)(minTime-prevms);
00706     trk=0;
00707     while (trk<info->ntracks)
00708     {
00709       tracks[trk]->currentMs(minTime);
00710       trk++;
00711     }
00712     midi->wait(minTime-diffTime);
00713       }
00714       trk=minTrk;
00715       tracks[trk]->readEvent(ev);
00716       switch (ev->command)
00717       {
00718     case (MIDI_NOTEON) : 
00719       midi->noteOn(ev->chn, ev->note, ev->vel);break;
00720     case (MIDI_NOTEOFF): 
00721       midi->noteOff(ev->chn, ev->note, ev->vel);break;
00722     case (MIDI_KEY_PRESSURE) :
00723       midi->keyPressure(ev->chn, ev->note,ev->vel);break;
00724     case (MIDI_PGM_CHANGE) :
00725       if (!ctl->forcepgm[ev->chn])
00726         midi->chnPatchChange(ev->chn, (ctl->gm==1)?(ev->patch):(MT32toGM[ev->patch]));break;
00727     case (MIDI_CHN_PRESSURE) :
00728       midi->chnPressure(ev->chn, ev->vel);break;
00729     case (MIDI_PITCH_BEND) :
00730       midi->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
00731     case (MIDI_CTL_CHANGE) :
00732       midi->chnController(ev->chn, ev->ctl,ev->d1);break;
00733     case (MIDI_SYSTEM_PREFIX) :
00734       if ((ev->command|ev->chn)==META_EVENT)
00735       {
00736         if ((ev->d1==5)||(ev->d1==1))
00737         {
00738           ctl->SPEVplayed++;
00739         }
00740         if (ev->d1==ME_SET_TEMPO)
00741         {
00742           absTimeAtChangeTempo=absTime;
00743           ticksplayed=0;
00744           ctl->SPEVplayed++;
00745           tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
00746 #ifdef PLAYERDEBUG
00747               printf("Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo);
00748 #endif
00749               midi->tmrSetTempo((int)tempoToMetronomeTempo(tempo));
00750               ctl->tempo=tempo;       
00751           for (j=0;j<info->ntracks;j++)
00752           {
00753         tracks[j]->changeTempo(tempo);
00754           }
00755         }
00756         if (ev->d1==ME_TIME_SIGNATURE)
00757         {
00758           ctl->num=ev->d2;
00759           ctl->den=ev->d3;
00760           ctl->SPEVplayed++;
00761         }
00762       }
00763       break;
00764       }
00765       if (calloutput)
00766       {
00767     midi->sync();
00768     output();
00769       }
00770 
00771     }
00772   ctl->ev=NULL;
00773   delete ev;
00774 #ifdef PLAYERDEBUG
00775   printf("Syncronizing ...\n");
00776 #endif
00777   if (halt) 
00778     midi->sync(1);
00779   else 
00780     midi->sync();
00781 #ifdef PLAYERDEBUG
00782   printf("Closing device ...\n");
00783 #endif
00784   midi->allNotesOff();
00785   midi->closeDev();
00786   ctl->playing=0;
00787 #ifdef PLAYERDEBUG
00788   printf("Bye...\n");
00789 #endif
00790   ctl->OK=1;
00791   ctl->finished=1;
00792 }
00793 
00794 
00795 void MidiPlayer::setPos(ulong gotomsec,MidiStatus *midistat)
00796 {
00797   int trk,minTrk;
00798   ulong tempo=(ulong)(500000 * ctl->ratioTempo);
00799   double minTime=0,maxTime,prevms=0;
00800   int i,j,likeplaying=1;
00801 
00802   MidiEvent *ev=new MidiEvent;
00803   ctl->SPEVplayed=0;
00804   for (i=0;i<info->ntracks;i++)
00805   {
00806     tracks[i]->init();
00807     tracks[i]->changeTempo(tempo);
00808   }
00809 
00810   for (i=0;i<16;i++)
00811   {
00812     if (ctl->forcepgm[i]) midistat->chnPatchChange(i, ctl->pgm[i]);
00813   }
00814 
00815   while (likeplaying)
00816   {
00817     trk=0;
00818     minTrk=0;
00819     maxTime=minTime + 120000L; /*milliseconds (2 minutes)*/
00820     minTime=maxTime;
00821     while (trk<info->ntracks)
00822     {
00823       if (tracks[trk]->absMsOfNextEvent()<minTime)
00824       {
00825     minTrk=trk;
00826     minTime=tracks[minTrk]->absMsOfNextEvent();
00827       }
00828       trk++;
00829     }
00830     if (minTime==maxTime) 
00831     {
00832       likeplaying=0;
00833 #ifdef GENERAL_DEBUG_MESSAGES
00834       printf("END of likeplaying\n");
00835 #endif
00836     }
00837     else
00838     {   
00839       if (minTime>=gotomsec)
00840       {
00841     prevms=gotomsec;
00842     likeplaying=0;
00843 #ifdef GENERAL_DEBUG_MESSAGES
00844     printf("Position reached !! \n");
00845 #endif
00846     minTime=gotomsec;
00847       }
00848       else
00849       {
00850     prevms=minTime;
00851       }
00852       trk=0;
00853       while (trk<info->ntracks)
00854       {
00855     tracks[trk]->currentMs(minTime);
00856     trk++;
00857       }
00858     }
00859 
00860     if (likeplaying)
00861     {
00862       trk=minTrk;
00863       tracks[trk]->readEvent(ev);
00864       switch (ev->command)
00865       {
00866     /*  case (MIDI_NOTEON) : 
00867         midistat->noteOn(ev->chn, ev->note, ev->vel);break;
00868         case (MIDI_NOTEOFF): 
00869         midistat->noteOff(ev->chn, ev->note, ev->vel);break;
00870         case (MIDI_KEY_PRESSURE) :
00871         midistat->keyPressure(ev->chn, ev->note,ev->vel);break;
00872      */
00873     case (MIDI_PGM_CHANGE) :
00874       if (!ctl->forcepgm[ev->chn]) midistat->chnPatchChange(ev->chn, ev->patch);break;
00875     case (MIDI_CHN_PRESSURE) :
00876       midistat->chnPressure(ev->chn, ev->vel);break;
00877     case (MIDI_PITCH_BEND) :
00878       midistat->chnPitchBender(ev->chn, ev->d1,ev->d2);break;
00879     case (MIDI_CTL_CHANGE) :
00880       midistat->chnController(ev->chn, ev->ctl,ev->d1);break;
00881     case (MIDI_SYSTEM_PREFIX) :
00882       if ((ev->command|ev->chn)==META_EVENT)
00883       {
00884         if ((ev->d1==5)||(ev->d1==1))
00885         {
00886           ctl->SPEVplayed++;
00887         }
00888         if (ev->d1==ME_SET_TEMPO)
00889         {
00890           ctl->SPEVplayed++;
00891           tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo);
00892 
00893           midistat->tmrSetTempo((int)tempoToMetronomeTempo(tempo));     
00894           for (j=0;j<info->ntracks;j++)
00895           {
00896         tracks[j]->changeTempo(tempo);
00897           }
00898         }
00899         if (ev->d1==ME_TIME_SIGNATURE)
00900         {
00901           ctl->num=ev->d2;
00902           ctl->den=ev->d3;
00903           ctl->SPEVplayed++;
00904         }
00905       }
00906       break;
00907       }
00908     }
00909   }
00910   delete ev;
00911   ctl->tempo=tempo;
00912 }
00913 
00914 
00915 void MidiPlayer::debugSpecialEvents(void)
00916 {
00917   SpecialEvent *pspev=spev;
00918   printf("**************************************\n");
00919   while ((pspev!=NULL)&&(pspev->type!=0))
00920   {
00921     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);
00922     pspev=pspev->next;
00923   }
00924 
00925 }
00926 
00927 void MidiPlayer::setParseSong(bool b)
00928 {
00929   parsesong=b;
00930 }
00931 
00932 void MidiPlayer::setGenerateBeats(bool b)
00933 {
00934   generatebeats=b;
00935 }
00936 
00937 void MidiPlayer::setTempoRatio(double ratio)
00938 {
00939   if (songLoaded)
00940   {
00941     ctl->ratioTempo=ratio;
00942     parseInfoData(info,tracks,ctl->ratioTempo);
00943     if (parsesong)
00944     {
00945       parseSpecialEvents();
00946       if (generatebeats) generateBeats();
00947 
00948     }
00949   }
00950   else
00951   {
00952     ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio);
00953     ctl->ratioTempo=ratio;
00954   }
00955 
00956 }
00957 
00958 #undef T2MS
00959 #undef MS2T
KDE Home | KDE Accessibility Home | Description of Access Keys