libkmid Library API Documentation

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
KDE Logo
This file is part of the documentation for libkmid Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:32:05 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003