# libkmid Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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., 59 Temple Place - Suite 330,
    00021     Boston, MA 02111-1307, 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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:28:30 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001