dynamic_flac.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Feb 2008 07:31:03 +0000
changeset 382 50501e45c57b
child 386 695494546b3c
permissions -rw-r--r--
Austen Dicken - Tue Feb 26 23:28:27 PST 2008

Ok, here is the patch I made for FLAC support.

I have tested it relatively thoroughly and currently the patch allows:
1. Pre-loading FLAC files and playing them via LoadWAV
2. The patch allows for FLAC support in the LoadMUS setting as well as:
* Pause / Resume
* Volume control
* Seeking

I also did a little benchmarking by comparing memory/cpu usage of playmus to
that of mplayer, and the results were very good. playmus typically took about
half the RAM as mplayer, though that may be attributed to mplayer being a more
"bulky" program. As such I would say that the two are probably about equal in
efficiency.

Also, it is important to note that, similar to the OGG support currently
built-in, my FLAC patch only supports 16 bit stereo-encoded sound. Also, it
is only for Native FLAC (standard) and not the derivative, Ogg-FLAC.

I have tried to find a simple way to detect Ogg-FLAC files, as the only
difference between Ogg-FLAC and Native FLAC support is changing the init_
function call, but after digging a little deeper it seems that Ogg-FLAC is
basically FLAC wrapped in an Ogg transport layer, so it would be better to have
a way to read the Ogg transport layer which then reads the inner audio files
according to the proper codec.

But anyway, that's another job for another day! For now this should provide
Native FLAC support!
slouken@382
     1
/*
slouken@382
     2
    SDL_mixer:  An audio mixer library based on the SDL library
slouken@382
     3
    Copyright (C) 1997-2004 Sam Lantinga
slouken@382
     4
slouken@382
     5
    This library is free software; you can redistribute it and/or
slouken@382
     6
    modify it under the terms of the GNU Library General Public
slouken@382
     7
    License as published by the Free Software Foundation; either
slouken@382
     8
    version 2 of the License, or (at your option) any later version.
slouken@382
     9
slouken@382
    10
    This library is distributed in the hope that it will be useful,
slouken@382
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@382
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@382
    13
    Library General Public License for more details.
slouken@382
    14
slouken@382
    15
    You should have received a copy of the GNU Library General Public
slouken@382
    16
    License along with this library; if not, write to the Free
slouken@382
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@382
    18
slouken@382
    19
    Sam Lantinga
slouken@382
    20
    slouken@libsdl.org
slouken@382
    21
slouken@382
    22
slouken@382
    23
    Implementation of the dynamic loading functionality for libFLAC.
slouken@382
    24
    									~ Austen Dicken (admin@cvpcs.org)
slouken@382
    25
*/
slouken@382
    26
slouken@382
    27
#ifdef FLAC_MUSIC
slouken@382
    28
slouken@382
    29
#include "SDL_loadso.h"
slouken@382
    30
slouken@382
    31
#include "dynamic_flac.h"
slouken@382
    32
slouken@382
    33
flac_loader flac = {
slouken@382
    34
	0, NULL
slouken@382
    35
};
slouken@382
    36
slouken@382
    37
#ifdef FLAC_DYNAMIC
slouken@382
    38
slouken@382
    39
int Mix_InitFLAC() {
slouken@382
    40
	if ( flac.loaded == 0 ) {
slouken@382
    41
		flac.handle = SDL_LoadObject(FLAC_DYNAMIC);
slouken@382
    42
		if ( flac.handle == NULL ) {
slouken@382
    43
			return -1;
slouken@382
    44
		}
slouken@382
    45
		flac.FLAC__stream_decoder_new =
slouken@382
    46
			(FLAC__StreamDecoder *(*)())
slouken@382
    47
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_new");
slouken@382
    48
		if ( flac.FLAC__stream_decoder_new == NULL ) {
slouken@382
    49
			SDL_UnloadObject(flac.handle);
slouken@382
    50
			return -1;
slouken@382
    51
		}
slouken@382
    52
		flac.FLAC__stream_decoder_delete =
slouken@382
    53
			(void (*)(FLAC__StreamDecoder *))
slouken@382
    54
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_delete");
slouken@382
    55
		if ( flac.FLAC__stream_decoder_delete == NULL ) {
slouken@382
    56
			SDL_UnloadObject(flac.handle);
slouken@382
    57
			return -1;
slouken@382
    58
		}
slouken@382
    59
		flac.FLAC__stream_decoder_init_stream =
slouken@382
    60
			(FLAC__StreamDecoderInitStatus (*)(
slouken@382
    61
						FLAC__StreamDecoder *,
slouken@382
    62
						FLAC__StreamDecoderReadCallback,
slouken@382
    63
						FLAC__StreamDecoderSeekCallback,
slouken@382
    64
						FLAC__StreamDecoderTellCallback,
slouken@382
    65
						FLAC__StreamDecoderLengthCallback,
slouken@382
    66
						FLAC__StreamDecoderEofCallback,
slouken@382
    67
						FLAC__StreamDecoderWriteCallback,
slouken@382
    68
						FLAC__StreamDecoderMetadataCallback,
slouken@382
    69
						FLAC__StreamDecoderErrorCallback,
slouken@382
    70
						void *))
slouken@382
    71
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_init_stream");
slouken@382
    72
		if ( flac.FLAC__stream_decoder_init_stream == NULL ) {
slouken@382
    73
			SDL_UnloadObject(flac.handle);
slouken@382
    74
			return -1;
slouken@382
    75
		}
slouken@382
    76
		flac.FLAC__stream_decoder_finish =
slouken@382
    77
			(FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@382
    78
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_finish");
slouken@382
    79
		if ( flac.FLAC__stream_decoder_finish == NULL ) {
slouken@382
    80
			SDL_UnloadObject(flac.handle);
slouken@382
    81
			return -1;
slouken@382
    82
		}
slouken@382
    83
		flac.FLAC__stream_decoder_flush =
slouken@382
    84
			(FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@382
    85
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_flush");
slouken@382
    86
		if ( flac.FLAC__stream_decoder_flush == NULL ) {
slouken@382
    87
			SDL_UnloadObject(flac.handle);
slouken@382
    88
			return -1;
slouken@382
    89
		}
slouken@382
    90
		flac.FLAC__stream_decoder_process_single =
slouken@382
    91
			(FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@382
    92
			SDL_LoadFunction(flac.handle,
slouken@382
    93
						"FLAC__stream_decoder_process_single");
slouken@382
    94
		if ( flac.FLAC__stream_decoder_process_single == NULL ) {
slouken@382
    95
			SDL_UnloadObject(flac.handle);
slouken@382
    96
			return -1;
slouken@382
    97
		}
slouken@382
    98
		flac.FLAC__stream_decoder_process_until_end_of_metadata =
slouken@382
    99
			(FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@382
   100
			SDL_LoadFunction(flac.handle,
slouken@382
   101
						"FLAC__stream_decoder_process_until_end_of_metadata");
slouken@382
   102
		if ( flac.FLAC__stream_decoder_process_until_end_of_metadata == NULL ) {
slouken@382
   103
			SDL_UnloadObject(flac.handle);
slouken@382
   104
			return -1;
slouken@382
   105
		}
slouken@382
   106
		flac.FLAC__stream_decoder_process_until_end_of_stream =
slouken@382
   107
			(FLAC__bool (*)(FLAC__StreamDecoder *))
slouken@382
   108
			SDL_LoadFunction(flac.handle,
slouken@382
   109
						"FLAC__stream_decoder_process_until_end_of_stream");
slouken@382
   110
		if ( flac.FLAC__stream_decoder_process_until_end_of_stream == NULL ) {
slouken@382
   111
			SDL_UnloadObject(flac.handle);
slouken@382
   112
			return -1;
slouken@382
   113
		}
slouken@382
   114
		flac.FLAC__stream_decoder_seek_absolute =
slouken@382
   115
			(FLAC__bool (*)(FLAC__StreamDecoder *, FLAC__uint64))
slouken@382
   116
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_seek_absolute");
slouken@382
   117
		if ( flac.FLAC__stream_decoder_seek_absolute == NULL ) {
slouken@382
   118
			SDL_UnloadObject(flac.handle);
slouken@382
   119
			return -1;
slouken@382
   120
		}
slouken@382
   121
		flac.FLAC__stream_decoder_get_state =
slouken@382
   122
			(FLAC__StreamDecoderState (*)(const FLAC__StreamDecoder *decoder))
slouken@382
   123
			SDL_LoadFunction(flac.handle, "FLAC__stream_decoder_get_state");
slouken@382
   124
		if ( flac.FLAC__stream_decoder_get_state == NULL ) {
slouken@382
   125
			SDL_UnloadObject(flac.handle);
slouken@382
   126
			return -1;
slouken@382
   127
		}
slouken@382
   128
	}
slouken@382
   129
	++flac.loaded;
slouken@382
   130
slouken@382
   131
	return 0;
slouken@382
   132
}
slouken@382
   133
void Mix_QuitFLAC() {
slouken@382
   134
	if ( flac.loaded == 0 ) {
slouken@382
   135
		return;
slouken@382
   136
	}
slouken@382
   137
	if ( flac.loaded == 1 ) {
slouken@382
   138
		SDL_UnloadObject(flac.handle);
slouken@382
   139
	}
slouken@382
   140
	--flac.loaded;
slouken@382
   141
}
slouken@382
   142
#else
slouken@382
   143
int Mix_InitFLAC() {
slouken@382
   144
	if ( flac.loaded == 0 ) {
slouken@382
   145
		flac.FLAC__stream_decoder_new = FLAC__stream_decoder_new;
slouken@382
   146
		flac.FLAC__stream_decoder_delete = FLAC__stream_decoder_delete;
slouken@382
   147
		flac.FLAC__stream_decoder_init_stream =
slouken@382
   148
							FLAC__stream_decoder_init_stream;
slouken@382
   149
		flac.FLAC__stream_decoder_finish = FLAC__stream_decoder_finish;
slouken@382
   150
		flac.FLAC__stream_decoder_flush = FLAC__stream_decoder_flush;
slouken@382
   151
		flac.FLAC__stream_decoder_process_single =
slouken@382
   152
							FLAC__stream_decoder_process_single;
slouken@382
   153
		flac.FLAC__stream_decoder_process_until_end_of_metadata =
slouken@382
   154
							FLAC__stream_decoder_process_until_end_of_metadata;
slouken@382
   155
		flac.FLAC__stream_decoder_process_until_end_of_stream =
slouken@382
   156
							FLAC__stream_decoder_process_until_end_of_stream;
slouken@382
   157
		flac.FLAC__stream_decoder_seek_absolute =
slouken@382
   158
							FLAC__stream_decoder_seek_absolute;
slouken@382
   159
		flac.FLAC__stream_decoder_get_state =
slouken@382
   160
							FLAC__stream_decoder_get_state;
slouken@382
   161
	}
slouken@382
   162
	++flac.loaded;
slouken@382
   163
slouken@382
   164
	return 0;
slouken@382
   165
}
slouken@382
   166
void Mix_QuitFLAC() {
slouken@382
   167
	if ( flac.loaded == 0 ) {
slouken@382
   168
		return;
slouken@382
   169
	}
slouken@382
   170
	if ( flac.loaded == 1 ) {
slouken@382
   171
	}
slouken@382
   172
	--flac.loaded;
slouken@382
   173
}
slouken@382
   174
#endif // FLAC_DYNAMIC
slouken@382
   175
slouken@382
   176
#endif // FLAC_MUSIC