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
27 #include "swfdec_audio_internal.h"
28 #include "swfdec_actor.h"
29 #include "swfdec_debug.h"
30 #include "swfdec_player_internal.h"
35 * @see_also: SwfdecPlayer
36 * @short_description: object used for audio output
38 * SwfdecAudio is the way audio output is provided by a #SwfdecPlayer. See
39 * its documentation on how to access #SwfdecAudio objects.
41 * An audio object gives access to one audio stream played inside a player.
42 * You are responsible for outputting this data, swfdec does not try to do this
45 * Audio data is always provided in 16bit host-endian stereo. If the data was
46 * encoded into a different format originally, Swfdec will already have decoded
47 * it. The data is always referenced relative to the player. Sample 0
48 * references the first sample to be played at the current position. If the
49 * player gets iterated, sample 0 changes. There is no way to access samples
50 * belonging to a previous state.
56 * This object is used for audio output. It is an abstract class.
59 G_DEFINE_ABSTRACT_TYPE (SwfdecAudio
, swfdec_audio
, G_TYPE_OBJECT
)
67 static guint signals
[LAST_SIGNAL
] = { 0, };
70 swfdec_audio_dispose (GObject
*object
)
72 G_GNUC_UNUSED SwfdecAudio
*audio
= SWFDEC_AUDIO (object
);
74 g_assert (audio
->actor
== NULL
);
75 g_assert (audio
->player
== NULL
);
77 G_OBJECT_CLASS (swfdec_audio_parent_class
)->dispose (object
);
81 swfdec_audio_class_init (SwfdecAudioClass
*klass
)
83 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
86 * SwfdecAudio::changed:
87 * @audio: the #SwfdecAudio affected
89 * This signal is emitted whenever the data of the @audio changed and cached
90 * data should be rerendered. This happens for example when the volume of the
91 * audio is changed by the Flash file.
93 signals
[CHANGED
] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass
),
94 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__VOID
,
97 * SwfdecAudio::new-data:
98 * @audio: the #SwfdecAudio affected
100 * This signal is emitted whenever new data was loaded into @audio. You want
101 * to listen to this signal when swfdec_audio_render() previously returned
102 * less samples than you wanted to render.
104 signals
[NEW_DATA
] = g_signal_new ("new-data", G_TYPE_FROM_CLASS (klass
),
105 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__VOID
,
108 object_class
->dispose
= swfdec_audio_dispose
;
112 swfdec_audio_init (SwfdecAudio
*audio
)
118 * @audio: audio to add
119 * @player: a #SwfdecPlayer to attach to or NULL
121 * Registers a new audio object for playback in @player. If player is %NULL,
122 * this function does nothing.
123 * The starting point of the audio stream will be equivalent the player's time.
126 swfdec_audio_add (SwfdecAudio
*audio
, SwfdecPlayer
*player
)
128 SwfdecPlayerPrivate
*priv
;
130 g_return_if_fail (SWFDEC_IS_AUDIO (audio
));
131 g_return_if_fail (audio
->player
== NULL
);
134 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
136 g_object_ref (audio
);
137 audio
->player
= player
;
139 priv
->audio
= g_list_append (priv
->audio
, audio
);
140 SWFDEC_INFO ("adding %s %p", G_OBJECT_TYPE_NAME (audio
), audio
);
144 swfdec_audio_remove (SwfdecAudio
*audio
)
146 g_return_if_fail (SWFDEC_IS_AUDIO (audio
));
148 if (audio
->player
!= NULL
) {
149 SwfdecPlayerPrivate
*priv
= audio
->player
->priv
;
150 SWFDEC_INFO ("removing %s %p", G_OBJECT_TYPE_NAME (audio
), audio
);
151 swfdec_audio_set_actor (audio
, NULL
);
152 priv
->audio
= g_list_remove (priv
->audio
, audio
);
154 g_signal_emit_by_name (audio
->player
, "audio-removed", audio
);
155 audio
->added
= FALSE
;
157 audio
->player
= NULL
;
158 g_object_unref (audio
);
163 * swfdec_audio_iterate:
164 * @audio: the #SwfdecAudio to iterate
165 * @n_samples: number of samples to remove
167 * Iterates the @audio. Iterating means discarding the first @n_samples
168 * samples of the audio stream.
170 * Returns: maximum number of remaining frames. If G_MAXUINT is returned,
171 * then the number of frames isn't known yet.
174 swfdec_audio_iterate (SwfdecAudio
*audio
, gsize n_samples
)
176 SwfdecAudioClass
*klass
;
178 g_return_val_if_fail (SWFDEC_IS_AUDIO (audio
), 0);
179 g_return_val_if_fail (n_samples
> 0, 0);
181 klass
= SWFDEC_AUDIO_GET_CLASS (audio
);
182 g_assert (klass
->iterate
);
183 return klass
->iterate (audio
, n_samples
);
187 swfdec_audio_set_actor (SwfdecAudio
*audio
, SwfdecActor
*actor
)
189 g_return_if_fail (SWFDEC_IS_AUDIO (audio
));
190 g_return_if_fail (audio
->player
!= NULL
);
191 g_return_if_fail (actor
== NULL
|| SWFDEC_IS_ACTOR (actor
));
194 g_object_ref (actor
);
197 g_object_unref (audio
->actor
);
199 audio
->actor
= actor
;
200 swfdec_audio_set_matrix (audio
, actor
? &actor
->sound_matrix
: NULL
);
204 swfdec_audio_set_matrix (SwfdecAudio
*audio
, const SwfdecSoundMatrix
*matrix
)
206 g_return_if_fail (SWFDEC_IS_AUDIO (audio
));
208 audio
->matrix
= matrix
;
211 /* FIXME: This function is pretty much a polling approach at sound matrix
212 * handling and it would be much nicer if we had a "changed" signal on the
213 * matrices. But matrices can't emit signals...
216 swfdec_audio_update_matrix (SwfdecAudio
*audio
)
218 SwfdecSoundMatrix sound
;
220 g_return_if_fail (SWFDEC_IS_AUDIO (audio
));
223 swfdec_sound_matrix_multiply (&sound
, audio
->matrix
,
224 &audio
->player
->priv
->sound_matrix
);
225 } else if (audio
->player
) {
226 sound
= audio
->player
->priv
->sound_matrix
;
228 if (swfdec_sound_matrix_is_equal (&sound
, &audio
->matrix_cache
))
231 audio
->matrix_cache
= sound
;
232 g_signal_emit (audio
, signals
[CHANGED
], 0);
236 * swfdec_audio_render:
237 * @audio: a #SwfdecAudio
238 * @dest: memory area to render to
239 * @start_offset: offset in samples at which to start rendering. The offset is
240 * calculated relative to the last iteration, so the value set
241 * by swfdec_player_set_audio_advance() is ignored.
242 * @n_samples: amount of samples to render.
244 * Renders the samples from @audio into the area pointed to by @dest. Existing
245 * data in @dest is overwritten.
247 * Returns: The amount of samples actually rendered. Usually this number is
248 * equal to @n_samples, but if you arrived at the end of stream or the
249 * stream is still loading, this number may be lower. It indicates
250 * that no more samples are available.
253 swfdec_audio_render (SwfdecAudio
*audio
, gint16
*dest
,
254 gsize start_offset
, gsize n_samples
)
256 SwfdecAudioClass
*klass
;
259 g_return_val_if_fail (SWFDEC_IS_AUDIO (audio
), 0);
260 g_return_val_if_fail (dest
!= NULL
, 0);
261 g_return_val_if_fail (n_samples
> 0, 0);
263 klass
= SWFDEC_AUDIO_GET_CLASS (audio
);
264 rendered
= klass
->render (audio
, dest
, start_offset
, n_samples
);
265 swfdec_sound_matrix_apply (&audio
->matrix_cache
, dest
, rendered
);
270 /*** SWFDEC_AUDIO_FORMAT ***/
272 /* SwfdecAudioFormat is represented in the least significant bits of a uint:
273 * - the LSBit is 1 if it's 16bit audio, 0 for 8bit
274 * - the next bit is 1 for stereo, 0 for mono
275 * - the other two bits are for the rate, see swfdec_audio_format_new()
276 * This is the same format the Flash file format uses to store audio formats.
280 swfdec_audio_format_parse (SwfdecBits
*bits
)
282 g_return_val_if_fail (bits
!= NULL
, 0);
284 return swfdec_bits_getbits (bits
, 4);
288 swfdec_audio_format_new (guint rate
, guint channels
, gboolean is_16bit
)
290 SwfdecAudioFormat ret
;
292 g_return_val_if_fail (channels
== 1 || channels
== 2, 0);
308 g_return_val_if_reached (0);
320 swfdec_audio_format_get_channels (SwfdecAudioFormat format
)
322 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), 2);
324 return (format
& 0x1) + 1;
328 swfdec_audio_format_is_16bit (SwfdecAudioFormat format
)
330 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), TRUE
);
332 return format
& 0x2 ? TRUE
: FALSE
;
336 swfdec_audio_format_get_rate (SwfdecAudioFormat format
)
338 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), 44100);
340 return 44100 / swfdec_audio_format_get_granularity (format
);
344 * swfdec_audio_format_get_granularity:
345 * @format: an auio format
347 * The granularity is a Swfdec-specific name, describing how often a sample in
348 * a 44100Hz audio stream is defined. So for example 44100Hz has a granularity
349 * of 1 and 11025Hz has a granularity of 4 (because only every fourth sample
352 * Returns: the granularity of the format
355 swfdec_audio_format_get_granularity (SwfdecAudioFormat format
)
357 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), 1);
359 return 1 << (3 - (format
>> 2));
363 swfdec_audio_format_to_string (SwfdecAudioFormat format
)
365 static const char *names
[] = {
367 "8bit 5.5kHz stereo",
369 "16bit 5.5kHz stereo",
373 "16bit 11kHz stereo",
377 "16bit 22kHz stereo",
383 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), "");
385 return names
[format
];
389 * swfdec_audio_format_get_bytes_per_sample:
390 * @format: audio format to check
392 * Computes the number of bytes required to store one sample of audio encoded
395 * Returns: The number of bytes for one sample
398 swfdec_audio_format_get_bytes_per_sample (SwfdecAudioFormat format
)
400 guint bps
[4] = { 1, 2, 2, 4 };
402 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
), 1);
404 return bps
[format
& 0x3];