track.cc

00001 /**************************************************************************
00002 
00003     track.cc  - class track, which has a midi file track and its events
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     Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
00024 
00025 ***************************************************************************/ 
00026 
00027 #include "track.h"
00028 #include <stdlib.h>
00029 #include "sndcard.h"
00030 #include "midispec.h"
00031 #include "midfile.h"
00032 
00033 #ifndef TRUE
00034 #define TRUE 1
00035 #endif
00036 #ifndef FALSE
00037 #define FALSE 0
00038 #endif
00039 
00040 #define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)tPCN)
00041 
00042 #define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)tPCN)/((double)60000L))
00043 
00044 #define PEDANTIC_TRACK
00045 #define CHANGETEMPO_ONLY_IN_TRACK0
00046 //#define TRACKDEBUG
00047 //#define TRACKDEBUG2
00048 
00049 MidiTrack::MidiTrack(FILE *file,int tpcn,int Id)
00050 {
00051   id=Id;
00052   tPCN=tpcn;
00053   currentpos=0;
00054   size=0;
00055   data=0L;
00056   tempo=1000000;
00057   if (feof(file)) 
00058   {
00059     clear();
00060     return; 
00061   };
00062   size=readLong(file);
00063 #ifdef TRACKDEBUG
00064   printf("Track %d : Size %ld\n",id,size);
00065 #endif
00066   data=new uchar[size];
00067   if (data==NULL)
00068   {
00069     perror("track: Not enough memory ?");
00070     exit(-1);
00071   }
00072   ulong rsize=0;
00073   if ((rsize=fread(data,1,size,file))!=size)
00074   {
00075     fprintf(stderr,"track (%d): File is corrupt : Couldn't load track (%ld!=%ld) !!\n", id, rsize, size);
00076     size=rsize;
00077   };
00078   /*
00079      ptrdata=data;
00080      current_ticks=0;
00081      delta_ticks=readVariableLengthValue();
00082      wait_ticks=delta_ticks;
00083      endoftrack=0;
00084    */
00085   init();
00086 }
00087 
00088 MidiTrack::~MidiTrack()
00089 {
00090   delete data;
00091   endoftrack=1;
00092   currentpos=0;
00093   size=0;
00094 }
00095 
00096 int MidiTrack::power2to(int i)
00097 {
00098   return 1<<i;
00099 }
00100 
00101 ulong MidiTrack::readVariableLengthValue(void)
00102 {
00103   ulong dticks=0;
00104 
00105   while ((*ptrdata) & 0x80)
00106   {
00107 #ifdef PEDANTIC_TRACK
00108     if (currentpos>=size)
00109     {
00110       endoftrack=1;
00111       fprintf(stderr, "track (%d) : EndofTrack found by accident !\n",id);
00112       delta_ticks = wait_ticks = ~0;    
00113       time_at_next_event=10000 * 60000L;
00114       return 0;
00115     }
00116     else
00117 #endif
00118     {
00119       dticks=(dticks << 7) | (*ptrdata) & 0x7F;
00120       ptrdata++;currentpos++;
00121     }
00122 
00123   }
00124   dticks=((dticks << 7) | (*ptrdata) & 0x7F);
00125   ptrdata++;currentpos++;
00126 
00127 #ifdef PEDANTIC_TRACK
00128 
00129   if (currentpos>=size)
00130   {
00131     endoftrack=1;
00132     fprintf(stderr,"track (%d): EndofTrack found by accident 2 !\n",id);
00133     dticks=0;
00134     delta_ticks = wait_ticks = ~0;  
00135     time_at_next_event=10000 * 60000L;
00136     return 0;
00137   }
00138 #endif
00139 #ifdef TRACKDEBUG
00140   printfdebug("track(%d): DTICKS : %ld\n",id,dticks);
00141   usleep(10);
00142 #endif
00143   return dticks;
00144 }
00145 
00146 int MidiTrack::ticksPassed (ulong ticks)
00147 {
00148   if (endoftrack==1) return 0;
00149   if (ticks>wait_ticks) 
00150   {
00151     printfdebug("track (%d): ERROR : TICKS PASSED > WAIT TICKS\n", id);
00152     return 1;
00153   }
00154   wait_ticks-=ticks;
00155   return 0;
00156 }
00157 
00158 int MidiTrack::msPassed (ulong ms)
00159 {
00160   if (endoftrack==1) return 0;
00161   current_time+=ms;
00162   //fprintf(stderr, "old + %ld = CURR %g  ", ms,current_time);
00163   if ( current_time>time_at_next_event )
00164   {
00165     fprintf(stderr, "track (%d): ERROR : MS PASSED > WAIT MS\n", id);
00166     return 1;
00167   }
00168 #ifdef TRACKDEBUG
00169   if (current_time==time_at_next_event) printfdebug("track(%d): _OK_",id);
00170 #endif
00171   return 0;
00172 }
00173 
00174 int MidiTrack::currentMs(double ms)
00175 {
00176   if (endoftrack==1) return 0;
00177   current_time=ms;
00178   //printfdebug("CURR %g",current_time);
00179 #ifdef PEDANTIC_TRACK
00180   if (current_time>time_at_next_event) 
00181   {
00182     fprintf(stderr,"track(%d): ERROR : MS PASSED > WAIT MS\n", id);
00183     exit(-1);
00184     return 1;
00185   }
00186 #endif
00187   return 0;
00188 }
00189 
00190 void MidiTrack::readEvent(MidiEvent *ev)
00191 {
00192   int i,j;
00193   if (endoftrack==1) 
00194   {
00195     ev->command=0;
00196     return;
00197   }
00198   /*
00199      printfdebug("...... %d\n",id);
00200      printfdebug("current : %g , tane : %g\n",current_time,time_at_next_event);
00201      printfdebug("......\n");
00202    */
00203   int skip_event=0;
00204   current_time=time_at_next_event;
00205   if (((*ptrdata)&0x80)!=0)
00206   {
00207     ev->command=(*ptrdata);
00208     ptrdata++;currentpos++;
00209     lastcommand=ev->command;
00210   }
00211   else
00212   {
00213     ev->command=lastcommand;
00214   }
00215 
00216 #ifdef PEDANTIC_TRACK
00217   if (currentpos>=size)
00218   {
00219     endoftrack=1;
00220     delta_ticks = wait_ticks = ~0;  
00221     time_at_next_event=10000 * 60000L;
00222     ev->command=MIDI_SYSTEM_PREFIX;
00223     ev->chn=0xF;
00224     ev->d1=ME_END_OF_TRACK;
00225     fprintf(stderr, "track (%d): EndofTrack found by accident 3\n",id);
00226     return;
00227   }
00228 #endif
00229 
00230   ev->chn=ev->command & 0xF;
00231   ev->command=ev->command & 0xF0;
00232   switch (ev->command)
00233   {
00234     case (MIDI_NOTEON) :
00235       ev->note = *ptrdata;ptrdata++;currentpos++;
00236       ev->vel  = *ptrdata;ptrdata++;currentpos++;
00237       if (ev->vel==0)
00238     note[ev->chn][ev->note]=FALSE;
00239       else
00240     note[ev->chn][ev->note]=TRUE;
00241 
00242 #ifdef TRACKDEBUG2
00243       if (ev->chn==6) {
00244     if (ev->vel==0) printfdebug("Note Onf\n");
00245     else printfdebug("Note On\n");
00246       };
00247 #endif
00248       break;
00249     case (MIDI_NOTEOFF) :
00250 #ifdef TRACKDEBUG2
00251       if (ev->chn==6) printfdebug("Note Off\n");
00252 #endif
00253       ev->note = *ptrdata;ptrdata++;currentpos++; 
00254       ev->vel  = *ptrdata;ptrdata++;currentpos++;
00255       note[ev->chn][ev->note]=FALSE;
00256 
00257       break;
00258     case (MIDI_KEY_PRESSURE) :
00259 #ifdef TRACKDEBUG2
00260       if (ev->chn==6) printfdebug ("Key press\n");
00261 #endif
00262       ev->note = *ptrdata;ptrdata++;currentpos++; 
00263       ev->vel  = *ptrdata;ptrdata++;currentpos++;
00264       break;
00265     case (MIDI_PGM_CHANGE) :
00266 #ifdef TRACKDEBUG2
00267       if (ev->chn==6) printfdebug ("Pgm\n");
00268 #endif
00269       ev->patch = *ptrdata;ptrdata++;currentpos++; 
00270       break;
00271     case (MIDI_CHN_PRESSURE) :
00272 #ifdef TRACKDEBUG2
00273       if (ev->chn==6) printfdebug ("Chn press\n");
00274 #endif
00275       ev->vel  = *ptrdata;ptrdata++;currentpos++;
00276       break;
00277     case (MIDI_PITCH_BEND) :
00278 #ifdef TRACKDEBUG2
00279       if (ev->chn==6) printfdebug ("Pitch\n");
00280 #endif
00281       ev->d1 = *ptrdata;ptrdata++;currentpos++; 
00282       ev->d2 = *ptrdata;ptrdata++;currentpos++;
00283       break;
00284     case (MIDI_CTL_CHANGE) :
00285 #ifdef TRACKDEBUG2
00286       if (ev->chn==6) printfdebug (stderr, "Ctl\n");
00287 #endif
00288       ev->ctl = *ptrdata;ptrdata++; currentpos++;
00289       ev->d1  = *ptrdata;ptrdata++;currentpos++;
00290       /*
00291      switch (ev->ctl)
00292      {
00293      case (96) : printfdebug("RPN Increment\n");break;
00294      case (97) : printfdebug("RPN Decrement\n");break;
00295      case (98) : printfdebug("nRPN 98 %d\n",ev->d1);break;
00296      case (99) : printfdebug("nRPN 99 %d\n",ev->d1);break;
00297      case (100) : printfdebug("RPN 100 %d\n",ev->d1);break;
00298      case (101) : printfdebug("RPN 101 %d\n",ev->d1);break;
00299      };
00300        */
00301       break;
00302 
00303     case (MIDI_SYSTEM_PREFIX) :
00304 #ifdef TRACKDEBUG2
00305       if (ev->chn==6) printfdebug ("Sys Prefix\n");
00306 #endif
00307       switch ((ev->command|ev->chn))
00308       {
00309     case (0xF0) : 
00310     case (0xF7) :
00311       ev->length=readVariableLengthValue();
00312 #ifdef PEDANTIC_TRACK
00313       if (endoftrack) 
00314       {
00315         ev->command=MIDI_SYSTEM_PREFIX;
00316         ev->chn=0xF;
00317         ev->d1=ME_END_OF_TRACK;
00318       }
00319       else
00320 #endif
00321       {
00322         ev->data=ptrdata;
00323         ptrdata+=ev->length;currentpos+=ev->length;
00324       }
00325       break;
00326     case (0xFE):
00327     case (0xF8):
00328       //        printfdebug("Active sensing\n");
00329       break;
00330     case (META_EVENT) : 
00331       ev->d1=*ptrdata;ptrdata++;currentpos++;
00332       switch (ev->d1)
00333       {
00334         case (ME_END_OF_TRACK) :
00335           i=0;
00336           j=0;
00337           while ((note[i][j]==FALSE)&&(i<16))
00338           {
00339         j++;
00340         if (j==128) { j=0; i++; };
00341           }
00342           if (i<16) // that is, if there is any key still pressed
00343           {
00344         ptrdata--;currentpos--;
00345         ev->chn=i;
00346         ev->command=MIDI_NOTEOFF;
00347         ev->note = j;
00348         ev->vel  = 0;
00349         note[ev->chn][ev->note]=FALSE;
00350         fprintf(stderr,"Note Off(simulated)\n");
00351         return;
00352           }
00353           else
00354           {
00355         endoftrack=1;
00356         delta_ticks = wait_ticks = ~0;
00357         time_at_next_event=10000 * 60000L;
00358 #ifdef TRACKDEBUG
00359         printfdebug("EndofTrack %d event\n",id);
00360 #endif
00361           }
00362           break;
00363         case (ME_SET_TEMPO):
00364           ev->length=readVariableLengthValue();
00365 #ifdef PEDANTIC_TRACK
00366           if (endoftrack) 
00367           {
00368         ev->command=MIDI_SYSTEM_PREFIX;
00369         ev->chn=0xF;
00370         ev->d1=ME_END_OF_TRACK;
00371           }
00372           else
00373 #endif
00374           {
00375         ev->data=ptrdata;
00376         ptrdata+=ev->length;currentpos+=ev->length;
00377         //  tempo=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]));
00378         //  ticks_from_previous_tempochange=0;
00379         //  time_at_previous_tempochange=current_time;
00380 #ifdef TRACKDEBUG
00381         printfdebug("Track %d : Set Tempo : %ld\n",id,tempo);
00382 #endif
00383 #ifdef CHANGETEMPO_ONLY_IN_TRACK0
00384         if (id!=0) skip_event=1;
00385 #endif
00386           }
00387           break;
00388         case (ME_TIME_SIGNATURE) :
00389           ev->length=*ptrdata;ptrdata++;currentpos++;
00390           ev->d2=*ptrdata;ptrdata++;currentpos++;
00391           ev->d3=power2to(*ptrdata);ptrdata++;currentpos++;
00392           ev->d4=*ptrdata;ptrdata++;currentpos++;
00393           ev->d5=*ptrdata;ptrdata++;currentpos++;
00394 #ifdef TRACKDEBUG
00395           printfdebug("TIME SIGNATURE :\n");    
00396           printfdebug("%d\n",ev->d2);
00397           printfdebug("----  %d metronome , %d number of 32nd notes per quarter note\n",ev->d4,ev->d5);
00398           printfdebug("%d\n",ev->d3);
00399 #endif
00400           break;
00401         case (ME_TRACK_SEQ_NUMBER) :
00402         case (ME_TEXT) :
00403         case (ME_COPYRIGHT) :
00404         case (ME_SEQ_OR_TRACK_NAME) :
00405         case (ME_TRACK_INSTR_NAME) :
00406         case (ME_LYRIC) :
00407         case (ME_MARKER) :
00408         case (ME_CUE_POINT) :
00409         case (ME_CHANNEL_PREFIX) :
00410         case (ME_MIDI_PORT) :
00411         case (ME_SMPTE_OFFSET) :
00412         case (ME_KEY_SIGNATURE) :
00413           ev->length=readVariableLengthValue();
00414 #ifdef PEDANTIC_TRACK
00415           if (endoftrack) 
00416           {
00417         ev->command=MIDI_SYSTEM_PREFIX;
00418         ev->chn=0xF;
00419         ev->d1=ME_END_OF_TRACK;
00420           }
00421           else
00422 #endif
00423           {
00424         ev->data=ptrdata;
00425         ptrdata+=ev->length;currentpos+=ev->length;
00426           }
00427           break;
00428         default: 
00429 #ifdef GENERAL_DEBUG_MESSAGES
00430           fprintf(stderr,"track (%d) : Default handler for meta event " \
00431           "0x%x\n", id, ev->d1);
00432 #endif
00433           ev->length=readVariableLengthValue();
00434 #ifdef PEDANTIC_TRACK
00435           if (endoftrack) 
00436           {
00437         ev->command=MIDI_SYSTEM_PREFIX;
00438         ev->chn=0xF;
00439         ev->d1=ME_END_OF_TRACK;
00440           }
00441           else
00442 #endif
00443           {
00444         ev->data=ptrdata;
00445         ptrdata+=ev->length;currentpos+=ev->length;
00446           }
00447           break;
00448       }
00449       break;
00450     default : 
00451       fprintf(stderr,"track (%d): Default handler for system event 0x%x\n",
00452           id, (ev->command|ev->chn));
00453       break;
00454       }
00455       break;
00456     default : 
00457       fprintf(stderr,"track (%d): Default handler for event 0x%x\n",
00458       id, (ev->command|ev->chn));
00459       break;
00460   }
00461 #ifdef PEDANTIC_TRACK
00462   if (currentpos>=size)
00463   {
00464     endoftrack=1;
00465     delta_ticks = wait_ticks = ~0;  
00466     time_at_next_event=10000 * 60000L;
00467     printfdebug("track (%d): EndofTrack reached\n",id);
00468   }
00469 #endif
00470   if (endoftrack==0)
00471   {
00472     current_ticks+=delta_ticks;
00473     delta_ticks=readVariableLengthValue();
00474 #ifdef PEDANTIC_TRACK
00475     if (endoftrack) 
00476     {
00477       ev->command=MIDI_SYSTEM_PREFIX;
00478       ev->chn=0xF;
00479       ev->d1=ME_END_OF_TRACK;
00480       return;
00481     }
00482 #endif
00483     ticks_from_previous_tempochange+=delta_ticks;
00484 
00485     time_at_next_event=T2MS(ticks_from_previous_tempochange)+time_at_previous_tempochange;
00486     /*
00487        printf("tane2 : %g, ticks : %g, delta_ticks %ld, tempo : %ld\n",
00488        time_at_next_event,ticks_from_previous_tempochange,delta_ticks,tempo);
00489        printf("timeatprevtc %g , curr %g\n",time_at_previous_tempochange,current_time);
00490      */
00491     wait_ticks=delta_ticks;
00492 
00493   }
00494   if (skip_event) readEvent(ev);
00495 }
00496 
00497 
00498 void MidiTrack::clear(void)
00499 {
00500   endoftrack=1;
00501   ptrdata=data;
00502   current_ticks=0;
00503   currentpos=0;
00504 
00505   for (int i=0;i<16;i++)
00506     for (int j=0;j<128;j++)
00507       note[i][j]=FALSE;
00508 
00509   delta_ticks = wait_ticks = ~0;    
00510   time_at_previous_tempochange=0;
00511   current_time=0;
00512   ticks_from_previous_tempochange=0;
00513   tempo=1000000;
00514   time_at_next_event=10000 * 60000L;
00515 
00516 }
00517 
00518 
00519 void MidiTrack::init(void)
00520 {
00521   if (data==0L) { clear(); return; };
00522   endoftrack=0;
00523   ptrdata=data;
00524   current_ticks=0;
00525   currentpos=0;
00526 
00527   for (int i=0;i<16;i++)
00528     for (int j=0;j<128;j++)
00529       note[i][j]=FALSE;
00530 
00531   delta_ticks=readVariableLengthValue();
00532   if (endoftrack) return;
00533   wait_ticks=delta_ticks;
00534 
00535 
00536   time_at_previous_tempochange=0;
00537   current_time=0;
00538   ticks_from_previous_tempochange=wait_ticks;
00539   tempo=1000000;
00540   time_at_next_event=T2MS(delta_ticks);
00541   //printf("tane1 : %g\n",time_at_next_event);
00542 }
00543 
00544 void MidiTrack::changeTempo(ulong t)
00545 {
00546   if (endoftrack==1) return;
00547   if (tempo==t) return;
00548   double ticks;
00549   time_at_previous_tempochange=current_time;
00550   ticks=MS2T(time_at_next_event-current_time);
00551   tempo=t;
00552   time_at_next_event=T2MS(ticks)+current_time;
00553   ticks_from_previous_tempochange=ticks;
00554 
00555 }
00556 
00557 /*
00558 double MidiTrack::absMsOfNextEvent (void) 
00559 {
00560   //printf("%d : %g\n",id,time_at_next_event);
00561   return time_at_next_event;
00562 }
00563 */
00564 
00565 #undef T2MS
00566 #undef MS2T
KDE Home | KDE Accessibility Home | Description of Access Keys