Mercurial > hg > forks > bilotrip-mj12
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 } |