2001-03-01 00:47:15 +00:00
/* in_flac - Winamp2 FLAC input plugin
2003-01-02 07:03:16 +00:00
* Copyright ( C ) 2000 , 2001 , 2002 , 2003 Josh Coalson
2000-12-10 04:09:52 +00:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program 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 General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <windows.h>
# include <mmreg.h>
# include <msacm.h>
# include <math.h>
2002-06-05 06:10:55 +00:00
# include <stdio.h>
2000-12-10 04:09:52 +00:00
2003-01-08 07:59:48 +00:00
# include "winamp2/in2.h"
2000-12-10 04:09:52 +00:00
# include "FLAC/all.h"
2002-08-23 06:43:04 +00:00
# include "plugin_common/all.h"
2003-01-08 07:59:48 +00:00
# include "share/grabbag.h"
# include "config.h"
2003-01-14 09:01:31 +00:00
# include "infobox.h"
# include "tagz.h"
2000-12-10 04:09:52 +00:00
2002-08-22 07:26:53 +00:00
2000-12-10 04:09:52 +00:00
typedef struct {
2001-06-23 03:03:24 +00:00
FLAC__bool abort_flag ;
2003-01-14 09:01:31 +00:00
int seek_to ;
int paused ;
2000-12-10 04:09:52 +00:00
unsigned total_samples ;
unsigned bits_per_sample ;
2003-01-08 07:59:48 +00:00
unsigned output_bits_per_sample ;
2000-12-10 04:09:52 +00:00
unsigned channels ;
unsigned sample_rate ;
2002-08-27 06:02:09 +00:00
unsigned length_in_msec ;
2003-01-08 07:59:48 +00:00
FLAC__bool has_replaygain ;
double replay_scale ;
2003-01-14 09:01:31 +00:00
DitherContext dither_context ;
2002-06-07 05:27:37 +00:00
} file_info_struct ;
2003-01-08 07:59:48 +00:00
2002-06-07 05:27:37 +00:00
static FLAC__bool safe_decoder_init_ ( const char * infilename , FLAC__FileDecoder * decoder ) ;
static void safe_decoder_finish_ ( FLAC__FileDecoder * decoder ) ;
static void safe_decoder_delete_ ( FLAC__FileDecoder * decoder ) ;
2002-06-10 18:25:43 +00:00
static FLAC__StreamDecoderWriteStatus write_callback_ ( const FLAC__FileDecoder * decoder , const FLAC__Frame * frame , const FLAC__int32 * const buffer [ ] , void * client_data ) ;
2002-06-08 04:53:42 +00:00
static void metadata_callback_ ( const FLAC__FileDecoder * decoder , const FLAC__StreamMetadata * metadata , void * client_data ) ;
2002-06-07 05:27:37 +00:00
static void error_callback_ ( const FLAC__FileDecoder * decoder , FLAC__StreamDecoderErrorStatus status , void * client_data ) ;
2002-09-04 07:57:56 +00:00
static void get_description_ ( const char * filename , char * description , unsigned max_size ) ;
2000-12-10 04:09:52 +00:00
2003-01-08 07:59:48 +00:00
char ini_name [ MAX_PATH ] ;
flac_config_t flac_cfg ;
2003-01-14 09:01:31 +00:00
static output_config_t cfg ; /* local copy */
2003-01-08 07:59:48 +00:00
2003-01-14 09:01:31 +00:00
static In_Module mod_ ; /* the input module (declared near the bottom of this file) */
2003-01-08 07:59:48 +00:00
static char lastfn_ [ MAX_PATH ] ; /* currently playing file (used for getting info on the current file) */
static int decode_pos_ms_ ; /* current decoding position, in milliseconds */
2002-08-27 06:02:09 +00:00
# define SAMPLES_PER_WRITE 576
2003-01-08 07:59:48 +00:00
static FLAC__int32 reservoir_ [ FLAC__MAX_BLOCK_SIZE * 2 /*for overflow*/ * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS ] ;
static char sample_buffer_ [ SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * ( 24 / 8 ) * 2 ] ; /* (24/8) for max bytes per sample, and 2 for who knows what */
static unsigned wide_samples_in_reservoir_ ;
2002-06-07 05:27:37 +00:00
static file_info_struct file_info_ ;
static FLAC__FileDecoder * decoder_ ;
2000-12-10 04:09:52 +00:00
2003-01-08 07:59:48 +00:00
static volatile int killDecodeThread = 0 ; /* the kill switch for the decode thread */
2003-01-14 09:01:31 +00:00
static HANDLE thread_handle = NULL ; /* the handle to the decode thread */
2002-07-11 06:17:48 +00:00
2003-01-08 07:59:48 +00:00
static DWORD WINAPI DecodeThread ( void * b ) ; /* the decode thread procedure */
2002-07-11 06:17:48 +00:00
2003-01-14 09:01:31 +00:00
static void show_error ( const char * message , . . . )
{
char foo [ 512 ] ;
va_list args ;
va_start ( args , message ) ;
vsprintf ( foo , message , args ) ;
va_end ( args ) ;
MessageBox ( mod_ . hMainWindow , foo , " FLAC Plug-in Error " , MB_ICONSTOP ) ;
}
2000-12-10 04:09:52 +00:00
void config ( HWND hwndParent )
{
2003-01-14 09:01:31 +00:00
if ( DoConfig ( mod_ . hDllInstance , hwndParent ) )
2003-01-08 07:59:48 +00:00
WriteConfig ( ) ;
2000-12-10 04:09:52 +00:00
}
2003-01-08 07:59:48 +00:00
2000-12-10 04:09:52 +00:00
void about ( HWND hwndParent )
{
2002-09-25 06:09:47 +00:00
MessageBox ( hwndParent , " Winamp FLAC Plugin v " VERSION " , by Josh Coalson \n See http://flac.sourceforge.net/ " , " About FLAC Plugin " , MB_OK ) ;
2000-12-10 04:09:52 +00:00
}
void init ( )
{
2003-01-08 07:59:48 +00:00
char * p ;
2002-06-07 05:27:37 +00:00
decoder_ = FLAC__file_decoder_new ( ) ;
strcpy ( lastfn_ , " " ) ;
2003-01-14 09:01:31 +00:00
/* read config */
2003-01-08 07:59:48 +00:00
GetModuleFileName ( NULL , ini_name , sizeof ( ini_name ) ) ;
p = strrchr ( ini_name , ' . ' ) ;
if ( ! p ) p = ini_name + strlen ( ini_name ) ;
strcpy ( p , " .ini " ) ;
ReadConfig ( ) ;
2000-12-10 04:09:52 +00:00
}
void quit ( )
{
2003-01-08 07:59:48 +00:00
WriteConfig ( ) ;
2002-06-07 05:27:37 +00:00
safe_decoder_delete_ ( decoder_ ) ;
decoder_ = 0 ;
2000-12-10 04:09:52 +00:00
}
int isourfile ( char * fn ) { return 0 ; }
2003-01-14 09:01:31 +00:00
2000-12-10 04:09:52 +00:00
int play ( char * fn )
{
int maxlatency ;
int thread_id ;
2003-01-08 07:59:48 +00:00
HANDLE input_file ;
2003-01-14 09:01:31 +00:00
DWORD file_size ; /*@@@ fixme 64-bit */
2000-12-10 04:09:52 +00:00
2003-01-14 09:01:31 +00:00
if ( decoder_ = = 0 )
2000-12-10 04:09:52 +00:00
return 1 ;
2001-06-29 02:51:01 +00:00
input_file = CreateFile ( fn , GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL ) ;
2003-01-08 07:59:48 +00:00
if ( input_file = = INVALID_HANDLE_VALUE )
2002-02-17 22:23:56 +00:00
return - 1 ;
2003-01-14 09:01:31 +00:00
file_size = GetFileSize ( input_file , NULL ) ;
2000-12-10 04:09:52 +00:00
CloseHandle ( input_file ) ;
2003-01-08 07:59:48 +00:00
file_info_ . abort_flag = false ;
file_info_ . has_replaygain = false ;
2003-01-14 09:01:31 +00:00
if ( ! safe_decoder_init_ ( fn , decoder_ ) )
2000-12-10 04:09:52 +00:00
return 1 ;
2002-09-05 06:58:31 +00:00
2003-01-14 09:01:31 +00:00
cfg = flac_cfg . output ;
2002-06-07 05:27:37 +00:00
strcpy ( lastfn_ , fn ) ;
2002-07-11 06:17:48 +00:00
wide_samples_in_reservoir_ = 0 ;
2003-01-14 09:01:31 +00:00
file_info_ . output_bits_per_sample = file_info_ . has_replaygain & & cfg . replaygain . enable ?
cfg . resolution . replaygain . bps_out :
cfg . resolution . normal . dither_24_to_16 ? min ( file_info_ . bits_per_sample , 16 ) : file_info_ . bits_per_sample ;
2003-01-08 07:59:48 +00:00
2003-01-14 09:01:31 +00:00
if ( file_info_ . has_replaygain & & cfg . replaygain . enable & & cfg . resolution . replaygain . dither )
FLAC__plugin_common__init_dither_context ( & file_info_ . dither_context , file_info_ . bits_per_sample , cfg . resolution . replaygain . noise_shaping ) ;
2000-12-10 04:09:52 +00:00
2003-01-08 07:59:48 +00:00
maxlatency = mod_ . outMod - > Open ( file_info_ . sample_rate , file_info_ . channels , file_info_ . output_bits_per_sample , - 1 , - 1 ) ;
2003-01-14 09:01:31 +00:00
if ( maxlatency < 0 ) /* error opening device */
2000-12-10 04:09:52 +00:00
return 1 ;
/* dividing by 1000 for the first parameter of setinfo makes it */
/* display 'H'... for hundred.. i.e. 14H Kbps. */
2003-01-14 09:01:31 +00:00
mod_ . SetInfo ( ( int ) ( file_size / ( 125. * file_info_ . total_samples / file_info_ . sample_rate ) ) , file_info_ . sample_rate / 1000 , file_info_ . channels , 1 ) ;
2000-12-10 04:09:52 +00:00
/* initialize vis stuff */
2002-06-07 05:27:37 +00:00
mod_ . SAVSAInit ( maxlatency , file_info_ . sample_rate ) ;
mod_ . VSASetInfo ( file_info_ . sample_rate , file_info_ . channels ) ;
2003-01-08 07:59:48 +00:00
/* set the output plug-ins default volume */
mod_ . outMod - > SetVolume ( - 666 ) ;
2000-12-10 04:09:52 +00:00
2003-01-14 09:01:31 +00:00
file_info_ . paused = 0 ;
file_info_ . seek_to = - 1 ;
2003-01-08 07:59:48 +00:00
decode_pos_ms_ = 0 ;
2001-06-29 02:51:01 +00:00
killDecodeThread = 0 ;
2003-01-14 09:01:31 +00:00
thread_handle = CreateThread ( NULL , 0 , DecodeThread , NULL , 0 , & thread_id ) ;
if ( ! thread_handle )
return 1 ;
2000-12-10 04:09:52 +00:00
return 0 ;
}
void pause ( )
{
2003-01-14 09:01:31 +00:00
file_info_ . paused = 1 ;
2002-06-07 05:27:37 +00:00
mod_ . outMod - > Pause ( 1 ) ;
2000-12-10 04:09:52 +00:00
}
void unpause ( )
{
2003-01-14 09:01:31 +00:00
file_info_ . paused = 0 ;
2002-06-07 05:27:37 +00:00
mod_ . outMod - > Pause ( 0 ) ;
2000-12-10 04:09:52 +00:00
}
2002-09-25 06:09:47 +00:00
2000-12-10 04:09:52 +00:00
int ispaused ( )
{
2003-01-14 09:01:31 +00:00
return file_info_ . paused ;
2000-12-10 04:09:52 +00:00
}
void stop ( )
{
2003-01-14 09:01:31 +00:00
if ( thread_handle ) {
2001-06-29 02:51:01 +00:00
killDecodeThread = 1 ;
2003-01-08 07:59:48 +00:00
if ( WaitForSingleObject ( thread_handle , 2000 ) = = WAIT_TIMEOUT ) {
2003-01-14 09:01:31 +00:00
show_error ( " Error while stopping decoding thread. " ) ;
2001-06-29 02:51:01 +00:00
TerminateThread ( thread_handle , 0 ) ;
2000-12-10 04:09:52 +00:00
}
CloseHandle ( thread_handle ) ;
2003-01-14 09:01:31 +00:00
thread_handle = NULL ;
2000-12-10 04:09:52 +00:00
}
2002-06-07 05:27:37 +00:00
safe_decoder_finish_ ( decoder_ ) ;
2000-12-10 04:09:52 +00:00
2002-06-07 05:27:37 +00:00
mod_ . outMod - > Close ( ) ;
2000-12-10 04:09:52 +00:00
2002-06-07 05:27:37 +00:00
mod_ . SAVSADeInit ( ) ;
2000-12-10 04:09:52 +00:00
}
int getlength ( )
{
2002-08-27 06:02:09 +00:00
return ( int ) file_info_ . length_in_msec ;
2000-12-10 04:09:52 +00:00
}
int getoutputtime ( )
{
2002-06-07 05:27:37 +00:00
return decode_pos_ms_ + ( mod_ . outMod - > GetOutputTime ( ) - mod_ . outMod - > GetWrittenTime ( ) ) ;
2000-12-10 04:09:52 +00:00
}
void setoutputtime ( int time_in_ms )
{
2003-01-14 09:01:31 +00:00
file_info_ . seek_to = time_in_ms ;
2000-12-10 04:09:52 +00:00
}
2002-06-07 05:27:37 +00:00
void setvolume ( int volume ) { mod_ . outMod - > SetVolume ( volume ) ; }
void setpan ( int pan ) { mod_ . outMod - > SetPan ( pan ) ; }
2000-12-10 04:09:52 +00:00
int infoDlg ( char * fn , HWND hwnd )
{
2003-01-14 09:01:31 +00:00
DoInfoBox ( mod_ . hDllInstance , hwnd , fn ) ;
2000-12-10 04:09:52 +00:00
return 0 ;
}
2002-06-11 06:15:28 +00:00
void getfileinfo ( char * filename , char * title , int * length_in_msec )
2000-12-10 04:09:52 +00:00
{
2002-06-10 04:42:35 +00:00
FLAC__StreamMetadata streaminfo ;
2002-06-05 06:10:55 +00:00
2003-01-08 07:59:48 +00:00
if ( ! filename | | ! * filename ) {
2002-06-07 05:27:37 +00:00
filename = lastfn_ ;
2003-01-14 09:01:31 +00:00
if ( length_in_msec ) {
2002-06-11 06:15:28 +00:00
* length_in_msec = getlength ( ) ;
length_in_msec = 0 ; /* force skip in following code */
2000-12-10 04:09:52 +00:00
}
}
2002-06-05 06:10:55 +00:00
2003-01-14 09:01:31 +00:00
if ( ! FLAC__metadata_get_streaminfo ( filename , & streaminfo ) ) {
if ( title )
sprintf ( title , " Invalid FLAC: %s " , filename ) ;
if ( length_in_msec )
2002-06-07 05:27:37 +00:00
* length_in_msec = - 1 ;
return ;
2002-06-05 06:10:55 +00:00
}
2002-06-07 05:27:37 +00:00
2003-01-14 09:01:31 +00:00
if ( title )
get_description_ ( filename , title , 400 ) ;
if ( length_in_msec )
2002-06-11 06:15:28 +00:00
* length_in_msec = ( int ) ( streaminfo . data . stream_info . total_samples * 10 / ( streaminfo . data . stream_info . sample_rate / 100 ) ) ;
2000-12-10 04:09:52 +00:00
}
2003-01-08 07:59:48 +00:00
void eq_set ( int on , char data [ 10 ] , int preamp ) { }
static void do_vis ( char * data , int nch , int resolution , int position , unsigned samples )
2000-12-10 04:09:52 +00:00
{
2003-01-08 07:59:48 +00:00
static char vis_buffer [ SAMPLES_PER_WRITE * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS ] ;
char * ptr ;
int size , count ;
/*
* Winamp visuals may have problems accepting sample sizes larger than
* 16 bits , so we reduce the sample size here if necessary .
*/
switch ( resolution ) {
case 32 :
case 24 :
size = resolution / 8 ;
count = samples * nch ;
data + = size - 1 ;
ptr = vis_buffer ;
while ( count - - ) {
* ptr + + = data [ 0 ] ^ 0x80 ;
data + = size ;
}
data = vis_buffer ;
resolution = 8 ;
/* fall through */
case 16 :
case 8 :
default :
mod_ . SAAddPCMData ( data , nch , resolution , position ) ;
mod_ . VSAAddPCMData ( data , nch , resolution , position ) ;
}
2000-12-10 04:09:52 +00:00
}
2003-01-08 07:59:48 +00:00
static DWORD WINAPI DecodeThread ( void * unused )
2000-12-10 04:09:52 +00:00
{
2001-06-29 02:51:01 +00:00
int done = 0 ;
2000-12-10 04:09:52 +00:00
2003-01-08 07:59:48 +00:00
( void ) unused ;
while ( ! killDecodeThread ) {
2002-08-27 06:02:09 +00:00
const unsigned channels = file_info_ . channels ;
const unsigned bits_per_sample = file_info_ . bits_per_sample ;
2003-01-08 07:59:48 +00:00
const unsigned target_bps = file_info_ . output_bits_per_sample ;
2002-08-27 06:02:09 +00:00
const unsigned sample_rate = file_info_ . sample_rate ;
2003-01-08 07:59:48 +00:00
2003-01-14 09:01:31 +00:00
if ( file_info_ . seek_to ! = - 1 ) {
const double distance = ( double ) file_info_ . seek_to / ( double ) getlength ( ) ;
2002-08-27 06:02:09 +00:00
const unsigned target_sample = ( unsigned ) ( distance * ( double ) file_info_ . total_samples ) ;
2002-06-07 05:27:37 +00:00
if ( FLAC__file_decoder_seek_absolute ( decoder_ , ( FLAC__uint64 ) target_sample ) ) {
decode_pos_ms_ = ( int ) ( distance * ( double ) getlength ( ) ) ;
2003-01-14 09:01:31 +00:00
file_info_ . seek_to = - 1 ;
2001-06-29 02:51:01 +00:00
done = 0 ;
2002-06-07 05:27:37 +00:00
mod_ . outMod - > Flush ( decode_pos_ms_ ) ;
2000-12-10 04:09:52 +00:00
}
}
2002-07-11 06:17:48 +00:00
if ( done ) {
if ( ! mod_ . outMod - > IsPlaying ( ) ) {
2002-06-07 05:27:37 +00:00
PostMessage ( mod_ . hMainWindow , WM_WA_MPEG_EOF , 0 , 0 ) ;
2000-12-10 04:09:52 +00:00
return 0 ;
}
Sleep ( 10 ) ;
}
2002-08-27 06:02:09 +00:00
else if ( mod_ . outMod - > CanWrite ( ) > = ( ( int ) ( SAMPLES_PER_WRITE * channels * ( ( target_bps + 7 ) / 8 ) ) < < ( mod_ . dsp_isactive ( ) ? 1 : 0 ) ) ) {
while ( wide_samples_in_reservoir_ < SAMPLES_PER_WRITE ) {
2002-06-07 05:27:37 +00:00
if ( FLAC__file_decoder_get_state ( decoder_ ) = = FLAC__FILE_DECODER_END_OF_FILE ) {
2000-12-10 04:09:52 +00:00
done = 1 ;
break ;
}
2002-08-12 07:19:59 +00:00
else if ( ! FLAC__file_decoder_process_single ( decoder_ ) ) {
2003-01-14 09:01:31 +00:00
show_error ( " Error while processing frame (%s). " , FLAC__FileDecoderStateString [ FLAC__file_decoder_get_state ( decoder_ ) ] ) ;
2002-06-18 16:08:36 +00:00
done = 1 ;
2000-12-10 04:09:52 +00:00
break ;
2002-06-18 16:08:36 +00:00
}
2000-12-10 04:09:52 +00:00
}
2002-07-11 06:17:48 +00:00
if ( wide_samples_in_reservoir_ = = 0 ) {
2001-06-29 02:51:01 +00:00
done = 1 ;
2000-12-10 04:09:52 +00:00
}
else {
2002-08-27 06:02:09 +00:00
const unsigned n = min ( wide_samples_in_reservoir_ , SAMPLES_PER_WRITE ) ;
2002-07-11 06:17:48 +00:00
const unsigned delta = n * channels ;
2003-01-08 07:59:48 +00:00
int bytes ;
2002-07-11 06:17:48 +00:00
unsigned i ;
2003-01-14 09:01:31 +00:00
if ( cfg . replaygain . enable & & file_info_ . has_replaygain ) {
2003-01-08 07:59:48 +00:00
bytes = ( int ) FLAC__plugin_common__apply_gain (
sample_buffer_ ,
2003-09-15 20:28:08 +00:00
true , /* little_endian_data_out */
2003-01-08 07:59:48 +00:00
reservoir_ ,
n ,
channels ,
bits_per_sample ,
target_bps ,
( float ) file_info_ . replay_scale ,
2003-01-14 09:01:31 +00:00
cfg . replaygain . hard_limit ,
cfg . resolution . replaygain . dither ,
( NoiseShaping ) cfg . resolution . replaygain . noise_shaping ,
2003-01-08 07:59:48 +00:00
& file_info_ . dither_context
) ;
}
else {
bytes = ( int ) FLAC__plugin_common__pack_pcm_signed_little_endian (
sample_buffer_ ,
reservoir_ ,
n ,
channels ,
bits_per_sample ,
target_bps
) ;
}
2002-07-11 06:17:48 +00:00
for ( i = delta ; i < wide_samples_in_reservoir_ * channels ; i + + )
2002-06-07 05:27:37 +00:00
reservoir_ [ i - delta ] = reservoir_ [ i ] ;
2002-07-11 06:17:48 +00:00
wide_samples_in_reservoir_ - = n ;
2002-06-07 05:27:37 +00:00
2003-01-08 07:59:48 +00:00
do_vis ( sample_buffer_ , channels , target_bps , decode_pos_ms_ , n ) ;
2002-06-07 05:27:37 +00:00
decode_pos_ms_ + = ( n * 1000 + sample_rate / 2 ) / sample_rate ;
2002-07-11 06:17:48 +00:00
if ( mod_ . dsp_isactive ( ) )
bytes = mod_ . dsp_dosamples ( ( short * ) sample_buffer_ , n , target_bps , channels , sample_rate ) * ( channels * target_bps / 8 ) ;
2002-06-07 05:27:37 +00:00
mod_ . outMod - > Write ( sample_buffer_ , bytes ) ;
2000-12-10 04:09:52 +00:00
}
}
else Sleep ( 20 ) ;
}
return 0 ;
}
2002-06-07 05:27:37 +00:00
In_Module mod_ =
2000-12-10 04:09:52 +00:00
{
IN_VER ,
2003-01-14 09:01:31 +00:00
" FLAC Reference Player v " VERSION ,
2000-12-10 04:09:52 +00:00
0 , /* hMainWindow */
0 , /* hDllInstance */
" FLAC \0 FLAC Audio File (*.FLAC) \0 "
,
1 , /* is_seekable */
1 , /* uses output */
config ,
about ,
init ,
quit ,
getfileinfo ,
infoDlg ,
isourfile ,
play ,
pause ,
unpause ,
ispaused ,
stop ,
getlength ,
getoutputtime ,
setoutputtime ,
setvolume ,
setpan ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* vis stuff */
0 , 0 , /* dsp */
eq_set ,
NULL , /* setinfo */
0 /* out_mod */
} ;
2003-01-14 09:01:31 +00:00
__declspec ( dllexport ) In_Module * winampGetInModule2 ( )
2000-12-10 04:09:52 +00:00
{
2002-06-07 05:27:37 +00:00
return & mod_ ;
2000-12-10 04:09:52 +00:00
}
2003-01-14 09:01:31 +00:00
BOOL WINAPI _DllMainCRTStartup ( HANDLE hInst , ULONG ul_reason_for_call , LPVOID lpReserved )
{
return TRUE ;
}
2000-12-10 04:09:52 +00:00
/***********************************************************************
* local routines
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-06-07 05:27:37 +00:00
FLAC__bool safe_decoder_init_ ( const char * filename , FLAC__FileDecoder * decoder )
2000-12-10 04:09:52 +00:00
{
2003-01-14 09:01:31 +00:00
FLAC__ASSERT ( 0 ! = decoder ) ;
2002-06-07 05:27:37 +00:00
safe_decoder_finish_ ( decoder ) ;
2001-06-16 07:32:25 +00:00
FLAC__file_decoder_set_md5_checking ( decoder , false ) ;
2002-06-07 05:27:37 +00:00
FLAC__file_decoder_set_filename ( decoder , filename ) ;
2003-01-08 07:59:48 +00:00
FLAC__file_decoder_set_metadata_ignore_all ( decoder ) ;
FLAC__file_decoder_set_metadata_respond ( decoder , FLAC__METADATA_TYPE_STREAMINFO ) ;
FLAC__file_decoder_set_metadata_respond ( decoder , FLAC__METADATA_TYPE_VORBIS_COMMENT ) ;
2002-06-07 05:27:37 +00:00
FLAC__file_decoder_set_metadata_callback ( decoder , metadata_callback_ ) ;
2003-01-08 07:59:48 +00:00
FLAC__file_decoder_set_write_callback ( decoder , write_callback_ ) ;
2002-06-07 05:27:37 +00:00
FLAC__file_decoder_set_error_callback ( decoder , error_callback_ ) ;
FLAC__file_decoder_set_client_data ( decoder , & file_info_ ) ;
2003-01-14 09:01:31 +00:00
2001-06-16 07:32:25 +00:00
if ( FLAC__file_decoder_init ( decoder ) ! = FLAC__FILE_DECODER_OK ) {
2003-01-14 09:01:31 +00:00
show_error ( " Error while initializing decoder (%s). " , FLAC__FileDecoderStateString [ FLAC__file_decoder_get_state ( decoder ) ] ) ;
2000-12-10 04:09:52 +00:00
return false ;
}
2002-08-12 07:19:59 +00:00
if ( ! FLAC__file_decoder_process_until_end_of_metadata ( decoder ) ) {
2003-01-14 09:01:31 +00:00
show_error ( " Error while processing metadata (%s). " , FLAC__FileDecoderStateString [ FLAC__file_decoder_get_state ( decoder ) ] ) ;
2000-12-10 04:09:52 +00:00
return false ;
}
2003-01-14 09:01:31 +00:00
if ( file_info_ . abort_flag )
return false ; /* metadata callback already popped up the error dialog */
2002-08-22 07:26:53 +00:00
2000-12-10 04:09:52 +00:00
return true ;
}
2002-06-07 05:27:37 +00:00
void safe_decoder_finish_ ( FLAC__FileDecoder * decoder )
{
if ( decoder & & FLAC__file_decoder_get_state ( decoder ) ! = FLAC__FILE_DECODER_UNINITIALIZED )
FLAC__file_decoder_finish ( decoder ) ;
}
void safe_decoder_delete_ ( FLAC__FileDecoder * decoder )
{
if ( decoder ) {
safe_decoder_finish_ ( decoder ) ;
FLAC__file_decoder_delete ( decoder ) ;
}
}
2002-06-10 18:25:43 +00:00
FLAC__StreamDecoderWriteStatus write_callback_ ( const FLAC__FileDecoder * decoder , const FLAC__Frame * frame , const FLAC__int32 * const buffer [ ] , void * client_data )
2000-12-10 04:09:52 +00:00
{
2002-08-27 06:02:09 +00:00
file_info_struct * file_info = ( file_info_struct * ) client_data ;
const unsigned channels = file_info - > channels , wide_samples = frame - > header . blocksize ;
2002-07-11 06:17:48 +00:00
unsigned wide_sample , offset_sample , channel ;
2000-12-10 04:09:52 +00:00
( void ) decoder ;
2002-08-27 06:02:09 +00:00
if ( file_info - > abort_flag )
2002-06-04 05:44:32 +00:00
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT ;
2000-12-10 04:09:52 +00:00
2002-07-11 06:17:48 +00:00
for ( offset_sample = wide_samples_in_reservoir_ * channels , wide_sample = 0 ; wide_sample < wide_samples ; wide_sample + + )
for ( channel = 0 ; channel < channels ; channel + + , offset_sample + + )
reservoir_ [ offset_sample ] = buffer [ channel ] [ wide_sample ] ;
2000-12-10 04:09:52 +00:00
2002-07-11 06:17:48 +00:00
wide_samples_in_reservoir_ + = wide_samples ;
2000-12-10 04:09:52 +00:00
2002-06-04 05:44:32 +00:00
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE ;
2000-12-10 04:09:52 +00:00
}
2002-06-08 04:53:42 +00:00
void metadata_callback_ ( const FLAC__FileDecoder * decoder , const FLAC__StreamMetadata * metadata , void * client_data )
2000-12-10 04:09:52 +00:00
{
2002-08-27 06:02:09 +00:00
file_info_struct * file_info = ( file_info_struct * ) client_data ;
2000-12-10 04:09:52 +00:00
( void ) decoder ;
2003-01-08 07:59:48 +00:00
2001-03-05 18:36:59 +00:00
if ( metadata - > type = = FLAC__METADATA_TYPE_STREAMINFO ) {
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( metadata - > data . stream_info . total_samples < 0x100000000 ) ; /* this plugin can only handle < 4 gigasamples */
2003-01-14 09:01:31 +00:00
file_info - > total_samples = ( unsigned ) ( metadata - > data . stream_info . total_samples & 0xfffffffful ) ;
2002-08-27 06:02:09 +00:00
file_info - > bits_per_sample = metadata - > data . stream_info . bits_per_sample ;
file_info - > channels = metadata - > data . stream_info . channels ;
file_info - > sample_rate = metadata - > data . stream_info . sample_rate ;
2002-06-07 05:27:37 +00:00
2003-01-14 09:01:31 +00:00
if ( file_info - > bits_per_sample ! = 8 & & file_info - > bits_per_sample ! = 16 & & file_info - > bits_per_sample ! = 24 ) {
show_error ( " This plugin can only handle 8/16/24-bit samples. " ) ;
2002-08-27 06:02:09 +00:00
file_info - > abort_flag = true ;
2002-08-22 07:26:53 +00:00
return ;
}
2002-08-27 06:02:09 +00:00
file_info - > length_in_msec = file_info - > total_samples * 10 / ( file_info - > sample_rate / 100 ) ;
2000-12-10 04:09:52 +00:00
}
2003-01-08 07:59:48 +00:00
else if ( metadata - > type = = FLAC__METADATA_TYPE_VORBIS_COMMENT ) {
double gain , peak ;
2003-01-14 09:01:31 +00:00
if ( grabbag__replaygain_load_from_vorbiscomment ( metadata , cfg . replaygain . album_mode , & gain , & peak ) ) {
2003-01-08 07:59:48 +00:00
file_info_ . has_replaygain = true ;
2003-01-14 09:01:31 +00:00
file_info_ . replay_scale = grabbag__replaygain_compute_scale_factor ( peak , gain , ( double ) cfg . replaygain . preamp , ! cfg . replaygain . hard_limit ) ;
2003-01-08 07:59:48 +00:00
}
}
2000-12-10 04:09:52 +00:00
}
2002-06-07 05:27:37 +00:00
void error_callback_ ( const FLAC__FileDecoder * decoder , FLAC__StreamDecoderErrorStatus status , void * client_data )
2000-12-10 04:09:52 +00:00
{
2003-01-14 09:01:31 +00:00
file_info_struct * file_info = ( file_info_struct * ) client_data ;
2000-12-10 04:09:52 +00:00
( void ) decoder ;
2002-06-04 05:44:32 +00:00
if ( status ! = FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC )
2002-08-27 06:02:09 +00:00
file_info - > abort_flag = true ;
2000-12-10 04:09:52 +00:00
}
2002-06-05 06:10:55 +00:00
2003-01-14 09:01:31 +00:00
/*
* title formatting
*/
typedef struct
2002-06-05 06:10:55 +00:00
{
2003-01-14 09:01:31 +00:00
FLAC_Plugin__CanonicalTag t ;
const char * filename ;
} tag_param_t ;
2002-09-04 07:57:56 +00:00
2003-01-14 09:01:31 +00:00
static __inline char * GetFileName ( const char * fullname )
2002-09-04 07:57:56 +00:00
{
2003-01-14 09:01:31 +00:00
const char * c = fullname + strlen ( fullname ) - 1 ;
while ( c > fullname )
{
if ( * c = = ' \\ ' | | * c = = ' / ' )
{
c + + ;
break ;
2002-09-04 07:57:56 +00:00
}
2003-01-14 09:01:31 +00:00
c - - ;
}
return ( char * ) c ;
}
static const T_CHAR * get_tag ( const T_CHAR * tag , void * param )
{
tag_param_t * p = ( tag_param_t * ) param ;
if ( ! stricmp ( tag , " path " ) | | ! stricmp ( tag , " filepath " ) | | ! stricmp ( tag , " url " ) )
return p - > filename ;
else if ( ! stricmp ( tag , " filename " ) )
{
static char foo [ MAX_PATH ] ;
char * c ;
strcpy ( foo , GetFileName ( p - > filename ) ) ;
if ( c = strrchr ( foo , ' . ' ) ) * c = 0 ;
return foo ;
2002-06-05 06:10:55 +00:00
}
2003-01-14 09:01:31 +00:00
else if ( ! stricmp ( tag , " title " ) )
return p - > t . title ;
else if ( ! stricmp ( tag , " artist " ) )
return p - > t . performer ? p - > t . performer : p - > t . composer ;
else if ( ! stricmp ( tag , " composer " ) )
return p - > t . composer ;
else if ( ! stricmp ( tag , " performer " ) )
return p - > t . performer ;
else if ( ! stricmp ( tag , " album " ) )
return p - > t . album ;
else if ( ! stricmp ( tag , " year " ) | | ! stricmp ( tag , " date " ) )
return p - > t . year_recorded ? p - > t . year_recorded : p - > t . year_performed ;
else if ( ! stricmp ( tag , " year_recorded " ) )
return p - > t . year_recorded ;
else if ( ! stricmp ( tag , " year_performed " ) )
return p - > t . year_performed ;
else if ( ! stricmp ( tag , " track_number " ) )
return p - > t . track_number ;
else if ( ! stricmp ( tag , " tracks_in_album " ) )
return p - > t . tracks_in_album ;
else if ( ! stricmp ( tag , " genre " ) )
return p - > t . genre ;
else if ( ! stricmp ( tag , " comment " ) | | ! stricmp ( tag , " description " ) )
return p - > t . comment ;
else return NULL ;
}
void get_description_ ( const char * filename , char * description , unsigned max_size )
{
tag_param_t param ;
FLAC_plugin__canonical_tag_init ( & param . t ) ;
FLAC_plugin__canonical_tag_get_combined ( filename , & param . t ) ;
param . filename = filename ;
tagz_format ( flac_cfg . title . tag_format , get_tag , NULL , & param , description , max_size ) ;
FLAC_plugin__canonical_tag_clear ( & param . t ) ;
2002-06-05 06:10:55 +00:00
}