@@ -88,6 +88,21 @@ Audio_File::filename ( void ) const | |||||
return _path; | return _path; | ||||
} | } | ||||
static bool is_poor_seeker ( const char * filename ) | |||||
{ | |||||
if ( ( strlen(filename) > 4 && | |||||
! strcasecmp( &filename[strlen(filename)-4], ".ogg" ) ) | |||||
|| | |||||
( strlen(filename) > 5 && | |||||
! strcasecmp( &filename[strlen(filename)-5], ".flac" ) ) | |||||
) | |||||
{ | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/** attempt to open any supported filetype */ | /** attempt to open any supported filetype */ | ||||
Audio_File * | Audio_File * | ||||
Audio_File::from_file ( const char * filename ) | Audio_File::from_file ( const char * filename ) | ||||
@@ -96,11 +111,21 @@ Audio_File::from_file ( const char * filename ) | |||||
Audio_File *a; | Audio_File *a; | ||||
if ( ( a = _open_files[ std::string( filename ) ] ) ) | |||||
if ( is_poor_seeker(filename) ) | |||||
{ | { | ||||
++a->_refs; | |||||
return a; | |||||
/* OGG and FLAC have poor seek performance, so they require | |||||
* separate file descriptors to be useful */ | |||||
} | |||||
else | |||||
{ | |||||
/* WAV are quick enough to seek that we can save | |||||
* filedescriptors by sharing them between regions */ | |||||
if ( ( a = _open_files[ std::string( filename ) ] ) ) | |||||
{ | |||||
++a->_refs; | |||||
return a; | |||||
} | |||||
} | } | ||||
if ( ( a = Audio_File_SF::from_file( filename ) ) ) | if ( ( a = Audio_File_SF::from_file( filename ) ) ) | ||||
@@ -118,7 +143,7 @@ Audio_File::from_file ( const char * filename ) | |||||
done: | done: | ||||
ASSERT( ! _open_files[ std::string( filename ) ], "Programming errror" ); | |||||
/* ASSERT( ! _open_files[ std::string( filename ) ], "Programming errror" ); */ | |||||
_open_files[ std::string( filename ) ] = a; | _open_files[ std::string( filename ) ] = a; | ||||
@@ -130,8 +155,15 @@ done: | |||||
Audio_File * | Audio_File * | ||||
Audio_File::duplicate ( void ) | Audio_File::duplicate ( void ) | ||||
{ | { | ||||
++_refs; | |||||
return this; | |||||
if ( is_poor_seeker( _filename ) ) | |||||
{ | |||||
return from_file(_filename); | |||||
} | |||||
else | |||||
{ | |||||
++_refs; | |||||
return this; | |||||
} | |||||
} | } | ||||
/** release the resources assoicated with this audio file if no other | /** release the resources assoicated with this audio file if no other | ||||
@@ -49,6 +49,7 @@ protected: | |||||
const char *name; | const char *name; | ||||
const char *extension; | const char *extension; | ||||
unsigned long id; | unsigned long id; | ||||
int quality; | |||||
}; | }; | ||||
char *_filename; | char *_filename; | ||||
@@ -42,11 +42,13 @@ const Audio_File::format_desc Audio_File_SF::supported_formats[] = | |||||
{ "Wav 24", "wav", SF_FORMAT_WAV | SF_FORMAT_PCM_24 | SF_ENDIAN_FILE }, | { "Wav 24", "wav", SF_FORMAT_WAV | SF_FORMAT_PCM_24 | SF_ENDIAN_FILE }, | ||||
{ "Wav 16", "wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE }, | { "Wav 16", "wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE }, | ||||
{ "Wav f32", "wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT | SF_ENDIAN_FILE }, | { "Wav f32", "wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT | SF_ENDIAN_FILE }, | ||||
{ "Au 24", "au", SF_FORMAT_AU | SF_FORMAT_PCM_24 | SF_ENDIAN_FILE }, | |||||
{ "Au 16", "au", SF_FORMAT_AU | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE }, | |||||
{ "FLAC", "flac", SF_FORMAT_FLAC | SF_FORMAT_PCM_24 }, | |||||
#ifdef HAS_SF_FORMAT_VORBIS | |||||
{ "Ogg Vorbis", "ogg", SF_FORMAT_OGG | SF_FORMAT_VORBIS | SF_FORMAT_PCM_16 }, | |||||
{ "Au 24", "au", SF_FORMAT_AU | SF_FORMAT_PCM_24 | SF_ENDIAN_FILE }, | |||||
{ "Au 16", "au", SF_FORMAT_AU | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE }, | |||||
{ "FLAC", "flac", SF_FORMAT_FLAC | SF_FORMAT_PCM_24 }, | |||||
#ifdef HAVE_SF_FORMAT_VORBIS | |||||
{ "Vorbis q10", "ogg", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 10 }, | |||||
{ "Vorbis q6", "ogg", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 6 }, | |||||
{ "Vorbis q3", "ogg", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 3 }, | |||||
#endif | #endif | ||||
{ 0, 0 } | { 0, 0 } | ||||
}; | }; | ||||
@@ -125,6 +127,14 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels | |||||
return NULL; | return NULL; | ||||
} | } | ||||
if ( !strcmp( fd->extension, "ogg" ) ) | |||||
{ | |||||
/* set high quality encoding for vorbis */ | |||||
double quality = ( fd->quality + 1 ) / (float)11; | |||||
sf_command( out, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof( double ) ); | |||||
} | |||||
Audio_File_SF *c = new Audio_File_SF; | Audio_File_SF *c = new Audio_File_SF; | ||||
c->_path = filepath; | c->_path = filepath; | ||||
@@ -31,7 +31,12 @@ def configure(conf): | |||||
# conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64') | # conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64') | ||||
conf.check_cfg(package='sndfile', uselib_store='SNDFILE',args="--cflags --libs", | conf.check_cfg(package='sndfile', uselib_store='SNDFILE',args="--cflags --libs", | ||||
atleast_version='1.0.17', mandatory=True) | |||||
atleast_version='1.0.18', mandatory=True) | |||||
conf.check(msg='Checking for SF_FORMAT_VORBIS', | |||||
define_name='HAVE_SF_FORMAT_VORBIS', | |||||
fragment='#include <sndfile.h>\nint main ( int argc, char **argv ) { return SF_FORMAT_VORBIS; }', | |||||
execute=False, mandatory=False) | |||||
conf.define('VERSION', PACKAGE_VERSION) | conf.define('VERSION', PACKAGE_VERSION) | ||||
conf.define('SYSTEM_PATH', '/'.join( [ conf.env.DATADIR, APPNAME ] ) ) | conf.define('SYSTEM_PATH', '/'.join( [ conf.env.DATADIR, APPNAME ] ) ) | ||||