comparison src/midifile.c @ 29:4df6d9714314

Automatic reindent/cleanup pass on the midi code.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 05 Aug 2013 19:17:05 +0300
parents 785057719d9b
children 26741527f3b7
comparison
equal deleted inserted replaced
28:ad838591513a 29:4df6d9714314
30 #include "midifile.h" 30 #include "midifile.h"
31 31
32 /* 32 /*
33 ** Internal Data Structures 33 ** Internal Data Structures
34 */ 34 */
35 typedef struct { 35 typedef struct
36 BYTE note, chn; 36 {
37 BYTE valid, p2; 37 BYTE note, chn;
38 DWORD end_pos; 38 BYTE valid, p2;
39 } MIDI_LAST_NOTE; 39 DWORD end_pos;
40 40 } MIDI_LAST_NOTE;
41 typedef struct { 41
42 BYTE *ptr; 42 typedef struct
43 BYTE *pBase; 43 {
44 BYTE *pEnd; 44 BYTE *ptr;
45 45 BYTE *pBase;
46 DWORD pos; 46 BYTE *pEnd;
47 DWORD dt; 47
48 /* For Reading MIDI Files */ 48 DWORD pos;
49 DWORD sz; /* size of whole iTrack */ 49 DWORD dt;
50 /* For Writing MIDI Files */ 50 /* For Reading MIDI Files */
51 DWORD iBlockSize; /* max size of track */ 51 DWORD sz; /* size of whole iTrack */
52 BYTE iDefaultChannel; /* use for write only */ 52 /* For Writing MIDI Files */
53 BYTE last_status; /* used for running status */ 53 DWORD iBlockSize; /* max size of track */
54 54 BYTE iDefaultChannel; /* use for write only */
55 MIDI_LAST_NOTE LastNote[MAX_TRACK_POLYPHONY]; 55 BYTE last_status; /* used for running status */
56 } MIDI_FILE_TRACK; 56
57 57 MIDI_LAST_NOTE LastNote[MAX_TRACK_POLYPHONY];
58 typedef struct { 58 } MIDI_FILE_TRACK;
59 DWORD iHeaderSize; 59
60 /**/ 60 typedef struct
61 WORD iVersion; /* 0, 1 or 2 */ 61 {
62 WORD iNumTracks; /* number of tracks... (will be 1 for MIDI type 0) */ 62 DWORD iHeaderSize;
63 WORD PPQN; /* pulses per quarter note */ 63 /**/ WORD iVersion; /* 0, 1 or 2 */
64 } MIDI_HEADER; 64 WORD iNumTracks; /* number of tracks... (will be 1 for MIDI type 0) */
65 65 WORD PPQN; /* pulses per quarter note */
66 typedef struct { 66 } MIDI_HEADER;
67 FILE *pFile; 67
68 BOOL bOpenForWriting; 68 typedef struct
69 69 {
70 MIDI_HEADER Header; 70 FILE *pFile;
71 BYTE *ptr; /* to whole data block */ 71 BOOL bOpenForWriting;
72 DWORD file_sz; 72
73 73 MIDI_HEADER Header;
74 MIDI_FILE_TRACK Track[MAX_MIDI_TRACKS]; 74 BYTE *ptr; /* to whole data block */
75 } _MIDI_FILE; 75 DWORD file_sz;
76
77 MIDI_FILE_TRACK Track[MAX_MIDI_TRACKS];
78 } _MIDI_FILE;
76 79
77 80
78 /* 81 /*
79 ** Internal Functions 82 ** Internal Functions
80 */ 83 */
81 #define DT_DEF 32 /* assume maximum delta-time + msg is no more than 32 bytes */ 84 #define DT_DEF 32 /* assume maximum delta-time + msg is no more than 32 bytes */
82 #define SWAP_WORD(w) (WORD)(((w)>>8)|((w)<<8)) 85 #define SWAP_WORD(w) (WORD)(((w)>>8)|((w)<<8))
83 #define SWAP_DWORD(d) (DWORD)((d)>>24)|(((d)>>8)&0xff00)|(((d)<<8)&0xff0000)|(((d)<<24)) 86 #define SWAP_DWORD(d) (DWORD)((d)>>24)|(((d)>>8)&0xff00)|(((d)<<8)&0xff0000)|(((d)<<24))
84 87
85 #define _VAR_CAST _MIDI_FILE *pMF = (_MIDI_FILE *)_pMF 88 #define _VAR_CAST _MIDI_FILE *pMF = (_MIDI_FILE *)_pMF
86 #define IsFilePtrValid(pMF) (pMF) 89 #define IsFilePtrValid(pMF) (pMF)
90 #define IsMessageValid(_x) ((_x)>=msgNoteOff && (_x)<=msgMetaEvent) 93 #define IsMessageValid(_x) ((_x)>=msgNoteOff && (_x)<=msgMetaEvent)
91 94
92 95
93 static BOOL _midiValidateTrack(const _MIDI_FILE *pMF, int iTrack) 96 static BOOL _midiValidateTrack(const _MIDI_FILE *pMF, int iTrack)
94 { 97 {
95 if (!IsFilePtrValid(pMF)) return FALSE; 98 if (!IsFilePtrValid(pMF))
96 99 return FALSE;
97 if (pMF->bOpenForWriting) 100
98 { 101 if (pMF->bOpenForWriting)
99 if (iTrack < 0 || iTrack >= MAX_MIDI_TRACKS) 102 {
100 return FALSE; 103 if (iTrack < 0 || iTrack >= MAX_MIDI_TRACKS)
101 } 104 return FALSE;
102 else /* open for reading */ 105 }
103 { 106 else /* open for reading */
104 if (!pMF->ptr) 107 {
105 return FALSE; 108 if (!pMF->ptr)
106 109 return FALSE;
107 if (iTrack < 0 || iTrack>=pMF->Header.iNumTracks) 110
108 return FALSE; 111 if (iTrack < 0 || iTrack >= pMF->Header.iNumTracks)
109 } 112 return FALSE;
110 113 }
111 return TRUE; 114
112 } 115 return TRUE;
113 116 }
114 static BYTE *_midiWriteVarLen(BYTE *ptr, int n) 117
115 { 118 static BYTE *_midiWriteVarLen(BYTE * ptr, int n)
116 register long buffer; 119 {
117 register long value=n; 120 register long buffer;
118 121 register long value = n;
119 buffer = value & 0x7f; 122
120 while ((value >>= 7) > 0) 123 buffer = value & 0x7f;
121 { 124 while ((value >>= 7) > 0)
122 buffer <<= 8; 125 {
123 buffer |= 0x80; 126 buffer <<= 8;
124 buffer += (value & 0x7f); 127 buffer |= 0x80;
125 } 128 buffer += (value & 0x7f);
126 129 }
127 while (TRUE) 130
128 { 131 while (TRUE)
129 *ptr++ = (BYTE)buffer; 132 {
130 if (buffer & 0x80) 133 *ptr++ = (BYTE) buffer;
131 buffer >>= 8; 134 if (buffer & 0x80)
132 else 135 buffer >>= 8;
133 break; 136 else
134 } 137 break;
135 138 }
136 return(ptr); 139
140 return (ptr);
137 } 141 }
138 142
139 /* Return a ptr to valid block of memory to store a message 143 /* Return a ptr to valid block of memory to store a message
140 ** of up to sz_reqd bytes 144 ** of up to sz_reqd bytes
141 */ 145 */
142 static BYTE *_midiGetPtr(_MIDI_FILE *pMF, int iTrack, int sz_reqd) 146 static BYTE *_midiGetPtr(_MIDI_FILE *pMF, int iTrack, int sz_reqd)
143 { 147 {
144 const DWORD mem_sz_inc = 8092; /* arbitary */ 148 const DWORD mem_sz_inc = 8092; /* arbitary */
145 BYTE *ptr; 149 BYTE *ptr;
146 int curr_offset; 150 int curr_offset;
147 MIDI_FILE_TRACK *pTrack = &pMF->Track[iTrack]; 151 MIDI_FILE_TRACK *pTrack = &pMF->Track[iTrack];
148 152
149 ptr = pTrack->ptr; 153 ptr = pTrack->ptr;
150 if (ptr == NULL || ptr+sz_reqd > pTrack->pEnd) /* need more RAM! */ 154 if (ptr == NULL || ptr + sz_reqd > pTrack->pEnd) /* need more RAM! */
151 { 155 {
152 curr_offset = ptr-pTrack->pBase; 156 curr_offset = ptr - pTrack->pBase;
153 if ((ptr = (BYTE *)realloc(pTrack->pBase, mem_sz_inc+pTrack->iBlockSize))) 157 if ((ptr =
154 { 158 (BYTE *) realloc(pTrack->pBase,
155 pTrack->pBase = ptr; 159 mem_sz_inc + pTrack->iBlockSize)))
156 pTrack->iBlockSize += mem_sz_inc; 160 {
157 pTrack->pEnd = ptr+pTrack->iBlockSize; 161 pTrack->pBase = ptr;
158 /* Move new ptr to continue data entry: */ 162 pTrack->iBlockSize += mem_sz_inc;
159 pTrack->ptr = ptr+curr_offset; 163 pTrack->pEnd = ptr + pTrack->iBlockSize;
160 ptr += curr_offset; 164 /* Move new ptr to continue data entry: */
161 } 165 pTrack->ptr = ptr + curr_offset;
162 else 166 ptr += curr_offset;
163 { 167 }
164 /* NO MEMORY LEFT */ 168 else
165 return NULL; 169 {
166 } 170 /* NO MEMORY LEFT */
167 } 171 return NULL;
168 172 }
169 return ptr; 173 }
174
175 return ptr;
170 } 176 }
171 177
172 178
173 static int _midiGetLength(int ppqn, int iNoteLen, BOOL bOverride) 179 static int _midiGetLength(int ppqn, int iNoteLen, BOOL bOverride)
174 { 180 {
175 int length = ppqn; 181 int length = ppqn;
176 182
177 if (bOverride) 183 if (bOverride)
178 { 184 {
179 length = iNoteLen; 185 length = iNoteLen;
180 } 186 }
181 else 187 else
182 { 188 {
183 switch(iNoteLen) 189 switch (iNoteLen)
184 { 190 {
185 case MIDI_NOTE_DOTTED_MINIM: 191 case MIDI_NOTE_DOTTED_MINIM:
186 length *= 3; 192 length *= 3;
187 break; 193 break;
188 194
189 case MIDI_NOTE_DOTTED_CROCHET: 195 case MIDI_NOTE_DOTTED_CROCHET:
190 length *= 3; 196 length *= 3;
191 length /= 2; 197 length /= 2;
192 break; 198 break;
193 199
194 case MIDI_NOTE_DOTTED_QUAVER: 200 case MIDI_NOTE_DOTTED_QUAVER:
195 length *= 3; 201 length *= 3;
196 length /= 4; 202 length /= 4;
197 break; 203 break;
198 204
199 case MIDI_NOTE_DOTTED_SEMIQUAVER: 205 case MIDI_NOTE_DOTTED_SEMIQUAVER:
200 length *= 3; 206 length *= 3;
201 length /= 8; 207 length /= 8;
202 break; 208 break;
203 209
204 case MIDI_NOTE_DOTTED_SEMIDEMIQUAVER: 210 case MIDI_NOTE_DOTTED_SEMIDEMIQUAVER:
205 length *= 3; 211 length *= 3;
206 length /= 16; 212 length /= 16;
207 break; 213 break;
208 214
209 case MIDI_NOTE_BREVE: 215 case MIDI_NOTE_BREVE:
210 length *= 4; 216 length *= 4;
211 break; 217 break;
212 218
213 case MIDI_NOTE_MINIM: 219 case MIDI_NOTE_MINIM:
214 length *= 2; 220 length *= 2;
215 break; 221 break;
216 222
217 case MIDI_NOTE_QUAVER: 223 case MIDI_NOTE_QUAVER:
218 length /= 2; 224 length /= 2;
219 break; 225 break;
220 226
221 case MIDI_NOTE_SEMIQUAVER: 227 case MIDI_NOTE_SEMIQUAVER:
222 length /= 4; 228 length /= 4;
223 break; 229 break;
224 230
225 case MIDI_NOTE_SEMIDEMIQUAVER: 231 case MIDI_NOTE_SEMIDEMIQUAVER:
226 length /= 8; 232 length /= 8;
227 break; 233 break;
228 234
229 case MIDI_NOTE_TRIPLE_CROCHET: 235 case MIDI_NOTE_TRIPLE_CROCHET:
230 length *= 2; 236 length *= 2;
231 length /= 3; 237 length /= 3;
232 break; 238 break;
233 } 239 }
234 } 240 }
235 241
236 return length; 242 return length;
237 } 243 }
238 244
239 /* 245 /*
240 ** midiFile* Functions 246 ** midiFile* Functions
241 */ 247 */
242 MIDI_FILE *midiFileCreate(const char *pFilename, BOOL bOverwriteIfExists) 248 MIDI_FILE *midiFileCreate(const char *pFilename, BOOL bOverwriteIfExists)
243 { 249 {
244 _MIDI_FILE *pMF = (_MIDI_FILE *)malloc(sizeof(_MIDI_FILE)); 250 _MIDI_FILE *pMF = (_MIDI_FILE *) malloc(sizeof(_MIDI_FILE));
245 int i; 251 int i;
246 252
247 if (!pMF) return NULL; 253 if (!pMF)
248 254 return NULL;
249 if (!bOverwriteIfExists) 255
250 { 256 if (!bOverwriteIfExists)
251 if ((pMF->pFile = fopen(pFilename, "r"))) 257 {
252 { 258 if ((pMF->pFile = fopen(pFilename, "r")))
253 fclose(pMF->pFile); 259 {
254 free(pMF); 260 fclose(pMF->pFile);
255 return NULL; 261 free(pMF);
256 } 262 return NULL;
257 } 263 }
258 264 }
259 if ((pMF->pFile = fopen(pFilename, "wb+"))) 265
260 {/*empty*/} 266 if ((pMF->pFile = fopen(pFilename, "wb+")))
261 else 267 { /*empty */
262 { 268 }
263 free((void *)pMF); 269 else
264 return NULL; 270 {
265 } 271 free((void *) pMF);
266 272 return NULL;
267 pMF->bOpenForWriting = TRUE; 273 }
268 pMF->Header.PPQN = MIDI_PPQN_DEFAULT; 274
269 pMF->Header.iVersion = MIDI_VERSION_DEFAULT; 275 pMF->bOpenForWriting = TRUE;
270 276 pMF->Header.PPQN = MIDI_PPQN_DEFAULT;
271 for(i=0;i<MAX_MIDI_TRACKS;++i) 277 pMF->Header.iVersion = MIDI_VERSION_DEFAULT;
272 { 278
273 pMF->Track[i].pos = 0; 279 for (i = 0; i < MAX_MIDI_TRACKS; ++i)
274 pMF->Track[i].ptr = NULL; 280 {
275 pMF->Track[i].pBase = NULL; 281 pMF->Track[i].pos = 0;
276 pMF->Track[i].pEnd = NULL; 282 pMF->Track[i].ptr = NULL;
277 pMF->Track[i].iBlockSize = 0; 283 pMF->Track[i].pBase = NULL;
278 pMF->Track[i].dt = 0; 284 pMF->Track[i].pEnd = NULL;
279 pMF->Track[i].iDefaultChannel = (BYTE)(i & 0xf); 285 pMF->Track[i].iBlockSize = 0;
280 286 pMF->Track[i].dt = 0;
281 memset(pMF->Track[i].LastNote, '\0', sizeof(pMF->Track[i].LastNote)); 287 pMF->Track[i].iDefaultChannel = (BYTE) (i & 0xf);
282 } 288
283 289 memset(pMF->Track[i].LastNote, '\0', sizeof(pMF->Track[i].LastNote));
284 return (MIDI_FILE *)pMF; 290 }
285 } 291
286 292 return (MIDI_FILE *) pMF;
287 int midiFileSetTracksDefaultChannel(MIDI_FILE *_pMF, int iTrack, int iChannel) 293 }
288 { 294
289 int prev; 295 int midiFileSetTracksDefaultChannel(MIDI_FILE *_pMF, int iTrack,
290 296 int iChannel)
291 _VAR_CAST; 297 {
292 if (!IsFilePtrValid(pMF)) return 0; 298 int prev;
293 if (!IsTrackValid(iTrack)) return 0; 299
294 if (!IsChannelValid(iChannel)) return 0; 300 _VAR_CAST;
295 301 if (!IsFilePtrValid(pMF))
296 /* For programmer each, iChannel is between 1 & 16 - but MIDI uses 302 return 0;
297 ** 0-15. Thus, the fudge factor of 1 :) 303 if (!IsTrackValid(iTrack))
298 */ 304 return 0;
299 prev = pMF->Track[iTrack].iDefaultChannel+1; 305 if (!IsChannelValid(iChannel))
300 pMF->Track[iTrack].iDefaultChannel = (BYTE)(iChannel-1); 306 return 0;
301 return prev; 307
302 } 308 /* For programmer each, iChannel is between 1 & 16 - but MIDI uses
303 309 ** 0-15. Thus, the fudge factor of 1 :)
304 int midiFileGetTracksDefaultChannel(const MIDI_FILE *_pMF, int iTrack) 310 */
305 { 311 prev = pMF->Track[iTrack].iDefaultChannel + 1;
306 _VAR_CAST; 312 pMF->Track[iTrack].iDefaultChannel = (BYTE) (iChannel - 1);
307 if (!IsFilePtrValid(pMF)) return 0; 313 return prev;
308 if (!IsTrackValid(iTrack)) return 0; 314 }
309 315
310 return pMF->Track[iTrack].iDefaultChannel+1; 316 int midiFileGetTracksDefaultChannel(const MIDI_FILE *_pMF, int iTrack)
311 } 317 {
312 318 _VAR_CAST;
313 int midiFileSetPPQN(MIDI_FILE *_pMF, int PPQN) 319 if (!IsFilePtrValid(pMF))
314 { 320 return 0;
315 int prev; 321 if (!IsTrackValid(iTrack))
316 322 return 0;
317 _VAR_CAST; 323
318 if (!IsFilePtrValid(pMF)) return MIDI_PPQN_DEFAULT; 324 return pMF->Track[iTrack].iDefaultChannel + 1;
319 prev = pMF->Header.PPQN; 325 }
320 pMF->Header.PPQN = (WORD)PPQN; 326
321 return prev; 327 int midiFileSetPPQN(MIDI_FILE *_pMF, int PPQN)
322 } 328 {
323 329 int prev;
324 int midiFileGetPPQN(const MIDI_FILE *_pMF) 330
325 { 331 _VAR_CAST;
326 _VAR_CAST; 332 if (!IsFilePtrValid(pMF))
327 if (!IsFilePtrValid(pMF)) return MIDI_PPQN_DEFAULT; 333 return MIDI_PPQN_DEFAULT;
328 return (int)pMF->Header.PPQN; 334 prev = pMF->Header.PPQN;
329 } 335 pMF->Header.PPQN = (WORD) PPQN;
330 336 return prev;
331 int midiFileSetVersion(MIDI_FILE *_pMF, int iVersion) 337 }
332 { 338
333 int prev; 339 int midiFileGetPPQN(const MIDI_FILE *_pMF)
334 340 {
335 _VAR_CAST; 341 _VAR_CAST;
336 if (!IsFilePtrValid(pMF)) return MIDI_VERSION_DEFAULT; 342 if (!IsFilePtrValid(pMF))
337 if (iVersion<0 || iVersion>2) return MIDI_VERSION_DEFAULT; 343 return MIDI_PPQN_DEFAULT;
338 prev = pMF->Header.iVersion; 344 return (int) pMF->Header.PPQN;
339 pMF->Header.iVersion = (WORD)iVersion; 345 }
340 return prev; 346
341 } 347 int midiFileSetVersion(MIDI_FILE *_pMF, int iVersion)
342 348 {
343 int midiFileGetVersion(const MIDI_FILE *_pMF) 349 int prev;
344 { 350
345 _VAR_CAST; 351 _VAR_CAST;
346 if (!IsFilePtrValid(pMF)) return MIDI_VERSION_DEFAULT; 352 if (!IsFilePtrValid(pMF))
347 return pMF->Header.iVersion; 353 return MIDI_VERSION_DEFAULT;
348 } 354 if (iVersion < 0 || iVersion > 2)
349 355 return MIDI_VERSION_DEFAULT;
350 MIDI_FILE *midiFileOpen(const char *pFilename) 356 prev = pMF->Header.iVersion;
351 { 357 pMF->Header.iVersion = (WORD) iVersion;
352 FILE *fp = fopen(pFilename, "rb"); 358 return prev;
353 _MIDI_FILE *pMF = NULL; 359 }
354 BYTE *ptr; 360
355 BOOL bValidFile=FALSE; 361 int midiFileGetVersion(const MIDI_FILE *_pMF)
356 long size; 362 {
357 363 _VAR_CAST;
358 if (fp) 364 if (!IsFilePtrValid(pMF))
359 { 365 return MIDI_VERSION_DEFAULT;
360 if ((pMF = (_MIDI_FILE *)malloc(sizeof(_MIDI_FILE)))) 366 return pMF->Header.iVersion;
361 { 367 }
362 fseek(fp, 0L, SEEK_END); 368
363 size = ftell(fp); 369 MIDI_FILE *midiFileOpen(const char *pFilename)
364 if ((pMF->ptr = (BYTE *)malloc(size))) 370 {
365 { 371 FILE *fp = fopen(pFilename, "rb");
366 fseek(fp, 0L, SEEK_SET); 372 _MIDI_FILE *pMF = NULL;
367 fread(pMF->ptr, sizeof(BYTE), size, fp); 373 BYTE *ptr;
368 /* Is this a valid MIDI file ? */ 374 BOOL bValidFile = FALSE;
369 ptr = pMF->ptr; 375 long size;
370 if (*(ptr+0) == 'M' && *(ptr+1) == 'T' && 376
371 *(ptr+2) == 'h' && *(ptr+3) == 'd') 377 if (fp)
372 { 378 {
373 DWORD dwData; 379 if ((pMF = (_MIDI_FILE *) malloc(sizeof(_MIDI_FILE))))
374 WORD wData; 380 {
375 int i; 381 fseek(fp, 0L, SEEK_END);
376 382 size = ftell(fp);
377 dwData = *((DWORD *)(ptr+4)); 383 if ((pMF->ptr = (BYTE *) malloc(size)))
378 pMF->Header.iHeaderSize = SWAP_DWORD(dwData); 384 {
379 385 fseek(fp, 0L, SEEK_SET);
380 wData = *((WORD *)(ptr+8)); 386 fread(pMF->ptr, sizeof(BYTE), size, fp);
381 pMF->Header.iVersion = (WORD)SWAP_WORD(wData); 387 /* Is this a valid MIDI file ? */
382 388 ptr = pMF->ptr;
383 wData = *((WORD *)(ptr+10)); 389 if (*(ptr + 0) == 'M' && *(ptr + 1) == 'T' &&
384 pMF->Header.iNumTracks = (WORD)SWAP_WORD(wData); 390 *(ptr + 2) == 'h' && *(ptr + 3) == 'd')
385 391 {
386 wData = *((WORD *)(ptr+12)); 392 DWORD dwData;
387 pMF->Header.PPQN = (WORD)SWAP_WORD(wData); 393 WORD wData;
388 394 int i;
389 ptr += pMF->Header.iHeaderSize+8; 395
390 /* 396 dwData = *((DWORD *) (ptr + 4));
391 ** Get all tracks 397 pMF->Header.iHeaderSize = SWAP_DWORD(dwData);
392 */ 398
393 for(i=0;i<MAX_MIDI_TRACKS;++i) 399 wData = *((WORD *) (ptr + 8));
394 { 400 pMF->Header.iVersion = (WORD) SWAP_WORD(wData);
395 pMF->Track[i].pos = 0; 401
396 pMF->Track[i].last_status = 0; 402 wData = *((WORD *) (ptr + 10));
397 } 403 pMF->Header.iNumTracks = (WORD) SWAP_WORD(wData);
398 404
399 for(i=0;i<pMF->Header.iNumTracks;++i) 405 wData = *((WORD *) (ptr + 12));
400 { 406 pMF->Header.PPQN = (WORD) SWAP_WORD(wData);
401 pMF->Track[i].pBase = ptr; 407
402 pMF->Track[i].ptr = ptr+8; 408 ptr += pMF->Header.iHeaderSize + 8;
403 dwData = *((DWORD *)(ptr+4)); 409 /*
404 pMF->Track[i].sz = SWAP_DWORD(dwData); 410 ** Get all tracks
405 pMF->Track[i].pEnd = ptr+pMF->Track[i].sz+8; 411 */
406 ptr += pMF->Track[i].sz+8; 412 for (i = 0; i < MAX_MIDI_TRACKS; ++i)
407 } 413 {
408 414 pMF->Track[i].pos = 0;
409 pMF->bOpenForWriting = FALSE; 415 pMF->Track[i].last_status = 0;
410 pMF->pFile = NULL; 416 }
411 bValidFile = TRUE; 417
412 } 418 for (i = 0; i < pMF->Header.iNumTracks; ++i)
413 } 419 {
414 } 420 pMF->Track[i].pBase = ptr;
415 421 pMF->Track[i].ptr = ptr + 8;
416 fclose(fp); 422 dwData = *((DWORD *) (ptr + 4));
417 } 423 pMF->Track[i].sz = SWAP_DWORD(dwData);
418 424 pMF->Track[i].pEnd = ptr + pMF->Track[i].sz + 8;
419 if (!bValidFile) 425 ptr += pMF->Track[i].sz + 8;
420 { 426 }
421 if (pMF) free((void *)pMF); 427
422 return NULL; 428 pMF->bOpenForWriting = FALSE;
423 } 429 pMF->pFile = NULL;
424 430 bValidFile = TRUE;
425 return (MIDI_FILE *)pMF; 431 }
426 } 432 }
427 433 }
428 typedef struct { 434
429 int iIdx; 435 fclose(fp);
430 int iEndPos; 436 }
431 } MIDI_END_POINT; 437
438 if (!bValidFile)
439 {
440 if (pMF)
441 free((void *) pMF);
442 return NULL;
443 }
444
445 return (MIDI_FILE *) pMF;
446 }
447
448 typedef struct
449 {
450 int iIdx;
451 int iEndPos;
452 } MIDI_END_POINT;
432 453
433 static int qs_cmp_pEndPoints(const void *e1, const void *e2) 454 static int qs_cmp_pEndPoints(const void *e1, const void *e2)
434 { 455 {
435 MIDI_END_POINT *p1 = (MIDI_END_POINT *)e1; 456 MIDI_END_POINT *p1 = (MIDI_END_POINT *) e1;
436 MIDI_END_POINT *p2 = (MIDI_END_POINT *)e2; 457 MIDI_END_POINT *p2 = (MIDI_END_POINT *) e2;
437 458
438 return p1->iEndPos-p2->iEndPos; 459 return p1->iEndPos - p2->iEndPos;
439 } 460 }
440 461
441 BOOL midiFileFlushTrack(MIDI_FILE *_pMF, int iTrack, BOOL bFlushToEnd, DWORD dwEndTimePos) 462 BOOL midiFileFlushTrack(MIDI_FILE *_pMF, int iTrack, BOOL bFlushToEnd,
442 { 463 DWORD dwEndTimePos)
443 int sz; 464 {
444 BYTE *ptr; 465 int sz;
445 MIDI_END_POINT *pEndPoints; 466 BYTE *ptr;
446 int num, i, mx_pts; 467 MIDI_END_POINT *pEndPoints;
447 BOOL bNoChanges = TRUE; 468 int num, i, mx_pts;
448 469 BOOL bNoChanges = TRUE;
449 _VAR_CAST; 470
450 if (!IsFilePtrValid(pMF)) return FALSE; 471 _VAR_CAST;
451 if (!_midiValidateTrack(pMF, iTrack)) return FALSE; 472 if (!IsFilePtrValid(pMF))
452 sz = sizeof(pMF->Track[0].LastNote)/sizeof(pMF->Track[0].LastNote[0]); 473 return FALSE;
453 474 if (!_midiValidateTrack(pMF, iTrack))
454 /* 475 return FALSE;
455 ** Flush all 476 sz = sizeof(pMF->Track[0].LastNote) / sizeof(pMF->Track[0].LastNote[0]);
456 */ 477
457 pEndPoints = (MIDI_END_POINT *)malloc(sz * sizeof(MIDI_END_POINT)); 478 /*
458 mx_pts = 0; 479 ** Flush all
459 for(i=0;i<sz;++i) 480 */
460 if (pMF->Track[iTrack].LastNote[i].valid) 481 pEndPoints = (MIDI_END_POINT *) malloc(sz * sizeof(MIDI_END_POINT));
461 { 482 mx_pts = 0;
462 pEndPoints[mx_pts].iIdx = i; 483 for (i = 0; i < sz; ++i)
463 pEndPoints[mx_pts].iEndPos = pMF->Track[iTrack].LastNote[i].end_pos; 484 if (pMF->Track[iTrack].LastNote[i].valid)
464 mx_pts++; 485 {
465 } 486 pEndPoints[mx_pts].iIdx = i;
466 487 pEndPoints[mx_pts].iEndPos =
467 if (bFlushToEnd) 488 pMF->Track[iTrack].LastNote[i].end_pos;
468 { 489 mx_pts++;
469 if (mx_pts) 490 }
470 dwEndTimePos = pEndPoints[mx_pts-1].iEndPos; 491
471 else 492 if (bFlushToEnd)
472 dwEndTimePos = pMF->Track[iTrack].pos; 493 {
473 } 494 if (mx_pts)
474 495 dwEndTimePos = pEndPoints[mx_pts - 1].iEndPos;
475 if (mx_pts) 496 else
476 { 497 dwEndTimePos = pMF->Track[iTrack].pos;
477 /* Sort, smallest first, and add the note off msgs */ 498 }
478 qsort(pEndPoints, mx_pts, sizeof(MIDI_END_POINT), qs_cmp_pEndPoints); 499
479 500 if (mx_pts)
480 i = 0; 501 {
481 while ((dwEndTimePos >= (DWORD)pEndPoints[i].iEndPos || bFlushToEnd) && i<mx_pts) 502 /* Sort, smallest first, and add the note off msgs */
482 { 503 qsort(pEndPoints, mx_pts, sizeof(MIDI_END_POINT), qs_cmp_pEndPoints);
483 ptr = _midiGetPtr(pMF, iTrack, DT_DEF); 504
484 if (!ptr) 505 i = 0;
485 return FALSE; 506 while ((dwEndTimePos >= (DWORD) pEndPoints[i].iEndPos || bFlushToEnd)
486 507 && i < mx_pts)
487 num = pEndPoints[i].iIdx; /* get 'LastNote' index */ 508 {
488 509 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
489 ptr = _midiWriteVarLen(ptr, pMF->Track[iTrack].LastNote[num].end_pos - pMF->Track[iTrack].pos); 510 if (!ptr)
490 /* msgNoteOn msgNoteOff */ 511 return FALSE;
491 *ptr++ = (BYTE)(msgNoteOff | pMF->Track[iTrack].LastNote[num].chn); 512
492 *ptr++ = pMF->Track[iTrack].LastNote[num].note; 513 num = pEndPoints[i].iIdx; /* get 'LastNote' index */
493 *ptr++ = 0; 514
494 515 ptr =
495 pMF->Track[iTrack].LastNote[num].valid = FALSE; 516 _midiWriteVarLen(ptr,
496 pMF->Track[iTrack].pos = pMF->Track[iTrack].LastNote[num].end_pos; 517 pMF->Track[iTrack].LastNote[num].end_pos -
497 518 pMF->Track[iTrack].pos);
498 pMF->Track[iTrack].ptr = ptr; 519 /* msgNoteOn msgNoteOff */
499 520 *ptr++ =
500 ++i; 521 (BYTE) (msgNoteOff | pMF->Track[iTrack].LastNote[num].chn);
501 bNoChanges = FALSE; 522 *ptr++ = pMF->Track[iTrack].LastNote[num].note;
502 } 523 *ptr++ = 0;
503 } 524
504 525 pMF->Track[iTrack].LastNote[num].valid = FALSE;
505 free((void *)pEndPoints); 526 pMF->Track[iTrack].pos = pMF->Track[iTrack].LastNote[num].end_pos;
506 /* 527
507 ** Re-calc current position 528 pMF->Track[iTrack].ptr = ptr;
508 */ 529
509 pMF->Track[iTrack].dt = dwEndTimePos - pMF->Track[iTrack].pos; 530 ++i;
510 531 bNoChanges = FALSE;
511 return TRUE; 532 }
512 } 533 }
513 534
514 BOOL midiFileSyncTracks(MIDI_FILE *_pMF, int iTrack1, int iTrack2) 535 free((void *) pEndPoints);
515 { 536 /*
516 int p1, p2; 537 ** Re-calc current position
517 538 */
518 _VAR_CAST; 539 pMF->Track[iTrack].dt = dwEndTimePos - pMF->Track[iTrack].pos;
519 if (!IsFilePtrValid(pMF)) return FALSE; 540
520 if (!IsTrackValid(iTrack1)) return FALSE; 541 return TRUE;
521 if (!IsTrackValid(iTrack2)) return FALSE; 542 }
522 543
523 p1 = pMF->Track[iTrack1].pos + pMF->Track[iTrack1].dt; 544 BOOL midiFileSyncTracks(MIDI_FILE *_pMF, int iTrack1, int iTrack2)
524 p2 = pMF->Track[iTrack2].pos + pMF->Track[iTrack2].dt; 545 {
525 546 int p1, p2;
526 if (p1 < p2) midiTrackIncTime(pMF, iTrack1, p2-p1, TRUE); 547
527 else if (p2 < p1) midiTrackIncTime(pMF, iTrack2, p1-p2, TRUE); 548 _VAR_CAST;
528 549 if (!IsFilePtrValid(pMF))
529 return TRUE; 550 return FALSE;
530 } 551 if (!IsTrackValid(iTrack1))
531 552 return FALSE;
532 553 if (!IsTrackValid(iTrack2))
533 BOOL midiFileClose(MIDI_FILE *_pMF) 554 return FALSE;
534 { 555
535 _VAR_CAST; 556 p1 = pMF->Track[iTrack1].pos + pMF->Track[iTrack1].dt;
536 if (!IsFilePtrValid(pMF)) return FALSE; 557 p2 = pMF->Track[iTrack2].pos + pMF->Track[iTrack2].dt;
537 558
538 if (pMF->bOpenForWriting) 559 if (p1 < p2)
539 { 560 midiTrackIncTime(pMF, iTrack1, p2 - p1, TRUE);
540 WORD iNumTracks = 0; 561 else if (p2 < p1)
541 WORD wTest = 256; 562 midiTrackIncTime(pMF, iTrack2, p1 - p2, TRUE);
542 BOOL bSwap = FALSE; 563
543 int i; 564 return TRUE;
544 565 }
545 /* Intel processor style-endians need byte swap :( */ 566
546 if (*((BYTE *)&wTest) == 0) 567
547 bSwap = TRUE; 568 BOOL midiFileClose(MIDI_FILE *_pMF)
548 569 {
549 /* Flush our buffers */ 570 _VAR_CAST;
550 for(i=0;i<MAX_MIDI_TRACKS;++i) 571 if (!IsFilePtrValid(pMF))
551 { 572 return FALSE;
552 if (pMF->Track[i].ptr) 573
553 { 574 if (pMF->bOpenForWriting)
554 midiSongAddEndSequence(pMF, i); 575 {
555 midiFileFlushTrack(pMF, i, TRUE, 0); 576 WORD iNumTracks = 0;
556 iNumTracks++; 577 WORD wTest = 256;
557 } 578 BOOL bSwap = FALSE;
558 } 579 int i;
559 /* 580
560 ** Header 581 /* Intel processor style-endians need byte swap :( */
561 */ 582 if (*((BYTE *) & wTest) == 0)
562 { 583 bSwap = TRUE;
563 const BYTE mthd[4] = {'M', 'T', 'h', 'd'}; 584
564 DWORD dwData; 585 /* Flush our buffers */
565 WORD wData; 586 for (i = 0; i < MAX_MIDI_TRACKS; ++i)
566 WORD version, PPQN; 587 {
567 588 if (pMF->Track[i].ptr)
568 fwrite(mthd, sizeof(BYTE), 4, pMF->pFile); 589 {
569 dwData = 6; 590 midiSongAddEndSequence(pMF, i);
570 if (bSwap) dwData = SWAP_DWORD(dwData); 591 midiFileFlushTrack(pMF, i, TRUE, 0);
571 fwrite(&dwData, sizeof(DWORD), 1, pMF->pFile); 592 iNumTracks++;
572 593 }
573 wData = (WORD)(iNumTracks==1?pMF->Header.iVersion:1); 594 }
574 if (bSwap) version = SWAP_WORD(wData); else version = (WORD)wData; 595 /*
575 if (bSwap) iNumTracks = SWAP_WORD(iNumTracks); 596 ** Header
576 wData = pMF->Header.PPQN; 597 */
577 if (bSwap) PPQN = SWAP_WORD(wData); else PPQN = wData; 598 {
578 fwrite(&version, sizeof(WORD), 1, pMF->pFile); 599 const BYTE mthd[4] = { 'M', 'T', 'h', 'd' };
579 fwrite(&iNumTracks, sizeof(WORD), 1, pMF->pFile); 600 DWORD dwData;
580 fwrite(&PPQN, sizeof(WORD), 1, pMF->pFile); 601 WORD wData;
581 } 602 WORD version, PPQN;
582 /* 603
583 ** Track data 604 fwrite(mthd, sizeof(BYTE), 4, pMF->pFile);
584 */ 605 dwData = 6;
585 for(i=0;i<MAX_MIDI_TRACKS;++i) 606 if (bSwap)
586 if (pMF->Track[i].ptr) 607 dwData = SWAP_DWORD(dwData);
587 { 608 fwrite(&dwData, sizeof(DWORD), 1, pMF->pFile);
588 const BYTE mtrk[4] = {'M', 'T', 'r', 'k'}; 609
589 DWORD sz, dwData; 610 wData = (WORD) (iNumTracks == 1 ? pMF->Header.iVersion : 1);
590 611 if (bSwap)
591 /* Write track header */ 612 version = SWAP_WORD(wData);
592 fwrite(&mtrk, sizeof(BYTE), 4, pMF->pFile); 613 else
593 614 version = (WORD) wData;
594 /* Write data size */ 615 if (bSwap)
595 sz = dwData = (int)(pMF->Track[i].ptr - pMF->Track[i].pBase); 616 iNumTracks = SWAP_WORD(iNumTracks);
596 if (bSwap) sz = SWAP_DWORD(sz); 617 wData = pMF->Header.PPQN;
597 fwrite(&sz, sizeof(DWORD), 1, pMF->pFile); 618 if (bSwap)
598 619 PPQN = SWAP_WORD(wData);
599 /* Write data */ 620 else
600 fwrite(pMF->Track[i].pBase, sizeof(BYTE), dwData, pMF->pFile); 621 PPQN = wData;
601 622 fwrite(&version, sizeof(WORD), 1, pMF->pFile);
602 /* Free memory */ 623 fwrite(&iNumTracks, sizeof(WORD), 1, pMF->pFile);
603 free((void *)pMF->Track[i].pBase); 624 fwrite(&PPQN, sizeof(WORD), 1, pMF->pFile);
604 } 625 }
605 626 /*
606 } 627 ** Track data
607 628 */
608 if (pMF->pFile) 629 for (i = 0; i < MAX_MIDI_TRACKS; ++i)
609 return fclose(pMF->pFile)?FALSE:TRUE; 630 if (pMF->Track[i].ptr)
610 free((void *)pMF); 631 {
611 return TRUE; 632 const BYTE mtrk[4] = { 'M', 'T', 'r', 'k' };
633 DWORD sz, dwData;
634
635 /* Write track header */
636 fwrite(&mtrk, sizeof(BYTE), 4, pMF->pFile);
637
638 /* Write data size */
639 sz = dwData = (int) (pMF->Track[i].ptr - pMF->Track[i].pBase);
640 if (bSwap)
641 sz = SWAP_DWORD(sz);
642 fwrite(&sz, sizeof(DWORD), 1, pMF->pFile);
643
644 /* Write data */
645 fwrite(pMF->Track[i].pBase, sizeof(BYTE), dwData, pMF->pFile);
646
647 /* Free memory */
648 free((void *) pMF->Track[i].pBase);
649 }
650
651 }
652
653 if (pMF->pFile)
654 return fclose(pMF->pFile) ? FALSE : TRUE;
655 free((void *) pMF);
656 return TRUE;
612 } 657 }
613 658
614 659
615 /* 660 /*
616 ** midiSong* Functions 661 ** midiSong* Functions
617 */ 662 */
618 BOOL midiSongAddSMPTEOffset(MIDI_FILE *_pMF, int iTrack, int iHours, int iMins, int iSecs, int iFrames, int iFFrames) 663 BOOL midiSongAddSMPTEOffset(MIDI_FILE *_pMF, int iTrack, int iHours,
619 { 664 int iMins, int iSecs, int iFrames, int iFFrames)
620 static BYTE tmp[] = {msgMetaEvent, metaSMPTEOffset, 0x05, 0,0,0,0,0}; 665 {
621 666 static BYTE tmp[] =
622 _VAR_CAST; 667 { msgMetaEvent, metaSMPTEOffset, 0x05, 0, 0, 0, 0, 0 };
623 if (!IsFilePtrValid(pMF)) return FALSE; 668
624 if (!IsTrackValid(iTrack)) return FALSE; 669 _VAR_CAST;
625 670 if (!IsFilePtrValid(pMF))
626 if (iMins<0 || iMins>59) iMins=0; 671 return FALSE;
627 if (iSecs<0 || iSecs>59) iSecs=0; 672 if (!IsTrackValid(iTrack))
628 if (iFrames<0 || iFrames>24) iFrames=0; 673 return FALSE;
629 674
630 tmp[3] = (BYTE)iHours; 675 if (iMins < 0 || iMins > 59)
631 tmp[4] = (BYTE)iMins; 676 iMins = 0;
632 tmp[5] = (BYTE)iSecs; 677 if (iSecs < 0 || iSecs > 59)
633 tmp[6] = (BYTE)iFrames; 678 iSecs = 0;
634 tmp[7] = (BYTE)iFFrames; 679 if (iFrames < 0 || iFrames > 24)
635 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 680 iFrames = 0;
636 } 681
637 682 tmp[3] = (BYTE) iHours;
638 683 tmp[4] = (BYTE) iMins;
639 BOOL midiSongAddSimpleTimeSig(MIDI_FILE *_pMF, int iTrack, int iNom, int iDenom) 684 tmp[5] = (BYTE) iSecs;
640 { 685 tmp[6] = (BYTE) iFrames;
641 return midiSongAddTimeSig(_pMF, iTrack, iNom, iDenom, 24, 8); 686 tmp[7] = (BYTE) iFFrames;
642 } 687 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
643 688 }
644 BOOL midiSongAddTimeSig(MIDI_FILE *_pMF, int iTrack, int iNom, int iDenom, int iClockInMetroTick, int iNotated32nds) 689
645 { 690
646 static BYTE tmp[] = {msgMetaEvent, metaTimeSig, 0x04, 0,0,0,0}; 691 BOOL midiSongAddSimpleTimeSig(MIDI_FILE *_pMF, int iTrack, int iNom,
647 692 int iDenom)
648 _VAR_CAST; 693 {
649 if (!IsFilePtrValid(pMF)) return FALSE; 694 return midiSongAddTimeSig(_pMF, iTrack, iNom, iDenom, 24, 8);
650 if (!IsTrackValid(iTrack)) return FALSE; 695 }
651 696
652 tmp[3] = (BYTE)iNom; 697 BOOL midiSongAddTimeSig(MIDI_FILE *_pMF, int iTrack, int iNom, int iDenom,
653 tmp[4] = (BYTE)(MIDI_NOTE_MINIM/iDenom); 698 int iClockInMetroTick, int iNotated32nds)
654 tmp[5] = (BYTE)iClockInMetroTick; 699 {
655 tmp[6] = (BYTE)iNotated32nds; 700 static BYTE tmp[] = { msgMetaEvent, metaTimeSig, 0x04, 0, 0, 0, 0 };
656 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 701
657 } 702 _VAR_CAST;
658 703 if (!IsFilePtrValid(pMF))
659 BOOL midiSongAddKeySig(MIDI_FILE *_pMF, int iTrack, tMIDI_KEYSIG iKey) 704 return FALSE;
660 { 705 if (!IsTrackValid(iTrack))
661 static BYTE tmp[] = {msgMetaEvent, metaKeySig, 0x02, 0, 0}; 706 return FALSE;
662 707
663 _VAR_CAST; 708 tmp[3] = (BYTE) iNom;
664 if (!IsFilePtrValid(pMF)) return FALSE; 709 tmp[4] = (BYTE) (MIDI_NOTE_MINIM / iDenom);
665 if (!IsTrackValid(iTrack)) return FALSE; 710 tmp[5] = (BYTE) iClockInMetroTick;
666 711 tmp[6] = (BYTE) iNotated32nds;
667 tmp[3] = (BYTE)((iKey&keyMaskKey)*((iKey&keyMaskNeg)?-1:1)); 712 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
668 tmp[4] = (BYTE)((iKey&keyMaskMin)?1:0); 713 }
669 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 714
670 } 715 BOOL midiSongAddKeySig(MIDI_FILE *_pMF, int iTrack, tMIDI_KEYSIG iKey)
671 716 {
672 BOOL midiSongAddTempo(MIDI_FILE *_pMF, int iTrack, int iTempo) 717 static BYTE tmp[] = { msgMetaEvent, metaKeySig, 0x02, 0, 0 };
673 { 718
674 static BYTE tmp[] = {msgMetaEvent, metaSetTempo, 0x03, 0,0,0}; 719 _VAR_CAST;
675 int us; /* micro-seconds per qn */ 720 if (!IsFilePtrValid(pMF))
676 721 return FALSE;
677 _VAR_CAST; 722 if (!IsTrackValid(iTrack))
678 if (!IsFilePtrValid(pMF)) return FALSE; 723 return FALSE;
679 if (!IsTrackValid(iTrack)) return FALSE; 724
680 725 tmp[3] = (BYTE) ((iKey & keyMaskKey) * ((iKey & keyMaskNeg) ? -1 : 1));
681 us = 60000000L/iTempo; 726 tmp[4] = (BYTE) ((iKey & keyMaskMin) ? 1 : 0);
682 tmp[3] = (BYTE)((us>>16)&0xff); 727 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
683 tmp[4] = (BYTE)((us>>8)&0xff); 728 }
684 tmp[5] = (BYTE)((us>>0)&0xff); 729
685 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 730 BOOL midiSongAddTempo(MIDI_FILE *_pMF, int iTrack, int iTempo)
686 } 731 {
687 732 static BYTE tmp[] = { msgMetaEvent, metaSetTempo, 0x03, 0, 0, 0 };
688 BOOL midiSongAddMIDIPort(MIDI_FILE *_pMF, int iTrack, int iPort) 733 int us; /* micro-seconds per qn */
689 { 734
690 static BYTE tmp[] = {msgMetaEvent, metaMIDIPort, 1, 0}; 735 _VAR_CAST;
691 736 if (!IsFilePtrValid(pMF))
692 _VAR_CAST; 737 return FALSE;
693 if (!IsFilePtrValid(pMF)) return FALSE; 738 if (!IsTrackValid(iTrack))
694 if (!IsTrackValid(iTrack)) return FALSE; 739 return FALSE;
695 tmp[3] = (BYTE)iPort; 740
696 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 741 us = 60000000L / iTempo;
697 } 742 tmp[3] = (BYTE) ((us >> 16) & 0xff);
698 743 tmp[4] = (BYTE) ((us >> 8) & 0xff);
699 BOOL midiSongAddEndSequence(MIDI_FILE *_pMF, int iTrack) 744 tmp[5] = (BYTE) ((us >> 0) & 0xff);
700 { 745 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
701 static BYTE tmp[] = {msgMetaEvent, metaEndSequence, 0}; 746 }
702 747
703 _VAR_CAST; 748 BOOL midiSongAddMIDIPort(MIDI_FILE *_pMF, int iTrack, int iPort)
704 if (!IsFilePtrValid(pMF)) return FALSE; 749 {
705 if (!IsTrackValid(iTrack)) return FALSE; 750 static BYTE tmp[] = { msgMetaEvent, metaMIDIPort, 1, 0 };
706 751
707 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0); 752 _VAR_CAST;
753 if (!IsFilePtrValid(pMF))
754 return FALSE;
755 if (!IsTrackValid(iTrack))
756 return FALSE;
757 tmp[3] = (BYTE) iPort;
758 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
759 }
760
761 BOOL midiSongAddEndSequence(MIDI_FILE *_pMF, int iTrack)
762 {
763 static BYTE tmp[] = { msgMetaEvent, metaEndSequence, 0 };
764
765 _VAR_CAST;
766 if (!IsFilePtrValid(pMF))
767 return FALSE;
768 if (!IsTrackValid(iTrack))
769 return FALSE;
770
771 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
708 } 772 }
709 773
710 774
711 /* 775 /*
712 ** midiTrack* Functions 776 ** midiTrack* Functions
713 */ 777 */
714 BOOL midiTrackAddRaw(MIDI_FILE *_pMF, int iTrack, int data_sz, const BYTE *pData, BOOL bMovePtr, int dt) 778 BOOL midiTrackAddRaw(MIDI_FILE *_pMF, int iTrack, int data_sz,
715 { 779 const BYTE * pData, BOOL bMovePtr, int dt)
716 MIDI_FILE_TRACK *pTrk; 780 {
717 BYTE *ptr; 781 MIDI_FILE_TRACK *pTrk;
718 int dtime; 782 BYTE *ptr;
719 783 int dtime;
720 _VAR_CAST; 784
721 if (!IsFilePtrValid(pMF)) return FALSE; 785 _VAR_CAST;
722 if (!IsTrackValid(iTrack)) return FALSE; 786 if (!IsFilePtrValid(pMF))
723 787 return FALSE;
724 pTrk = &pMF->Track[iTrack]; 788 if (!IsTrackValid(iTrack))
725 ptr = _midiGetPtr(pMF, iTrack, data_sz+DT_DEF); 789 return FALSE;
726 if (!ptr) 790
727 return FALSE; 791 pTrk = &pMF->Track[iTrack];
728 792 ptr = _midiGetPtr(pMF, iTrack, data_sz + DT_DEF);
729 dtime = pTrk->dt; 793 if (!ptr)
730 if (bMovePtr) 794 return FALSE;
731 dtime += dt; 795
732 796 dtime = pTrk->dt;
733 ptr = _midiWriteVarLen(ptr, dtime); 797 if (bMovePtr)
734 memcpy(ptr, pData, data_sz); 798 dtime += dt;
735 799
736 pTrk->pos += dtime; 800 ptr = _midiWriteVarLen(ptr, dtime);
737 pTrk->dt = 0; 801 memcpy(ptr, pData, data_sz);
738 pTrk->ptr = ptr+data_sz; 802
739 803 pTrk->pos += dtime;
740 return TRUE; 804 pTrk->dt = 0;
741 } 805 pTrk->ptr = ptr + data_sz;
742 806
743 807 return TRUE;
744 BOOL midiTrackIncTime(MIDI_FILE *_pMF, int iTrack, int iDeltaTime, BOOL bOverridePPQN) 808 }
745 { 809
746 DWORD will_end_at; 810
747 811 BOOL midiTrackIncTime(MIDI_FILE *_pMF, int iTrack, int iDeltaTime,
748 _VAR_CAST; 812 BOOL bOverridePPQN)
749 if (!IsFilePtrValid(pMF)) return FALSE; 813 {
750 if (!IsTrackValid(iTrack)) return FALSE; 814 DWORD will_end_at;
751 815
752 will_end_at = _midiGetLength(pMF->Header.PPQN, iDeltaTime, bOverridePPQN); 816 _VAR_CAST;
753 will_end_at += pMF->Track[iTrack].pos + pMF->Track[iTrack].dt; 817 if (!IsFilePtrValid(pMF))
754 818 return FALSE;
755 midiFileFlushTrack(pMF, iTrack, FALSE, will_end_at); 819 if (!IsTrackValid(iTrack))
756 820 return FALSE;
757 return TRUE; 821
758 } 822 will_end_at = _midiGetLength(pMF->Header.PPQN, iDeltaTime, bOverridePPQN);
759 823 will_end_at += pMF->Track[iTrack].pos + pMF->Track[iTrack].dt;
760 BOOL midiTrackAddText(MIDI_FILE *_pMF, int iTrack, tMIDI_TEXT iType, const char *pTxt) 824
761 { 825 midiFileFlushTrack(pMF, iTrack, FALSE, will_end_at);
762 BYTE *ptr; 826
763 int sz; 827 return TRUE;
764 828 }
765 _VAR_CAST; 829
766 if (!IsFilePtrValid(pMF)) return FALSE; 830 BOOL midiTrackAddText(MIDI_FILE *_pMF, int iTrack, tMIDI_TEXT iType,
767 if (!IsTrackValid(iTrack)) return FALSE; 831 const char *pTxt)
768 832 {
769 sz = strlen(pTxt); 833 BYTE *ptr;
770 if ((ptr = _midiGetPtr(pMF, iTrack, sz+DT_DEF))) 834 int sz;
771 { 835
772 *ptr++ = 0; /* delta-time=0 */ 836 _VAR_CAST;
773 *ptr++ = msgMetaEvent; 837 if (!IsFilePtrValid(pMF))
774 *ptr++ = (BYTE)iType; 838 return FALSE;
775 ptr = _midiWriteVarLen((BYTE *)ptr, sz); 839 if (!IsTrackValid(iTrack))
776 strcpy((char *)ptr, pTxt); 840 return FALSE;
777 pMF->Track[iTrack].ptr = ptr+sz; 841
778 return TRUE; 842 sz = strlen(pTxt);
779 } 843 if ((ptr = _midiGetPtr(pMF, iTrack, sz + DT_DEF)))
780 else 844 {
781 { 845 *ptr++ = 0; /* delta-time=0 */
782 return FALSE; 846 *ptr++ = msgMetaEvent;
783 } 847 *ptr++ = (BYTE) iType;
784 } 848 ptr = _midiWriteVarLen((BYTE *) ptr, sz);
785 849 strcpy((char *) ptr, pTxt);
786 BOOL midiTrackSetKeyPressure(MIDI_FILE *pMF, int iTrack, int iNote, int iAftertouch) 850 pMF->Track[iTrack].ptr = ptr + sz;
787 { 851 return TRUE;
788 return midiTrackAddMsg(pMF, iTrack, msgNoteKeyPressure, iNote, iAftertouch); 852 }
789 } 853 else
790 854 {
791 BOOL midiTrackAddControlChange(MIDI_FILE *pMF, int iTrack, tMIDI_CC iCCType, int iParam) 855 return FALSE;
792 { 856 }
793 return midiTrackAddMsg(pMF, iTrack, msgControlChange, iCCType, iParam); 857 }
794 } 858
795 859 BOOL midiTrackSetKeyPressure(MIDI_FILE *pMF, int iTrack, int iNote,
796 BOOL midiTrackAddProgramChange(MIDI_FILE *pMF, int iTrack, int iInstrPatch) 860 int iAftertouch)
797 { 861 {
798 return midiTrackAddMsg(pMF, iTrack, msgSetProgram, iInstrPatch, 0); 862 return midiTrackAddMsg(pMF, iTrack, msgNoteKeyPressure, iNote,
799 } 863 iAftertouch);
800 864 }
801 BOOL midiTrackChangeKeyPressure(MIDI_FILE *pMF, int iTrack, int iDeltaPressure) 865
802 { 866 BOOL midiTrackAddControlChange(MIDI_FILE *pMF, int iTrack, tMIDI_CC iCCType,
803 return midiTrackAddMsg(pMF, iTrack, msgChangePressure, iDeltaPressure&0x7f, 0); 867 int iParam)
804 } 868 {
805 869 return midiTrackAddMsg(pMF, iTrack, msgControlChange, iCCType, iParam);
806 BOOL midiTrackSetPitchWheel(MIDI_FILE *pMF, int iTrack, int iWheelPos) 870 }
807 { 871
808 WORD wheel = (WORD)iWheelPos; 872 BOOL midiTrackAddProgramChange(MIDI_FILE *pMF, int iTrack, int iInstrPatch)
809 873 {
810 /* bitshift 7 instead of eight because we're dealing with 7 bit numbers */ 874 return midiTrackAddMsg(pMF, iTrack, msgSetProgram, iInstrPatch, 0);
811 wheel += MIDI_WHEEL_CENTRE; 875 }
812 return midiTrackAddMsg(pMF, iTrack, msgSetPitchWheel, wheel&0x7f, (wheel>>7)&0x7f); 876
813 } 877 BOOL midiTrackChangeKeyPressure(MIDI_FILE *pMF, int iTrack,
814 878 int iDeltaPressure)
815 BOOL midiTrackAddMsg(MIDI_FILE *_pMF, int iTrack, tMIDI_MSG iMsg, int iParam1, int iParam2) 879 {
816 { 880 return midiTrackAddMsg(pMF, iTrack, msgChangePressure,
817 BYTE *ptr; 881 iDeltaPressure & 0x7f, 0);
818 BYTE data[3]; 882 }
819 int sz; 883
820 884 BOOL midiTrackSetPitchWheel(MIDI_FILE *pMF, int iTrack, int iWheelPos)
821 _VAR_CAST; 885 {
822 if (!IsFilePtrValid(pMF)) return FALSE; 886 WORD wheel = (WORD) iWheelPos;
823 if (!IsTrackValid(iTrack)) return FALSE; 887
824 if (!IsMessageValid(iMsg)) return FALSE; 888 /* bitshift 7 instead of eight because we're dealing with 7 bit numbers */
825 889 wheel += MIDI_WHEEL_CENTRE;
826 ptr = _midiGetPtr(pMF, iTrack, DT_DEF); 890 return midiTrackAddMsg(pMF, iTrack, msgSetPitchWheel, wheel & 0x7f,
827 if (!ptr) 891 (wheel >> 7) & 0x7f);
828 return FALSE; 892 }
829 893
830 data[0] = (BYTE)(iMsg | pMF->Track[iTrack].iDefaultChannel); 894 BOOL midiTrackAddMsg(MIDI_FILE *_pMF, int iTrack, tMIDI_MSG iMsg,
831 data[1] = (BYTE)(iParam1 & 0x7f); 895 int iParam1, int iParam2)
832 data[2] = (BYTE)(iParam2 & 0x7f); 896 {
833 /* 897 BYTE *ptr;
834 ** Is this msg a single, or double BYTE, prm? 898 BYTE data[3];
835 */ 899 int sz;
836 switch(iMsg) 900
837 { 901 _VAR_CAST;
838 case msgSetProgram: /* only one byte required for these msgs */ 902 if (!IsFilePtrValid(pMF))
839 case msgChangePressure: 903 return FALSE;
840 sz = 2; 904 if (!IsTrackValid(iTrack))
841 break; 905 return FALSE;
842 906 if (!IsMessageValid(iMsg))
843 default: /* double byte messages */ 907 return FALSE;
844 sz = 3; 908
845 break; 909 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
846 } 910 if (!ptr)
847 911 return FALSE;
848 return midiTrackAddRaw(pMF, iTrack, sz, data, FALSE, 0); 912
849 913 data[0] = (BYTE) (iMsg | pMF->Track[iTrack].iDefaultChannel);
850 } 914 data[1] = (BYTE) (iParam1 & 0x7f);
851 915 data[2] = (BYTE) (iParam2 & 0x7f);
852 BOOL midiTrackAddNote(MIDI_FILE *_pMF, int iTrack, int iNote, int iLength, int iVol, BOOL bAutoInc, BOOL bOverrideLength) 916 /*
853 { 917 ** Is this msg a single, or double BYTE, prm?
854 MIDI_FILE_TRACK *pTrk; 918 */
855 BYTE *ptr; 919 switch (iMsg)
856 BOOL bSuccess = FALSE; 920 {
857 int i, chn; 921 case msgSetProgram: /* only one byte required for these msgs */
858 922 case msgChangePressure:
859 _VAR_CAST; 923 sz = 2;
860 if (!IsFilePtrValid(pMF)) return FALSE; 924 break;
861 if (!IsTrackValid(iTrack)) return FALSE; 925
862 if (!IsNoteValid(iNote)) return FALSE; 926 default: /* double byte messages */
863 927 sz = 3;
864 pTrk = &pMF->Track[iTrack]; 928 break;
865 ptr = _midiGetPtr(pMF, iTrack, DT_DEF); 929 }
866 if (!ptr) 930
867 return FALSE; 931 return midiTrackAddRaw(pMF, iTrack, sz, data, FALSE, 0);
868 932
869 chn = pTrk->iDefaultChannel; 933 }
870 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverrideLength); 934
871 935 BOOL midiTrackAddNote(MIDI_FILE *_pMF, int iTrack, int iNote, int iLength,
872 for(i=0;i<sizeof(pTrk->LastNote)/sizeof(pTrk->LastNote[0]);++i) 936 int iVol, BOOL bAutoInc, BOOL bOverrideLength)
873 if (pTrk->LastNote[i].valid == FALSE) 937 {
874 { 938 MIDI_FILE_TRACK *pTrk;
875 pTrk->LastNote[i].note = (BYTE)iNote; 939 BYTE *ptr;
876 pTrk->LastNote[i].chn = (BYTE)chn; 940 BOOL bSuccess = FALSE;
877 pTrk->LastNote[i].end_pos = pTrk->pos+pTrk->dt+iLength; 941 int i, chn;
878 pTrk->LastNote[i].valid = TRUE; 942
879 bSuccess = TRUE; 943 _VAR_CAST;
880 944 if (!IsFilePtrValid(pMF))
881 ptr = _midiWriteVarLen(ptr, pTrk->dt); /* delta-time */ 945 return FALSE;
882 *ptr++ = (BYTE)(msgNoteOn | chn); 946 if (!IsTrackValid(iTrack))
883 *ptr++ = (BYTE)iNote; 947 return FALSE;
884 *ptr++ = (BYTE)iVol; 948 if (!IsNoteValid(iNote))
885 break; 949 return FALSE;
886 } 950
887 951 pTrk = &pMF->Track[iTrack];
888 if (!bSuccess) 952 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
889 return FALSE; 953 if (!ptr)
890 954 return FALSE;
891 pTrk->ptr = ptr; 955
892 956 chn = pTrk->iDefaultChannel;
893 pTrk->pos += pTrk->dt; 957 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverrideLength);
894 pTrk->dt = 0; 958
895 959 for (i = 0; i < sizeof(pTrk->LastNote) / sizeof(pTrk->LastNote[0]); ++i)
896 if (bAutoInc) 960 if (pTrk->LastNote[i].valid == FALSE)
897 return midiTrackIncTime(pMF, iTrack, iLength, bOverrideLength); 961 {
898 962 pTrk->LastNote[i].note = (BYTE) iNote;
899 return TRUE; 963 pTrk->LastNote[i].chn = (BYTE) chn;
900 } 964 pTrk->LastNote[i].end_pos = pTrk->pos + pTrk->dt + iLength;
901 965 pTrk->LastNote[i].valid = TRUE;
902 BOOL midiTrackAddRest(MIDI_FILE *_pMF, int iTrack, int iLength, BOOL bOverridePPQN) 966 bSuccess = TRUE;
903 { 967
904 _VAR_CAST; 968 ptr = _midiWriteVarLen(ptr, pTrk->dt); /* delta-time */
905 if (!IsFilePtrValid(pMF)) return FALSE; 969 *ptr++ = (BYTE) (msgNoteOn | chn);
906 if (!IsTrackValid(iTrack)) return FALSE; 970 *ptr++ = (BYTE) iNote;
907 971 *ptr++ = (BYTE) iVol;
908 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverridePPQN); 972 break;
909 return midiTrackIncTime(pMF, iTrack, iLength, bOverridePPQN); 973 }
910 } 974
911 975 if (!bSuccess)
912 int midiTrackGetEndPos(MIDI_FILE *_pMF, int iTrack) 976 return FALSE;
913 { 977
914 _VAR_CAST; 978 pTrk->ptr = ptr;
915 if (!IsFilePtrValid(pMF)) return FALSE; 979
916 if (!IsTrackValid(iTrack)) return FALSE; 980 pTrk->pos += pTrk->dt;
917 981 pTrk->dt = 0;
918 return pMF->Track[iTrack].pos; 982
983 if (bAutoInc)
984 return midiTrackIncTime(pMF, iTrack, iLength, bOverrideLength);
985
986 return TRUE;
987 }
988
989 BOOL midiTrackAddRest(MIDI_FILE *_pMF, int iTrack, int iLength,
990 BOOL bOverridePPQN)
991 {
992 _VAR_CAST;
993 if (!IsFilePtrValid(pMF))
994 return FALSE;
995 if (!IsTrackValid(iTrack))
996 return FALSE;
997
998 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverridePPQN);
999 return midiTrackIncTime(pMF, iTrack, iLength, bOverridePPQN);
1000 }
1001
1002 int midiTrackGetEndPos(MIDI_FILE *_pMF, int iTrack)
1003 {
1004 _VAR_CAST;
1005 if (!IsFilePtrValid(pMF))
1006 return FALSE;
1007 if (!IsTrackValid(iTrack))
1008 return FALSE;
1009
1010 return pMF->Track[iTrack].pos;
919 } 1011 }
920 1012
921 /* 1013 /*
922 ** midiRead* Functions 1014 ** midiRead* Functions
923 */ 1015 */
924 static BYTE *_midiReadVarLen(BYTE *ptr, DWORD *num) 1016 static BYTE *_midiReadVarLen(BYTE * ptr, DWORD * num)
925 { 1017 {
926 register DWORD value; 1018 register DWORD value;
927 register BYTE c; 1019 register BYTE c;
928 1020
929 if ((value = *ptr++) & 0x80) 1021 if ((value = *ptr++) & 0x80)
930 { 1022 {
931 value &= 0x7f; 1023 value &= 0x7f;
932 do 1024 do
933 { 1025 {
934 value = (value << 7) + ((c = *ptr++) & 0x7f); 1026 value = (value << 7) + ((c = *ptr++) & 0x7f);
935 } while (c & 0x80); 1027 }
936 } 1028 while (c & 0x80);
937 *num = value; 1029 }
938 return(ptr); 1030 *num = value;
939 } 1031 return (ptr);
940 1032 }
941 1033
942 static BOOL _midiReadTrackCopyData(MIDI_MSG *pMsg, BYTE *ptr, DWORD sz, BOOL bCopyPtrData) 1034
943 { 1035 static BOOL _midiReadTrackCopyData(MIDI_MSG * pMsg, BYTE * ptr, DWORD sz,
944 if (sz > pMsg->data_sz) 1036 BOOL bCopyPtrData)
945 { 1037 {
946 pMsg->data = (BYTE *)realloc(pMsg->data, sz); 1038 if (sz > pMsg->data_sz)
947 pMsg->data_sz = sz; 1039 {
948 } 1040 pMsg->data = (BYTE *) realloc(pMsg->data, sz);
949 1041 pMsg->data_sz = sz;
950 if (!pMsg->data) 1042 }
951 return FALSE; 1043
952 1044 if (!pMsg->data)
953 if (bCopyPtrData && ptr) 1045 return FALSE;
954 memcpy(pMsg->data, ptr, sz); 1046
955 1047 if (bCopyPtrData && ptr)
956 return TRUE; 1048 memcpy(pMsg->data, ptr, sz);
1049
1050 return TRUE;
957 } 1051 }
958 1052
959 int midiReadGetNumTracks(const MIDI_FILE *_pMF) 1053 int midiReadGetNumTracks(const MIDI_FILE *_pMF)
960 { 1054 {
961 _VAR_CAST; 1055 _VAR_CAST;
962 return pMF->Header.iNumTracks; 1056 return pMF->Header.iNumTracks;
963 } 1057 }
964 1058
965 BOOL midiReadGetNextMessage(const MIDI_FILE *_pMF, int iTrack, MIDI_MSG *pMsg) 1059 BOOL midiReadGetNextMessage(const MIDI_FILE *_pMF, int iTrack,
966 { 1060 MIDI_MSG * pMsg)
967 MIDI_FILE_TRACK *pTrack; 1061 {
968 BYTE *bptr, *pMsgDataPtr; 1062 MIDI_FILE_TRACK *pTrack;
969 int sz; 1063 BYTE *bptr, *pMsgDataPtr;
970 1064 int sz;
971 _VAR_CAST; 1065
972 if (!IsTrackValid(iTrack)) return FALSE; 1066 _VAR_CAST;
973 1067 if (!IsTrackValid(iTrack))
974 pTrack = &pMF->Track[iTrack]; 1068 return FALSE;
975 /* FIXME: Check if there is data on this track first!!! */ 1069
976 if (pTrack->ptr >= pTrack->pEnd) 1070 pTrack = &pMF->Track[iTrack];
977 return FALSE; 1071 /* FIXME: Check if there is data on this track first!!! */
978 1072 if (pTrack->ptr >= pTrack->pEnd)
979 pTrack->ptr = _midiReadVarLen(pTrack->ptr, &pMsg->dt); 1073 return FALSE;
980 pTrack->pos += pMsg->dt; 1074
981 1075 pTrack->ptr = _midiReadVarLen(pTrack->ptr, &pMsg->dt);
982 pMsg->dwAbsPos = pTrack->pos; 1076 pTrack->pos += pMsg->dt;
983 1077
984 if (*pTrack->ptr & 0x80) /* Is this is sys message */ 1078 pMsg->dwAbsPos = pTrack->pos;
985 { 1079
986 pMsg->iType = (tMIDI_MSG)((*pTrack->ptr) & 0xf0); 1080 if (*pTrack->ptr & 0x80) /* Is this is sys message */
987 pMsgDataPtr = pTrack->ptr+1; 1081 {
988 1082 pMsg->iType = (tMIDI_MSG) ((*pTrack->ptr) & 0xf0);
989 /* SysEx & Meta events don't carry channel info, but something 1083 pMsgDataPtr = pTrack->ptr + 1;
990 ** important in their lower bits that we must keep */ 1084
991 if (pMsg->iType == 0xf0) 1085 /* SysEx & Meta events don't carry channel info, but something
992 pMsg->iType = (tMIDI_MSG)(*pTrack->ptr); 1086 ** important in their lower bits that we must keep */
993 } 1087 if (pMsg->iType == 0xf0)
994 else /* just data - so use the last msg type */ 1088 pMsg->iType = (tMIDI_MSG) (*pTrack->ptr);
995 { 1089 }
996 pMsg->iType = pMsg->iLastMsgType; 1090 else /* just data - so use the last msg type */
997 pMsgDataPtr = pTrack->ptr; 1091 {
998 } 1092 pMsg->iType = pMsg->iLastMsgType;
999 1093 pMsgDataPtr = pTrack->ptr;
1000 pMsg->iLastMsgType = (tMIDI_MSG)pMsg->iType; 1094 }
1001 pMsg->iLastMsgChnl = (BYTE)((*pTrack->ptr) & 0x0f)+1; 1095
1002 1096 pMsg->iLastMsgType = (tMIDI_MSG) pMsg->iType;
1003 switch(pMsg->iType) 1097 pMsg->iLastMsgChnl = (BYTE) ((*pTrack->ptr) & 0x0f) + 1;
1004 { 1098
1005 case msgNoteOn: 1099 switch (pMsg->iType)
1006 pMsg->MsgData.NoteOn.iChannel = pMsg->iLastMsgChnl; 1100 {
1007 pMsg->MsgData.NoteOn.iNote = *(pMsgDataPtr); 1101 case msgNoteOn:
1008 pMsg->MsgData.NoteOn.iVolume = *(pMsgDataPtr+1); 1102 pMsg->MsgData.NoteOn.iChannel = pMsg->iLastMsgChnl;
1009 pMsg->iMsgSize = 3; 1103 pMsg->MsgData.NoteOn.iNote = *(pMsgDataPtr);
1010 break; 1104 pMsg->MsgData.NoteOn.iVolume = *(pMsgDataPtr + 1);
1011 1105 pMsg->iMsgSize = 3;
1012 case msgNoteOff: 1106 break;
1013 pMsg->MsgData.NoteOff.iChannel = pMsg->iLastMsgChnl; 1107
1014 pMsg->MsgData.NoteOff.iNote = *(pMsgDataPtr); 1108 case msgNoteOff:
1015 pMsg->iMsgSize = 3; 1109 pMsg->MsgData.NoteOff.iChannel = pMsg->iLastMsgChnl;
1016 break; 1110 pMsg->MsgData.NoteOff.iNote = *(pMsgDataPtr);
1017 1111 pMsg->iMsgSize = 3;
1018 case msgNoteKeyPressure: 1112 break;
1019 pMsg->MsgData.NoteKeyPressure.iChannel = pMsg->iLastMsgChnl; 1113
1020 pMsg->MsgData.NoteKeyPressure.iNote = *(pMsgDataPtr); 1114 case msgNoteKeyPressure:
1021 pMsg->MsgData.NoteKeyPressure.iPressure = *(pMsgDataPtr+1); 1115 pMsg->MsgData.NoteKeyPressure.iChannel = pMsg->iLastMsgChnl;
1022 pMsg->iMsgSize = 3; 1116 pMsg->MsgData.NoteKeyPressure.iNote = *(pMsgDataPtr);
1023 break; 1117 pMsg->MsgData.NoteKeyPressure.iPressure = *(pMsgDataPtr + 1);
1024 1118 pMsg->iMsgSize = 3;
1025 case msgSetParameter: 1119 break;
1026 pMsg->MsgData.NoteParameter.iChannel = pMsg->iLastMsgChnl; 1120
1027 pMsg->MsgData.NoteParameter.iControl = (tMIDI_CC)*(pMsgDataPtr); 1121 case msgSetParameter:
1028 pMsg->MsgData.NoteParameter.iParam = *(pMsgDataPtr+1); 1122 pMsg->MsgData.NoteParameter.iChannel = pMsg->iLastMsgChnl;
1029 pMsg->iMsgSize = 3; 1123 pMsg->MsgData.NoteParameter.iControl = (tMIDI_CC) * (pMsgDataPtr);
1030 break; 1124 pMsg->MsgData.NoteParameter.iParam = *(pMsgDataPtr + 1);
1031 1125 pMsg->iMsgSize = 3;
1032 case msgSetProgram: 1126 break;
1033 pMsg->MsgData.ChangeProgram.iChannel = pMsg->iLastMsgChnl; 1127
1034 pMsg->MsgData.ChangeProgram.iProgram = *(pMsgDataPtr); 1128 case msgSetProgram:
1035 pMsg->iMsgSize = 2; 1129 pMsg->MsgData.ChangeProgram.iChannel = pMsg->iLastMsgChnl;
1036 break; 1130 pMsg->MsgData.ChangeProgram.iProgram = *(pMsgDataPtr);
1037 1131 pMsg->iMsgSize = 2;
1038 case msgChangePressure: 1132 break;
1039 pMsg->MsgData.ChangePressure.iChannel = pMsg->iLastMsgChnl; 1133
1040 pMsg->MsgData.ChangePressure.iPressure = *(pMsgDataPtr); 1134 case msgChangePressure:
1041 pMsg->iMsgSize = 2; 1135 pMsg->MsgData.ChangePressure.iChannel = pMsg->iLastMsgChnl;
1042 break; 1136 pMsg->MsgData.ChangePressure.iPressure = *(pMsgDataPtr);
1043 1137 pMsg->iMsgSize = 2;
1044 case msgSetPitchWheel: 1138 break;
1045 pMsg->MsgData.PitchWheel.iChannel = pMsg->iLastMsgChnl; 1139
1046 pMsg->MsgData.PitchWheel.iPitch = *(pMsgDataPtr) | (*(pMsgDataPtr+1) << 7); 1140 case msgSetPitchWheel:
1047 pMsg->MsgData.PitchWheel.iPitch -= MIDI_WHEEL_CENTRE; 1141 pMsg->MsgData.PitchWheel.iChannel = pMsg->iLastMsgChnl;
1048 pMsg->iMsgSize = 3; 1142 pMsg->MsgData.PitchWheel.iPitch =
1049 break; 1143 *(pMsgDataPtr) | (*(pMsgDataPtr + 1) << 7);
1050 1144 pMsg->MsgData.PitchWheel.iPitch -= MIDI_WHEEL_CENTRE;
1051 case msgMetaEvent: 1145 pMsg->iMsgSize = 3;
1052 /* We can use 'pTrack->ptr' from now on, since meta events 1146 break;
1053 ** always have bit 7 set */ 1147
1054 bptr = pTrack->ptr; 1148 case msgMetaEvent:
1055 pMsg->MsgData.MetaEvent.iType = (tMIDI_META)*(pTrack->ptr+1); 1149 /* We can use 'pTrack->ptr' from now on, since meta events
1056 pTrack->ptr = _midiReadVarLen(pTrack->ptr+2, &pMsg->iMsgSize); 1150 ** always have bit 7 set */
1057 sz = (pTrack->ptr-bptr)+pMsg->iMsgSize; 1151 bptr = pTrack->ptr;
1058 1152 pMsg->MsgData.MetaEvent.iType = (tMIDI_META) * (pTrack->ptr + 1);
1059 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE) 1153 pTrack->ptr = _midiReadVarLen(pTrack->ptr + 2, &pMsg->iMsgSize);
1060 return FALSE; 1154 sz = (pTrack->ptr - bptr) + pMsg->iMsgSize;
1061 1155
1062 /* Now copy the data...*/ 1156 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE)
1063 memcpy(pMsg->data, bptr, sz); 1157 return FALSE;
1064 1158
1065 /* Now place it in a neat structure */ 1159 /* Now copy the data... */
1066 switch(pMsg->MsgData.MetaEvent.iType) 1160 memcpy(pMsg->data, bptr, sz);
1067 { 1161
1068 case metaMIDIPort: 1162 /* Now place it in a neat structure */
1069 pMsg->MsgData.MetaEvent.Data.iMIDIPort = *(pTrack->ptr+0); 1163 switch (pMsg->MsgData.MetaEvent.iType)
1070 break; 1164 {
1071 case metaSequenceNumber: 1165 case metaMIDIPort:
1072 pMsg->MsgData.MetaEvent.Data.iSequenceNumber = *(pTrack->ptr+0); 1166 pMsg->MsgData.MetaEvent.Data.iMIDIPort = *(pTrack->ptr + 0);
1073 break; 1167 break;
1074 case metaTextEvent: 1168 case metaSequenceNumber:
1075 case metaCopyright: 1169 pMsg->MsgData.MetaEvent.Data.iSequenceNumber = *(pTrack->ptr + 0);
1076 case metaTrackName: 1170 break;
1077 case metaInstrument: 1171 case metaTextEvent:
1078 case metaLyric: 1172 case metaCopyright:
1079 case metaMarker: 1173 case metaTrackName:
1080 case metaCuePoint: 1174 case metaInstrument:
1081 /* TODO - Add NULL terminator ??? */ 1175 case metaLyric:
1082 pMsg->MsgData.MetaEvent.Data.Text.pData = pTrack->ptr; 1176 case metaMarker:
1083 break; 1177 case metaCuePoint:
1084 case metaEndSequence: 1178 /* TODO - Add NULL terminator ??? */
1085 /* NO DATA */ 1179 pMsg->MsgData.MetaEvent.Data.Text.pData = pTrack->ptr;
1086 break; 1180 break;
1087 case metaSetTempo: 1181 case metaEndSequence:
1088 { 1182 /* NO DATA */
1089 DWORD us = ((*(pTrack->ptr+0))<<16)|((*(pTrack->ptr+1))<<8)|(*(pTrack->ptr+2)); 1183 break;
1090 pMsg->MsgData.MetaEvent.Data.Tempo.iBPM = 60000000L/us; 1184 case metaSetTempo:
1091 } 1185 {
1092 break; 1186 DWORD us =
1093 case metaSMPTEOffset: 1187 ((*(pTrack->ptr + 0)) << 16) | ((*(pTrack->ptr + 1)) << 8)
1094 pMsg->MsgData.MetaEvent.Data.SMPTE.iHours = *(pTrack->ptr+0); 1188 | (*(pTrack->ptr + 2));
1095 pMsg->MsgData.MetaEvent.Data.SMPTE.iMins= *(pTrack->ptr+1); 1189 pMsg->MsgData.MetaEvent.Data.Tempo.iBPM = 60000000L / us;
1096 pMsg->MsgData.MetaEvent.Data.SMPTE.iSecs = *(pTrack->ptr+2); 1190 }
1097 pMsg->MsgData.MetaEvent.Data.SMPTE.iFrames = *(pTrack->ptr+3); 1191 break;
1098 pMsg->MsgData.MetaEvent.Data.SMPTE.iFF = *(pTrack->ptr+4); 1192 case metaSMPTEOffset:
1099 break; 1193 pMsg->MsgData.MetaEvent.Data.SMPTE.iHours = *(pTrack->ptr + 0);
1100 case metaTimeSig: 1194 pMsg->MsgData.MetaEvent.Data.SMPTE.iMins = *(pTrack->ptr + 1);
1101 pMsg->MsgData.MetaEvent.Data.TimeSig.iNom = *(pTrack->ptr+0); 1195 pMsg->MsgData.MetaEvent.Data.SMPTE.iSecs = *(pTrack->ptr + 2);
1102 pMsg->MsgData.MetaEvent.Data.TimeSig.iDenom = *(pTrack->ptr+1) * MIDI_NOTE_MINIM; 1196 pMsg->MsgData.MetaEvent.Data.SMPTE.iFrames = *(pTrack->ptr + 3);
1103 /* TODO: Variations without 24 & 8 */ 1197 pMsg->MsgData.MetaEvent.Data.SMPTE.iFF = *(pTrack->ptr + 4);
1104 break; 1198 break;
1105 case metaKeySig: 1199 case metaTimeSig:
1106 if (*pTrack->ptr & 0x80) 1200 pMsg->MsgData.MetaEvent.Data.TimeSig.iNom = *(pTrack->ptr + 0);
1107 { 1201 pMsg->MsgData.MetaEvent.Data.TimeSig.iDenom =
1108 /* Do some trendy sign extending in reverse :) */ 1202 *(pTrack->ptr + 1) * MIDI_NOTE_MINIM;
1109 pMsg->MsgData.MetaEvent.Data.KeySig.iKey = ((256-*pTrack->ptr)&keyMaskKey); 1203 /* TODO: Variations without 24 & 8 */
1110 pMsg->MsgData.MetaEvent.Data.KeySig.iKey |= keyMaskNeg; 1204 break;
1111 } 1205 case metaKeySig:
1112 else 1206 if (*pTrack->ptr & 0x80)
1113 { 1207 {
1114 pMsg->MsgData.MetaEvent.Data.KeySig.iKey = (tMIDI_KEYSIG)(*pTrack->ptr&keyMaskKey); 1208 /* Do some trendy sign extending in reverse :) */
1115 } 1209 pMsg->MsgData.MetaEvent.Data.KeySig.iKey =
1116 if (*(pTrack->ptr+1)) 1210 ((256 - *pTrack->ptr) & keyMaskKey);
1117 pMsg->MsgData.MetaEvent.Data.KeySig.iKey |= keyMaskMin; 1211 pMsg->MsgData.MetaEvent.Data.KeySig.iKey |= keyMaskNeg;
1118 break; 1212 }
1119 case metaSequencerSpecific: 1213 else
1120 pMsg->MsgData.MetaEvent.Data.Sequencer.iSize = pMsg->iMsgSize; 1214 {
1121 pMsg->MsgData.MetaEvent.Data.Sequencer.pData = pTrack->ptr; 1215 pMsg->MsgData.MetaEvent.Data.KeySig.iKey =
1122 break; 1216 (tMIDI_KEYSIG) (*pTrack->ptr & keyMaskKey);
1123 } 1217 }
1124 1218 if (*(pTrack->ptr + 1))
1125 pTrack->ptr += pMsg->iMsgSize; 1219 pMsg->MsgData.MetaEvent.Data.KeySig.iKey |= keyMaskMin;
1126 pMsg->iMsgSize = sz; 1220 break;
1127 break; 1221 case metaSequencerSpecific:
1128 1222 pMsg->MsgData.MetaEvent.Data.Sequencer.iSize = pMsg->iMsgSize;
1129 case msgSysEx1: 1223 pMsg->MsgData.MetaEvent.Data.Sequencer.pData = pTrack->ptr;
1130 case msgSysEx2: 1224 break;
1131 bptr = pTrack->ptr; 1225 }
1132 pTrack->ptr = _midiReadVarLen(pTrack->ptr+1, &pMsg->iMsgSize); 1226
1133 sz = (pTrack->ptr-bptr)+pMsg->iMsgSize; 1227 pTrack->ptr += pMsg->iMsgSize;
1134 1228 pMsg->iMsgSize = sz;
1135 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE) 1229 break;
1136 return FALSE; 1230
1137 1231 case msgSysEx1:
1138 /* Now copy the data... */ 1232 case msgSysEx2:
1139 memcpy(pMsg->data, bptr, sz); 1233 bptr = pTrack->ptr;
1140 pTrack->ptr += pMsg->iMsgSize; 1234 pTrack->ptr = _midiReadVarLen(pTrack->ptr + 1, &pMsg->iMsgSize);
1141 pMsg->iMsgSize = sz; 1235 sz = (pTrack->ptr - bptr) + pMsg->iMsgSize;
1142 pMsg->MsgData.SysEx.pData = pMsg->data; 1236
1143 pMsg->MsgData.SysEx.iSize = sz; 1237 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE)
1144 break; 1238 return FALSE;
1145 } 1239
1146 /* 1240 /* Now copy the data... */
1147 ** Standard MIDI messages use a common copy routine 1241 memcpy(pMsg->data, bptr, sz);
1148 */ 1242 pTrack->ptr += pMsg->iMsgSize;
1149 pMsg->bImpliedMsg = FALSE; 1243 pMsg->iMsgSize = sz;
1150 if ((pMsg->iType&0xf0) != 0xf0) 1244 pMsg->MsgData.SysEx.pData = pMsg->data;
1151 { 1245 pMsg->MsgData.SysEx.iSize = sz;
1152 if (*pTrack->ptr & 0x80) 1246 break;
1153 { 1247 }
1154 } 1248 /*
1155 else 1249 ** Standard MIDI messages use a common copy routine
1156 { 1250 */
1157 pMsg->bImpliedMsg = TRUE; 1251 pMsg->bImpliedMsg = FALSE;
1158 pMsg->iImpliedMsg = pMsg->iLastMsgType; 1252 if ((pMsg->iType & 0xf0) != 0xf0)
1159 pMsg->iMsgSize--; 1253 {
1160 } 1254 if (*pTrack->ptr & 0x80)
1161 _midiReadTrackCopyData(pMsg, pTrack->ptr, pMsg->iMsgSize, TRUE); 1255 {
1162 pTrack->ptr+=pMsg->iMsgSize; 1256 }
1163 } 1257 else
1164 return TRUE; 1258 {
1165 } 1259 pMsg->bImpliedMsg = TRUE;
1166 1260 pMsg->iImpliedMsg = pMsg->iLastMsgType;
1167 void midiReadInitMessage(MIDI_MSG *pMsg) 1261 pMsg->iMsgSize--;
1168 { 1262 }
1169 pMsg->data = NULL; 1263 _midiReadTrackCopyData(pMsg, pTrack->ptr, pMsg->iMsgSize, TRUE);
1170 pMsg->data_sz = 0; 1264 pTrack->ptr += pMsg->iMsgSize;
1171 pMsg->bImpliedMsg = FALSE; 1265 }
1172 } 1266 return TRUE;
1173 1267 }
1174 void midiReadFreeMessage(MIDI_MSG *pMsg) 1268
1175 { 1269 void midiReadInitMessage(MIDI_MSG * pMsg)
1176 if (pMsg->data) free((void *)pMsg->data); 1270 {
1177 pMsg->data = NULL; 1271 pMsg->data = NULL;
1178 } 1272 pMsg->data_sz = 0;
1273 pMsg->bImpliedMsg = FALSE;
1274 }
1275
1276 void midiReadFreeMessage(MIDI_MSG * pMsg)
1277 {
1278 if (pMsg->data)
1279 free((void *) pMsg->data);
1280 pMsg->data = NULL;
1281 }