• 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 
42 MidiTrack::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 
81 MidiTrack::~MidiTrack()
82 {
83  delete data;
84  endoftrack=1;
85  currentpos=0;
86  size=0;
87 }
88 
89 int MidiTrack::power2to(int i)
90 {
91  return 1<<i;
92 }
93 
94 ulong 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 
139 int 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 
151 int 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 
167 int 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 
183 void 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 
491 void 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 
512 void 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 
537 void 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 /*
551 double 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.1
This website is maintained by Timothy Pearson.