annotate decoders/timidity/readmidi.c @ 474:c66080364dff

Most decoders now report total sample play time, now. Technically, this breaks binary compatibility with the 1.0 branch, since it extends the Sound_Sample struct, but most (all?) programs are just passing pointers allocated by SDL_sound around, and might be okay. Source-level compatibility is not broken...yet! :) --ryan. -------- Original Message -------- Subject: SDL_sound patch: Finding total length of time of sound file. Date: Sun, 26 Jan 2003 09:31:17 -0800 (PST) Hi Ryan, I am working with Eric Wing and helping him modify SDL_sound. AS part of our efforts in improving and enhancing SDL_sound, we like to submit this patch. We modified the codecs to find the total time of a sound file. Below is the explanation of the patch. The patch is appended as an attachment to this email. * MOTIVATION: We needed the ability to get the total play time of a sample (And we noticed that we're not the only ones). Since SDL_sound blocks direct access to the specific decoders, there is no way for a user to know this information short of decoding the whole thing. Because of this, we believe this will be a useful addition, even though the accuracy may not be perfect (subject to each decoder) or the information may not always be available. * CONTRIBUTORS: Wesley Leong (modified the majority of the codecs and verified the results) Eric Wing (showed everyone how to do modify codec, modified mikmod) Wang Lam (modified a handful of codecs, researched into specs and int overflow) Ahilan Anantha (modified a few codecs and helped with integer math) * GENERAL ISSUES: We chose the value to be milliseconds as an Sint32. Milliseconds because that's what Sound_Seek takes as a parameter and -1 to allow for instances/codecs where the value could not be determined. We are not sure if this is the final convention you want, so we are willing to work with you on this. We also expect the total_time field to be set on open and never again modified by SDL_sound. Users may access it directly much like the sample buffer and buffer_size. We thought about recomputing the time on DecodeAll, but since users may seek or decode small chunks first, not all the data may be there. So this is better done by the user. This may be good information to document. Currently, all the main codecs are implemented except for QuickTime.
author Ryan C. Gordon <icculus@icculus.org>
date Sat, 08 May 2004 08:19:50 +0000
parents 2d887640d300
children
rev   line source
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
1 /*
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
2
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
3 TiMidity -- Experimental MIDI to WAVE converter
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
4 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
5
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
6 This program is free software; you can redistribute it and/or modify
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
7 it under the terms of the GNU General Public License as published by
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
8 the Free Software Foundation; either version 2 of the License, or
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
9 (at your option) any later version.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
10
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
11 This program is distributed in the hope that it will be useful,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
14 GNU General Public License for more details.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
15
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
17 along with this program; if not, write to the Free Software
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
19
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
20 */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
21
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
22 #if HAVE_CONFIG_H
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
23 # include <config.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
24 #endif
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
25
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
26 #include <stdio.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
27 #include <stdlib.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
28 #include <string.h>
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
29
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
30 #include "SDL_sound.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
31
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
32 #define __SDL_SOUND_INTERNAL__
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
33 #include "SDL_sound_internal.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
34
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
35 #include "timidity.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
36 #include "common.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
37 #include "instrum.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
38 #include "playmidi.h"
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
39
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
40 /* Computes how many (fractional) samples one MIDI delta-time unit contains */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
41 static void compute_sample_increment(MidiSong *song, Sint32 tempo,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
42 Sint32 divisions)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
43 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
44 double a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
45 a = (double) (tempo) * (double) (song->rate) * (65536.0/1000000.0) /
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
46 (double)(divisions);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
47
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
48 song->sample_correction = (Sint32)(a) & 0xFFFF;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
49 song->sample_increment = (Sint32)(a) >> 16;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
50
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
51 SNDDBG(("Samples per delta-t: %d (correction %d)",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
52 song->sample_increment, song->sample_correction));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
53 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
54
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
55 /* Read variable-length number (7 bits per byte, MSB first) */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
56 static Sint32 getvl(SDL_RWops *rw)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
57 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
58 Sint32 l=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
59 Uint8 c;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
60 for (;;)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
61 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
62 SDL_RWread(rw, &c, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
63 l += (c & 0x7f);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
64 if (!(c & 0x80)) return l;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
65 l<<=7;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
66 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
67 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
68
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
69 /* Print a string from the file, followed by a newline. Any non-ASCII
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
70 or unprintable characters will be converted to periods. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
71 static int dumpstring(SDL_RWops *rw, Sint32 len, char *label)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
72 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
73 signed char *s=safe_malloc(len+1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
74 if (len != (Sint32) SDL_RWread(rw, s, 1, len))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
75 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
76 free(s);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
77 return -1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
78 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
79 s[len]='\0';
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
80 while (len--)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
81 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
82 if (s[len]<32)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
83 s[len]='.';
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
84 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
85 SNDDBG(("%s%s", label, s));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
86 free(s);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
87 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
88 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
89
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
90 #define MIDIEVENT(at,t,ch,pa,pb) \
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
91 new=safe_malloc(sizeof(MidiEventList)); \
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
92 new->event.time=at; new->event.type=t; new->event.channel=ch; \
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
93 new->event.a=pa; new->event.b=pb; new->next=0;\
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
94 return new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
95
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
96 #define MAGIC_EOT ((MidiEventList *)(-1))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
97
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
98 /* Read a MIDI event, returning a freshly allocated element that can
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
99 be linked to the event list */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
100 static MidiEventList *read_midi_event(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
101 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
102 static Uint8 laststatus, lastchan;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
103 static Uint8 nrpn=0, rpn_msb[16], rpn_lsb[16]; /* one per channel */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
104 Uint8 me, type, a,b,c;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
105 Sint32 len;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
106 MidiEventList *new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
107
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
108 for (;;)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
109 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
110 song->at += getvl(song->rw);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
111 if (SDL_RWread(song->rw, &me, 1, 1) != 1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
112 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
113 SNDDBG(("read_midi_event: SDL_RWread() failure\n"));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
114 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
115 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
116
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
117 if(me==0xF0 || me == 0xF7) /* SysEx event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
118 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
119 len=getvl(song->rw);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
120 SDL_RWseek(song->rw, len, SEEK_CUR);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
121 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
122 else if(me==0xFF) /* Meta event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
123 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
124 SDL_RWread(song->rw, &type, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
125 len=getvl(song->rw);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
126 if (type>0 && type<16)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
127 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
128 static char *label[]={
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
129 "Text event: ", "Text: ", "Copyright: ", "Track name: ",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
130 "Instrument: ", "Lyric: ", "Marker: ", "Cue point: "};
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
131 dumpstring(song->rw, len, label[(type>7) ? 0 : type]);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
132 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
133 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
134 switch(type)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
135 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
136 case 0x2F: /* End of Track */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
137 return MAGIC_EOT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
138
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
139 case 0x51: /* Tempo */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
140 SDL_RWread(song->rw, &a, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
141 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
142 SDL_RWread(song->rw, &c, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
143 MIDIEVENT(song->at, ME_TEMPO, c, a, b);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
144
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
145 default:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
146 SNDDBG(("(Meta event type 0x%02x, length %d)\n", type, len));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
147 SDL_RWseek(song->rw, len, SEEK_CUR);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
148 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
149 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
150 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
151 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
152 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
153 a=me;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
154 if (a & 0x80) /* status byte */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
155 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
156 lastchan=a & 0x0F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
157 laststatus=(a>>4) & 0x07;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
158 SDL_RWread(song->rw, &a, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
159 a &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
160 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
161 switch(laststatus)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
162 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
163 case 0: /* Note off */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
164 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
165 b &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
166 MIDIEVENT(song->at, ME_NOTEOFF, lastchan, a,b);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
167
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
168 case 1: /* Note on */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
169 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
170 b &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
171 MIDIEVENT(song->at, ME_NOTEON, lastchan, a,b);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
172
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
173 case 2: /* Key Pressure */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
174 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
175 b &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
176 MIDIEVENT(song->at, ME_KEYPRESSURE, lastchan, a, b);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
177
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
178 case 3: /* Control change */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
179 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
180 b &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
181 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
182 int control=255;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
183 switch(a)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
184 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
185 case 7: control=ME_MAINVOLUME; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
186 case 10: control=ME_PAN; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
187 case 11: control=ME_EXPRESSION; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
188 case 64: control=ME_SUSTAIN; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
189 case 120: control=ME_ALL_SOUNDS_OFF; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
190 case 121: control=ME_RESET_CONTROLLERS; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
191 case 123: control=ME_ALL_NOTES_OFF; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
192
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
193 /* These should be the SCC-1 tone bank switch
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
194 commands. I don't know why there are two, or
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
195 why the latter only allows switching to bank 0.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
196 Also, some MIDI files use 0 as some sort of
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
197 continuous controller. This will cause lots of
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
198 warnings about undefined tone banks. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
199 case 0: control=ME_TONE_BANK; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
200 case 32:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
201 if (b!=0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
202 SNDDBG(("(Strange: tone bank change 0x20%02x)\n", b));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
203 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
204 control=ME_TONE_BANK;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
205 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
206
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
207 case 100: nrpn=0; rpn_msb[lastchan]=b; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
208 case 101: nrpn=0; rpn_lsb[lastchan]=b; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
209 case 99: nrpn=1; rpn_msb[lastchan]=b; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
210 case 98: nrpn=1; rpn_lsb[lastchan]=b; break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
211
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
212 case 6:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
213 if (nrpn)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
214 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
215 SNDDBG(("(Data entry (MSB) for NRPN %02x,%02x: %d)\n",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
216 rpn_msb[lastchan], rpn_lsb[lastchan], b));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
217 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
218 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
219
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
220 switch((rpn_msb[lastchan]<<8) | rpn_lsb[lastchan])
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
221 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
222 case 0x0000: /* Pitch bend sensitivity */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
223 control=ME_PITCH_SENS;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
224 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
225
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
226 case 0x7F7F: /* RPN reset */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
227 /* reset pitch bend sensitivity to 2 */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
228 MIDIEVENT(song->at, ME_PITCH_SENS, lastchan, 2, 0);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
229
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
230 default:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
231 SNDDBG(("(Data entry (MSB) for RPN %02x,%02x: %d)\n",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
232 rpn_msb[lastchan], rpn_lsb[lastchan], b));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
233 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
234 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
235 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
236
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
237 default:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
238 SNDDBG(("(Control %d: %d)\n", a, b));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
239 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
240 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
241 if (control != 255)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
242 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
243 MIDIEVENT(song->at, control, lastchan, b, 0);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
244 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
245 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
246 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
247
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
248 case 4: /* Program change */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
249 a &= 0x7f;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
250 MIDIEVENT(song->at, ME_PROGRAM, lastchan, a, 0);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
251
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
252 case 5: /* Channel pressure - NOT IMPLEMENTED */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
253 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
254
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
255 case 6: /* Pitch wheel */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
256 SDL_RWread(song->rw, &b, 1, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
257 b &= 0x7F;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
258 MIDIEVENT(song->at, ME_PITCHWHEEL, lastchan, a, b);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
259
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
260 default:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
261 SNDDBG(("*** Can't happen: status 0x%02X, channel 0x%02X\n",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
262 laststatus, lastchan));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
263 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
264 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
265 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
266 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
267
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
268 return new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
269 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
270
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
271 #undef MIDIEVENT
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
272
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
273 /* Read a midi track into the linked list, either merging with any previous
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
274 tracks or appending to them. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
275 static int read_track(MidiSong *song, int append)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
276 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
277 MidiEventList *meep;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
278 MidiEventList *next, *new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
279 Sint32 len;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
280 char tmp[4];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
281
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
282 meep = song->evlist;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
283 if (append && meep)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
284 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
285 /* find the last event in the list */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
286 for (; meep->next; meep=meep->next)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
287 ;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
288 song->at = meep->event.time;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
289 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
290 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
291 song->at=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
292
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
293 /* Check the formalities */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
294
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
295 if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
296 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
297 SNDDBG(("Can't read track header.\n"));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
298 return -1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
299 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
300 len=SDL_SwapBE32(len);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
301 if (memcmp(tmp, "MTrk", 4))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
302 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
303 SNDDBG(("Corrupt MIDI file.\n"));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
304 return -2;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
305 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
306
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
307 for (;;)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
308 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
309 if (!(new=read_midi_event(song))) /* Some kind of error */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
310 return -2;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
311
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
312 if (new==MAGIC_EOT) /* End-of-track Hack. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
313 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
314 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
315 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
316
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
317 next=meep->next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
318 while (next && (next->event.time < new->event.time))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
319 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
320 meep=next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
321 next=meep->next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
322 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
323
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
324 new->next=next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
325 meep->next=new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
326
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
327 song->event_count++; /* Count the event. (About one?) */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
328 meep=new;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
329 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
330 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
331
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
332 /* Free the linked event list from memory. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
333 static void free_midi_list(MidiSong *song)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
334 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
335 MidiEventList *meep, *next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
336 if (!(meep = song->evlist)) return;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
337 while (meep)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
338 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
339 next=meep->next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
340 free(meep);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
341 meep=next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
342 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
343 song->evlist=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
344 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
345
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
346 /* Allocate an array of MidiEvents and fill it from the linked list of
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
347 events, marking used instruments for loading. Convert event times to
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
348 samples: handle tempo changes. Strip unnecessary events from the list.
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
349 Free the linked list. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
350 static MidiEvent *groom_list(MidiSong *song, Sint32 divisions,Sint32 *eventsp,
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
351 Sint32 *samplesp)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
352 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
353 MidiEvent *groomed_list, *lp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
354 MidiEventList *meep;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
355 Sint32 i, our_event_count, tempo, skip_this_event, new_value;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
356 Sint32 sample_cum, samples_to_do, at, st, dt, counting_time;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
357
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
358 int current_bank[16], current_set[16], current_program[16];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
359 /* Or should each bank have its own current program? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
360
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
361 for (i=0; i<16; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
362 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
363 current_bank[i]=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
364 current_set[i]=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
365 current_program[i]=song->default_program;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
366 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
367
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
368 tempo=500000;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
369 compute_sample_increment(song, tempo, divisions);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
370
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
371 /* This may allocate a bit more than we need */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
372 groomed_list=lp=safe_malloc(sizeof(MidiEvent) * (song->event_count+1));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
373 meep=song->evlist;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
374
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
375 our_event_count=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
376 st=at=sample_cum=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
377 counting_time=2; /* We strip any silence before the first NOTE ON. */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
378
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
379 for (i = 0; i < song->event_count; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
380 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
381 skip_this_event=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
382
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
383 if (meep->event.type==ME_TEMPO)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
384 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
385 tempo=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
386 meep->event.channel + meep->event.b * 256 + meep->event.a * 65536;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
387 compute_sample_increment(song, tempo, divisions);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
388 skip_this_event=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
389 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
390 else switch (meep->event.type)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
391 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
392 case ME_PROGRAM:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
393 if (ISDRUMCHANNEL(song, meep->event.channel))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
394 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
395 if (song->drumset[meep->event.a]) /* Is this a defined drumset? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
396 new_value=meep->event.a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
397 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
398 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
399 SNDDBG(("Drum set %d is undefined\n", meep->event.a));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
400 new_value=meep->event.a=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
401 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
402 if (current_set[meep->event.channel] != new_value)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
403 current_set[meep->event.channel]=new_value;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
404 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
405 skip_this_event=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
406 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
407 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
408 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
409 new_value=meep->event.a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
410 if ((current_program[meep->event.channel] != SPECIAL_PROGRAM)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
411 && (current_program[meep->event.channel] != new_value))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
412 current_program[meep->event.channel] = new_value;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
413 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
414 skip_this_event=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
415 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
416 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
417
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
418 case ME_NOTEON:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
419 if (counting_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
420 counting_time=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
421 if (ISDRUMCHANNEL(song, meep->event.channel))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
422 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
423 /* Mark this instrument to be loaded */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
424 if (!(song->drumset[current_set[meep->event.channel]]
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
425 ->instrument[meep->event.a]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
426 song->drumset[current_set[meep->event.channel]]
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
427 ->instrument[meep->event.a] = MAGIC_LOAD_INSTRUMENT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
428 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
429 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
430 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
431 if (current_program[meep->event.channel]==SPECIAL_PROGRAM)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
432 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
433 /* Mark this instrument to be loaded */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
434 if (!(song->tonebank[current_bank[meep->event.channel]]
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
435 ->instrument[current_program[meep->event.channel]]))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
436 song->tonebank[current_bank[meep->event.channel]]
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
437 ->instrument[current_program[meep->event.channel]] =
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
438 MAGIC_LOAD_INSTRUMENT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
439 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
440 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
441
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
442 case ME_TONE_BANK:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
443 if (ISDRUMCHANNEL(song, meep->event.channel))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
444 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
445 skip_this_event=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
446 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
447 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
448 if (song->tonebank[meep->event.a]) /* Is this a defined tone bank? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
449 new_value=meep->event.a;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
450 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
451 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
452 SNDDBG(("Tone bank %d is undefined\n", meep->event.a));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
453 new_value=meep->event.a=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
454 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
455 if (current_bank[meep->event.channel]!=new_value)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
456 current_bank[meep->event.channel]=new_value;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
457 else
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
458 skip_this_event=1;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
459 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
460 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
461
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
462 /* Recompute time in samples*/
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
463 if ((dt=meep->event.time - at) && !counting_time)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
464 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
465 samples_to_do = song->sample_increment * dt;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
466 sample_cum += song->sample_correction * dt;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
467 if (sample_cum & 0xFFFF0000)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
468 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
469 samples_to_do += ((sample_cum >> 16) & 0xFFFF);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
470 sample_cum &= 0x0000FFFF;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
471 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
472 st += samples_to_do;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
473 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
474 else if (counting_time==1) counting_time=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
475 if (!skip_this_event)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
476 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
477 /* Add the event to the list */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
478 *lp=meep->event;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
479 lp->time=st;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
480 lp++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
481 our_event_count++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
482 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
483 at=meep->event.time;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
484 meep=meep->next;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
485 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
486 /* Add an End-of-Track event */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
487 lp->time=st;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
488 lp->type=ME_EOT;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
489 our_event_count++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
490 free_midi_list(song);
474
c66080364dff Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents: 199
diff changeset
491
199
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
492 *eventsp=our_event_count;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
493 *samplesp=st;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
494 return groomed_list;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
495 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
496
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
497 MidiEvent *read_midi_file(MidiSong *song, Sint32 *count, Sint32 *sp)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
498 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
499 Sint32 len, divisions;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
500 Sint16 format, tracks, divisions_tmp;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
501 int i;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
502 char tmp[4];
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
503
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
504 song->event_count=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
505 song->at=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
506 song->evlist=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
507
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
508 if (SDL_RWread(song->rw, tmp, 1, 4) != 4 || SDL_RWread(song->rw, &len, 4, 1) != 1)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
509 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
510 SNDDBG(("Not a MIDI file!\n"));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
511 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
512 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
513 len=SDL_SwapBE32(len);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
514 if (memcmp(tmp, "MThd", 4) || len < 6)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
515 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
516 SNDDBG(("Not a MIDI file!\n"));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
517 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
518 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
519
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
520 SDL_RWread(song->rw, &format, 2, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
521 SDL_RWread(song->rw, &tracks, 2, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
522 SDL_RWread(song->rw, &divisions_tmp, 2, 1);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
523 format=SDL_SwapBE16(format);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
524 tracks=SDL_SwapBE16(tracks);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
525 divisions_tmp=SDL_SwapBE16(divisions_tmp);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
526
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
527 if (divisions_tmp<0)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
528 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
529 /* SMPTE time -- totally untested. Got a MIDI file that uses this? */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
530 divisions=
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
531 (Sint32)(-(divisions_tmp/256)) * (Sint32)(divisions_tmp & 0xFF);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
532 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
533 else divisions=(Sint32)(divisions_tmp);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
534
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
535 if (len > 6)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
536 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
537 SNDDBG(("MIDI file header size %u bytes", len));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
538 SDL_RWseek(song->rw, len-6, SEEK_CUR); /* skip the excess */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
539 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
540 if (format<0 || format >2)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
541 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
542 SNDDBG(("Unknown MIDI file format %d\n", format));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
543 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
544 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
545 SNDDBG(("Format: %d Tracks: %d Divisions: %d\n",
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
546 format, tracks, divisions));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
547
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
548 /* Put a do-nothing event first in the list for easier processing */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
549 song->evlist=safe_malloc(sizeof(MidiEventList));
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
550 song->evlist->event.time=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
551 song->evlist->event.type=ME_NONE;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
552 song->evlist->next=0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
553 song->event_count++;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
554
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
555 switch(format)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
556 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
557 case 0:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
558 if (read_track(song, 0))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
559 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
560 free_midi_list(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
561 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
562 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
563 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
564
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
565 case 1:
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
566 for (i=0; i<tracks; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
567 if (read_track(song, 0))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
568 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
569 free_midi_list(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
570 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
571 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
572 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
573
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
574 case 2: /* We simply play the tracks sequentially */
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
575 for (i=0; i<tracks; i++)
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
576 if (read_track(song, 1))
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
577 {
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
578 free_midi_list(song);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
579 return 0;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
580 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
581 break;
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
582 }
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
583 return groom_list(song, divisions, count, sp);
2d887640d300 Initial add.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
584 }