music_flac.c
上传用户:nini_0081
上传日期:2022-07-21
资源大小:2628k
文件大小:16k
- /*
- SDL_mixer: An audio mixer library based on the SDL library
- Copyright (C) 1997-2009 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken@libsdl.org
- This file is used to support SDL_LoadMUS playback of FLAC files.
- ~ Austen Dicken (admin@cvpcs.org)
- */
- #ifdef FLAC_MUSIC
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "SDL_mixer.h"
- #include "dynamic_flac.h"
- #include "music_flac.h"
- /* This is the format of the audio mixer data */
- static SDL_AudioSpec mixer;
- /* Initialize the FLAC player, with the given mixer settings
- This function returns 0, or -1 if there was an error.
- */
- int FLAC_init(SDL_AudioSpec *mixerfmt)
- {
- mixer = *mixerfmt;
- return(0);
- }
- /* Set the volume for an FLAC stream */
- void FLAC_setvolume(FLAC_music *music, int volume)
- {
- music->volume = volume;
- }
- /* Load an FLAC stream from the given file */
- FLAC_music *FLAC_new(const char *file)
- {
- SDL_RWops *rw;
- rw = SDL_RWFromFile (file, "rb");
- if (rw == NULL) {
- SDL_SetError ("Couldn't open %s", file);
- return NULL;
- }
- return FLAC_new_RW (rw);
- }
- static FLAC__StreamDecoderReadStatus flac_read_music_cb(
- const FLAC__StreamDecoder *decoder,
- FLAC__byte buffer[],
- size_t *bytes,
- void *client_data)
- {
- FLAC_music *data = (FLAC_music*)client_data;
- // make sure there is something to be reading
- if (*bytes > 0) {
- *bytes = SDL_RWread (data->rwops, buffer, sizeof (FLAC__byte), *bytes);
- if (*bytes < 0) { // error in read
- return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
- }
- else if (*bytes == 0 ) { // no data was read (EOF)
- return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
- }
- else { // data was read, continue
- return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
- }
- }
- else {
- return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
- }
- }
- static FLAC__StreamDecoderSeekStatus flac_seek_music_cb(
- const FLAC__StreamDecoder *decoder,
- FLAC__uint64 absolute_byte_offset,
- void *client_data)
- {
- FLAC_music *data = (FLAC_music*)client_data;
- if (SDL_RWseek (data->rwops, absolute_byte_offset, RW_SEEK_SET) < 0) {
- return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
- }
- else {
- return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
- }
- }
- static FLAC__StreamDecoderTellStatus flac_tell_music_cb(
- const FLAC__StreamDecoder *decoder,
- FLAC__uint64 *absolute_byte_offset,
- void *client_data )
- {
- FLAC_music *data = (FLAC_music*)client_data;
- int pos = SDL_RWtell (data->rwops);
- if (pos < 0) {
- return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
- }
- else {
- *absolute_byte_offset = (FLAC__uint64)pos;
- return FLAC__STREAM_DECODER_TELL_STATUS_OK;
- }
- }
- static FLAC__StreamDecoderLengthStatus flac_length_music_cb (
- const FLAC__StreamDecoder *decoder,
- FLAC__uint64 *stream_length,
- void *client_data)
- {
- FLAC_music *data = (FLAC_music*)client_data;
- int pos = SDL_RWtell (data->rwops);
- int length = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
- if (SDL_RWseek (data->rwops, pos, RW_SEEK_SET) != pos || length < 0) {
- /* there was an error attempting to return the stream to the original
- * position, or the length was invalid. */
- return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
- }
- else {
- *stream_length = (FLAC__uint64)length;
- return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
- }
- }
- static FLAC__bool flac_eof_music_cb(
- const FLAC__StreamDecoder *decoder,
- void *client_data )
- {
- FLAC_music *data = (FLAC_music*)client_data;
- int pos = SDL_RWtell (data->rwops);
- int end = SDL_RWseek (data->rwops, 0, RW_SEEK_END);
- // was the original position equal to the end (a.k.a. the seek didn't move)?
- if (pos == end) {
- // must be EOF
- return true;
- }
- else {
- // not EOF, return to the original position
- SDL_RWseek (data->rwops, pos, RW_SEEK_SET);
- return false;
- }
- }
- static FLAC__StreamDecoderWriteStatus flac_write_music_cb(
- const FLAC__StreamDecoder *decoder,
- const FLAC__Frame *frame,
- const FLAC__int32 *const buffer[],
- void *client_data)
- {
- FLAC_music *data = (FLAC_music *)client_data;
- size_t i;
- if (data->flac_data.total_samples == 0) {
- SDL_SetError ("Given FLAC file does not specify its sample count.");
- return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- if (data->flac_data.channels != 2 ||
- data->flac_data.bits_per_sample != 16) {
- SDL_SetError("Current FLAC support is only for 16 bit Stereo files.");
- return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- for (i = 0; i < frame->header.blocksize; i++) {
- FLAC__int16 i16;
- FLAC__uint16 ui16;
- // make sure we still have at least two bytes that can be read (one for
- // each channel)
- if (data->flac_data.max_to_read >= 4) {
- // does the data block exist?
- if (!data->flac_data.data) {
- data->flac_data.data_len = data->flac_data.max_to_read;
- data->flac_data.data_read = 0;
- // create it
- data->flac_data.data =
- (char *)malloc (data->flac_data.data_len);
- if (!data->flac_data.data) {
- return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- }
- i16 = (FLAC__int16)buffer[0][i];
- ui16 = (FLAC__uint16)i16;
- *((data->flac_data.data) + (data->flac_data.data_read++)) =
- (char)(ui16);
- *((data->flac_data.data) + (data->flac_data.data_read++)) =
- (char)(ui16 >> 8);
- i16 = (FLAC__int16)buffer[1][i];
- ui16 = (FLAC__uint16)i16;
- *((data->flac_data.data) + (data->flac_data.data_read++)) =
- (char)(ui16);
- *((data->flac_data.data) + (data->flac_data.data_read++)) =
- (char)(ui16 >> 8);
- data->flac_data.max_to_read -= 4;
- if (data->flac_data.max_to_read < 4) {
- // we need to set this so that the read halts from the
- // FLAC_getsome function.
- data->flac_data.max_to_read = 0;
- }
- }
- else {
- // we need to write to the overflow
- if (!data->flac_data.overflow) {
- data->flac_data.overflow_len =
- 4 * (frame->header.blocksize - i);
- data->flac_data.overflow_read = 0;
- // make it big enough for the rest of the block
- data->flac_data.overflow =
- (char *)malloc (data->flac_data.overflow_len);
- if (!data->flac_data.overflow) {
- return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- }
- }
- i16 = (FLAC__int16)buffer[0][i];
- ui16 = (FLAC__uint16)i16;
- *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
- (char)(ui16);
- *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
- (char)(ui16 >> 8);
- i16 = (FLAC__int16)buffer[1][i];
- ui16 = (FLAC__uint16)i16;
- *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
- (char)(ui16);
- *((data->flac_data.overflow) + (data->flac_data.overflow_read++)) =
- (char)(ui16 >> 8);
- }
- }
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
- }
- static void flac_metadata_music_cb(
- const FLAC__StreamDecoder *decoder,
- const FLAC__StreamMetadata *metadata,
- void *client_data)
- {
- FLAC_music *data = (FLAC_music *)client_data;
- if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
- data->flac_data.sample_rate = metadata->data.stream_info.sample_rate;
- data->flac_data.channels = metadata->data.stream_info.channels;
- data->flac_data.total_samples =
- metadata->data.stream_info.total_samples;
- data->flac_data.bits_per_sample =
- metadata->data.stream_info.bits_per_sample;
- data->flac_data.sample_size = data->flac_data.channels *
- ((data->flac_data.bits_per_sample) / 8);
- }
- }
- static void flac_error_music_cb(
- const FLAC__StreamDecoder *decoder,
- FLAC__StreamDecoderErrorStatus status,
- void *client_data)
- {
- // print an SDL error based on the error status
- switch (status) {
- case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
- SDL_SetError ("Error processing the FLAC file [LOST_SYNC].");
- break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
- SDL_SetError ("Error processing the FLAC file [BAD_HEADER].");
- break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
- SDL_SetError ("Error processing the FLAC file [CRC_MISMATCH].");
- break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM:
- SDL_SetError ("Error processing the FLAC file [UNPARSEABLE].");
- break;
- default:
- SDL_SetError ("Error processing the FLAC file [UNKNOWN].");
- break;
- }
- }
- /* Load an FLAC stream from an SDL_RWops object */
- FLAC_music *FLAC_new_RW(SDL_RWops *rw)
- {
- FLAC_music *music;
- int init_stage = 0;
- int was_error = 1;
- music = (FLAC_music *)malloc ( sizeof (*music));
- if (music) {
- /* Initialize the music structure */
- memset (music, 0, (sizeof (*music)));
- FLAC_stop (music);
- FLAC_setvolume (music, MIX_MAX_VOLUME);
- music->section = -1;
- music->rwops = rw;
- music->flac_data.max_to_read = 0;
- music->flac_data.overflow = NULL;
- music->flac_data.overflow_len = 0;
- music->flac_data.overflow_read = 0;
- music->flac_data.data = NULL;
- music->flac_data.data_len = 0;
- music->flac_data.data_read = 0;
- if (Mix_Init(MIX_INIT_FLAC)) {
- init_stage++; // stage 1!
- music->flac_decoder = flac.FLAC__stream_decoder_new ();
- if (music->flac_decoder != NULL) {
- init_stage++; // stage 2!
- if (flac.FLAC__stream_decoder_init_stream(
- music->flac_decoder,
- flac_read_music_cb, flac_seek_music_cb,
- flac_tell_music_cb, flac_length_music_cb,
- flac_eof_music_cb, flac_write_music_cb,
- flac_metadata_music_cb, flac_error_music_cb,
- music) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
- init_stage++; // stage 3!
- if (flac.FLAC__stream_decoder_process_until_end_of_metadata
- (music->flac_decoder)) {
- was_error = 0;
- } else {
- SDL_SetError("FLAC__stream_decoder_process_until_end_of_metadata() failed");
- }
- } else {
- SDL_SetError("FLAC__stream_decoder_init_stream() failed");
- }
- } else {
- SDL_SetError("FLAC__stream_decoder_new() failed");
- }
- }
- if (was_error) {
- switch (init_stage) {
- case 3:
- flac.FLAC__stream_decoder_finish( music->flac_decoder );
- case 2:
- flac.FLAC__stream_decoder_delete( music->flac_decoder );
- case 1:
- case 0:
- free(music);
- SDL_RWclose(rw);
- break;
- }
- return NULL;
- }
- }
- else {
- SDL_OutOfMemory();
- }
- return music;
- }
- /* Start playback of a given FLAC stream */
- void FLAC_play(FLAC_music *music)
- {
- music->playing = 1;
- }
- /* Return non-zero if a stream is currently playing */
- int FLAC_playing(FLAC_music *music)
- {
- return(music->playing);
- }
- /* Read some FLAC stream data and convert it for output */
- static void FLAC_getsome(FLAC_music *music)
- {
- int section;
- SDL_AudioCVT *cvt;
- /* GET AUDIO wAVE DATA */
- // set the max number of characters to read
- music->flac_data.max_to_read = 8192;
- // clear out the data buffer if it exists
- if (music->flac_data.data) {
- free (music->flac_data.data);
- }
- music->flac_data.data_len = music->flac_data.max_to_read;
- music->flac_data.data_read = 0;
- music->flac_data.data = (char *)malloc (music->flac_data.data_len);
- // we have data to read
- while(music->flac_data.max_to_read > 0) {
- // first check if there is data in the overflow from before
- if (music->flac_data.overflow) {
- size_t overflow_len = music->flac_data.overflow_read;
- if (overflow_len > music->flac_data.max_to_read) {
- size_t overflow_extra_len = overflow_len -
- music->flac_data.max_to_read;
- char* new_overflow = (char *)malloc (overflow_extra_len);
- memcpy (music->flac_data.data+music->flac_data.data_read,
- music->flac_data.overflow, music->flac_data.max_to_read);
- music->flac_data.data_read += music->flac_data.max_to_read;
- memcpy (new_overflow,
- music->flac_data.overflow + music->flac_data.max_to_read,
- overflow_extra_len);
- free (music->flac_data.overflow);
- music->flac_data.overflow = new_overflow;
- music->flac_data.overflow_len = overflow_extra_len;
- music->flac_data.overflow_read = 0;
- music->flac_data.max_to_read = 0;
- }
- else {
- memcpy (music->flac_data.data+music->flac_data.data_read,
- music->flac_data.overflow, overflow_len);
- music->flac_data.data_read += overflow_len;
- free (music->flac_data.overflow);
- music->flac_data.overflow = NULL;
- music->flac_data.overflow_len = 0;
- music->flac_data.overflow_read = 0;
- music->flac_data.max_to_read -= overflow_len;
- }
- }
- else {
- if (!flac.FLAC__stream_decoder_process_single (
- music->flac_decoder)) {
- music->flac_data.max_to_read = 0;
- }
- if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
- == FLAC__STREAM_DECODER_END_OF_STREAM) {
- music->flac_data.max_to_read = 0;
- }
- }
- }
- if (music->flac_data.data_read <= 0) {
- if (music->flac_data.data_read == 0) {
- music->playing = 0;
- }
- return;
- }
- cvt = &music->cvt;
- if (section != music->section) {
- SDL_BuildAudioCVT (cvt, AUDIO_S16, (Uint8)music->flac_data.channels,
- (int)music->flac_data.sample_rate, mixer.format,
- mixer.channels, mixer.freq);
- if (cvt->buf) {
- free (cvt->buf);
- }
- cvt->buf = (Uint8 *)malloc (music->flac_data.data_len * cvt->len_mult);
- music->section = section;
- }
- if (cvt->buf) {
- memcpy (cvt->buf, music->flac_data.data, music->flac_data.data_read);
- if (cvt->needed) {
- cvt->len = music->flac_data.data_read;
- SDL_ConvertAudio (cvt);
- }
- else {
- cvt->len_cvt = music->flac_data.data_read;
- }
- music->len_available = music->cvt.len_cvt;
- music->snd_available = music->cvt.buf;
- }
- else {
- SDL_SetError ("Out of memory");
- music->playing = 0;
- }
- }
- /* Play some of a stream previously started with FLAC_play() */
- int FLAC_playAudio(FLAC_music *music, Uint8 *snd, int len)
- {
- int mixable;
- while ((len > 0) && music->playing) {
- if (!music->len_available) {
- FLAC_getsome (music);
- }
- mixable = len;
- if (mixable > music->len_available) {
- mixable = music->len_available;
- }
- if (music->volume == MIX_MAX_VOLUME) {
- memcpy (snd, music->snd_available, mixable);
- }
- else {
- SDL_MixAudio (snd, music->snd_available, mixable, music->volume);
- }
- music->len_available -= mixable;
- music->snd_available += mixable;
- len -= mixable;
- snd += mixable;
- }
- return len;
- }
- /* Stop playback of a stream previously started with FLAC_play() */
- void FLAC_stop(FLAC_music *music)
- {
- music->playing = 0;
- }
- /* Close the given FLAC_music object */
- void FLAC_delete(FLAC_music *music)
- {
- if (music) {
- if (music->flac_decoder) {
- flac.FLAC__stream_decoder_finish (music->flac_decoder);
- flac.FLAC__stream_decoder_delete (music->flac_decoder);
- }
- if (music->flac_data.data) {
- free (music->flac_data.data);
- }
- if (music->flac_data.overflow) {
- free (music->flac_data.overflow);
- }
- if (music->cvt.buf) {
- free (music->cvt.buf);
- }
- free (music);
- }
- }
- /* Jump (seek) to a given position (time is in seconds) */
- void FLAC_jump_to_time(FLAC_music *music, double time)
- {
- if (music) {
- if (music->flac_decoder) {
- double seek_sample = music->flac_data.sample_rate * time;
- // clear data if it has data
- if (music->flac_data.data) {
- free (music->flac_data.data);
- music->flac_data.data = NULL;
- }
- // clear overflow if it has data
- if (music->flac_data.overflow) {
- free (music->flac_data.overflow);
- music->flac_data.overflow = NULL;
- }
- if (!flac.FLAC__stream_decoder_seek_absolute (music->flac_decoder,
- (FLAC__uint64)seek_sample)) {
- if (flac.FLAC__stream_decoder_get_state (music->flac_decoder)
- == FLAC__STREAM_DECODER_SEEK_ERROR) {
- flac.FLAC__stream_decoder_flush (music->flac_decoder);
- }
- SDL_SetError
- ("Seeking of FLAC stream failed: libFLAC seek failed.");
- }
- }
- else {
- SDL_SetError
- ("Seeking of FLAC stream failed: FLAC decoder was NULL.");
- }
- }
- else {
- SDL_SetError ("Seeking of FLAC stream failed: music was NULL.");
- }
- }
- #endif /* FLAC_MUSIC */