• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • libtdemid
 

libtdemid

  • libtdemid
track.cpp
1/**************************************************************************
2
3 track.cpp - class track, which has a midi file track and its events
4 This file is part of LibKMid 0.9.5
5 Copyright (C) 1997,98,99,2000 Antonio Larrosa Jimenez
6 LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libtdemid.html
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
23 Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org>
24
25***************************************************************************/
26
27#include "track.h"
28#include <stdlib.h>
29#include "sndcard.h"
30#include "midispec.h"
31#include "midfile.h"
32
33#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)tPCN)
34
35#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)tPCN)/((double)60000L))
36
37#define PEDANTIC_TRACK
38#define CHANGETEMPO_ONLY_IN_TRACK0
39//#define TRACKDEBUG
40//#define TRACKDEBUG2
41
42MidiTrack::MidiTrack(FILE *file,int tpcn,int Id)
43{
44 id=Id;
45 tPCN=tpcn;
46 currentpos=0;
47 size=0;
48 data=0L;
49 tempo=1000000;
50 if (feof(file))
51 {
52 clear();
53 return;
54 };
55 size=readLong(file);
56#ifdef TRACKDEBUG
57 printf("Track %d : Size %ld\n",id,size);
58#endif
59 data=new uchar[size];
60 if (data==NULL)
61 {
62 perror("track: Not enough memory ?");
63 exit(-1);
64 }
65 ulong rsize=0;
66 if ((rsize=fread(data,1,size,file))!=size)
67 {
68 fprintf(stderr,"track (%d): File is corrupt : Couldn't load track (%ld!=%ld) !!\n", id, rsize, size);
69 size=rsize;
70 };
71 /*
72 ptrdata=data;
73 current_ticks=0;
74 delta_ticks=readVariableLengthValue();
75 wait_ticks=delta_ticks;
76 endoftrack=0;
77 */
78 init();
79}
80
81MidiTrack::~MidiTrack()
82{
83 delete data;
84 endoftrack=1;
85 currentpos=0;
86 size=0;
87}
88
89int MidiTrack::power2to(int i)
90{
91 return 1<<i;
92}
93
94ulong MidiTrack::readVariableLengthValue(void)
95{
96 ulong dticks=0;
97
98 while ((*ptrdata) & 0x80)
99 {
100#ifdef PEDANTIC_TRACK
101 if (currentpos>=size)
102 {
103 endoftrack=1;
104 fprintf(stderr, "track (%d) : EndofTrack found by accident !\n",id);
105 delta_ticks = wait_ticks = ~0;
106 time_at_next_event=10000 * 60000L;
107 return 0;
108 }
109 else
110#endif
111 {
112 dticks=(dticks << 7) | (*ptrdata) & 0x7F;
113 ptrdata++;currentpos++;
114 }
115
116 }
117 dticks=((dticks << 7) | (*ptrdata) & 0x7F);
118 ptrdata++;currentpos++;
119
120#ifdef PEDANTIC_TRACK
121
122 if (currentpos>=size)
123 {
124 endoftrack=1;
125 fprintf(stderr,"track (%d): EndofTrack found by accident 2 !\n",id);
126 dticks=0;
127 delta_ticks = wait_ticks = ~0;
128 time_at_next_event=10000 * 60000L;
129 return 0;
130 }
131#endif
132#ifdef TRACKDEBUG
133 printfdebug("track(%d): DTICKS : %ld\n",id,dticks);
134 usleep(10);
135#endif
136 return dticks;
137}
138
139int MidiTrack::ticksPassed (ulong ticks)
140{
141 if (endoftrack==1) return 0;
142 if (ticks>wait_ticks)
143 {
144 printfdebug("track (%d): ERROR : TICKS PASSED > WAIT TICKS\n", id);
145 return 1;
146 }
147 wait_ticks-=ticks;
148 return 0;
149}
150
151int MidiTrack::msPassed (ulong ms)
152{
153 if (endoftrack==1) return 0;
154 current_time+=ms;
155 //fprintf(stderr, "old + %ld = CURR %g ", ms,current_time);
156 if ( current_time>time_at_next_event )
157 {
158 fprintf(stderr, "track (%d): ERROR : MS PASSED > WAIT MS\n", id);
159 return 1;
160 }
161#ifdef TRACKDEBUG
162 if (current_time==time_at_next_event) printfdebug("track(%d): _OK_",id);
163#endif
164 return 0;
165}
166
167int MidiTrack::currentMs(double ms)
168{
169 if (endoftrack==1) return 0;
170 current_time=ms;
171 //printfdebug("CURR %g",current_time);
172#ifdef PEDANTIC_TRACK
173 if (current_time>time_at_next_event)
174 {
175 fprintf(stderr,"track(%d): ERROR : MS PASSED > WAIT MS\n", id);
176 exit(-1);
177 return 1;
178 }
179#endif
180 return 0;
181}
182
183void MidiTrack::readEvent(MidiEvent *ev)
184{
185 int i,j;
186 if (endoftrack==1)
187 {
188 ev->command=0;
189 return;
190 }
191 /*
192 printfdebug("...... %d\n",id);
193 printfdebug("current : %g , tane : %g\n",current_time,time_at_next_event);
194 printfdebug("......\n");
195 */
196 int skip_event=0;
197 current_time=time_at_next_event;
198 if (((*ptrdata)&0x80)!=0)
199 {
200 ev->command=(*ptrdata);
201 ptrdata++;currentpos++;
202 lastcommand=ev->command;
203 }
204 else
205 {
206 ev->command=lastcommand;
207 }
208
209#ifdef PEDANTIC_TRACK
210 if (currentpos>=size)
211 {
212 endoftrack=1;
213 delta_ticks = wait_ticks = ~0;
214 time_at_next_event=10000 * 60000L;
215 ev->command=MIDI_SYSTEM_PREFIX;
216 ev->chn=0xF;
217 ev->d1=ME_END_OF_TRACK;
218 fprintf(stderr, "track (%d): EndofTrack found by accident 3\n",id);
219 return;
220 }
221#endif
222
223 ev->chn=ev->command & 0xF;
224 ev->command=ev->command & 0xF0;
225 switch (ev->command)
226 {
227 case (MIDI_NOTEON) :
228 ev->note = *ptrdata;ptrdata++;currentpos++;
229 ev->vel = *ptrdata;ptrdata++;currentpos++;
230 if (ev->vel==0)
231 note[ev->chn][ev->note]=false;
232 else
233 note[ev->chn][ev->note]=true;
234
235#ifdef TRACKDEBUG2
236 if (ev->chn==6) {
237 if (ev->vel==0) printfdebug("Note Onf\n");
238 else printfdebug("Note On\n");
239 };
240#endif
241 break;
242 case (MIDI_NOTEOFF) :
243#ifdef TRACKDEBUG2
244 if (ev->chn==6) printfdebug("Note Off\n");
245#endif
246 ev->note = *ptrdata;ptrdata++;currentpos++;
247 ev->vel = *ptrdata;ptrdata++;currentpos++;
248 note[ev->chn][ev->note]=false;
249
250 break;
251 case (MIDI_KEY_PRESSURE) :
252#ifdef TRACKDEBUG2
253 if (ev->chn==6) printfdebug ("Key press\n");
254#endif
255 ev->note = *ptrdata;ptrdata++;currentpos++;
256 ev->vel = *ptrdata;ptrdata++;currentpos++;
257 break;
258 case (MIDI_PGM_CHANGE) :
259#ifdef TRACKDEBUG2
260 if (ev->chn==6) printfdebug ("Pgm\n");
261#endif
262 ev->patch = *ptrdata;ptrdata++;currentpos++;
263 break;
264 case (MIDI_CHN_PRESSURE) :
265#ifdef TRACKDEBUG2
266 if (ev->chn==6) printfdebug ("Chn press\n");
267#endif
268 ev->vel = *ptrdata;ptrdata++;currentpos++;
269 break;
270 case (MIDI_PITCH_BEND) :
271#ifdef TRACKDEBUG2
272 if (ev->chn==6) printfdebug ("Pitch\n");
273#endif
274 ev->d1 = *ptrdata;ptrdata++;currentpos++;
275 ev->d2 = *ptrdata;ptrdata++;currentpos++;
276 break;
277 case (MIDI_CTL_CHANGE) :
278#ifdef TRACKDEBUG2
279 if (ev->chn==6) printfdebug (stderr, "Ctl\n");
280#endif
281 ev->ctl = *ptrdata;ptrdata++; currentpos++;
282 ev->d1 = *ptrdata;ptrdata++;currentpos++;
283 /*
284 switch (ev->ctl)
285 {
286 case (96) : printfdebug("RPN Increment\n");break;
287 case (97) : printfdebug("RPN Decrement\n");break;
288 case (98) : printfdebug("nRPN 98 %d\n",ev->d1);break;
289 case (99) : printfdebug("nRPN 99 %d\n",ev->d1);break;
290 case (100) : printfdebug("RPN 100 %d\n",ev->d1);break;
291 case (101) : printfdebug("RPN 101 %d\n",ev->d1);break;
292 };
293 */
294 break;
295
296 case (MIDI_SYSTEM_PREFIX) :
297#ifdef TRACKDEBUG2
298 if (ev->chn==6) printfdebug ("Sys Prefix\n");
299#endif
300 switch ((ev->command|ev->chn))
301 {
302 case (0xF0) :
303 case (0xF7) :
304 ev->length=readVariableLengthValue();
305#ifdef PEDANTIC_TRACK
306 if (endoftrack)
307 {
308 ev->command=MIDI_SYSTEM_PREFIX;
309 ev->chn=0xF;
310 ev->d1=ME_END_OF_TRACK;
311 }
312 else
313#endif
314 {
315 ev->data=ptrdata;
316 ptrdata+=ev->length;currentpos+=ev->length;
317 }
318 break;
319 case (0xFE):
320 case (0xF8):
321 // printfdebug("Active sensing\n");
322 break;
323 case (META_EVENT) :
324 ev->d1=*ptrdata;ptrdata++;currentpos++;
325 switch (ev->d1)
326 {
327 case (ME_END_OF_TRACK) :
328 i=0;
329 j=0;
330 while ((i<16)&&(note[i][j]==false))
331 {
332 j++;
333 if (j==128) { j=0; i++; };
334 }
335 if (i<16) // that is, if there is any key still pressed
336 {
337 ptrdata--;currentpos--;
338 ev->chn=i;
339 ev->command=MIDI_NOTEOFF;
340 ev->note = j;
341 ev->vel = 0;
342 note[ev->chn][ev->note]=false;
343 fprintf(stderr,"Note Off(simulated)\n");
344 return;
345 }
346 else
347 {
348 endoftrack=1;
349 delta_ticks = wait_ticks = ~0;
350 time_at_next_event=10000 * 60000L;
351#ifdef TRACKDEBUG
352 printfdebug("EndofTrack %d event\n",id);
353#endif
354 }
355 break;
356 case (ME_SET_TEMPO):
357 ev->length=readVariableLengthValue();
358#ifdef PEDANTIC_TRACK
359 if (endoftrack)
360 {
361 ev->command=MIDI_SYSTEM_PREFIX;
362 ev->chn=0xF;
363 ev->d1=ME_END_OF_TRACK;
364 }
365 else
366#endif
367 {
368 ev->data=ptrdata;
369 ptrdata+=ev->length;currentpos+=ev->length;
370 // tempo=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]));
371 // ticks_from_previous_tempochange=0;
372 // time_at_previous_tempochange=current_time;
373#ifdef TRACKDEBUG
374 printfdebug("Track %d : Set Tempo : %ld\n",id,tempo);
375#endif
376#ifdef CHANGETEMPO_ONLY_IN_TRACK0
377 if (id!=0) skip_event=1;
378#endif
379 }
380 break;
381 case (ME_TIME_SIGNATURE) :
382 ev->length=*ptrdata;ptrdata++;currentpos++;
383 ev->d2=*ptrdata;ptrdata++;currentpos++;
384 ev->d3=power2to(*ptrdata);ptrdata++;currentpos++;
385 ev->d4=*ptrdata;ptrdata++;currentpos++;
386 ev->d5=*ptrdata;ptrdata++;currentpos++;
387#ifdef TRACKDEBUG
388 printfdebug("TIME SIGNATURE :\n");
389 printfdebug("%d\n",ev->d2);
390 printfdebug("---- %d metronome , %d number of 32nd notes per quarter note\n",ev->d4,ev->d5);
391 printfdebug("%d\n",ev->d3);
392#endif
393 break;
394 case (ME_TRACK_SEQ_NUMBER) :
395 case (ME_TEXT) :
396 case (ME_COPYRIGHT) :
397 case (ME_SEQ_OR_TRACK_NAME) :
398 case (ME_TRACK_INSTR_NAME) :
399 case (ME_LYRIC) :
400 case (ME_MARKER) :
401 case (ME_CUE_POINT) :
402 case (ME_CHANNEL_PREFIX) :
403 case (ME_MIDI_PORT) :
404 case (ME_SMPTE_OFFSET) :
405 case (ME_KEY_SIGNATURE) :
406 ev->length=readVariableLengthValue();
407#ifdef PEDANTIC_TRACK
408 if (endoftrack)
409 {
410 ev->command=MIDI_SYSTEM_PREFIX;
411 ev->chn=0xF;
412 ev->d1=ME_END_OF_TRACK;
413 }
414 else
415#endif
416 {
417 ev->data=ptrdata;
418 ptrdata+=ev->length;currentpos+=ev->length;
419 }
420 break;
421 default:
422#ifdef GENERAL_DEBUG_MESSAGES
423 fprintf(stderr,"track (%d) : Default handler for meta event " \
424 "0x%x\n", id, ev->d1);
425#endif
426 ev->length=readVariableLengthValue();
427#ifdef PEDANTIC_TRACK
428 if (endoftrack)
429 {
430 ev->command=MIDI_SYSTEM_PREFIX;
431 ev->chn=0xF;
432 ev->d1=ME_END_OF_TRACK;
433 }
434 else
435#endif
436 {
437 ev->data=ptrdata;
438 ptrdata+=ev->length;currentpos+=ev->length;
439 }
440 break;
441 }
442 break;
443 default :
444 fprintf(stderr,"track (%d): Default handler for system event 0x%x\n",
445 id, (ev->command|ev->chn));
446 break;
447 }
448 break;
449 default :
450 fprintf(stderr,"track (%d): Default handler for event 0x%x\n",
451 id, (ev->command|ev->chn));
452 break;
453 }
454#ifdef PEDANTIC_TRACK
455 if (currentpos>=size)
456 {
457 endoftrack=1;
458 delta_ticks = wait_ticks = ~0;
459 time_at_next_event=10000 * 60000L;
460 printfdebug("track (%d): EndofTrack reached\n",id);
461 }
462#endif
463 if (endoftrack==0)
464 {
465 current_ticks+=delta_ticks;
466 delta_ticks=readVariableLengthValue();
467#ifdef PEDANTIC_TRACK
468 if (endoftrack)
469 {
470 ev->command=MIDI_SYSTEM_PREFIX;
471 ev->chn=0xF;
472 ev->d1=ME_END_OF_TRACK;
473 return;
474 }
475#endif
476 ticks_from_previous_tempochange+=delta_ticks;
477
478 time_at_next_event=T2MS(ticks_from_previous_tempochange)+time_at_previous_tempochange;
479 /*
480 printf("tane2 : %g, ticks : %g, delta_ticks %ld, tempo : %ld\n",
481 time_at_next_event,ticks_from_previous_tempochange,delta_ticks,tempo);
482 printf("timeatprevtc %g , curr %g\n",time_at_previous_tempochange,current_time);
483 */
484 wait_ticks=delta_ticks;
485
486 }
487 if (skip_event) readEvent(ev);
488}
489
490
491void MidiTrack::clear(void)
492{
493 endoftrack=1;
494 ptrdata=data;
495 current_ticks=0;
496 currentpos=0;
497
498 for (int i=0;i<16;i++)
499 for (int j=0;j<128;j++)
500 note[i][j]=false;
501
502 delta_ticks = wait_ticks = ~0;
503 time_at_previous_tempochange=0;
504 current_time=0;
505 ticks_from_previous_tempochange=0;
506 tempo=1000000;
507 time_at_next_event=10000 * 60000L;
508
509}
510
511
512void MidiTrack::init(void)
513{
514 if (data==0L) { clear(); return; };
515 endoftrack=0;
516 ptrdata=data;
517 current_ticks=0;
518 currentpos=0;
519
520 for (int i=0;i<16;i++)
521 for (int j=0;j<128;j++)
522 note[i][j]=false;
523
524 delta_ticks=readVariableLengthValue();
525 if (endoftrack) return;
526 wait_ticks=delta_ticks;
527
528
529 time_at_previous_tempochange=0;
530 current_time=0;
531 ticks_from_previous_tempochange=wait_ticks;
532 tempo=1000000;
533 time_at_next_event=T2MS(delta_ticks);
534 //printf("tane1 : %g\n",time_at_next_event);
535}
536
537void MidiTrack::changeTempo(ulong t)
538{
539 if (endoftrack==1) return;
540 if (tempo==t) return;
541 double ticks;
542 time_at_previous_tempochange=current_time;
543 ticks=MS2T(time_at_next_event-current_time);
544 tempo=t;
545 time_at_next_event=T2MS(ticks)+current_time;
546 ticks_from_previous_tempochange=ticks;
547
548}
549
550/*
551double MidiTrack::absMsOfNextEvent (void)
552{
553 //printf("%d : %g\n",id,time_at_next_event);
554 return time_at_next_event;
555}
556*/
557
558#undef T2MS
559#undef MS2T
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.cpp:183
MidiTrack::clear
void clear(void)
Clears the internal variables.
Definition: track.cpp:491
MidiTrack::init
void init(void)
Initializes the iterator.
Definition: track.cpp:512
MidiTrack::MidiTrack
MidiTrack(FILE *file, int tpcn, int Id)
Constructor.
Definition: track.cpp:42
MidiTrack::currentMs
int currentMs(double ms)
Returns the current millisecond which the iterator is at.
Definition: track.cpp:167
MidiTrack::~MidiTrack
~MidiTrack()
Destructor.
Definition: track.cpp:81
MidiTrack::ticksPassed
int ticksPassed(ulong ticks)
Makes the iterator advance the given number of ticks.
Definition: track.cpp:139
MidiTrack::changeTempo
void changeTempo(ulong t)
Change the tempo of the song.
Definition: track.cpp:537
MidiTrack::msPassed
int msPassed(ulong ms)
Makes the iterator advance the given number of milliseconds.
Definition: track.cpp:151
MidiEvent
An structure that represents a MIDI event.
Definition: track.h:38
MidiEvent::length
ulong length
Length of the generic data variable.
Definition: track.h:104
MidiEvent::d5
uchar d5
Data 5.
Definition: track.h:94
MidiEvent::command
uchar command
MIDI Command.
Definition: track.h:44
MidiEvent::ctl
uchar ctl
Patch (if command was a controller command)
Definition: track.h:69
MidiEvent::chn
uchar chn
Channel.
Definition: track.h:49
MidiEvent::note
uchar note
Note.
Definition: track.h:54
MidiEvent::d3
uchar d3
Data 3.
Definition: track.h:84
MidiEvent::d2
uchar d2
Data 2.
Definition: track.h:79
MidiEvent::patch
uchar patch
Patch (if command was a change patch command)
Definition: track.h:64
MidiEvent::d1
uchar d1
Data 1.
Definition: track.h:74
MidiEvent::vel
uchar vel
Velocity.
Definition: track.h:59
MidiEvent::d4
uchar d4
Data 4.
Definition: track.h:89
MidiEvent::data
uchar * data
The data for commands like text, sysex, etc.
Definition: track.h:109

libtdemid

Skip menu "libtdemid"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

libtdemid

Skip menu "libtdemid"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for libtdemid by doxygen 1.9.4
This website is maintained by Timothy Pearson.