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