Mercurial > SDL_sound_CoreAudio
comparison decoders/flac.c @ 166:d8904267d23c
Cleanups, fixes and enhancements by Torbj�rn Andersson.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 26 Nov 2001 04:32:55 +0000 |
parents | 77482005beb6 |
children | 3849438b735e |
comparison
equal
deleted
inserted
replaced
165:9b26ed9eaf04 | 166:d8904267d23c |
---|---|
77 { | 77 { |
78 FLAC__StreamDecoder *decoder; | 78 FLAC__StreamDecoder *decoder; |
79 SDL_RWops *rw; | 79 SDL_RWops *rw; |
80 Sound_Sample *sample; | 80 Sound_Sample *sample; |
81 Uint32 frame_size; | 81 Uint32 frame_size; |
82 Uint8 metadata_found; | 82 Uint8 is_flac; |
83 } flac_t; | 83 } flac_t; |
84 | |
85 | |
86 static void free_flac(flac_t *f) | |
87 { | |
88 FLAC__stream_decoder_finish(f->decoder); | |
89 FLAC__stream_decoder_delete(f->decoder); | |
90 free(f); | |
91 } /* free_flac */ | |
84 | 92 |
85 | 93 |
86 static FLAC__StreamDecoderReadStatus FLAC_read_callback( | 94 static FLAC__StreamDecoderReadStatus FLAC_read_callback( |
87 const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], | 95 const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], |
88 unsigned int *bytes, void *client_data) | 96 unsigned int *bytes, void *client_data) |
124 const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, | 132 const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, |
125 const FLAC__int32 *buffer[], void *client_data) | 133 const FLAC__int32 *buffer[], void *client_data) |
126 { | 134 { |
127 flac_t *f = (flac_t *) client_data; | 135 flac_t *f = (flac_t *) client_data; |
128 Uint32 i, j; | 136 Uint32 i, j; |
137 Uint32 sample; | |
129 Uint8 *dst; | 138 Uint8 *dst; |
130 | 139 |
131 #if 0 | 140 #if 0 |
132 SNDDBG(("FLAC: Write callback.\n")); | 141 SNDDBG(("FLAC: Write callback.\n")); |
133 #endif | 142 #endif |
138 if (f->frame_size > f->sample->buffer_size) | 147 if (f->frame_size > f->sample->buffer_size) |
139 Sound_SetBufferSize(f->sample, f->frame_size); | 148 Sound_SetBufferSize(f->sample, f->frame_size); |
140 | 149 |
141 dst = f->sample->buffer; | 150 dst = f->sample->buffer; |
142 | 151 |
143 if (frame->header.bits_per_sample == 8) | 152 /* If the sample is neither exactly 8-bit nor 16-bit, it will have to |
144 { | 153 * be converted. Unfortunately the buffer is read-only, so we either |
145 for (i = 0; i < frame->header.blocksize; i++) | 154 * have to check for each sample, or make a copy of the buffer. I'm |
146 for (j = 0; j < frame->header.channels; j++) | 155 * not sure which way is best, so I've arbitrarily picked the former. |
147 *dst++ = buffer[j][i] & 0x000000ff; | 156 */ |
148 } /* if */ | 157 if (f->sample->actual.format == AUDIO_S8) |
149 else | |
150 { | 158 { |
151 for (i = 0; i < frame->header.blocksize; i++) | 159 for (i = 0; i < frame->header.blocksize; i++) |
152 for (j = 0; j < frame->header.channels; j++) | 160 for (j = 0; j < frame->header.channels; j++) |
153 { | 161 { |
154 *dst++ = (buffer[j][i] & 0x0000ff00) >> 8; | 162 sample = buffer[j][i]; |
155 *dst++ = buffer[j][i] & 0x000000ff; | 163 if (frame->header.bits_per_sample < 8) |
164 sample <<= (8 - frame->header.bits_per_sample); | |
165 *dst++ = sample & 0x00ff; | |
166 } /* for */ | |
167 } /* if */ | |
168 else | |
169 { | |
170 for (i = 0; i < frame->header.blocksize; i++) | |
171 for (j = 0; j < frame->header.channels; j++) | |
172 { | |
173 sample = buffer[j][i]; | |
174 if (frame->header.bits_per_sample < 16) | |
175 sample <<= (16 - frame->header.bits_per_sample); | |
176 else if (frame->header.bits_per_sample > 16) | |
177 sample >>= (frame->header.bits_per_sample - 16); | |
178 *dst++ = (sample & 0xff00) >> 8; | |
179 *dst++ = sample & 0x00ff; | |
156 } /* for */ | 180 } /* for */ |
157 } /* else */ | 181 } /* else */ |
158 | 182 |
159 return(FLAC__STREAM_DECODER_WRITE_CONTINUE); | 183 return(FLAC__STREAM_DECODER_WRITE_CONTINUE); |
160 } /* FLAC_write_callback */ | 184 } /* FLAC_write_callback */ |
166 { | 190 { |
167 flac_t *f = (flac_t *) client_data; | 191 flac_t *f = (flac_t *) client_data; |
168 | 192 |
169 SNDDBG(("FLAC: Metadata callback.\n")); | 193 SNDDBG(("FLAC: Metadata callback.\n")); |
170 | 194 |
195 /* There are several kinds of metadata, but STREAMINFO is the only | |
196 * one that always has to be there. | |
197 */ | |
171 if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) | 198 if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) |
172 { | 199 { |
173 SNDDBG(("FLAC: Metadata is streaminfo.\n")); | 200 SNDDBG(("FLAC: Metadata is streaminfo.\n")); |
174 f->metadata_found = 1; | 201 |
202 f->is_flac = 1; | |
175 f->sample->actual.channels = metadata->data.stream_info.channels; | 203 f->sample->actual.channels = metadata->data.stream_info.channels; |
176 f->sample->actual.rate = metadata->data.stream_info.sample_rate; | 204 f->sample->actual.rate = metadata->data.stream_info.sample_rate; |
177 | 205 |
178 /* !!! FIXME: I believe bits_per_sample may be anywhere between | 206 if (metadata->data.stream_info.bits_per_sample > 8) |
179 * 4 and 24. We can only handle 8 and 16 at present. | 207 f->sample->actual.format = AUDIO_S16MSB; |
180 */ | 208 else |
181 switch (metadata->data.stream_info.bits_per_sample) | 209 f->sample->actual.format = AUDIO_S8; |
182 { | |
183 case 8: | |
184 f->sample->actual.format = AUDIO_S8; | |
185 break; | |
186 case 16: | |
187 f->sample->actual.format = AUDIO_S16MSB; | |
188 break; | |
189 default: | |
190 Sound_SetError("FLAC: Unsupported sample width."); | |
191 f->sample->actual.format = 0; | |
192 break; | |
193 } /* switch */ | |
194 } /* if */ | 210 } /* if */ |
195 } /* FLAC_metadata_callback */ | 211 } /* FLAC_metadata_callback */ |
196 | 212 |
197 | 213 |
198 void FLAC_error_callback( | 214 void FLAC_error_callback( |
199 const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, | 215 const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, |
200 void *client_data) | 216 void *client_data) |
201 { | 217 { |
202 flac_t *f = (flac_t *) client_data; | 218 flac_t *f = (flac_t *) client_data; |
203 | 219 |
220 /* !!! FIXME: Is every error really fatal? I don't know... */ | |
204 Sound_SetError(FLAC__StreamDecoderErrorStatusString[status]); | 221 Sound_SetError(FLAC__StreamDecoderErrorStatusString[status]); |
205 f->sample->flags |= SOUND_SAMPLEFLAG_ERROR; | 222 f->sample->flags |= SOUND_SAMPLEFLAG_ERROR; |
206 } /* FLAC_error_callback */ | 223 } /* FLAC_error_callback */ |
207 | 224 |
208 | 225 |
222 { | 239 { |
223 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | 240 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
224 SDL_RWops *rw = internal->rw; | 241 SDL_RWops *rw = internal->rw; |
225 FLAC__StreamDecoder *decoder; | 242 FLAC__StreamDecoder *decoder; |
226 flac_t *f; | 243 flac_t *f; |
244 int i; | |
227 | 245 |
228 f = (flac_t *) malloc(sizeof (flac_t)); | 246 f = (flac_t *) malloc(sizeof (flac_t)); |
229 BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0); | 247 BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0); |
230 | 248 |
231 decoder = FLAC__stream_decoder_new(); | 249 decoder = FLAC__stream_decoder_new(); |
243 FLAC__stream_decoder_set_client_data(decoder, f); | 261 FLAC__stream_decoder_set_client_data(decoder, f); |
244 | 262 |
245 f->rw = internal->rw; | 263 f->rw = internal->rw; |
246 f->sample = sample; | 264 f->sample = sample; |
247 f->decoder = decoder; | 265 f->decoder = decoder; |
248 | 266 f->sample->actual.format = 0; |
267 f->is_flac = 0; | |
268 | |
269 #if 0 | |
270 /* !!! FIXME: | |
271 * | |
272 * It should be possible to play a FLAC stream starting at any frame, | |
273 * but we can only do that if we know for sure that it is a FLAC | |
274 * stream. Otherwise we have to check for metadata, and then we need | |
275 * the entire stream, from the beginning. | |
276 * | |
277 * But getting this to work right seems to be an enormous pain in the | |
278 * butt for what is, at the moment, a very small gain. Maybe later. | |
279 */ | |
280 for (i = 0; extensions_flac[i] != NULL; i++) | |
281 if (__Sound_strcasecmp(ext, extensions_flac[i]) == 0) | |
282 { | |
283 f->is_flac = 1; | |
284 break; | |
285 } /* if */ | |
286 #endif | |
287 | |
288 internal->decoder_private = f; | |
249 FLAC__stream_decoder_init(decoder); | 289 FLAC__stream_decoder_init(decoder); |
250 internal->decoder_private = f; | 290 |
251 | 291 /* If we are not sure this is a FLAC stream, check for the STREAMINFO |
252 f->metadata_found = 0; | 292 * metadata block. If not, we'd have to peek at the first audio frame |
253 f->sample->actual.format = 0; | 293 * and get the sound format from there but, as stated above, that is |
254 FLAC__stream_decoder_process_metadata(decoder); | 294 * not yet implemented. |
255 | 295 */ |
256 if (f->sample->actual.format == 0) | 296 if (!f->is_flac) |
257 { | 297 { |
258 if (f->metadata_found == 0) | 298 FLAC__stream_decoder_process_metadata(decoder); |
259 Sound_SetError("FLAC: No metadata found."); | 299 |
260 FLAC__stream_decoder_finish(decoder); | 300 /* Still not FLAC? Give up. */ |
261 FLAC__stream_decoder_delete(decoder); | 301 if (!f->is_flac) |
262 free(f); | 302 { |
263 return(0); | 303 Sound_SetError("FLAC: No metadata found. Not a FLAC stream?"); |
304 free_flac(f); | |
305 return(0); | |
306 } /* if */ | |
264 } /* if */ | 307 } /* if */ |
265 | 308 |
266 SNDDBG(("FLAC: Accepting data stream.\n")); | 309 SNDDBG(("FLAC: Accepting data stream.\n")); |
267 | 310 |
268 sample->flags = SOUND_SAMPLEFLAG_NONE; | 311 sample->flags = SOUND_SAMPLEFLAG_NONE; |
273 static void FLAC_close(Sound_Sample *sample) | 316 static void FLAC_close(Sound_Sample *sample) |
274 { | 317 { |
275 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | 318 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
276 flac_t *f = (flac_t *) internal->decoder_private; | 319 flac_t *f = (flac_t *) internal->decoder_private; |
277 | 320 |
278 FLAC__stream_decoder_finish(f->decoder); | 321 free_flac(f); |
279 FLAC__stream_decoder_delete(f->decoder); | |
280 free(f); | |
281 } /* FLAC_close */ | 322 } /* FLAC_close */ |
282 | 323 |
283 | 324 |
284 static Uint32 FLAC_read(Sound_Sample *sample) | 325 static Uint32 FLAC_read(Sound_Sample *sample) |
285 { | 326 { |