• 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 
49 MidiTrack::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 
88 MidiTrack::~MidiTrack()
89 {
90  delete data;
91  endoftrack=1;
92  currentpos=0;
93  size=0;
94 }
95 
96 int MidiTrack::power2to(int i)
97 {
98  return 1<<i;
99 }
100 
101 ulong 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 
146 int 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 
158 int 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 
174 int 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 
190 void 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 
498 void 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 
519 void 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 
544 void 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 /*
558 double 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.1
This website is maintained by Timothy Pearson.