Mercurial > SDL_sound_CoreAudio
comparison decoders/midi.c @ 108:803ba4dabbce
Initial add, from Torbj�rn Andersson.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Wed, 03 Oct 2001 20:17:13 +0000 |
parents | |
children | 70baf29577d8 |
comparison
equal
deleted
inserted
replaced
107:427541211bfd | 108:803ba4dabbce |
---|---|
1 /* | |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2.1 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * MIDI decoder for SDL_sound, using TiMidity. | |
22 * | |
23 * This is a rough, proof-of-concept implementation. A number of things need | |
24 * to be fixed or at the very least looked at: | |
25 * | |
26 * - I have only tested this with TiMidity++. Does TiMidity use the same | |
27 * command-line options? | |
28 * - No attempt is made to ensure that the input really is MIDI. Eek. Does | |
29 * anyone here know how to recognize MIDI? | |
30 * - Error handling is a joke. | |
31 * - Did I make any stupid errors in the process communication? | |
32 * - TiMidity++ spews a number of messages (to stderr?) which should be | |
33 * silenced eventually. | |
34 * - This has to be the least portable decoder that has ever been written. | |
35 * - Etc. | |
36 * | |
37 * Oh, and the whole thing should be rewritten as a generic "send data to | |
38 * external decoder" thing so this version should either be scrapped or | |
39 * cannibalized for ideas. :-) | |
40 * | |
41 * Please see the file LICENSE in the source's root directory. | |
42 * | |
43 * This file written by Torbjörn Andersson. (d91tan@Update.UU.SE) | |
44 */ | |
45 | |
46 #if HAVE_CONFIG_H | |
47 # include <config.h> | |
48 #endif | |
49 | |
50 #ifdef SOUND_SUPPORTS_MIDI | |
51 | |
52 #include <stdio.h> | |
53 #include <stdlib.h> | |
54 #include <string.h> | |
55 #include <assert.h> | |
56 #include <unistd.h> | |
57 #include <signal.h> | |
58 #include <sys/types.h> | |
59 #include <sys/wait.h> | |
60 #include "SDL_sound.h" | |
61 | |
62 #define __SDL_SOUND_INTERNAL__ | |
63 #include "SDL_sound_internal.h" | |
64 | |
65 | |
66 static int MIDI_init(void); | |
67 static void MIDI_quit(void); | |
68 static int MIDI_open(Sound_Sample *sample, const char *ext); | |
69 static void MIDI_close(Sound_Sample *sample); | |
70 static Uint32 MIDI_read(Sound_Sample *sample); | |
71 | |
72 const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI = | |
73 { | |
74 { | |
75 "MIDI", | |
76 "MIDI music through the TiMidity MIDI to WAVE converter", | |
77 "Torbjörn Andersson <d91tan@Update.UU.SE>", | |
78 "http://www.goice.co.jp/member/mo/timidity/" | |
79 }, | |
80 | |
81 MIDI_init, /* init() method */ | |
82 MIDI_quit, /* quit() method */ | |
83 MIDI_open, /* open() method */ | |
84 MIDI_close, /* close() method */ | |
85 MIDI_read /* read() method */ | |
86 }; | |
87 | |
88 /* this is what we store in our internal->decoder_private field... */ | |
89 typedef struct | |
90 { | |
91 int fd_audio; | |
92 } midi_t; | |
93 | |
94 | |
95 static void sig_pipe(int signo) | |
96 { | |
97 signal(signo, sig_pipe); | |
98 } /* sig_pipe */ | |
99 | |
100 | |
101 static int MIDI_init(void) | |
102 { | |
103 if (signal(SIGPIPE, sig_pipe) == SIG_ERR) | |
104 { | |
105 Sound_SetError("MIDI: Could not set up SIGPIPE signal handler."); | |
106 return(0); | |
107 } /* if */ | |
108 return(1); | |
109 } /* MIDI_init */ | |
110 | |
111 | |
112 static void MIDI_quit(void) | |
113 { | |
114 /* it's a no-op. */ | |
115 } /* MIDI_quit */ | |
116 | |
117 | |
118 static int MIDI_open(Sound_Sample *sample, const char *ext) | |
119 { | |
120 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
121 SDL_RWops *rw = internal->rw; | |
122 midi_t *m; | |
123 Uint8 buf[BUFSIZ]; | |
124 ssize_t retval; | |
125 int fd1[2]; | |
126 int fd2[2]; | |
127 pid_t pid; | |
128 | |
129 /* TiMidity does all the conversions we need. */ | |
130 memcpy(&sample->actual, &sample->desired, sizeof (Sound_AudioInfo)); | |
131 sample->flags = SOUND_SAMPLEFLAG_NONE; | |
132 | |
133 if (pipe(fd1) < 0 || pipe(fd2) < 0) | |
134 { | |
135 Sound_SetError("MIDI: Pipe error."); | |
136 return(0); | |
137 } /* if */ | |
138 | |
139 pid = fork(); | |
140 if (pid < 0) | |
141 { | |
142 Sound_SetError("MIDI: Fork error."); | |
143 return(0); | |
144 } /* if */ | |
145 | |
146 if (pid == 0) | |
147 { | |
148 /* child */ | |
149 char arg_freq[10]; /* !!! FIXME: Large enough? */ | |
150 char arg_format[10]; | |
151 char *arg_list[] = | |
152 { "timidity", "-s", NULL, NULL, "-o", "-", "-", NULL }; | |
153 | |
154 arg_list[2] = arg_freq; | |
155 arg_list[3] = arg_format; | |
156 | |
157 close(fd1[1]); | |
158 close(fd2[0]); | |
159 | |
160 /* !!! FIXME: Errors should be propagated back to the parent */ | |
161 | |
162 if (fd1[0] != STDIN_FILENO) | |
163 { | |
164 if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) | |
165 return(0); | |
166 close(fd1[0]); | |
167 } /* if */ | |
168 | |
169 if (fd2[1] != STDOUT_FILENO) | |
170 { | |
171 if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) | |
172 return(0); | |
173 close(fd2[1]); | |
174 } /* if */ | |
175 | |
176 /* Construct command-line arguments matching the audio format */ | |
177 sprintf(arg_freq, "%d", sample->actual.rate); | |
178 sprintf(arg_format, "-Or%c%c%cl", | |
179 (sample->actual.format & 0x0008) ? '8' : '1', | |
180 (sample->actual.format & 0x8000) ? 's' : 'u', | |
181 (sample->actual.channels == 1) ? 'M' : 'S'); | |
182 if ((sample->actual.format & 0x0010) && | |
183 (sample->actual.format & 0x7fff) != (AUDIO_S16SYS & 0x7fff)) | |
184 strcat(arg_format, "x"); | |
185 | |
186 if (execvp("timidity", arg_list) < 0) | |
187 return(0); | |
188 | |
189 SNDDBG(("MIDI: Is this line ever reached?")); | |
190 return(1); | |
191 } /* if */ | |
192 | |
193 /* parent */ | |
194 close(fd1[0]); | |
195 close(fd2[1]); | |
196 | |
197 /* Copy the entire file to the child process */ | |
198 for (;;) | |
199 { | |
200 retval = SDL_RWread(internal->rw, buf, 1, BUFSIZ); | |
201 if (retval == 0) | |
202 break; | |
203 | |
204 if (write(fd1[1], buf, retval) != retval) | |
205 { | |
206 Sound_SetError("MIDI: Could not send data to child process."); | |
207 return(0); | |
208 } | |
209 } /* for */ | |
210 | |
211 close(fd1[1]); | |
212 | |
213 /* !!! FIXME: We still need some way of recognizing valid MIDI data */ | |
214 | |
215 m = (midi_t *) malloc(sizeof(midi_t)); | |
216 BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, 0); | |
217 internal->decoder_private = (void *) m; | |
218 | |
219 /* This is where we'll read the converted audio data. */ | |
220 m->fd_audio = fd2[0]; | |
221 | |
222 SNDDBG(("MIDI: Accepting data stream.\n")); | |
223 return(1); /* we'll handle this data. */ | |
224 } /* MIDI_open */ | |
225 | |
226 | |
227 static void MIDI_close(Sound_Sample *sample) | |
228 { | |
229 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
230 | |
231 close(((midi_t *) internal->decoder_private)->fd_audio); | |
232 free(internal->decoder_private); | |
233 } /* MIDI_close */ | |
234 | |
235 | |
236 static Uint32 MIDI_read(Sound_Sample *sample) | |
237 { | |
238 ssize_t retval; | |
239 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
240 midi_t *m = (midi_t *) internal->decoder_private; | |
241 | |
242 /* | |
243 * We don't actually do any decoding, so we read the converted data | |
244 * directly into the internal buffer. | |
245 */ | |
246 retval = read(m->fd_audio, internal->buffer, internal->buffer_size); | |
247 | |
248 /* Make sure the read went smoothly... */ | |
249 if (retval == 0) | |
250 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
251 | |
252 else if (retval == -1) | |
253 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
254 | |
255 /* (next call this EAGAIN may turn into an EOF or error.) */ | |
256 else if (retval < internal->buffer_size) | |
257 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; | |
258 | |
259 return(retval); | |
260 } /* MIDI_read */ | |
261 | |
262 #endif /* SOUND_SUPPORTS_MIDI */ | |
263 | |
264 /* end of midi.c ... */ | |
265 |