ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
midi.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31#include <sys/types.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <ctype.h>
36#ifndef __APPLE__
37#include <malloc.h>
38#endif
39#include "midi.h"
40
41char * strcopy( char * _dest, const char * _source );
42
48
61
68
77
78#define DT_DEF 32
79
80#if ( defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN ) || \
81 defined(__BIG_ENDIAN__) || \
82 defined(__ARMEB__) || \
83 defined(__THUMBEB__) || \
84 defined(__AARCH64EB__) || \
85 defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
86 #define SWAP_WORD(w) (w)
87 #define SWAP_DWORD(d) (d)
88#else
89 #define SWAP_WORD(w) (WORD)(((w)>>8)|((w)<<8))
90 #define SWAP_DWORD(d) (DWORD)((d)>>24)|(((d)>>8)&0xff00)|(((d)<<8)&0xff0000)|(((d)<<24))
91#endif
92
93#define _VAR_CAST MidiFileInternal *pMF = (MidiFileInternal *)_pMF
94#define IsFilePtrValid(pMF) (pMF)
95#define IsTrackValid(_x) (_midiValidateTrack(pMF, _x))
96#define IsChannelValid(_x) ((_x)>=1 && (_x)<=16)
97#define IsNoteValid(_x) ((_x)>=0 && (_x)<128)
98#define IsMessageValid(_x) ((_x)>=messageNoteOff && (_x)<=messageMetaEvent)
99
100static int _midiValidateTrack(const MidiFileInternal *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
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
121static BYTE *_midiWriteVarLen(BYTE *ptr, int n){
122register long buffer;
123register long value=n;
124
125 buffer = value & 0x7f;
126 while ((value >>= 7) > 0)
127 {
128 buffer <<= 8;
129 buffer |= 0x80;
130 buffer += (value & 0x7f);
131 }
132
133 while (TRUE)
134 {
135 *ptr++ = (BYTE)buffer;
136 if (buffer & 0x80)
137 buffer >>= 8;
138 else
139 break;
140 }
141
142 return(ptr);
143}
144
145static BYTE *_midiGetPtr(MidiFileInternal *pMF, int iTrack, int sz_reqd)
146{
147const DWORD mem_sz_inc = 8092;
148BYTE *ptr;
149int curr_offset;
150MidiFileTrack *pTrack = &pMF->Track[iTrack];
151
152 ptr = pTrack->ptr;
153 if (ptr == NULL || ptr+sz_reqd > pTrack->pEnd)
154 {
155 curr_offset = ptr-pTrack->pBase;
156 if ((ptr = (BYTE *)realloc(pTrack->pBase, mem_sz_inc+pTrack->iBlockSize)))
157 {
158 pTrack->pBase = ptr;
159 pTrack->iBlockSize += mem_sz_inc;
160 pTrack->pEnd = ptr+pTrack->iBlockSize;
161 pTrack->ptr = ptr+curr_offset;
162 ptr += curr_offset;
163 }
164 else
165 {
166 return NULL;
167 }
168 }
169
170 return ptr;
171}
172
173
174static int _midiGetLength(int ppqn, int iNoteLen, int bOverride)
175{
176int length = ppqn;
177
178 if (bOverride)
179 {
180 length = iNoteLen;
181 }
182 else
183 {
184 switch(iNoteLen)
185 {
187 length *= 3;
188 break;
189
191 length *= 3;
192 length /= 2;
193 break;
194
196 length *= 3;
197 length /= 4;
198 break;
199
201 length *= 3;
202 length /= 8;
203 break;
204
206 length *= 3;
207 length /= 16;
208 break;
209
211 length *= 4;
212 break;
213
215 length *= 2;
216 break;
217
219 length /= 2;
220 break;
221
223 length /= 4;
224 break;
225
227 length /= 8;
228 break;
229
231 length *= 2;
232 length /= 3;
233 break;
234 }
235 }
236
237 return length;
238}
239
240MidiFile *midiFileCreate(const char *pFilename, int bOverwriteIfExists)
241{
243int i;
244
245 if (!pMF) return NULL;
246
247 if (!bOverwriteIfExists)
248 {
249 if ((pMF->pFile = fopen(pFilename, "r")))
250 {
251 fclose(pMF->pFile);
252 free(pMF);
253 return NULL;
254 }
255 }
256
257 if ((pMF->pFile = fopen(pFilename, "wb+")))
258 { }
259 else
260 {
261 free((void *)pMF);
262 return NULL;
263 }
264
265 pMF->bOpenForWriting = TRUE;
268
269 for(i=0;i<MAX_MIDI_TRACKS;++i)
270 {
271 pMF->Track[i].pos = 0;
272 pMF->Track[i].ptr = NULL;
273 pMF->Track[i].pBase = NULL;
274 pMF->Track[i].pEnd = NULL;
275 pMF->Track[i].iBlockSize = 0;
276 pMF->Track[i].dt = 0;
277 pMF->Track[i].iDefaultChannel = (BYTE)(i & 0xf);
278
279 memset(pMF->Track[i].LastNote, '\0', sizeof(pMF->Track[i].LastNote));
280 }
281
282 return (MidiFile *)pMF;
283}
284
285int midiFileSetTracksDefaultChannel(MidiFile *_pMF, int iTrack, int iChannel)
286{
287int prev;
288
289 _VAR_CAST;
290 if (!IsFilePtrValid(pMF)) return 0;
291 if (!IsTrackValid(iTrack)) return 0;
292 if (!IsChannelValid(iChannel)) return 0;
293
294 prev = pMF->Track[iTrack].iDefaultChannel+1;
295 pMF->Track[iTrack].iDefaultChannel = (BYTE)(iChannel-1);
296 return prev;
297}
298
299int midiFileGetTracksDefaultChannel(const MidiFile *_pMF, int iTrack)
300{
301 _VAR_CAST;
302 if (!IsFilePtrValid(pMF)) return 0;
303 if (!IsTrackValid(iTrack)) return 0;
304
305 return pMF->Track[iTrack].iDefaultChannel+1;
306}
307
308int midiFileSetPPQN(MidiFile *_pMF, int PPQN)
309{
310int prev;
311
312 _VAR_CAST;
313 if (!IsFilePtrValid(pMF)) return MIDI_PPQN_DEFAULT;
314 prev = pMF->Header.PPQN;
315 pMF->Header.PPQN = (WORD)PPQN;
316 return prev;
317}
318
319int midiFileGetPPQN(const MidiFile *_pMF)
320{
321 _VAR_CAST;
322 if (!IsFilePtrValid(pMF)) return MIDI_PPQN_DEFAULT;
323 return (int)pMF->Header.PPQN;
324}
325
326int midiFileSetVersion(MidiFile *_pMF, int iVersion)
327{
328int prev;
329
330 _VAR_CAST;
331 if (!IsFilePtrValid(pMF)) return MIDI_VERSION_DEFAULT;
332 if (iVersion<0 || iVersion>2) return MIDI_VERSION_DEFAULT;
333 prev = pMF->Header.iVersion;
334 pMF->Header.iVersion = (WORD)iVersion;
335 return prev;
336}
337
339{
340 _VAR_CAST;
341 if (!IsFilePtrValid(pMF)) return MIDI_VERSION_DEFAULT;
342 return pMF->Header.iVersion;
343}
344
345MidiFile *midiFileOpen(const char *pFilename)
346{
347FILE *fp = fopen(pFilename, "rb");
348MidiFileInternal *pMF = NULL;
349BYTE *ptr;
350int bValidFile=FALSE;
351long size;
352
353 if (fp)
354 {
355 if ((pMF = (MidiFileInternal *)malloc(sizeof(MidiFileInternal))))
356 {
357 fseek(fp, 0L, SEEK_END);
358 size = ftell(fp);
359 if ((pMF->ptr = (BYTE *)malloc(size)))
360 {
361 fseek(fp, 0L, SEEK_SET);
362 (void)!fread(pMF->ptr, sizeof(BYTE), size, fp);
363 ptr = pMF->ptr;
364 if (*(ptr+0) == 'M' && *(ptr+1) == 'T' &&
365 *(ptr+2) == 'h' && *(ptr+3) == 'd')
366 {
367 DWORD dwData;
368 WORD wData;
369 int i;
370
371 dwData = *((DWORD *)(ptr+4));
372 pMF->Header.iHeaderSize = SWAP_DWORD(dwData);
373
374 wData = *((WORD *)(ptr+8));
375 pMF->Header.iVersion = (WORD)SWAP_WORD(wData);
376
377 wData = *((WORD *)(ptr+10));
378 pMF->Header.iNumTracks = (WORD)SWAP_WORD(wData);
379
380 wData = *((WORD *)(ptr+12));
381 pMF->Header.PPQN = (WORD)SWAP_WORD(wData);
382
383 ptr += pMF->Header.iHeaderSize+8;
384
385 for(i=0;i<MAX_MIDI_TRACKS;++i)
386 {
387 pMF->Track[i].pos = 0;
388 pMF->Track[i].last_status = 0;
389 }
390
391 for(i=0;i<pMF->Header.iNumTracks;++i)
392 {
393 pMF->Track[i].pBase = ptr;
394 pMF->Track[i].ptr = ptr+8;
395 dwData = *((DWORD *)(ptr+4));
396 pMF->Track[i].sz = SWAP_DWORD(dwData);
397 pMF->Track[i].pEnd = ptr+pMF->Track[i].sz+8;
398 ptr += pMF->Track[i].sz+8;
399 }
400
401 pMF->bOpenForWriting = FALSE;
402 pMF->pFile = NULL;
403 bValidFile = TRUE;
404 }
405 }
406 }
407
408 fclose(fp);
409 }
410
411 if (!bValidFile)
412 {
413 if (pMF) free((void *)pMF);
414 return NULL;
415 }
416
417 return (MidiFile *)pMF;
418}
419
420typedef struct {
421 int iIdx;
424
425static int qs_cmp_pEndPoints(const void *e1, const void *e2)
426{
429
430 return p1->iEndPos-p2->iEndPos;
431}
432
433int midiFileFlushTrack(MidiFile *_pMF, int iTrack, int bFlushToEnd, DWORD dwEndTimePos)
434{
435int sz;
436BYTE *ptr;
437MIDI_END_POINT *pEndPoints;
438int num, i, mx_pts;
439
440 _VAR_CAST;
441 if (!IsFilePtrValid(pMF)) return FALSE;
442 if (!_midiValidateTrack(pMF, iTrack)) return FALSE;
443 sz = sizeof(pMF->Track[0].LastNote)/sizeof(pMF->Track[0].LastNote[0]);
444
445 pEndPoints = (MIDI_END_POINT *)malloc(sz * sizeof(MIDI_END_POINT));
446 mx_pts = 0;
447 for(i=0;i<sz;++i)
448 if (pMF->Track[iTrack].LastNote[i].valid)
449 {
450 pEndPoints[mx_pts].iIdx = i;
451 pEndPoints[mx_pts].iEndPos = pMF->Track[iTrack].LastNote[i].end_pos;
452 mx_pts++;
453 }
454
455 if (bFlushToEnd)
456 {
457 if (mx_pts)
458 dwEndTimePos = pEndPoints[mx_pts-1].iEndPos;
459 else
460 dwEndTimePos = pMF->Track[iTrack].pos;
461 }
462
463 if (mx_pts)
464 {
465 qsort(pEndPoints, mx_pts, sizeof(MIDI_END_POINT), qs_cmp_pEndPoints);
466
467 i = 0;
468 while ((dwEndTimePos >= (DWORD)pEndPoints[i].iEndPos || bFlushToEnd) && i<mx_pts)
469 {
470 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
471 if (!ptr)
472 return FALSE;
473
474 num = pEndPoints[i].iIdx;
475
476 ptr = _midiWriteVarLen(ptr, pMF->Track[iTrack].LastNote[num].end_pos - pMF->Track[iTrack].pos);
477 *ptr++ = (BYTE)(messageNoteOff | pMF->Track[iTrack].LastNote[num].chn);
478 *ptr++ = pMF->Track[iTrack].LastNote[num].note;
479 *ptr++ = 0;
480
481 pMF->Track[iTrack].LastNote[num].valid = FALSE;
482 pMF->Track[iTrack].pos = pMF->Track[iTrack].LastNote[num].end_pos;
483
484 pMF->Track[iTrack].ptr = ptr;
485
486 ++i;
487 }
488 }
489
490 free((void *)pEndPoints);
491 pMF->Track[iTrack].dt = dwEndTimePos - pMF->Track[iTrack].pos;
492
493 return TRUE;
494}
495
496int midiFileSyncTracks(MidiFile *_pMF, int iTrack1, int iTrack2)
497{
498int p1, p2;
499
500 _VAR_CAST;
501 if (!IsFilePtrValid(pMF)) return FALSE;
502 if (!IsTrackValid(iTrack1)) return FALSE;
503 if (!IsTrackValid(iTrack2)) return FALSE;
504
505 p1 = pMF->Track[iTrack1].pos + pMF->Track[iTrack1].dt;
506 p2 = pMF->Track[iTrack2].pos + pMF->Track[iTrack2].dt;
507
508 if (p1 < p2) midiTrackIncTime(pMF, iTrack1, p2-p1, TRUE);
509 else if (p2 < p1) midiTrackIncTime(pMF, iTrack2, p1-p2, TRUE);
510
511 return TRUE;
512}
513
514
516{
517 _VAR_CAST;
518 if (!IsFilePtrValid(pMF)) return FALSE;
519
520 if (pMF->bOpenForWriting)
521 {
522 WORD iNumTracks = 0;
523 WORD wTest = 256;
524 int bSwap = FALSE;
525 int i;
526
527 if (*((BYTE *)&wTest) == 0)
528 bSwap = TRUE;
529
530 for(i=0;i<MAX_MIDI_TRACKS;++i)
531 {
532 if (pMF->Track[i].ptr)
533 {
535 midiFileFlushTrack(pMF, i, TRUE, 0);
536 iNumTracks++;
537 }
538 }
539
540 {
541 const BYTE mthd[4] = {'M', 'T', 'h', 'd'};
542 DWORD dwData;
543 WORD wData;
544 WORD version, PPQN;
545
546 fwrite(mthd, sizeof(BYTE), 4, pMF->pFile);
547 dwData = 6;
548 if (bSwap) dwData = SWAP_DWORD(dwData);
549 fwrite(&dwData, sizeof(DWORD), 1, pMF->pFile);
550
551 wData = (WORD)(iNumTracks==1?pMF->Header.iVersion:1);
552 if (bSwap) version = SWAP_WORD(wData); else version = (WORD)wData;
553 if (bSwap) iNumTracks = SWAP_WORD(iNumTracks);
554 wData = pMF->Header.PPQN;
555 if (bSwap) PPQN = SWAP_WORD(wData); else PPQN = wData;
556 fwrite(&version, sizeof(WORD), 1, pMF->pFile);
557 fwrite(&iNumTracks, sizeof(WORD), 1, pMF->pFile);
558 fwrite(&PPQN, sizeof(WORD), 1, pMF->pFile);
559 }
560
561 for(i=0;i<MAX_MIDI_TRACKS;++i)
562 if (pMF->Track[i].ptr)
563 {
564 const BYTE mtrk[4] = {'M', 'T', 'r', 'k'};
565 DWORD sz, dwData;
566
567 fwrite(&mtrk, sizeof(BYTE), 4, pMF->pFile);
568
569 sz = dwData = (int)(pMF->Track[i].ptr - pMF->Track[i].pBase);
570 if (bSwap) sz = SWAP_DWORD(sz);
571 fwrite(&sz, sizeof(DWORD), 1, pMF->pFile);
572
573 fwrite(pMF->Track[i].pBase, sizeof(BYTE), dwData, pMF->pFile);
574
575 free((void *)pMF->Track[i].pBase);
576 }
577
578 }
579
580 if (pMF->pFile)
581 return fclose(pMF->pFile)?FALSE:TRUE;
582 free((void *)pMF);
583 return TRUE;
584}
585
586int midiSongAddSMPTEOffset(MidiFile *_pMF, int iTrack, int iHours, int iMins, int iSecs, int iFrames, int iFFrames)
587{
588static BYTE tmp[] = {messageMetaEvent, metaInfoSMPTEOffset, 0x05, 0,0,0,0,0};
589
590 _VAR_CAST;
591 if (!IsFilePtrValid(pMF)) return FALSE;
592 if (!IsTrackValid(iTrack)) return FALSE;
593
594 if (iMins<0 || iMins>59) iMins=0;
595 if (iSecs<0 || iSecs>59) iSecs=0;
596 if (iFrames<0 || iFrames>24) iFrames=0;
597
598 tmp[3] = (BYTE)iHours;
599 tmp[4] = (BYTE)iMins;
600 tmp[5] = (BYTE)iSecs;
601 tmp[6] = (BYTE)iFrames;
602 tmp[7] = (BYTE)iFFrames;
603 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
604}
605
606
607int midiSongAddSimpleTimeSig(MidiFile *_pMF, int iTrack, int iNom, int iDenom)
608{
609 return midiSongAddTimeSig(_pMF, iTrack, iNom, iDenom, 24, 8);
610}
611
612int midiSongAddTimeSig(MidiFile *_pMF, int iTrack, int iNom, int iDenom, int iClockInMetroTick, int iNotated32nds)
613{
614static BYTE tmp[] = {messageMetaEvent, metaInfoTimeSig, 0x04, 0,0,0,0};
615
616 _VAR_CAST;
617 if (!IsFilePtrValid(pMF)) return FALSE;
618 if (!IsTrackValid(iTrack)) return FALSE;
619
620 tmp[3] = (BYTE)iNom;
621 tmp[4] = (BYTE)(MIDI_DURATION_MINIM/iDenom);
622 tmp[5] = (BYTE)iClockInMetroTick;
623 tmp[6] = (BYTE)iNotated32nds;
624 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
625}
626
627int midiSongAddKeySig(MidiFile *_pMF, int iTrack, MidiNote iKey)
628{
629static BYTE tmp[] = {messageMetaEvent, metaInfoKeySig, 0x02, 0, 0};
630
631 _VAR_CAST;
632 if (!IsFilePtrValid(pMF)) return FALSE;
633 if (!IsTrackValid(iTrack)) return FALSE;
634
635 tmp[3] = (BYTE)((iKey&noteMaskKey)*((iKey&noteMaskNeg)?-1:1));
636 tmp[4] = (BYTE)((iKey&noteMaskMin)?1:0);
637 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
638}
639
640int midiSongAddTempo(MidiFile *_pMF, int iTrack, int iTempo)
641{
642static BYTE tmp[] = {messageMetaEvent, metaInfoSetTempo, 0x03, 0,0,0};
643int us;
644
645 _VAR_CAST;
646 if (!IsFilePtrValid(pMF)) return FALSE;
647 if (!IsTrackValid(iTrack)) return FALSE;
648
649 us = 60000000L/iTempo;
650 tmp[3] = (BYTE)((us>>16)&0xff);
651 tmp[4] = (BYTE)((us>>8)&0xff);
652 tmp[5] = (BYTE)((us>>0)&0xff);
653 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
654}
655
656int midiSongAddMIDIPort(MidiFile *_pMF, int iTrack, int iPort)
657{
658static BYTE tmp[] = {messageMetaEvent, metaInfoMIDIPort, 1, 0};
659
660 _VAR_CAST;
661 if (!IsFilePtrValid(pMF)) return FALSE;
662 if (!IsTrackValid(iTrack)) return FALSE;
663 tmp[3] = (BYTE)iPort;
664 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
665}
666
667int midiSongAddEndSequence(MidiFile *_pMF, int iTrack)
668{
669static BYTE tmp[] = {messageMetaEvent, metaInfoEndSequence, 0};
670
671 _VAR_CAST;
672 if (!IsFilePtrValid(pMF)) return FALSE;
673 if (!IsTrackValid(iTrack)) return FALSE;
674
675 return midiTrackAddRaw(pMF, iTrack, sizeof(tmp), tmp, FALSE, 0);
676}
677
678int midiTrackAddRaw(MidiFile *_pMF, int iTrack, int data_sz, const BYTE *pData, int bMovePtr, int dt)
679{
680MidiFileTrack *pTrk;
681BYTE *ptr;
682int dtime;
683
684 _VAR_CAST;
685 if (!IsFilePtrValid(pMF)) return FALSE;
686 if (!IsTrackValid(iTrack)) return FALSE;
687
688 pTrk = &pMF->Track[iTrack];
689 ptr = _midiGetPtr(pMF, iTrack, data_sz+DT_DEF);
690 if (!ptr)
691 return FALSE;
692
693 dtime = pTrk->dt;
694 if (bMovePtr)
695 dtime += dt;
696
697 ptr = _midiWriteVarLen(ptr, dtime);
698 memcpy(ptr, pData, data_sz);
699
700 pTrk->pos += dtime;
701 pTrk->dt = 0;
702 pTrk->ptr = ptr+data_sz;
703
704 return TRUE;
705}
706
707
708int midiTrackIncTime(MidiFile *_pMF, int iTrack, int iDeltaTime, int bOverridePPQN)
709{
710DWORD will_end_at;
711
712 _VAR_CAST;
713 if (!IsFilePtrValid(pMF)) return FALSE;
714 if (!IsTrackValid(iTrack)) return FALSE;
715
716 will_end_at = _midiGetLength(pMF->Header.PPQN, iDeltaTime, bOverridePPQN);
717 will_end_at += pMF->Track[iTrack].pos + pMF->Track[iTrack].dt;
718
719 midiFileFlushTrack(pMF, iTrack, FALSE, will_end_at);
720
721 return TRUE;
722}
723
724int midiTrackAddText(MidiFile *_pMF, int iTrack, MidiTextInfo iType, const char *pTxt)
725{
726BYTE *ptr;
727int sz;
728
729 _VAR_CAST;
730 if (!IsFilePtrValid(pMF)) return FALSE;
731 if (!IsTrackValid(iTrack)) return FALSE;
732
733 sz = strlen(pTxt);
734 if ((ptr = _midiGetPtr(pMF, iTrack, sz+DT_DEF)))
735 {
736 *ptr++ = 0;
737 *ptr++ = messageMetaEvent;
738 *ptr++ = (BYTE)iType;
739 ptr = _midiWriteVarLen((BYTE *)ptr, sz);
740 strcopy((char *)ptr, pTxt);
741 pMF->Track[iTrack].ptr = ptr+sz;
742 return TRUE;
743 }
744 else
745 {
746 return FALSE;
747 }
748}
749
750int midiTrackSetKeyPressure(MidiFile *pMF, int iTrack, int iNote, int iAftertouch)
751{
752 return midiTrackAddMsg(pMF, iTrack, messageNoteKeyPressure, iNote, iAftertouch);
753}
754
755int midiTrackAddControlChange(MidiFile *pMF, int iTrack, MidiControlCommand iCCType, int iParam)
756{
757 return midiTrackAddMsg(pMF, iTrack, messageControlChange, iCCType, iParam);
758}
759
760int midiTrackAddProgramChange(MidiFile *pMF, int iTrack, int iInstrPatch)
761{
762 return midiTrackAddMsg(pMF, iTrack, messageSetProgram, iInstrPatch, 0);
763}
764
765int midiTrackChangeKeyPressure(MidiFile *pMF, int iTrack, int iDeltaPressure)
766{
767 return midiTrackAddMsg(pMF, iTrack, messageChangePressure, iDeltaPressure&0x7f, 0);
768}
769
770int midiTrackSetPitchWheel(MidiFile *pMF, int iTrack, int iWheelPos)
771{
772WORD wheel = (WORD)iWheelPos;
773
774 wheel += MIDI_WHEEL_CENTRE;
775 return midiTrackAddMsg(pMF, iTrack, messageSetPitchWheel, wheel&0x7f, (wheel>>7)&0x7f);
776}
777
778int midiTrackAddMsg(MidiFile *_pMF, int iTrack, MidiMessage iMsg, int iParam1, int iParam2)
779{
780BYTE *ptr;
781BYTE data[3];
782int sz;
783
784 _VAR_CAST;
785 if (!IsFilePtrValid(pMF)) return FALSE;
786 if (!IsTrackValid(iTrack)) return FALSE;
787 if (!IsMessageValid(iMsg)) return FALSE;
788
789 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
790 if (!ptr)
791 return FALSE;
792
793 data[0] = (BYTE)(iMsg | pMF->Track[iTrack].iDefaultChannel);
794 data[1] = (BYTE)(iParam1 & 0x7f);
795 data[2] = (BYTE)(iParam2 & 0x7f);
796 switch(iMsg)
797 {
798 case messageSetProgram:
800 sz = 2;
801 break;
802
803 default:
804 sz = 3;
805 break;
806 }
807
808 return midiTrackAddRaw(pMF, iTrack, sz, data, FALSE, 0);
809
810}
811
812int midiTrackAddNote(MidiFile *_pMF, int iTrack, int iNote, int iLength, int iVol, int bAutoInc, int bOverrideLength)
813{
814MidiFileTrack *pTrk;
815BYTE *ptr;
816int bSuccess = FALSE;
817int i, chn;
818
819 _VAR_CAST;
820 if (!IsFilePtrValid(pMF)) return FALSE;
821 if (!IsTrackValid(iTrack)) return FALSE;
822 if (!IsNoteValid(iNote)) return FALSE;
823
824 pTrk = &pMF->Track[iTrack];
825 ptr = _midiGetPtr(pMF, iTrack, DT_DEF);
826 if (!ptr)
827 return FALSE;
828
829 chn = pTrk->iDefaultChannel;
830 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverrideLength);
831
832 for(i=0;i<sizeof(pTrk->LastNote)/sizeof(pTrk->LastNote[0]);++i)
833 if (pTrk->LastNote[i].valid == FALSE)
834 {
835 pTrk->LastNote[i].note = (BYTE)iNote;
836 pTrk->LastNote[i].chn = (BYTE)chn;
837 pTrk->LastNote[i].end_pos = pTrk->pos+pTrk->dt+iLength;
838 pTrk->LastNote[i].valid = TRUE;
839 bSuccess = TRUE;
840
841 ptr = _midiWriteVarLen(ptr, pTrk->dt);
842 *ptr++ = (BYTE)(messageNoteOn | chn);
843 *ptr++ = (BYTE)iNote;
844 *ptr++ = (BYTE)iVol;
845 break;
846 }
847
848 if (!bSuccess)
849 return FALSE;
850
851 pTrk->ptr = ptr;
852
853 pTrk->pos += pTrk->dt;
854 pTrk->dt = 0;
855
856 if (bAutoInc)
857 return midiTrackIncTime(pMF, iTrack, iLength, bOverrideLength);
858
859 return TRUE;
860}
861
862int midiTrackAddRest(MidiFile *_pMF, int iTrack, int iLength, int bOverridePPQN)
863{
864 _VAR_CAST;
865 if (!IsFilePtrValid(pMF)) return FALSE;
866 if (!IsTrackValid(iTrack)) return FALSE;
867
868 iLength = _midiGetLength(pMF->Header.PPQN, iLength, bOverridePPQN);
869 return midiTrackIncTime(pMF, iTrack, iLength, bOverridePPQN);
870}
871
872int midiTrackGetEndPos(MidiFile *_pMF, int iTrack)
873{
874 _VAR_CAST;
875 if (!IsFilePtrValid(pMF)) return FALSE;
876 if (!IsTrackValid(iTrack)) return FALSE;
877
878 return pMF->Track[iTrack].pos;
879}
880
881static BYTE *_midiReadVarLen(BYTE *ptr, DWORD *num)
882{
883register DWORD value;
884register BYTE c;
885
886 if ((value = *ptr++) & 0x80)
887 {
888 value &= 0x7f;
889 do
890 {
891 value = (value << 7) + ((c = *ptr++) & 0x7f);
892 } while (c & 0x80);
893 }
894 *num = value;
895 return(ptr);
896}
897
898
899static int _midiReadTrackCopyData(MidiMessagePayload *pMsg, BYTE *ptr, DWORD sz, int bCopyPtrData)
900{
901 if (sz > pMsg->data_sz)
902 {
903 pMsg->data = (BYTE *)realloc(pMsg->data, sz);
904 pMsg->data_sz = sz;
905 }
906
907 if (!pMsg->data)
908 return FALSE;
909
910 if (bCopyPtrData && ptr)
911 memcpy(pMsg->data, ptr, sz);
912
913 return TRUE;
914}
915
917{
918 _VAR_CAST;
919 return pMF->Header.iNumTracks;
920}
921
922int midiReadGetNextMessage(const MidiFile *_pMF, int iTrack, MidiMessagePayload *pMsg)
923{
924MidiFileTrack *pTrack;
925BYTE *bptr, *pMsgDataPtr;
926int sz;
927
928 _VAR_CAST;
929 if (!IsTrackValid(iTrack)) return FALSE;
930
931 pTrack = &pMF->Track[iTrack];
932 if (pTrack->ptr >= pTrack->pEnd)
933 return FALSE;
934
935 pTrack->ptr = _midiReadVarLen(pTrack->ptr, &pMsg->dt);
936 pTrack->pos += pMsg->dt;
937
938 pMsg->dwAbsPos = pTrack->pos;
939
940 if (*pTrack->ptr & 0x80)
941 {
942 pMsg->iType = (MidiMessage)((*pTrack->ptr) & 0xf0);
943 pMsgDataPtr = pTrack->ptr+1;
944
945 if (pMsg->iType == 0xf0)
946 pMsg->iType = (MidiMessage)(*pTrack->ptr);
947 }
948 else
949 {
950 pMsg->iType = pMsg->iLastMsgType;
951 pMsgDataPtr = pTrack->ptr;
952 }
953
954 pMsg->iLastMsgType = (MidiMessage)pMsg->iType;
955 pMsg->iLastMsgChnl = (BYTE)((*pTrack->ptr) & 0x0f)+1;
956
957 switch(pMsg->iType)
958 {
959 case messageNoteOn:
960 pMsg->MsgData.NoteOn.iChannel = pMsg->iLastMsgChnl;
961 pMsg->MsgData.NoteOn.iNote = *(pMsgDataPtr);
962 pMsg->MsgData.NoteOn.iVolume = *(pMsgDataPtr+1);
963 pMsg->iMsgSize = 3;
964 // printf( "NOTE ON [channel=%2.2x, note=%2.2x, volume=%2.2x]\n",
965 // pMsg->MsgData.NoteOn.iChannel,
966 // pMsg->MsgData.NoteOn.iNote,
967 // pMsg->MsgData.NoteOn.iVolume
968 // );
969 break;
970
971 case messageNoteOff:
972 pMsg->MsgData.NoteOff.iChannel = pMsg->iLastMsgChnl;
973 pMsg->MsgData.NoteOff.iNote = *(pMsgDataPtr);
974 pMsg->iMsgSize = 3;
975 // printf( "NOTE OFF [channel=%2.2x, note=%2.2x]\n",
976 // pMsg->MsgData.NoteOff.iChannel,
977 // pMsg->MsgData.NoteOff.iNote
978 // );
979 break;
980
983 pMsg->MsgData.NoteKeyPressure.iNote = *(pMsgDataPtr);
984 pMsg->MsgData.NoteKeyPressure.iPressure = *(pMsgDataPtr+1);
985 pMsg->iMsgSize = 3;
986 // printf( "NOTE KEY PRESSURE [channel=%2.2x, note=%2.2x, pressure=%2.2x]\n",
987 // pMsg->MsgData.NoteKeyPressure.iChannel,
988 // pMsg->MsgData.NoteKeyPressure.iNote,
989 // pMsg->MsgData.NoteKeyPressure.iPressure
990 // );
991 break;
992
995 pMsg->MsgData.NoteParameter.iControl = (MidiControlCommand)*(pMsgDataPtr);
996 pMsg->MsgData.NoteParameter.iParam = *(pMsgDataPtr+1);
997 pMsg->iMsgSize = 3;
998 // printf( "SET PARAMETER [channel=%2.2x, control=%2.2x, param=%2.2x]\n",
999 // pMsg->MsgData.NoteParameter.iChannel,
1000 // pMsg->MsgData.NoteParameter.iControl,
1001 // pMsg->MsgData.NoteParameter.iParam
1002 // );
1003 break;
1004
1005 case messageSetProgram:
1007 pMsg->MsgData.ChangeProgram.iProgram = *(pMsgDataPtr);
1008 pMsg->iMsgSize = 2;
1009 // printf( "SET PROGRAM [channel=%2.2x, program=%2.2x]\n",
1010 // pMsg->MsgData.ChangeProgram.iChannel,
1011 // pMsg->MsgData.ChangeProgram.iProgram
1012 // );
1013 break;
1014
1017 pMsg->MsgData.ChangePressure.iPressure = *(pMsgDataPtr);
1018 pMsg->iMsgSize = 2;
1019 // printf( "CHANGE PRESSURE [channel=%2.2x, pressure=%2.2x]\n",
1020 // pMsg->MsgData.ChangePressure.iChannel,
1021 // pMsg->MsgData.ChangePressure.iPressure
1022 // );
1023 break;
1024
1027 pMsg->MsgData.PitchWheel.iPitch = *(pMsgDataPtr) | (*(pMsgDataPtr+1) << 7);
1029 pMsg->iMsgSize = 3;
1030 // printf( "PITCH WHEEL [channel=%2.2x, pitch=%2.2x]\n",
1031 // pMsg->MsgData.PitchWheel.iChannel,
1032 // pMsg->MsgData.PitchWheel.iPitch
1033 // );
1034 break;
1035
1036 case messageMetaEvent:
1037 // printf( "META EVENT\n" );
1038 bptr = pTrack->ptr;
1039 pMsg->MsgData.MetaEvent.iType = (MidiMetaInfo)*(pTrack->ptr+1);
1040 pTrack->ptr = _midiReadVarLen(pTrack->ptr+2, &pMsg->iMsgSize);
1041 sz = (pTrack->ptr-bptr)+pMsg->iMsgSize;
1042
1043 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE)
1044 return FALSE;
1045
1046 memcpy(pMsg->data, bptr, sz);
1047
1048 switch(pMsg->MsgData.MetaEvent.iType)
1049 {
1050 case metaInfoMIDIPort:
1051 pMsg->MsgData.MetaEvent.Data.iMIDIPort = *(pTrack->ptr+0);
1052 break;
1054 pMsg->MsgData.MetaEvent.Data.iSequenceNumber = *(pTrack->ptr+0);
1055 break;
1056 case metaInfoTextEvent:
1057 case metaInfoCopyright:
1058 case metaInfoTrackName:
1059 case metaInfoInstrument:
1060 case metaInfoLyric:
1061 case metaInfoMarker:
1062 case metaInfoCuePoint:
1063 pMsg->MsgData.MetaEvent.Data.Text.pData = pTrack->ptr;
1064 break;
1066 break;
1067 case metaInfoSetTempo:
1068 {
1069 DWORD us = ((*(pTrack->ptr+0))<<16)|((*(pTrack->ptr+1))<<8)|(*(pTrack->ptr+2));
1070 pMsg->MsgData.MetaEvent.Data.Tempo.iBPM = 60000000L/us;
1071 }
1072 break;
1074 pMsg->MsgData.MetaEvent.Data.SMPTE.iHours = *(pTrack->ptr+0);
1075 pMsg->MsgData.MetaEvent.Data.SMPTE.iMins= *(pTrack->ptr+1);
1076 pMsg->MsgData.MetaEvent.Data.SMPTE.iSecs = *(pTrack->ptr+2);
1077 pMsg->MsgData.MetaEvent.Data.SMPTE.iFrames = *(pTrack->ptr+3);
1078 pMsg->MsgData.MetaEvent.Data.SMPTE.iFF = *(pTrack->ptr+4);
1079 break;
1080 case metaInfoTimeSig:
1081 pMsg->MsgData.MetaEvent.Data.TimeSig.iNom = *(pTrack->ptr+0);
1083 break;
1084 case metaInfoKeySig:
1085 if (*pTrack->ptr & 0x80)
1086 {
1087 pMsg->MsgData.MetaEvent.Data.KeySig.iKey = ((256-*pTrack->ptr)&noteMaskKey);
1089 }
1090 else
1091 {
1093 }
1094 if (*(pTrack->ptr+1))
1096 break;
1099 pMsg->MsgData.MetaEvent.Data.Sequencer.pData = pTrack->ptr;
1100 break;
1101 }
1102
1103 pTrack->ptr += pMsg->iMsgSize;
1104 pMsg->iMsgSize = sz;
1105 break;
1106
1107 case messageSysEx1:
1108 case messageSysEx2:
1109 // printf( "SYS1/SYS2\n" );
1110 bptr = pTrack->ptr;
1111 pTrack->ptr = _midiReadVarLen(pTrack->ptr+1, &pMsg->iMsgSize);
1112 sz = (pTrack->ptr-bptr)+pMsg->iMsgSize;
1113
1114 if (_midiReadTrackCopyData(pMsg, pTrack->ptr, sz, FALSE) == FALSE)
1115 return FALSE;
1116
1117 memcpy(pMsg->data, bptr, sz);
1118 pTrack->ptr += pMsg->iMsgSize;
1119 pMsg->iMsgSize = sz;
1120 pMsg->MsgData.SysEx.pData = pMsg->data;
1121 pMsg->MsgData.SysEx.iSize = sz;
1122 break;
1123 }
1124 pMsg->bImpliedMsg = FALSE;
1125 if ((pMsg->iType&0xf0) != 0xf0)
1126 {
1127 if (*pTrack->ptr & 0x80)
1128 {
1129 }
1130 else
1131 {
1132 pMsg->bImpliedMsg = TRUE;
1133 pMsg->iImpliedMsg = pMsg->iLastMsgType;
1134 pMsg->iMsgSize--;
1135 }
1136 _midiReadTrackCopyData(pMsg, pTrack->ptr, pMsg->iMsgSize, TRUE);
1137 pTrack->ptr+=pMsg->iMsgSize;
1138 }
1139 return TRUE;
1140}
1141
1143{
1144 pMsg->data = NULL;
1145 pMsg->data_sz = 0;
1146 pMsg->bImpliedMsg = FALSE;
1147}
1148
1150{
1151 if (pMsg->data) free((void *)pMsg->data);
1152 pMsg->data = NULL;
1153}
1154
1155static char *szPatchList[128] = {
1156 "Acoustic Grand Piano",
1157 "Bright Acoustic Piano",
1158 "Electric Grand Piano",
1159 "Honky-tonk Piano",
1160 "Electric Piano 1",
1161 "Electric Piano 2",
1162 "Harpsichord",
1163 "Clavinet",
1164 "Celesta",
1165 "Glockenspiel",
1166 "Music Box",
1167 "Vibraphone",
1168 "Marimba",
1169 "Xylophone",
1170 "Tubular Bells",
1171 "Dulcimer",
1172 "Draw Organ",
1173 "Percussive Organ",
1174 "Rock Organ",
1175 "Church Organ",
1176 "Reed Organ",
1177 "Accordian",
1178 "Harmonica",
1179 "Tango Accordian",
1180 "Acoustic Guitar (nylon)",
1181 "Acoustic Guitar (steel)",
1182 "Electric Guitar (jazz)",
1183 "Electric Guitar (clean)",
1184 "Electric Guitar (muted)",
1185 "Overdriven Guitar",
1186 "Distortion Guitar",
1187 "Guitar harmonics",
1188 "Acoustic bass",
1189 "Electric Bass (finger)",
1190 "Electric Bass (picked)",
1191 "Fretless Bass",
1192 "Slap Bass 1",
1193 "Slap Bass 2",
1194 "Synth bass 1",
1195 "Synth bass 2",
1196 "Violin",
1197 "Viola",
1198 "Cello",
1199 "Contrabass",
1200 "Tremolo strings",
1201 "Pizzicato strings",
1202 "Orchestral harp",
1203 "Timpani",
1204 "String ensemble 1",
1205 "String ensemble 2",
1206 "Synth strings 1",
1207 "Synth strings 2",
1208 "Choir Ahhs",
1209 "Voice oohs",
1210 "Synth voice",
1211 "Orchestra hit",
1212 "Trumpet",
1213 "Trombone",
1214 "Tuba",
1215 "Muted trumpet",
1216 "French horn",
1217 "Brass section",
1218 "Synth brass 1",
1219 "Synth brass 2",
1220 "Soprano sax",
1221 "Alto sax",
1222 "Tenor sax",
1223 "Baritone sax",
1224 "Oboe",
1225 "English horn",
1226 "Bassoon",
1227 "Clarinet",
1228 "Picclo",
1229 "Flute",
1230 "Recorder",
1231 "Pan Flute",
1232 "Bottle Blow",
1233 "Shakuhachi",
1234 "Whistle",
1235 "Ocarina",
1236 "Lead 5 (Square)",
1237 "Lead 5 (Sawtooth)",
1238 "Lead 5 (Calliope)",
1239 "Lead 5 (Chiff)",
1240 "Lead 5 (Charang)",
1241 "Lead 5 (Voice)",
1242 "Lead 5 (Fifths)",
1243 "Lead 5 (Bass+lead)",
1244 "Pad 1 (New age)",
1245 "Pad 2 (Warm)",
1246 "Pad 3 (Polysynth)",
1247 "Pad 4 (Choir)",
1248 "Pad 5 (Bowed)",
1249 "Pad 6 (Metallic)",
1250 "Pad 7 (Halo)",
1251 "Pad 8 (Sweep)",
1252 "FX 1 (Rain)",
1253 "FX 2 (Soundtrack)",
1254 "FX 3 (Crystal)",
1255 "FX 4 (Atmosphere)",
1256 "FX 5 (Brightness)",
1257 "FX 6 (Goblins)",
1258 "FX 7 (Echoes)",
1259 "FX 8 (Sci-fi)",
1260 "Sitar",
1261 "Banjo",
1262 "Shamisen",
1263 "Koto",
1264 "Kalimba",
1265 "Bagpipe",
1266 "Fiddle",
1267 "Shanai",
1268 "Tinkle bell",
1269 "Agogo",
1270 "Steel drums",
1271 "Woodblock",
1272 "Taiko drum",
1273 "Melodic tom",
1274 "Synth drum",
1275 "Reverse cymbal",
1276 "Guitar fret noise",
1277 "Breath noise",
1278 "Seashore",
1279 "Bird tweet",
1280 "Telephone ring",
1281 "Helicopter",
1282 "Applause",
1283 "Gunshot",
1284};
1285
1286static char *szGMDrums[128]={
1287 "???",
1288 "???",
1289 "???",
1290 "???",
1291 "???",
1292 "???",
1293 "???",
1294 "???",
1295 "???",
1296 "???",
1297 "???",
1298 "???",
1299 "???",
1300 "???",
1301 "???",
1302 "???",
1303 "???",
1304 "???",
1305 "???",
1306 "???",
1307 "???",
1308 "???",
1309 "???",
1310 "???",
1311 "???",
1312 "???",
1313 "???",
1314 "High Q",
1315 "Slap",
1316 "???",
1317 "???",
1318 "Sticks",
1319 "Square click",
1320 "???",
1321 "???",
1322 "Acoustic Kick Drum",
1323 "Electric Kick Drum",
1324 "Side Stick",
1325 "Acoustic Snare Drum",
1326 "Hand Clap",
1327 "Electric Snare Drum ",
1328 "Low Floor Tom",
1329 "Closed Hi Hat",
1330 "High Floor Tom",
1331 "Opening Hi Hat",
1332 "Low Tom",
1333 "Open Hi Hat",
1334 "Low Mid Tom",
1335 "High Mid Tom",
1336 "Crash Cymbal 1",
1337 "High Tom",
1338 "Ride Cymbal 1",
1339 "Chinese Boom",
1340 "Ride Bell",
1341 "Tamborine",
1342 "Splash cymbal",
1343 "Cowbell",
1344 "Crash Cymbal (2)",
1345 "Vibra Slap",
1346 "Ride Cymbal (2)",
1347 "Hi bongo",
1348 "Lo bongo",
1349 "Mute High Conga",
1350 "Open High Conga",
1351 "Low Conga",
1352 "High Timbale",
1353 "Low Timbale",
1354 "High Agogo",
1355 "Low Agogo",
1356 "Cabasa",
1357 "Maracas",
1358 "Short Hi Whistle",
1359 "Long Low Whistle",
1360 "Short Guiro",
1361 "Long Guiro",
1362 "Claves",
1363 "High Woodblock",
1364 "Low Woodblock",
1365 "Mute Cuica",
1366 "Open Cuica",
1367 "Mute Triangle",
1368 "Open Triangle",
1369 "Shaker",
1370 "Jingle Bell",
1371 "Tring",
1372 "Castinets",
1373 "Mute Sudro",
1374 "Open Sudro",
1375};
1376
1377static char *szCCList[] = {
1378 "Bank Select",
1379 "Modulation",
1380 "Breath Control",
1381 "Undefined 3",
1382 "Foot",
1383 "Portamento Time",
1384 "Date Entry",
1385 "Volume ",
1386 "Balance",
1387 "Undefined 9",
1388 "Pan",
1389 "Expression",
1390 "Effort Control 1",
1391 "Effort Control 2",
1392 "Undefined 14",
1393 "Undefined 15",
1394 "General Purpose 1",
1395 "General Purpose 2",
1396 "General Purpose 3",
1397 "General Purpose 4",
1398 "Undefined 20",
1399 "Undefined 21",
1400 "Undefined 22",
1401 "Undefined 23",
1402 "Undefined 24",
1403 "Undefined 25",
1404 "Undefined 26",
1405 "Undefined 27",
1406 "Undefined 28",
1407 "Undefined 29",
1408 "Undefined 30",
1409 "Undefined 31",
1410 "lsb-32", "lsb-33", "lsb-34", "lsb-35", "lsb-36", "lsb-37", "lsb-38",
1411 "lsb-39", "lsb-40", "lsb-41", "lsb-42", "lsb-43", "lsb-44", "lsb-45",
1412 "lsb-46", "lsb-47", "lsb-48", "lsb-49", "lsb-50", "lsb-51", "lsb-52",
1413 "lsb-53", "lsb-54", "lsb-55", "lsb-56", "lsb-57", "lsb-58", "lsb-59",
1414 "lsb-60", "lsb-61", "lsb-62", "lsb-63",
1415
1416 "Sustain Pedal",
1417 "Portamento",
1418 "Pedal Sustenuto",
1419 "Pedal Soft",
1420 "Legato Foot Switch",
1421 "Hold 2",
1422 "Sound Variation",
1423 "Harm Content",
1424 "Release Time",
1425 "Attack Time",
1426 "Brightness",
1427 "Reverb",
1428 "Delay",
1429 "Pitch Transpose",
1430 "Flange",
1431 "Special FX",
1432 "General Purpose 5",
1433 "General Purpose 6",
1434 "General Purpose 7",
1435 "General Purpose 8",
1436 "Portamento Control",
1437 "Undefined 85",
1438 "Undefined 86",
1439 "Undefined 87",
1440 "Undefined 88",
1441 "Undefined 89",
1442 "Undefined 90",
1443 "FX Depth",
1444 "Tremelo Depth",
1445 "Chorus Depth",
1446 "Celesta Depth",
1447 "Phaser Depth",
1448 "Data Inc",
1449 "Data Dec",
1450 "Non Reg Param LSB",
1451 "Non Ref Param MSB",
1452 "Reg Param LSB",
1453 "Reg Param MSB",
1454 "Undefined 102",
1455 "Undefined 103",
1456 "Undefined 104",
1457 "Undefined 105",
1458 "Undefined 106",
1459 "Undefined 107",
1460 "Undefined 108",
1461 "Undefined 109",
1462 "Undefined 110",
1463 "Undefined 111",
1464 "Undefined 112",
1465 "Undefined 113",
1466 "Undefined 114",
1467 "Undefined 115",
1468 "Undefined 116",
1469 "Undefined 117",
1470 "Undefined 118",
1471 "Undefined 119",
1472 "All Sound Off",
1473 "Reset All Controllers",
1474 "Local Control",
1475 "All Notes Off",
1476 "Omni Mode Off",
1477 "Omni Mode On",
1478 "Mono Mode On",
1479 "Poly Mode On",
1480};
1481
1482static char *szNoteName[] = {
1483 "C ",
1484 "Db",
1485 "D ",
1486 "Eb",
1487 "E ",
1488 "F ",
1489 "Gb",
1490 "G ",
1491 "Ab",
1492 "A ",
1493 "Bb",
1494 "B ",
1495};
1496
1497static float fFreqlist[] = {
1498 261.63f,
1499 277.18f,
1500 293.66f,
1501 311.13f,
1502 329.63f,
1503 349.23f,
1504 369.99f,
1505 392.00f,
1506 415.30f,
1507 440.00f,
1508 466.16f,
1509 493.88f,
1510};
1511
1512int muGetInstrumentName(char *pName, int iInstr)
1513{
1514 if (iInstr < 0 || iInstr > 127)
1515 return FALSE;
1516 strcopy(pName, szPatchList[iInstr]);
1517 return TRUE;
1518}
1519
1520int muGetDrumName(char *pName, int iInstr)
1521{
1522 if (iInstr < 0 || iInstr > 127)
1523 return FALSE;
1524 strcopy(pName, szGMDrums[iInstr]);
1525 return TRUE;
1526}
1527
1528int muGetMIDIMsgName(char *pName, MidiMessage iMsg)
1529{
1530 switch(iMsg)
1531 {
1532 case messageNoteOff:
1533 strcopy(pName, "Note off");
1534 break;
1535
1536 case messageNoteOn:
1537 strcopy(pName, "Note on");
1538 break;
1539
1541 strcopy(pName, "Note key pressure");
1542 break;
1543
1545 strcopy(pName, "Set parameter");
1546 break;
1547
1548 case messageSetProgram:
1549 strcopy(pName, "Set program");
1550 break;
1551
1553 strcopy(pName, "Change pressure");
1554 break;
1555
1557 strcopy(pName, "Set pitch wheel");
1558 break;
1559
1560 case messageMetaEvent:
1561 strcopy(pName, "Meta event");
1562 break;
1563
1564 case messageSysEx1:
1565 strcopy(pName, "SysEx1");
1566 break;
1567
1568 case messageSysEx2:
1569 strcopy(pName, "SysEx2");
1570 break;
1571
1572 default:
1573 return FALSE;
1574 }
1575 return TRUE;
1576}
1577
1579{
1580 if (iCC < 0 || iCC > 127)
1581 return FALSE;
1582 strcopy(pName, szCCList[iCC]);
1583 return TRUE;
1584}
1585
1586int muGetKeySigName(char *pName, MidiNote iKey)
1587{
1588static char *iKeysList[2][8] = {
1589{"C ", "G ", "D ", "A ", "E ", "B ", "F#", "C#", },
1590{"C ", "F ", "Bb", "Eb", "Ab", "Db", "Gb", "Cb", },
1591};
1592
1593int iRootNum = (iKey&7);
1594int iFlats = (iKey&noteMaskNeg);
1595int iMin = (iKey&noteMaskMin);
1596
1597 strcopy(pName,iKeysList[iFlats?1:0][iRootNum]);
1598 strcat(pName,iMin?" Min":" Maj");
1599 return TRUE;
1600}
1601
1602int muGetTextName(char *pName, MidiTextInfo iEvent)
1603{
1604 if (iEvent<1 || iEvent>7) return FALSE;
1605 return muGetMetaName(pName, (MidiMetaInfo)iEvent);
1606}
1607
1608int muGetMetaName(char *pName, MidiMetaInfo iEvent)
1609{
1610 switch(iEvent)
1611 {
1612 case metaInfoSequenceNumber: strcopy(pName, "Sequence Number"); break;
1613 case metaInfoTextEvent: strcopy(pName, "Text Event"); break;
1614 case metaInfoCopyright: strcopy(pName, "Copyright"); break;
1615 case metaInfoTrackName: strcopy(pName, "Track Name"); break;
1616 case metaInfoInstrument: strcopy(pName, "Instrument"); break;
1617 case metaInfoLyric: strcopy(pName, "Lyric"); break;
1618 case metaInfoMarker: strcopy(pName, "Marker"); break;
1619 case metaInfoCuePoint: strcopy(pName, "Cue Point"); break;
1620 case metaInfoMIDIPort: strcopy(pName, "MIDI Port"); break;
1621 case metaInfoEndSequence: strcopy(pName, "End Sequence"); break;
1622 case metaInfoSetTempo: strcopy(pName, "Set Tempo"); break;
1623 case metaInfoSMPTEOffset: strcopy(pName, "SMPTE Offset"); break;
1624 case metaInfoTimeSig: strcopy(pName, "Time Sig"); break;
1625 case metaInfoKeySig: strcopy(pName, "Key Sig"); break;
1626 case metaInfoSequencerSpecific: strcopy(pName, "Sequencer Specific"); break;
1627 default: return FALSE;
1628 }
1629 return TRUE;
1630
1631}
1632
1633int muGetNoteFromName(const char *pName)
1634{
1635int note_map[] = {9, 11, 0, 2, 4, 5, 7};
1636char *p, cpy[16];
1637int note=0;
1638
1639 strncpy(cpy, pName, 15);
1640 cpy[15] = '\0';
1641 p = cpy;
1642
1643 while(!isalpha(*p) && *p)
1644 p++;
1645
1646 if (*p)
1647 {
1648 note = toupper(*p)-'A';
1649 if (note >= 0 && note <= 7)
1650 {
1651 note = note_map[note];
1652 p++;
1653 if (*p == 'b')
1654 note--, p++;
1655 else if (*p == '#')
1656 note++, p++;
1657
1658 note += atoi(p)*12+MIDI_NOTE_C0;
1659 }
1660 }
1661
1662 return note;
1663}
1664
1665char *muGetNameFromNote(char *pStr, int iNote)
1666{
1667 if (!pStr) return NULL;
1668
1669 if (iNote<0 || iNote>127)
1670 strcopy(pStr, "ERR");
1671 else
1672 sprintf(pStr, "%s%d", szNoteName[iNote%12], ((iNote-MIDI_NOTE_C0)/12));
1673
1674 return pStr;
1675}
1676
1677float muGetFreqFromNote(int iNote)
1678{
1679int oct = iNote/12-5;
1680float freq;
1681
1682 if (iNote<0 || iNote>127) return 0;
1683
1684 freq = fFreqlist[iNote%12];
1685
1686 while(oct > 0)
1687 freq *= 2.0f, oct--;
1688
1689 while(oct < 0)
1690 freq /= 2.0f, oct++;
1691
1692 return freq;
1693}
1694
1695int muGetNoteFromFreq(float fFreq)
1696{
1697int iNote, iBestNote=0;
1698float fDiff=20000, f;
1699
1700 for(iNote=0;iNote<127;++iNote)
1701 {
1702 f = muGetFreqFromNote(iNote);
1703 f -= fFreq; if (f<0) f=-f;
1704 if (f < fDiff)
1705 {
1706 fDiff = f;
1707 iBestNote = iNote;
1708 }
1709 }
1710
1711 return iBestNote;
1712}
1713
1714
1715int muGuessChord(const int *pNoteStatus, const int channel, const int lowRange, const int highRange) {
1716 int octave[24];
1717 int i;
1718 int lowestNote=999;
1719 int startNote = 999;
1720 int chordRoot = 0;
1721 int chordType = 0;
1722 int chordAdditions = 0;
1723
1724 for(i=0;i<24;++i) {
1725 octave[i] = 0;
1726 }
1727
1728 for(i=lowRange;i<=highRange;++i) {
1729 if (pNoteStatus[channel*128 + i]) {
1730 if (i<lowestNote) {
1731 lowestNote = i;
1732 }
1733 ++octave[i%12];
1734 ++octave[i%12+12];
1735 if ((i%12) < startNote) {
1736 startNote = i%12;
1737 }
1738 }
1739 }
1740
1741 if (lowestNote == 999) {
1742 return -1;
1743 }
1744
1745 lowestNote %= 12;
1746
1747 if (octave[startNote+3] && octave[startNote+8]) {
1748 chordRoot = startNote+8;
1749 chordType = CHORD_TYPE_MAJOR;
1750 } else if (octave[startNote+5] && octave[startNote+9]) {
1751 chordRoot = startNote+5;
1752 chordType = CHORD_TYPE_MAJOR;
1753 } else if (octave[startNote+4] && octave[startNote+7]) {
1754 chordRoot = startNote;
1755 chordType = CHORD_TYPE_MAJOR;
1756 } else if (octave[startNote+4] && octave[startNote+9]) {
1757 chordRoot = startNote+9;
1758 chordType = CHORD_TYPE_MINOR;
1759 } else if (octave[startNote+5] && octave[startNote+8]) {
1760 chordRoot = startNote+5;
1761 chordType = CHORD_TYPE_MINOR;
1762 } else if (octave[startNote+3] && octave[startNote+7]) {
1763 chordRoot = startNote;
1764 chordType = CHORD_TYPE_MINOR;
1765 } else if (octave[startNote+3] && octave[startNote+6]) {
1766 chordRoot = lowestNote;
1767 chordType = CHORD_TYPE_DIM;
1768 } else if (octave[startNote+6] && octave[startNote+9]) {
1769 chordRoot = lowestNote;
1770 chordType = CHORD_TYPE_DIM;
1771 } else if (octave[startNote+4] && octave[startNote+8]) {
1772 chordRoot = lowestNote;
1773 chordType = CHORD_TYPE_AUG;
1774 }
1775 if (octave[chordRoot + 10]) {
1776 chordAdditions |= CHORD_ADD_7TH;
1777 }
1778 if (octave[chordRoot + 11]) {
1779 chordAdditions |= CHORD_ADD_MAJ7TH;
1780 }
1781 if (octave[chordRoot + 2]) {
1782 chordAdditions |= CHORD_ADD_9TH;
1783 }
1784
1785 chordRoot %= 12;
1786
1787 if (chordType == 0) {
1788 return -1;
1789 }
1790
1791 return chordRoot | chordType | chordAdditions | (lowestNote<<16);
1792}
1793
1794char *muGetChordName(char *str, int chord) {
1795 int root = chord & CHORD_ROOT_MASK;
1796 int bass = (chord & CHORD_BASS_MASK) >> 16;
1797
1798 if (root < 0 || root > 11) {
1799 root = 0;
1800 }
1801
1802 if (bass < 0 || bass > 11) {
1803 bass = 0;
1804 }
1805
1806 strcopy(str, szNoteName[root]);
1807
1808 switch(chord & CHORD_TYPE_MASK) {
1809 case CHORD_TYPE_MAJOR:
1810 break;
1811 case CHORD_TYPE_MINOR:
1812 strcat(str, "m");
1813 break;
1814 case CHORD_TYPE_AUG:
1815 strcat(str, " aug");
1816 break;
1817 case CHORD_TYPE_DIM:
1818 strcat(str, " dim");
1819 break;
1820 }
1821
1822 if (chord & CHORD_ADD_7TH) {
1823 strcat(str, "+7");
1824 }
1825 if (chord & CHORD_ADD_9TH) {
1826 strcat(str, "+9");
1827 }
1828 if (chord & CHORD_ADD_MAJ7TH) {
1829 strcat(str, "+7M");
1830 }
1831
1832 if (bass != root) {
1833 strcat(str, "/");
1834 strcat(str, szNoteName[bass]);
1835 }
1836
1837 return str;
1838}
int size
Definition _optimizer.c:678
#define SWAP_WORD(w)
Definition midi.c:89
#define IsTrackValid(_x)
Definition midi.c:95
int midiTrackAddText(MidiFile *_pMF, int iTrack, MidiTextInfo iType, const char *pTxt)
Definition midi.c:724
float muGetFreqFromNote(int iNote)
Definition midi.c:1677
int midiTrackAddRest(MidiFile *_pMF, int iTrack, int iLength, int bOverridePPQN)
Definition midi.c:862
int muGetMetaName(char *pName, MidiMetaInfo iEvent)
Definition midi.c:1608
struct _MidiFileInternal MidiFileInternal
int midiTrackAddControlChange(MidiFile *pMF, int iTrack, MidiControlCommand iCCType, int iParam)
Definition midi.c:755
int muGetMIDIMsgName(char *pName, MidiMessage iMsg)
Definition midi.c:1528
int midiTrackSetKeyPressure(MidiFile *pMF, int iTrack, int iNote, int iAftertouch)
Definition midi.c:750
int midiSongAddSimpleTimeSig(MidiFile *_pMF, int iTrack, int iNom, int iDenom)
Definition midi.c:607
#define SWAP_DWORD(d)
Definition midi.c:90
int midiTrackAddNote(MidiFile *_pMF, int iTrack, int iNote, int iLength, int iVol, int bAutoInc, int bOverrideLength)
Definition midi.c:812
int muGetKeySigName(char *pName, MidiNote iKey)
Definition midi.c:1586
int muGetNoteFromName(const char *pName)
Definition midi.c:1633
int muGuessChord(const int *pNoteStatus, const int channel, const int lowRange, const int highRange)
Definition midi.c:1715
int midiFileGetPPQN(const MidiFile *_pMF)
Definition midi.c:319
int midiTrackAddRaw(MidiFile *_pMF, int iTrack, int data_sz, const BYTE *pData, int bMovePtr, int dt)
Definition midi.c:678
int midiFileSetPPQN(MidiFile *_pMF, int PPQN)
Definition midi.c:308
#define _VAR_CAST
Definition midi.c:93
int midiTrackGetEndPos(MidiFile *_pMF, int iTrack)
Definition midi.c:872
int midiSongAddTempo(MidiFile *_pMF, int iTrack, int iTempo)
Definition midi.c:640
int midiFileSetVersion(MidiFile *_pMF, int iVersion)
Definition midi.c:326
MidiFile * midiFileOpen(const char *pFilename)
Definition midi.c:345
int muGetNoteFromFreq(float fFreq)
Definition midi.c:1695
int muGetControlName(char *pName, MidiControlCommand iCC)
Definition midi.c:1578
int midiReadGetNextMessage(const MidiFile *_pMF, int iTrack, MidiMessagePayload *pMsg)
Definition midi.c:922
int midiSongAddTimeSig(MidiFile *_pMF, int iTrack, int iNom, int iDenom, int iClockInMetroTick, int iNotated32nds)
Definition midi.c:612
char * muGetChordName(char *str, int chord)
Definition midi.c:1794
void midiReadInitMessage(MidiMessagePayload *pMsg)
Definition midi.c:1142
int midiTrackSetPitchWheel(MidiFile *pMF, int iTrack, int iWheelPos)
Definition midi.c:770
int midiFileGetVersion(const MidiFile *_pMF)
Definition midi.c:338
struct _MidiFileTrack MidiFileTrack
struct _MidiHeader MidiHeader
int midiTrackAddMsg(MidiFile *_pMF, int iTrack, MidiMessage iMsg, int iParam1, int iParam2)
Definition midi.c:778
#define IsChannelValid(_x)
Definition midi.c:96
struct _MidiLastNote MidiLastNote
int muGetInstrumentName(char *pName, int iInstr)
Definition midi.c:1512
#define IsMessageValid(_x)
Definition midi.c:98
int midiSongAddMIDIPort(MidiFile *_pMF, int iTrack, int iPort)
Definition midi.c:656
#define IsFilePtrValid(pMF)
Definition midi.c:94
MidiFile * midiFileCreate(const char *pFilename, int bOverwriteIfExists)
Definition midi.c:240
#define IsNoteValid(_x)
Definition midi.c:97
char * muGetNameFromNote(char *pStr, int iNote)
Definition midi.c:1665
char * strcopy(char *_dest, const char *_source)
int midiFileSyncTracks(MidiFile *_pMF, int iTrack1, int iTrack2)
Definition midi.c:496
int midiSongAddEndSequence(MidiFile *_pMF, int iTrack)
Definition midi.c:667
int midiFileFlushTrack(MidiFile *_pMF, int iTrack, int bFlushToEnd, DWORD dwEndTimePos)
Definition midi.c:433
#define DT_DEF
Definition midi.c:78
int muGetTextName(char *pName, MidiTextInfo iEvent)
Definition midi.c:1602
int midiFileSetTracksDefaultChannel(MidiFile *_pMF, int iTrack, int iChannel)
Definition midi.c:285
int midiSongAddSMPTEOffset(MidiFile *_pMF, int iTrack, int iHours, int iMins, int iSecs, int iFrames, int iFFrames)
Definition midi.c:586
int midiTrackIncTime(MidiFile *_pMF, int iTrack, int iDeltaTime, int bOverridePPQN)
Definition midi.c:708
int midiTrackAddProgramChange(MidiFile *pMF, int iTrack, int iInstrPatch)
Definition midi.c:760
int midiTrackChangeKeyPressure(MidiFile *pMF, int iTrack, int iDeltaPressure)
Definition midi.c:765
int midiFileGetTracksDefaultChannel(const MidiFile *_pMF, int iTrack)
Definition midi.c:299
int midiSongAddKeySig(MidiFile *_pMF, int iTrack, MidiNote iKey)
Definition midi.c:627
int midiReadGetNumTracks(const MidiFile *_pMF)
Definition midi.c:916
void midiReadFreeMessage(MidiMessagePayload *pMsg)
Definition midi.c:1149
int muGetDrumName(char *pName, int iInstr)
Definition midi.c:1520
int midiFileClose(MidiFile *_pMF)
Definition midi.c:515
enum _MidiMetaInfo MidiMetaInfo
@ messageChangePressure
Definition midi.h:42
@ messageNoteOn
Definition midi.h:38
@ messageSysEx1
Definition midi.h:45
@ messageSetPitchWheel
Definition midi.h:43
@ messageControlChange
Definition midi.h:48
@ messageMetaEvent
Definition midi.h:44
@ messageNoteKeyPressure
Definition midi.h:39
@ messageNoteOff
Definition midi.h:37
@ messageSetProgram
Definition midi.h:41
@ messageSetParameter
Definition midi.h:40
@ messageSysEx2
Definition midi.h:46
@ noteMaskNeg
Definition midi.h:257
@ noteMaskKey
Definition midi.h:260
@ noteMaskMin
Definition midi.h:259
#define MIDI_DURATION_MINIM
Definition midi.h:363
#define MIDI_DURATION_DOTTED_SEMIQUAVER
Definition midi.h:372
#define MIDI_DURATION_DOTTED_QUAVER
Definition midi.h:371
#define CHORD_ADD_7TH
Definition midi.h:568
#define MIDI_DURATION_QUAVER
Definition midi.h:365
#define MIDI_DURATION_TRIPLE_CROCHET
Definition midi.h:375
struct _MidiMessagePayload MidiMessagePayload
#define MIDI_DURATION_SEMIQUAVER
Definition midi.h:366
unsigned char BYTE
Definition midi.h:586
#define MIDI_DURATION_BREVE
Definition midi.h:362
#define MIDI_VERSION_DEFAULT
Definition midi.h:597
enum _MidiMessage MidiMessage
#define CHORD_ADD_MAJ7TH
Definition midi.h:570
#define CHORD_BASS_MASK
Definition midi.h:560
#define MIDI_DURATION_DOTTED_SEMIDEMIQUAVER
Definition midi.h:373
#define CHORD_TYPE_AUG
Definition midi.h:565
#define MIDI_NOTE_C0
Definition midi.h:338
#define MIDI_DURATION_DOTTED_MINIM
Definition midi.h:369
enum _ControlCommand MidiControlCommand
#define MAX_TRACK_POLYPHONY
Definition midi.h:600
void MidiFile
Definition midi.h:602
#define CHORD_TYPE_MINOR
Definition midi.h:564
#define CHORD_TYPE_MASK
Definition midi.h:559
#define MIDI_WHEEL_CENTRE
Definition midi.h:291
#define TRUE
Definition midi.h:590
#define FALSE
Definition midi.h:593
uint16_t WORD
Definition midi.h:587
#define CHORD_ADD_9TH
Definition midi.h:569
#define MAX_MIDI_TRACKS
Definition midi.h:599
#define CHORD_ROOT_MASK
Definition midi.h:558
enum _MidiTextInfo MidiTextInfo
#define MIDI_DURATION_SEMIDEMIQUAVER
Definition midi.h:367
enum _MidiNote MidiNote
#define CHORD_TYPE_MAJOR
Definition midi.h:563
#define MIDI_PPQN_DEFAULT
Definition midi.h:596
#define MIDI_DURATION_DOTTED_CROCHET
Definition midi.h:370
@ metaInfoTrackName
Definition midi.h:267
@ metaInfoTextEvent
Definition midi.h:265
@ metaInfoCuePoint
Definition midi.h:271
@ metaInfoSequenceNumber
Definition midi.h:264
@ metaInfoKeySig
Definition midi.h:277
@ metaInfoMarker
Definition midi.h:270
@ metaInfoSequencerSpecific
Definition midi.h:278
@ metaInfoSetTempo
Definition midi.h:274
@ metaInfoMIDIPort
Definition midi.h:272
@ metaInfoInstrument
Definition midi.h:268
@ metaInfoTimeSig
Definition midi.h:276
@ metaInfoCopyright
Definition midi.h:266
@ metaInfoEndSequence
Definition midi.h:273
@ metaInfoLyric
Definition midi.h:269
@ metaInfoSMPTEOffset
Definition midi.h:275
uint32_t DWORD
Definition midi.h:588
#define CHORD_TYPE_DIM
Definition midi.h:566
#define cpy(ticks, adrmode)
Definition sidreloc.c:535
MidiFileTrack Track[MAX_MIDI_TRACKS]
Definition midi.c:75
MidiHeader Header
Definition midi.c:72
FILE * pFile
Definition midi.c:70
int bOpenForWriting
Definition midi.c:71
DWORD file_sz
Definition midi.c:74
BYTE * ptr
Definition midi.c:73
DWORD sz
Definition midi.c:55
BYTE * pBase
Definition midi.c:51
DWORD dt
Definition midi.c:54
BYTE iDefaultChannel
Definition midi.c:57
DWORD pos
Definition midi.c:53
BYTE * pEnd
Definition midi.c:52
DWORD iBlockSize
Definition midi.c:56
BYTE * ptr
Definition midi.c:50
BYTE last_status
Definition midi.c:58
MidiLastNote LastNote[MAX_TRACK_POLYPHONY]
Definition midi.c:59
DWORD iHeaderSize
Definition midi.c:63
WORD iVersion
Definition midi.c:64
WORD iNumTracks
Definition midi.c:65
WORD PPQN
Definition midi.c:66
BYTE note
Definition midi.c:44
BYTE p2
Definition midi.c:45
BYTE valid
Definition midi.c:45
BYTE chn
Definition midi.c:44
DWORD end_pos
Definition midi.c:46
union _MidiMessagePayload::_MsgData::_MetaEvent::_Data Data
MidiMessage iLastMsgType
Definition midi.h:682
MidiMessage iImpliedMsg
Definition midi.h:612
union _MidiMessagePayload::_MsgData MsgData
MidiMessage iType
Definition midi.h:605
int iEndPos
Definition midi.c:422
void * malloc(YYSIZE_T)
void free(void *)
char version[MAX_TEMPORARY_STORAGE]
Definition ugbc.tab.c:53835
@ L
Definition ugbc.tab.h:508
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_Tempo Tempo
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_KeySig KeySig
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_SMPTE SMPTE
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_Sequencer Sequencer
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_Text Text
struct _MidiMessagePayload::_MsgData::_MetaEvent::_Data::_TimeSig TimeSig
struct _MidiMessagePayload::_MsgData::_NoteOff NoteOff
struct _MidiMessagePayload::_MsgData::_SysEx SysEx
struct _MidiMessagePayload::_MsgData::_NoteParameter NoteParameter
struct _MidiMessagePayload::_MsgData::_MetaEvent MetaEvent
struct _MidiMessagePayload::_MsgData::_NoteKeyPressure NoteKeyPressure
struct _MidiMessagePayload::_MsgData::_PitchWheel PitchWheel
struct _MidiMessagePayload::_MsgData::_ChangeProgram ChangeProgram
struct _MidiMessagePayload::_MsgData::_ChangePressure ChangePressure
struct _MidiMessagePayload::_MsgData::_NoteOn NoteOn