2024-10-24 11:33:08 -07:00
# include "fluidsynth_backend.hpp"
# include <algorithm>
# include <ipc/common.pb.h>
# include <exception>
# include <filesystem>
# include "file_backend.hpp"
# include <stddef.h>
# include <string.h>
# include <file_backend.hpp>
# include <util.hpp>
2024-12-11 12:56:17 -08:00
# include <filesystem>
# include <limits.h>
namespace fs = std : : filesystem ;
2024-10-26 09:01:06 -07:00
void FluidSynthBackend : : fluidsynth_get_property_list_wrapper ( void * udata , const char * name , int type ) {
2024-10-24 11:33:08 -07:00
( ( FluidSynthBackend * ) udata ) - > fluidsynth_get_property_list ( name , type ) ;
}
2024-10-26 09:01:06 -07:00
void FluidSynthBackend : : fluidsynth_get_property_list ( const char * name , int type ) {
Property property ;
property . set_path ( fmt : : format ( " fluidsynth/{0} " , name ) ) ;
property . set_name ( name ) ;
switch ( type ) {
2024-12-11 12:56:17 -08:00
case FLUID_NO_TYPE :
2024-10-26 09:01:06 -07:00
case FLUID_NUM_TYPE : {
property . set_type ( PropertyType : : Double ) ;
2024-12-11 12:56:17 -08:00
double min , max ;
if ( fluid_settings_getnum_range ( settings , name , & min , & max ) = = FLUID_OK ) {
auto * range = property . mutable_hint ( ) - > mutable_range ( ) ;
range - > set_min ( min ) ;
range - > set_max ( max ) ;
}
2024-10-26 09:01:06 -07:00
} break ;
case FLUID_INT_TYPE : {
property . set_type ( PropertyType : : Int ) ;
2024-12-11 12:56:17 -08:00
int min , max ;
if ( fluid_settings_getint_range ( settings , name , & min , & max ) = = FLUID_OK ) {
auto * range = property . mutable_hint ( ) - > mutable_range ( ) ;
range - > set_min ( min ) ;
range - > set_max ( max ) ;
}
2024-10-26 09:01:06 -07:00
} break ;
case FLUID_STR_TYPE : {
property . set_type ( PropertyType : : String ) ;
} break ;
2024-12-11 12:56:17 -08:00
default : {
throw std : : exception ( ) ;
} break ;
2024-10-26 09:01:06 -07:00
}
property . set_id ( PropertyId : : BackendSpecific ) ;
fluidsynth_properties . push_back ( property ) ;
}
2024-10-24 11:33:08 -07:00
std : : vector < Property > FluidSynthBackend : : get_property_list ( ) {
2024-10-26 09:01:06 -07:00
return fluidsynth_properties ;
2024-10-24 11:33:08 -07:00
}
void FluidSynthBackend : : load ( const char * filename ) {
memset ( & spec , 0 , sizeof ( spec ) ) ;
current_file = filename ;
2024-10-26 09:01:06 -07:00
spec . format = AUDIO_F32SYS ;
2024-10-24 11:33:08 -07:00
spec . samples = 100 ;
spec . channels = 2 ;
2024-12-11 12:56:17 -08:00
spec . freq = 96000 ;
2024-10-24 11:33:08 -07:00
spec . size = 100 * 2 * sizeof ( int16_t ) ;
2024-12-11 12:56:17 -08:00
File * file = open_file ( filename ) ;
settings = new_fluid_settings ( ) ;
fluid_settings_setnum ( settings , " synth.sample-rate " , 96000.0 ) ;
2024-12-12 10:43:42 -08:00
fluid_settings_setnum ( settings , " synth.gain " , 0.5 ) ;
2024-10-26 09:01:06 -07:00
fluid_settings_foreach ( settings , ( void * ) this , & fluidsynth_get_property_list_wrapper ) ;
2024-12-11 12:56:17 -08:00
synth = new_fluid_synth ( settings ) ;
player = new_fluid_player ( synth ) ;
fs : : path fpath ( filename ) ;
fpath = fpath . parent_path ( ) / fpath . stem ( ) ;
std : : string fpath_str = fpath . string ( ) ;
std : : vector < std : : string > try_paths = std : : vector < std : : string > ( {
fpath_str + " .sf2 " , fpath_str + " .dls "
} ) ;
bool found = false ;
for ( auto & path : try_paths ) {
const char * path_c = path . c_str ( ) ;
if ( fluid_is_soundfont ( path_c ) ) {
fluid_synth_sfload ( synth , path_c , 1 ) ;
found = true ;
break ;
}
}
if ( ! found ) {
WARNING . writeln ( " Could not find a valid companion file to use as a sound font. Make sure the extension is all-lowercase, if you're on a case sensitive filesystem (Such as on Linux). " ) ;
throw std : : exception ( ) ;
}
file_data = malloc ( file - > get_len ( ) ) ;
file_len = file - > read ( file_data , 1 , file - > get_len ( ) ) ;
delete file ;
file_data = realloc ( file_data , file_len ) ;
fluid_player_add_mem ( player , file_data , file_len ) ;
2024-10-24 11:33:08 -07:00
}
extern SDL_AudioSpec obtained ;
2024-10-26 09:01:06 -07:00
void FluidSynthBackend : : switch_stream ( int idx ) {
2024-12-11 12:56:17 -08:00
fluid_player_play ( player ) ;
2024-10-24 11:33:08 -07:00
}
2024-10-26 09:01:06 -07:00
void FluidSynthBackend : : cleanup ( ) {
2024-12-11 12:56:17 -08:00
delete_fluid_player ( player ) ;
player = nullptr ;
delete_fluid_synth ( synth ) ;
synth = nullptr ;
delete_fluid_settings ( settings ) ;
settings = nullptr ;
file_len = 0 ;
free ( file_data ) ;
file_data = nullptr ;
2024-10-24 11:33:08 -07:00
}
2024-10-26 09:01:06 -07:00
size_t FluidSynthBackend : : render ( void * buf , size_t maxlen ) {
2024-12-11 12:56:17 -08:00
size_t sample_type_len = sizeof ( float ) ;
maxlen / = sample_type_len * 2 ;
maxlen * = sample_type_len * 2 ;
if ( fluid_synth_write_float ( synth , maxlen / 2 / sample_type_len , buf , 0 , 2 , buf , 1 , 2 ) = = FLUID_FAILED ) {
return 0 ;
}
return maxlen ;
}
bool FluidSynthBackend : : is_fluidsynth_setting ( std : : string path ) {
const char * prefix = " fluidsynth/ " ;
if ( path . length ( ) < strlen ( prefix ) ) return false ;
return path . substr ( 0 , strlen ( prefix ) ) = = std : : string ( prefix ) ;
2024-10-24 11:33:08 -07:00
}
2024-10-26 09:01:06 -07:00
void FluidSynthBackend : : seek ( double position ) {
2024-12-11 12:56:17 -08:00
fluid_player_seek ( player , position ) ;
2024-10-24 11:33:08 -07:00
}
2024-10-26 09:01:06 -07:00
double FluidSynthBackend : : get_position ( ) {
2024-12-11 12:56:17 -08:00
return fluid_player_get_current_tick ( player ) ;
2024-10-24 11:33:08 -07:00
}
2024-10-26 09:01:06 -07:00
int FluidSynthBackend : : get_stream_idx ( ) {
2024-10-24 11:33:08 -07:00
return 0 ;
2024-12-11 12:56:17 -08:00
}
void FluidSynthBackend : : set_fluidsynth_property_str ( std : : string path , std : : string val ) {
fluid_settings_setstr ( settings , path . c_str ( ) , val . c_str ( ) ) ;
}
void FluidSynthBackend : : set_fluidsynth_property_num ( std : : string path , double val ) {
fluid_settings_setnum ( settings , path . c_str ( ) , val ) ;
}
void FluidSynthBackend : : set_fluidsynth_property_int ( std : : string path , int val ) {
fluid_settings_setint ( settings , path . c_str ( ) , val ) ;
}
std : : optional < std : : string > FluidSynthBackend : : get_fluidsynth_property_str ( std : : string path ) {
char * tmp ;
if ( fluid_settings_dupstr ( settings , path . c_str ( ) , & tmp ) = = FLUID_OK ) {
std : : string output = tmp ;
free ( ( void * ) tmp ) ;
return output ;
} else {
return { } ;
}
}
std : : optional < double > FluidSynthBackend : : get_fluidsynth_property_num ( std : : string path ) {
double output = NAN ;
if ( fluid_settings_getnum ( settings , path . c_str ( ) , & output ) = = FLUID_OK ) return output ;
else return { } ;
}
std : : optional < int > FluidSynthBackend : : get_fluidsynth_property_int ( std : : string path ) {
int output = 0 ;
if ( fluid_settings_getint ( settings , path . c_str ( ) , & output ) = = FLUID_OK ) return output ;
else return { } ;
}
void FluidSynthBackend : : reset_fluidsynth_property ( std : : string path ) {
switch ( fluid_settings_get_type ( settings , path . c_str ( ) ) ) {
case FLUID_INT_TYPE : {
int output ;
if ( fluid_settings_getint_default ( settings , path . c_str ( ) , & output ) = = FLUID_OK ) {
fluid_settings_setint ( settings , path . c_str ( ) , output ) ;
}
} break ;
case FLUID_STR_TYPE : {
char * val ;
if ( fluid_settings_getstr_default ( settings , path . c_str ( ) , & val ) = = FLUID_OK ) {
fluid_settings_setstr ( settings , path . c_str ( ) , val ) ;
}
} break ;
case FLUID_NUM_TYPE : {
double val ;
if ( fluid_settings_getnum_default ( settings , path . c_str ( ) , & val ) = = FLUID_OK ) {
fluid_settings_setnum ( settings , path . c_str ( ) , val ) ;
}
} break ;
}
2024-12-12 10:43:42 -08:00
}