@@ -88,6 +88,21 @@ Audio_File::filename ( void ) const | |||
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 */ | |||
Audio_File * | |||
Audio_File::from_file ( const char * filename ) | |||
@@ -96,11 +111,21 @@ Audio_File::from_file ( const char * filename ) | |||
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 ) ) ) | |||
@@ -118,7 +143,7 @@ Audio_File::from_file ( const char * filename ) | |||
done: | |||
ASSERT( ! _open_files[ std::string( filename ) ], "Programming errror" ); | |||
/* ASSERT( ! _open_files[ std::string( filename ) ], "Programming errror" ); */ | |||
_open_files[ std::string( filename ) ] = a; | |||
@@ -130,8 +155,15 @@ done: | |||
Audio_File * | |||
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 | |||
@@ -49,6 +49,7 @@ protected: | |||
const char *name; | |||
const char *extension; | |||
unsigned long id; | |||
int quality; | |||
}; | |||
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 16", "wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16 | 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 | |||
{ 0, 0 } | |||
}; | |||
@@ -125,6 +127,14 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels | |||
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; | |||
c->_path = filepath; | |||
@@ -31,7 +31,12 @@ def configure(conf): | |||
# conf.env.append_value('CXXFLAGS', '-D_FILE_OFFSET_BITS=64') | |||
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('SYSTEM_PATH', '/'.join( [ conf.env.DATADIR, APPNAME ] ) ) | |||