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