Bug 22803 - Make header conform to implementation
[swfdec.git] / swfdec / swfdec_sound.c
blobd228e45e54cf48eed351f3b40049ac0babad6069
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2008 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_sound.h"
27 #include "swfdec_audio_decoder.h"
28 #include "swfdec_audio_event.h"
29 #include "swfdec_audio_internal.h"
30 #include "swfdec_bits.h"
31 #include "swfdec_buffer.h"
32 #include "swfdec_button.h"
33 #include "swfdec_debug.h"
34 #include "swfdec_player_internal.h"
35 #include "swfdec_sound_provider.h"
36 #include "swfdec_sprite.h"
37 #include "swfdec_swf_decoder.h"
39 /*** SWFDEC_SOUND_PROVIDER ***/
41 static void
42 swfdec_sound_sound_provider_start (SwfdecSoundProvider *provider,
43 SwfdecActor *actor, gsize samples_offset, guint loops)
45 SwfdecSound *sound = SWFDEC_SOUND (provider);
46 SwfdecAudio *audio;
48 audio = swfdec_audio_event_new (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor)),
49 sound, samples_offset, loops);
50 swfdec_audio_set_actor (audio, actor);
51 g_object_unref (audio);
54 typedef struct {
55 SwfdecActor * actor;
56 SwfdecSound * sound;
57 } RemoveData;
59 static gboolean
60 swfdec_sound_object_should_stop (SwfdecAudio *audio, gpointer datap)
62 RemoveData *data = datap;
63 SwfdecAudioEvent *event;
65 if (!SWFDEC_IS_AUDIO_EVENT (audio))
66 return FALSE;
67 event = SWFDEC_AUDIO_EVENT (audio);
68 if (event->sound != data->sound)
69 return FALSE;
70 return audio->actor == data->actor;
73 static void
74 swfdec_sound_sound_provider_stop (SwfdecSoundProvider *provider, SwfdecActor *actor)
76 RemoveData data = { actor, SWFDEC_SOUND (provider) };
78 swfdec_player_stop_sounds (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor)),
79 swfdec_sound_object_should_stop, &data);
82 static SwfdecSoundMatrix *
83 swfdec_sound_sound_provider_get_matrix (SwfdecSoundProvider *provider)
85 return NULL;
88 static void
89 swfdec_sound_sound_provider_init (SwfdecSoundProviderInterface *iface)
91 iface->start = swfdec_sound_sound_provider_start;
92 iface->stop = swfdec_sound_sound_provider_stop;
93 iface->get_matrix = swfdec_sound_sound_provider_get_matrix;
96 /*** SWFDEC_SOUND ***/
98 G_DEFINE_TYPE_WITH_CODE (SwfdecSound, swfdec_sound, SWFDEC_TYPE_CHARACTER,
99 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_SOUND_PROVIDER, swfdec_sound_sound_provider_init))
101 static void
102 swfdec_sound_dispose (GObject *object)
104 SwfdecSound * sound = SWFDEC_SOUND (object);
106 if (sound->decoded)
107 swfdec_buffer_unref (sound->decoded);
108 if (sound->encoded)
109 swfdec_buffer_unref (sound->encoded);
111 G_OBJECT_CLASS (swfdec_sound_parent_class)->dispose (object);
114 static void
115 swfdec_sound_class_init (SwfdecSoundClass * g_class)
117 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
119 object_class->dispose = swfdec_sound_dispose;
122 static void
123 swfdec_sound_init (SwfdecSound * sound)
129 tag_func_define_sound (SwfdecSwfDecoder * s, guint tag)
131 SwfdecBits *b = &s->b;
132 int id;
133 int n_samples;
134 SwfdecSound *sound;
136 id = swfdec_bits_get_u16 (b);
137 sound = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SOUND);
138 if (!sound)
139 return SWFDEC_STATUS_OK;
141 sound->codec = swfdec_bits_getbits (b, 4);
142 SWFDEC_LOG (" codec: %u", sound->codec);
143 sound->format = swfdec_audio_format_parse (b);
144 SWFDEC_LOG (" format: %s", swfdec_audio_format_to_string (sound->format));
145 n_samples = swfdec_bits_get_u32 (b);
146 sound->n_samples = n_samples;
148 switch (sound->codec) {
149 case 0:
150 if (swfdec_audio_format_is_16bit (sound->format))
151 SWFDEC_WARNING ("undefined endianness for s16 sound");
152 /* just assume LE and hope it works (FIXME: want a switch for this?) */
153 sound->codec = SWFDEC_AUDIO_CODEC_UNCOMPRESSED;
154 /* fall through */
155 case 3:
156 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
157 break;
158 case 2:
159 sound->skip = swfdec_bits_get_u16 (b);
160 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
161 break;
162 case 1:
163 case 5:
164 case 6:
165 sound->encoded = swfdec_bits_get_buffer (&s->b, -1);
166 break;
167 default:
168 SWFDEC_WARNING ("unknown codec %d", sound->codec);
170 sound->n_samples *= swfdec_audio_format_get_granularity (sound->format);
172 swfdec_decoder_use_audio_codec (SWFDEC_DECODER (s), sound->codec, sound->format);
174 return SWFDEC_STATUS_OK;
177 SwfdecBuffer *
178 swfdec_sound_get_decoded (SwfdecSound *sound)
180 gpointer decoder;
181 SwfdecBuffer *tmp;
182 SwfdecBufferQueue *queue;
183 guint sample_bytes;
184 guint n_samples;
185 guint depth;
187 g_return_val_if_fail (SWFDEC_IS_SOUND (sound), NULL);
189 if (sound->decoded) {
190 return sound->decoded;
192 if (sound->encoded == NULL)
193 return NULL;
195 decoder = swfdec_audio_decoder_new (sound->codec, sound->format);
196 if (decoder == NULL)
197 return NULL;
199 swfdec_audio_decoder_push (decoder, sound->encoded);
200 swfdec_audio_decoder_push (decoder, NULL);
201 queue = swfdec_buffer_queue_new ();
202 while ((tmp = swfdec_audio_decoder_pull (decoder))) {
203 swfdec_buffer_queue_push (queue, tmp);
205 g_object_unref (decoder);
206 depth = swfdec_buffer_queue_get_depth (queue);
207 if (depth == 0) {
208 SWFDEC_ERROR ("decoding didn't produce any data, bailing");
209 return NULL;
211 tmp = swfdec_buffer_queue_pull (queue, depth);
212 swfdec_buffer_queue_unref (queue);
214 sample_bytes = 4;
215 n_samples = sound->n_samples;
217 SWFDEC_LOG ("after decoding, got %"G_GSIZE_FORMAT" samples, should get %u and skip %u",
218 tmp->length / sample_bytes, n_samples, sound->skip);
219 if (sound->skip) {
220 SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, sound->skip * sample_bytes,
221 tmp->length - sound->skip * sample_bytes);
222 swfdec_buffer_unref (tmp);
223 tmp = tmp2;
225 if (tmp->length > n_samples * sample_bytes) {
226 SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, 0, n_samples * sample_bytes);
227 SWFDEC_DEBUG ("%u samples in %u bytes should be available, but %"G_GSIZE_FORMAT" bytes are, cutting them off",
228 n_samples, n_samples * sample_bytes, tmp->length);
229 swfdec_buffer_unref (tmp);
230 tmp = tmp2;
231 } else if (tmp->length < n_samples * sample_bytes) {
232 /* we handle this case in swfdec_sound_render */
233 /* FIXME: this message is important when writing new codecs, so I made it a warning.
234 * It's probably not worth more than INFO for the usual case though */
235 SWFDEC_WARNING ("%u samples in %u bytes should be available, but only %"G_GSIZE_FORMAT" bytes are",
236 n_samples, n_samples * sample_bytes, tmp->length);
238 /* only assign here, the decoding code checks this variable */
239 sound->decoded = tmp;
241 return sound->decoded;
244 void
245 swfdec_sound_chunk_free (SwfdecSoundChunk *chunk)
247 g_return_if_fail (chunk != NULL);
249 g_free (chunk->envelope);
250 g_free (chunk);
253 SwfdecSoundChunk *
254 swfdec_sound_parse_chunk (SwfdecSwfDecoder *s, SwfdecBits *b, int id)
256 int has_envelope;
257 int has_loops;
258 int has_out_point;
259 int has_in_point;
260 guint i, j;
261 SwfdecSound *sound;
262 SwfdecSoundChunk *chunk;
264 sound = swfdec_swf_decoder_get_character (s, id);
265 if (!SWFDEC_IS_SOUND (sound)) {
266 SWFDEC_ERROR ("given id %d does not reference a sound object", id);
267 return NULL;
270 chunk = g_new0 (SwfdecSoundChunk, 1);
271 chunk->sound = sound;
272 SWFDEC_DEBUG ("parsing sound chunk for sound %d", SWFDEC_CHARACTER (sound)->id);
274 swfdec_bits_getbits (b, 2);
275 chunk->stop = swfdec_bits_getbits (b, 1);
276 chunk->no_restart = swfdec_bits_getbits (b, 1);
277 has_envelope = swfdec_bits_getbits (b, 1);
278 has_loops = swfdec_bits_getbits (b, 1);
279 has_out_point = swfdec_bits_getbits (b, 1);
280 has_in_point = swfdec_bits_getbits (b, 1);
281 if (has_in_point) {
282 chunk->start_sample = swfdec_bits_get_u32 (b);
283 SWFDEC_LOG (" start_sample = %u", chunk->start_sample);
284 } else {
285 chunk->start_sample = 0;
287 if (has_out_point) {
288 chunk->stop_sample = swfdec_bits_get_u32 (b);
289 if (chunk->stop_sample == 0) {
290 SWFDEC_FIXME ("stop sample == 0???");
292 SWFDEC_LOG (" stop_sample = %u", chunk->stop_sample);
293 if (chunk->stop_sample <= chunk->start_sample) {
294 SWFDEC_ERROR ("stopping before starting? (start sample %u, stop sample %u)",
295 chunk->start_sample, chunk->stop_sample);
296 chunk->stop_sample = 0;
298 } else {
299 chunk->stop_sample = 0;
301 if (has_loops) {
302 chunk->loop_count = swfdec_bits_get_u16 (b);
303 if (chunk->loop_count == 0) {
304 SWFDEC_ERROR ("loop_count 0 not allowed, setting to 1");
305 chunk->loop_count = 1;
307 SWFDEC_LOG (" loop_count = %u", chunk->loop_count);
308 } else {
309 chunk->loop_count = 1;
311 if (has_envelope) {
312 chunk->n_envelopes = swfdec_bits_get_u8 (b);
313 chunk->envelope = g_new0 (SwfdecSoundEnvelope, chunk->n_envelopes);
314 SWFDEC_LOG (" n_envelopes = %u", chunk->n_envelopes);
317 for (i = 0; i < chunk->n_envelopes && swfdec_bits_left (b); i++) {
318 chunk->envelope[i].offset = swfdec_bits_get_u32 (b);
319 if (i > 0 && chunk->envelope[i-1].offset > chunk->envelope[i].offset) {
320 SWFDEC_ERROR ("unordered sound envelopes");
321 chunk->envelope[i].offset = chunk->envelope[i-1].offset;
324 for (j = 0; j < 2; j++) {
325 chunk->envelope[i].volume[j] = swfdec_bits_get_u16 (b);
326 if (chunk->envelope[i].volume[j] > 32768) {
327 SWFDEC_FIXME ("too big envelope volumes (%u > 32768) not handled correctly",
328 chunk->envelope[i].volume[j]);
329 chunk->envelope[i].volume[j] = 32768;
333 SWFDEC_LOG (" envelope = %u { %u, %u }", chunk->envelope[i].offset,
334 (guint) chunk->envelope[i].volume[0], (guint) chunk->envelope[i].volume[1]);
337 if (i < chunk->n_envelopes)
338 SWFDEC_ERROR ("out of bits when reading sound envelopes");
340 return chunk;
344 tag_func_define_button_sound (SwfdecSwfDecoder * s, guint tag)
346 guint i;
347 guint id;
348 SwfdecButton *button;
350 id = swfdec_bits_get_u16 (&s->b);
351 button = (SwfdecButton *) swfdec_swf_decoder_get_character (s, id);
352 if (!SWFDEC_IS_BUTTON (button)) {
353 SWFDEC_ERROR ("id %u is not a button", id);
354 return SWFDEC_STATUS_OK;
356 SWFDEC_LOG ("loading sound events for button %u", id);
357 for (i = 0; i < 4; i++) {
358 id = swfdec_bits_get_u16 (&s->b);
359 if (id) {
360 SWFDEC_LOG ("loading sound %u for button event %u", id, i);
361 if (button->sounds[i]) {
362 SWFDEC_ERROR ("need to delete previous sound for button %u's event %u",
363 SWFDEC_CHARACTER (button)->id, i);
364 swfdec_sound_chunk_free (button->sounds[i]);
366 button->sounds[i] = swfdec_sound_parse_chunk (s, &s->b, id);
370 return SWFDEC_STATUS_OK;
374 * swfdec_sound_buffer_get_n_samples:
375 * @buffer: data to examine
376 * @format: format the data in @buffer is in
378 * Determines the number of samples inside @buffer that would be available if
379 * it were to be rendered using the default Flash format, 44100Hz.
381 * Returns: Number of samples contained in @buffer when rendered
383 guint
384 swfdec_sound_buffer_get_n_samples (const SwfdecBuffer *buffer, SwfdecAudioFormat format)
386 g_return_val_if_fail (buffer != NULL, 0);
387 g_return_val_if_fail (buffer->length % (2 * swfdec_audio_format_get_channels (format)) == 0, 0);
389 return buffer->length / (2 * swfdec_audio_format_get_channels (format)) *
390 swfdec_audio_format_get_granularity (format);
394 * swfdec_sound_render_buffer:
395 * @dest: target buffer to render to
396 * @source: source data to render
397 * @offset: offset in 44100Hz samples into @source
398 * @n_samples: number of samples to render into @dest. If more data would be
399 * rendered than is available in @source, 0 samples are used instead.
401 * Adds data from @source into @dest
403 void
404 swfdec_sound_buffer_render (gint16 *dest, const SwfdecBuffer *source,
405 guint offset, guint n_samples)
407 g_return_if_fail (dest != NULL);
408 g_return_if_fail (source != NULL);
409 g_return_if_fail ((offset + n_samples) * 4 <= source->length);
411 memcpy (dest, source->data + 4 * offset, 4 * n_samples);