📄 swfdec_sound.c
字号:
swfdec_sound_chunk_free (SwfdecSoundChunk *chunk){ g_return_if_fail (chunk != NULL); g_free (chunk->envelope); g_free (chunk);}SwfdecSoundChunk *swfdec_sound_parse_chunk (SwfdecSwfDecoder *s, int id){ int has_envelope; int has_loops; int has_out_point; int has_in_point; guint i, j; SwfdecSound *sound; SwfdecSoundChunk *chunk; SwfdecBits *b = &s->b; sound = swfdec_swf_decoder_get_character (s, id); if (!SWFDEC_IS_SOUND (sound)) { SWFDEC_ERROR ("given id %d does not reference a sound object", id); return NULL; } chunk = g_new0 (SwfdecSoundChunk, 1); chunk->sound = sound; SWFDEC_DEBUG ("parsing sound chunk for sound %d", SWFDEC_CHARACTER (sound)->id); swfdec_bits_getbits (b, 2); chunk->stop = swfdec_bits_getbits (b, 1); chunk->no_restart = swfdec_bits_getbits (b, 1); has_envelope = swfdec_bits_getbits (b, 1); has_loops = swfdec_bits_getbits (b, 1); has_out_point = swfdec_bits_getbits (b, 1); has_in_point = swfdec_bits_getbits (b, 1); if (has_in_point) { chunk->start_sample = swfdec_bits_get_u32 (b); } else { chunk->start_sample = 0; } if (has_out_point) { chunk->stop_sample = swfdec_bits_get_u32 (b); if (chunk->stop_sample > sound->n_samples) { SWFDEC_INFO ("more samples specified (%u) than available (%u)", chunk->stop_sample, sound->n_samples); } } else { chunk->stop_sample = sound->n_samples; } if (has_loops) { chunk->loop_count = swfdec_bits_get_u16 (b); } else { chunk->loop_count = 1; } if (has_envelope) { chunk->n_envelopes = swfdec_bits_get_u8 (b); chunk->envelope = g_new (SwfdecSoundEnvelope, chunk->n_envelopes); } SWFDEC_LOG (" start_sample = %u", chunk->start_sample); SWFDEC_LOG (" stop_sample = %u", chunk->stop_sample); SWFDEC_LOG (" loop_count = %u", chunk->loop_count); SWFDEC_LOG (" n_envelopes = %u", chunk->n_envelopes); for (i = 0; i < chunk->n_envelopes; i++) { chunk->envelope[i].offset = swfdec_bits_get_u32 (b); if (chunk->envelope[i].offset < chunk->start_sample) { SWFDEC_WARNING ("envelope entry offset too small (%d vs %d)", chunk->envelope[i].offset, chunk->start_sample); chunk->envelope[i].offset = chunk->start_sample; } if (i > 0 && chunk->envelope[i].offset <= chunk->envelope[i-1].offset) { /* FIXME: figure out how to handle this */ SWFDEC_ERROR ("sound evelope offsets not sorted"); } for (j = 0; j < 2; j++) { chunk->envelope[i].volume[j] = swfdec_bits_get_u16 (b); if (chunk->envelope[i].volume[j] > 32768) { SWFDEC_ERROR ("envelope volume too big: %u > 32768", chunk->envelope[i].volume[j]); chunk->envelope[i].volume[j] = 32768; } } SWFDEC_LOG (" envelope = %u { %u, %u }", chunk->envelope[i].offset, (guint) chunk->envelope[i].volume[0], (guint) chunk->envelope[i].volume[1]); /* FIXME: check that mono sound gets averaged and then do this here? */ } return chunk;}inttag_func_start_sound (SwfdecSwfDecoder * s, guint tag){ SwfdecBits *b = &s->b; SwfdecSoundChunk *chunk; int id; SwfdecSpriteFrame *frame = &s->parse_sprite->frames[s->parse_sprite->parse_frame]; id = swfdec_bits_get_u16 (b); chunk = swfdec_sound_parse_chunk (s, id); if (chunk) { /* append to keep order */ SWFDEC_DEBUG ("appending StartSound event for sound %u to frame %u", id, s->parse_sprite->parse_frame); frame->sound = g_slist_append (frame->sound, chunk); } return SWFDEC_STATUS_OK;}inttag_func_define_button_sound (SwfdecSwfDecoder * s, guint tag){ guint i; guint id; SwfdecButton *button; id = swfdec_bits_get_u16 (&s->b); button = (SwfdecButton *) swfdec_swf_decoder_get_character (s, id); if (!SWFDEC_IS_BUTTON (button)) { SWFDEC_ERROR ("id %u is not a button", id); return SWFDEC_STATUS_OK; } SWFDEC_LOG ("loading sound events for button %u", id); for (i = 0; i < 4; i++) { id = swfdec_bits_get_u16 (&s->b); if (id) { SWFDEC_LOG ("loading sound %u for button event %u", id, i); if (button->sounds[i]) { SWFDEC_ERROR ("need to delete previous sound for button %u's event %u", SWFDEC_CHARACTER (button)->id, i); swfdec_sound_chunk_free (button->sounds[i]); } button->sounds[i] = swfdec_sound_parse_chunk (s, id); } } return SWFDEC_STATUS_OK;}/** * swfdec_sound_buffer_get_n_samples: * @buffer: data to examine * @format: format the data in @buffer is in * * Determines the number of samples inside @buffer that would be available if * it were to be rendered using the default Flash format, 44100Hz. * * Returns: Number of samples contained in @buffer when rendered **/guintswfdec_sound_buffer_get_n_samples (const SwfdecBuffer *buffer, SwfdecAudioOut format){ g_return_val_if_fail (buffer != NULL, 0); g_return_val_if_fail (buffer->length % (2 * SWFDEC_AUDIO_OUT_N_CHANNELS (format)) == 0, 0); return buffer->length / (2 * SWFDEC_AUDIO_OUT_N_CHANNELS (format)) * SWFDEC_AUDIO_OUT_GRANULARITY (format);}/** * swfdec_sound_render_buffer: * @dest: target buffer to render to * @source: source data to render * @format: format of data in @source and @previous * @previous: previous buffer or NULL for none. This is necessary for * upsampling at buffer boundaries * @offset: offset in 44100Hz samples into @source * @n_samples: number of samples to render into @dest. If more data would be * rendered than is available in @source, 0 samples are used instead. * * Adds data from @source into @dest using the same upsampling algorithm as * Flash player. **//* NB: if you improve the upsampling algorithm, tests might start to break */voidswfdec_sound_buffer_render (gint16 *dest, const SwfdecBuffer *source, SwfdecAudioOut format, const SwfdecBuffer *previous, guint offset, guint n_samples){ guint i, j; guint channels = SWFDEC_AUDIO_OUT_N_CHANNELS (format); guint rate = SWFDEC_AUDIO_OUT_GRANULARITY (format); gint16 *src, *end; g_return_if_fail (dest != NULL); g_return_if_fail (source != NULL); g_return_if_fail (swfdec_sound_buffer_get_n_samples (source, format) > 0); g_return_if_fail (format != 0); g_return_if_fail (previous == NULL || swfdec_sound_buffer_get_n_samples (previous, format) > 0); src = (gint16 *) source->data; end = (gint16 *) (source->data + source->length); src += channels * (offset / rate); offset %= rate; if (offset) { offset = rate - offset; /* NB: dest will be pointing to uninitialized memory now */ dest -= offset * 2; n_samples += offset; } /* this is almost the same as the channels == 1 case, so check for bugfixes in both branches */ if (channels == 1) { int values[rate + 1]; if (src >= end) n_samples = 0; else if (src != (gint16 *) source->data) values[0] = src[-1]; else if (previous) values[0] = ((gint16 *) previous->data)[previous->length / 2 - 1]; else values[0] = *src; while (n_samples > 0) { if (src > end) break; else if (src == end) values[rate] = 0; else values[rate] = *src; src++; for (i = rate / 2; i >= 1; i /= 2) { for (j = i; j < rate; j += 2 * i) { values[j] = (values[j + i] + values[j - i]) / 2; } } for (i = offset; i < MIN (rate, n_samples); i++) { dest[2 * i] += values[i + 1]; dest[2 * i + 1] += values[i + 1]; } dest += 2 * rate; values[0] = values[rate]; offset = 0; n_samples -= MIN (n_samples, rate); } } else { int values[2][rate + 1]; if (src >= end) { n_samples = 0; } else if (src != (gint16 *) source->data) { values[0][0] = src[-2]; values[1][0] = src[-1]; } else if (previous) { values[0][0] = ((gint16 *) previous->data)[previous->length / 2 - 2]; values[1][0] = ((gint16 *) previous->data)[previous->length / 2 - 1]; } else { values[0][0] = src[0]; values[1][0] = src[1]; } while (n_samples > 0) { if (src > end) { break; } else if (src == end) { values[0][rate] = 0; values[1][rate] = 0; } else { values[0][rate] = src[0]; values[1][rate] = src[1]; } src += 2; for (i = rate / 2; i >= 1; i /= 2) { for (j = i; j < rate; j += 2 * i) { values[0][j] = (values[0][j + i] + values[0][j - i]) / 2; values[1][j] = (values[1][j + i] + values[1][j - i]) / 2; } } for (i = offset; i < MIN (rate, n_samples); i++) { dest[2 * i] += values[0][i + 1]; dest[2 * i + 1] += values[1][i + 1]; } dest += 2 * rate; values[0][0] = values[0][rate]; values[1][0] = values[1][rate]; offset = 0; n_samples -= MIN (n_samples, rate); } }}/** * swfdec_sound_render: * @sound: a #SwfdecSound * @dest: target to add to * @offset: offset in samples into the data * @n_samples: amount of samples to render * * Renders the given sound onto the existing data in @dest. **/voidswfdec_sound_render (SwfdecSound *sound, gint16 *dest, guint offset, guint n_samples){ SwfdecBuffer *buffer; SwfdecAudioOut format; g_return_if_fail (SWFDEC_IS_SOUND (sound)); /* FIXME: I need a return_if_fail for !created_by_define_sound */ buffer = swfdec_sound_get_decoded (sound, &format); if (buffer == NULL) return; swfdec_sound_buffer_render (dest, buffer, format, NULL, offset, n_samples);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -