rewrite SwfdecAudioFormat handling
[swfdec.git] / libswfdec / swfdec_sound.c
blob90c90293c41b9bf7d6866b2603f563b8a117b14c
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <string.h>
26 #include "swfdec_audio_internal.h"
27 #include "swfdec_sound.h"
28 #include "swfdec_bits.h"
29 #include "swfdec_buffer.h"
30 #include "swfdec_button.h"
31 #include "swfdec_debug.h"
32 #include "swfdec_sprite.h"
33 #include "swfdec_swf_decoder.h"
35 G_DEFINE_TYPE (SwfdecSound, swfdec_sound, SWFDEC_TYPE_CACHED)
37 static void
38 swfdec_sound_unload (SwfdecCached *cached)
40 SwfdecSound * sound = SWFDEC_SOUND (cached);
42 if (sound->decoded) {
43 swfdec_buffer_unref (sound->decoded);
44 sound->decoded = NULL;
48 static void
49 swfdec_sound_dispose (GObject *object)
51 SwfdecSound * sound = SWFDEC_SOUND (object);
53 if (sound->encoded)
54 swfdec_buffer_unref (sound->encoded);
56 G_OBJECT_CLASS (swfdec_sound_parent_class)->dispose (object);
59 static void
60 swfdec_sound_class_init (SwfdecSoundClass * g_class)
62 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
63 SwfdecCachedClass *cached_class = SWFDEC_CACHED_CLASS (g_class);
65 object_class->dispose = swfdec_sound_dispose;
67 cached_class->unload = swfdec_sound_unload;
70 static void
71 swfdec_sound_init (SwfdecSound * sound)
76 int
77 tag_func_sound_stream_block (SwfdecSwfDecoder * s, guint tag)
79 SwfdecSound *sound;
80 SwfdecBuffer *chunk;
81 int n_samples;
82 int skip;
84 sound = SWFDEC_SOUND (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head);
86 if (!sound) {
87 SWFDEC_WARNING ("no streaming sound block");
88 return SWFDEC_STATUS_OK;
91 n_samples = swfdec_bits_get_u16 (&s->b);
92 if (sound->format == SWFDEC_AUDIO_CODEC_MP3) {
93 skip = swfdec_bits_get_s16 (&s->b);
94 } else {
95 skip = 0;
97 if (swfdec_bits_left (&s->b) == 0) {
98 SWFDEC_DEBUG ("empty sound block n_samples=%d skip=%d", n_samples,
99 skip);
100 chunk = NULL;
101 return SWFDEC_STATUS_OK;
102 } else {
103 chunk = swfdec_bits_get_buffer (&s->b, -1);
104 if (chunk == NULL) {
105 SWFDEC_ERROR ("empty sound chunk");
106 return SWFDEC_STATUS_OK;
108 SWFDEC_LOG ("got a buffer with %u samples, %d skip and %u bytes mp3 data", n_samples, skip,
109 chunk->length);
110 /* use this to write out the stream data to stdout - nice way to get an mp3 file :) */
111 //write (1, (void *) chunk->data, chunk->length);
114 swfdec_sprite_add_sound_chunk (s->parse_sprite, s->parse_sprite->parse_frame, chunk, skip, n_samples);
116 return SWFDEC_STATUS_OK;
120 tag_func_define_sound (SwfdecSwfDecoder * s, guint tag)
122 SwfdecBits *b = &s->b;
123 int id;
124 int n_samples;
125 SwfdecSound *sound;
127 id = swfdec_bits_get_u16 (b);
128 sound = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SOUND);
129 if (!sound)
130 return SWFDEC_STATUS_OK;
132 sound->format = swfdec_bits_getbits (b, 4);
133 SWFDEC_LOG (" codec: %u", sound->format);
134 sound->original_format = swfdec_audio_format_parse (b);
135 SWFDEC_LOG (" format: %s", swfdec_audio_format_to_string (sound->original_format));
136 n_samples = swfdec_bits_get_u32 (b);
137 sound->n_samples = n_samples;
139 switch (sound->format) {
140 case 0:
141 if (swfdec_audio_format_is_16bit (sound->original_format))
142 SWFDEC_WARNING ("undefined endianness for s16 sound");
143 /* just assume LE and hope it works (FIXME: want a switch for this?) */
144 sound->format = SWFDEC_AUDIO_CODEC_UNCOMPRESSED;
145 /* fall through */
146 case 3:
147 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
148 break;
149 case 2:
150 sound->skip = swfdec_bits_get_u16 (b);
151 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
152 break;
153 case 1:
154 case 5:
155 case 6:
156 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
157 break;
158 default:
159 SWFDEC_WARNING ("unknown format %d", sound->format);
161 sound->n_samples *= swfdec_audio_format_get_granularity (sound->original_format);
163 return SWFDEC_STATUS_OK;
166 static SwfdecBuffer *
167 swfdec_sound_get_decoded (SwfdecSound *sound, SwfdecAudioFormat *format)
169 gpointer decoder;
170 SwfdecBuffer *tmp;
171 SwfdecBufferQueue *queue;
172 guint sample_bytes;
174 g_return_val_if_fail (SWFDEC_IS_SOUND (sound), NULL);
175 g_return_val_if_fail (format != NULL, NULL);
177 if (sound->decoded) {
178 swfdec_cached_use (SWFDEC_CACHED (sound));
179 *format = sound->decoded_format;
180 return sound->decoded;
182 if (sound->encoded == NULL)
183 return NULL;
185 decoder = swfdec_audio_decoder_new (sound->format, sound->original_format);
186 if (decoder == NULL)
187 return NULL;
188 sound->decoded_format = swfdec_audio_decoder_get_format (decoder);
189 sample_bytes = 2 * swfdec_audio_format_get_channels (sound->decoded_format);
190 /* FIXME: The size is only a guess */
191 swfdec_cached_load (SWFDEC_CACHED (sound), sound->n_samples * sample_bytes);
193 swfdec_audio_decoder_push (decoder, sound->encoded);
194 swfdec_audio_decoder_push (decoder, NULL);
195 queue = swfdec_buffer_queue_new ();
196 while ((tmp = swfdec_audio_decoder_pull (decoder)))
197 swfdec_buffer_queue_push (queue, tmp);
198 swfdec_audio_decoder_free (decoder);
199 tmp = swfdec_buffer_queue_pull (queue, swfdec_buffer_queue_get_depth (queue));
200 swfdec_buffer_queue_unref (queue);
202 SWFDEC_LOG ("after decoding, got %u samples, should get %u and skip %u",
203 tmp->length / sample_bytes, sound->n_samples, sound->skip);
204 if (sound->skip) {
205 SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, sound->skip * sample_bytes,
206 tmp->length - sound->skip * sample_bytes);
207 swfdec_buffer_unref (tmp);
208 tmp = tmp2;
210 /* sound buffer may be bigger due to mp3 not having sample boundaries */
211 if (tmp->length * swfdec_audio_format_get_granularity (sound->decoded_format)
212 > sound->n_samples * sample_bytes) {
213 SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, 0,
214 sound->n_samples * sample_bytes / swfdec_audio_format_get_granularity (sound->decoded_format));
215 swfdec_buffer_unref (tmp);
216 tmp = tmp2;
218 if (tmp->length * swfdec_audio_format_get_granularity (sound->decoded_format)
219 < sound->n_samples * sample_bytes) {
220 /* we handle this case in swfdec_sound_render */
221 /* FIXME: this message is important when writing new codecs, so I made it a warning.
222 * It's probably not worth more than INFO for the usual case though */
223 SWFDEC_WARNING ("%u samples in %u bytes should be available, but only %u bytes are",
224 sound->n_samples / swfdec_audio_format_get_granularity (sound->decoded_format),
225 sound->n_samples * sample_bytes / swfdec_audio_format_get_granularity (sound->decoded_format),
226 tmp->length);
228 /* only assign here, the decoding code checks this variable */
229 sound->decoded = tmp;
231 *format = sound->decoded_format;
232 return sound->decoded;
236 tag_func_sound_stream_head (SwfdecSwfDecoder * s, guint tag)
238 SwfdecBits *b = &s->b;
239 SwfdecAudioFormat playback;
240 int n_samples;
241 int latency;
242 SwfdecSound *sound;
244 /* we don't care about playback suggestions */
245 if (swfdec_bits_getbits (b, 4)) {
246 SWFDEC_ERROR ("0 bits aren't 0");
248 playback = swfdec_audio_format_parse (b);
249 SWFDEC_LOG (" suggested playback format: %s", swfdec_audio_format_to_string (playback));
251 sound = g_object_new (SWFDEC_TYPE_SOUND, NULL);
252 sound->format = swfdec_bits_getbits (b, 4);
253 sound->original_format = swfdec_audio_format_parse (b);
254 n_samples = swfdec_bits_get_u16 (b);
256 if (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head)
257 g_object_unref (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head);
258 s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head = sound;
260 switch (sound->format) {
261 case 0:
262 if (swfdec_audio_format_is_16bit (sound->original_format)) {
263 SWFDEC_WARNING ("undefined endianness for s16 sound");
264 /* just assume LE and hope it works (FIXME: want a switch for this?) */
265 sound->format = SWFDEC_AUDIO_CODEC_UNCOMPRESSED;
267 break;
268 case 2:
269 /* latency seek */
270 latency = swfdec_bits_get_s16 (b);
271 break;
272 case 1:
273 case 3:
274 case 6:
275 break;
276 default:
277 SWFDEC_WARNING ("unknown format %d", sound->format);
280 return SWFDEC_STATUS_OK;
283 void
284 swfdec_sound_chunk_free (SwfdecSoundChunk *chunk)
286 g_return_if_fail (chunk != NULL);
288 g_free (chunk->envelope);
289 g_free (chunk);
292 SwfdecSoundChunk *
293 swfdec_sound_parse_chunk (SwfdecSwfDecoder *s, int id)
295 int has_envelope;
296 int has_loops;
297 int has_out_point;
298 int has_in_point;
299 guint i, j;
300 SwfdecSound *sound;
301 SwfdecSoundChunk *chunk;
302 SwfdecBits *b = &s->b;
304 sound = swfdec_swf_decoder_get_character (s, id);
305 if (!SWFDEC_IS_SOUND (sound)) {
306 SWFDEC_ERROR ("given id %d does not reference a sound object", id);
307 return NULL;
310 chunk = g_new0 (SwfdecSoundChunk, 1);
311 chunk->sound = sound;
312 SWFDEC_DEBUG ("parsing sound chunk for sound %d", SWFDEC_CHARACTER (sound)->id);
314 swfdec_bits_getbits (b, 2);
315 chunk->stop = swfdec_bits_getbits (b, 1);
316 chunk->no_restart = swfdec_bits_getbits (b, 1);
317 has_envelope = swfdec_bits_getbits (b, 1);
318 has_loops = swfdec_bits_getbits (b, 1);
319 has_out_point = swfdec_bits_getbits (b, 1);
320 has_in_point = swfdec_bits_getbits (b, 1);
321 if (has_in_point) {
322 chunk->start_sample = swfdec_bits_get_u32 (b);
323 } else {
324 chunk->start_sample = 0;
326 if (has_out_point) {
327 chunk->stop_sample = swfdec_bits_get_u32 (b);
328 if (chunk->stop_sample > sound->n_samples) {
329 SWFDEC_INFO ("more samples specified (%u) than available (%u)",
330 chunk->stop_sample, sound->n_samples);
332 } else {
333 chunk->stop_sample = sound->n_samples;
335 if (has_loops) {
336 chunk->loop_count = swfdec_bits_get_u16 (b);
337 } else {
338 chunk->loop_count = 1;
340 if (has_envelope) {
341 chunk->n_envelopes = swfdec_bits_get_u8 (b);
342 chunk->envelope = g_new (SwfdecSoundEnvelope, chunk->n_envelopes);
344 SWFDEC_LOG (" start_sample = %u", chunk->start_sample);
345 SWFDEC_LOG (" stop_sample = %u", chunk->stop_sample);
346 SWFDEC_LOG (" loop_count = %u", chunk->loop_count);
347 SWFDEC_LOG (" n_envelopes = %u", chunk->n_envelopes);
349 for (i = 0; i < chunk->n_envelopes; i++) {
350 chunk->envelope[i].offset = swfdec_bits_get_u32 (b);
351 if (chunk->envelope[i].offset < chunk->start_sample) {
352 SWFDEC_WARNING ("envelope entry offset too small (%d vs %d)",
353 chunk->envelope[i].offset, chunk->start_sample);
354 chunk->envelope[i].offset = chunk->start_sample;
356 if (i > 0 && chunk->envelope[i].offset <=
357 chunk->envelope[i-1].offset) {
358 /* FIXME: figure out how to handle this */
359 SWFDEC_ERROR ("sound evelope offsets not sorted");
361 for (j = 0; j < 2; j++) {
362 chunk->envelope[i].volume[j] = swfdec_bits_get_u16 (b);
363 if (chunk->envelope[i].volume[j] > 32768) {
364 SWFDEC_ERROR ("envelope volume too big: %u > 32768",
365 chunk->envelope[i].volume[j]);
366 chunk->envelope[i].volume[j] = 32768;
369 SWFDEC_LOG (" envelope = %u { %u, %u }", chunk->envelope[i].offset,
370 (guint) chunk->envelope[i].volume[0], (guint) chunk->envelope[i].volume[1]);
371 /* FIXME: check that mono sound gets averaged and then do this here? */
374 return chunk;
378 tag_func_start_sound (SwfdecSwfDecoder * s, guint tag)
380 SwfdecBits *b = &s->b;
381 SwfdecSoundChunk *chunk;
382 int id;
383 SwfdecSpriteFrame *frame = &s->parse_sprite->frames[s->parse_sprite->parse_frame];
385 id = swfdec_bits_get_u16 (b);
387 chunk = swfdec_sound_parse_chunk (s, id);
388 if (chunk) {
389 /* append to keep order */
390 SWFDEC_DEBUG ("appending StartSound event for sound %u to frame %u", id,
391 s->parse_sprite->parse_frame);
392 frame->sound = g_slist_append (frame->sound, chunk);
395 return SWFDEC_STATUS_OK;
399 tag_func_define_button_sound (SwfdecSwfDecoder * s, guint tag)
401 guint i;
402 guint id;
403 SwfdecButton *button;
405 id = swfdec_bits_get_u16 (&s->b);
406 button = (SwfdecButton *) swfdec_swf_decoder_get_character (s, id);
407 if (!SWFDEC_IS_BUTTON (button)) {
408 SWFDEC_ERROR ("id %u is not a button", id);
409 return SWFDEC_STATUS_OK;
411 SWFDEC_LOG ("loading sound events for button %u", id);
412 for (i = 0; i < 4; i++) {
413 id = swfdec_bits_get_u16 (&s->b);
414 if (id) {
415 SWFDEC_LOG ("loading sound %u for button event %u", id, i);
416 if (button->sounds[i]) {
417 SWFDEC_ERROR ("need to delete previous sound for button %u's event %u",
418 SWFDEC_CHARACTER (button)->id, i);
419 swfdec_sound_chunk_free (button->sounds[i]);
421 button->sounds[i] = swfdec_sound_parse_chunk (s, id);
425 return SWFDEC_STATUS_OK;
429 * swfdec_sound_buffer_get_n_samples:
430 * @buffer: data to examine
431 * @format: format the data in @buffer is in
433 * Determines the number of samples inside @buffer that would be available if
434 * it were to be rendered using the default Flash format, 44100Hz.
436 * Returns: Number of samples contained in @buffer when rendered
438 guint
439 swfdec_sound_buffer_get_n_samples (const SwfdecBuffer *buffer, SwfdecAudioFormat format)
441 g_return_val_if_fail (buffer != NULL, 0);
442 g_return_val_if_fail (buffer->length % (2 * swfdec_audio_format_get_channels (format)) == 0, 0);
444 return buffer->length / (2 * swfdec_audio_format_get_channels (format)) *
445 swfdec_audio_format_get_granularity (format);
449 * swfdec_sound_render_buffer:
450 * @dest: target buffer to render to
451 * @source: source data to render
452 * @format: format of data in @source and @previous
453 * @previous: previous buffer or NULL for none. This is necessary for
454 * upsampling at buffer boundaries
455 * @offset: offset in 44100Hz samples into @source
456 * @n_samples: number of samples to render into @dest. If more data would be
457 * rendered than is available in @source, 0 samples are used instead.
459 * Adds data from @source into @dest using the same upsampling algorithm as
460 * Flash player.
462 /* NB: if you improve the upsampling algorithm, tests might start to break */
463 void
464 swfdec_sound_buffer_render (gint16 *dest, const SwfdecBuffer *source,
465 SwfdecAudioFormat format, const SwfdecBuffer *previous,
466 guint offset, guint n_samples)
468 guint i, j;
469 guint channels = swfdec_audio_format_get_channels (format);
470 guint rate = swfdec_audio_format_get_granularity (format);
471 gint16 *src, *end;
473 g_return_if_fail (dest != NULL);
474 g_return_if_fail (source != NULL);
475 g_return_if_fail (swfdec_sound_buffer_get_n_samples (source, format) > 0);
476 g_return_if_fail (format != 0);
477 g_return_if_fail (previous == NULL || swfdec_sound_buffer_get_n_samples (previous, format) > 0);
479 src = (gint16 *) source->data;
480 end = (gint16 *) (source->data + source->length);
481 src += channels * (offset / rate);
482 offset %= rate;
483 if (offset) {
484 offset = rate - offset;
485 /* NB: dest will be pointing to uninitialized memory now */
486 dest -= offset * 2;
487 n_samples += offset;
489 /* this is almost the same as the channels == 1 case, so check for bugfixes in both branches */
490 if (channels == 1) {
491 int values[rate + 1];
492 if (src >= end)
493 n_samples = 0;
494 else if (src != (gint16 *) source->data)
495 values[0] = src[-1];
496 else if (previous)
497 values[0] = ((gint16 *) previous->data)[previous->length / 2 - 1];
498 else
499 values[0] = *src;
500 while (n_samples > 0) {
501 if (src > end)
502 break;
503 else if (src == end)
504 values[rate] = 0;
505 else
506 values[rate] = *src;
507 src++;
508 for (i = rate / 2; i >= 1; i /= 2) {
509 for (j = i; j < rate; j += 2 * i) {
510 values[j] = (values[j + i] + values[j - i]) / 2;
513 for (i = offset; i < MIN (rate, n_samples); i++) {
514 dest[2 * i] += values[i + 1];
515 dest[2 * i + 1] += values[i + 1];
517 dest += 2 * rate;
518 values[0] = values[rate];
519 offset = 0;
520 n_samples -= MIN (n_samples, rate);
522 } else {
523 int values[2][rate + 1];
524 if (src >= end) {
525 n_samples = 0;
526 } else if (src != (gint16 *) source->data) {
527 values[0][0] = src[-2];
528 values[1][0] = src[-1];
529 } else if (previous) {
530 values[0][0] = ((gint16 *) previous->data)[previous->length / 2 - 2];
531 values[1][0] = ((gint16 *) previous->data)[previous->length / 2 - 1];
532 } else {
533 values[0][0] = src[0];
534 values[1][0] = src[1];
536 while (n_samples > 0) {
537 if (src > end) {
538 break;
539 } else if (src == end) {
540 values[0][rate] = 0;
541 values[1][rate] = 0;
542 } else {
543 values[0][rate] = src[0];
544 values[1][rate] = src[1];
546 src += 2;
547 for (i = rate / 2; i >= 1; i /= 2) {
548 for (j = i; j < rate; j += 2 * i) {
549 values[0][j] = (values[0][j + i] + values[0][j - i]) / 2;
550 values[1][j] = (values[1][j + i] + values[1][j - i]) / 2;
553 for (i = offset; i < MIN (rate, n_samples); i++) {
554 dest[2 * i] += values[0][i + 1];
555 dest[2 * i + 1] += values[1][i + 1];
557 dest += 2 * rate;
558 values[0][0] = values[0][rate];
559 values[1][0] = values[1][rate];
560 offset = 0;
561 n_samples -= MIN (n_samples, rate);
567 * swfdec_sound_render:
568 * @sound: a #SwfdecSound
569 * @dest: target to add to
570 * @offset: offset in samples into the data
571 * @n_samples: amount of samples to render
573 * Renders the given sound onto the existing data in @dest.
575 void
576 swfdec_sound_render (SwfdecSound *sound, gint16 *dest,
577 guint offset, guint n_samples)
579 SwfdecBuffer *buffer;
580 SwfdecAudioFormat format;
581 g_return_if_fail (SWFDEC_IS_SOUND (sound));
582 /* FIXME: I need a return_if_fail for !created_by_define_sound */
584 buffer = swfdec_sound_get_decoded (sound, &format);
585 if (buffer == NULL)
586 return;
587 swfdec_sound_buffer_render (dest, buffer, format,
588 NULL, offset, n_samples);