| @@ -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 ] ) ) | |||