22#include < cmath>
33#include < cstdio>
44#include < cstdlib>
5+ #include < ranges>
56#include < string>
7+ #include < string_view>
68
79#ifdef _WIN32
810#ifndef WIN32_LEAN_AND_MEAN
@@ -84,6 +86,12 @@ static std::string get_env_var(const char* var_name)
8486 return env_var;
8587}
8688
89+ #ifdef _WIN32
90+ constexpr auto PathSeparator = std::string_view(" ;" );
91+ #else
92+ constexpr auto PathSeparator = std::string_view(" :" );
93+ #endif
94+
8795extern std::string plugin_path;
8896
8997NukedSc55::NukedSc55 (const clap_plugin_t _plugin_class,
@@ -92,7 +100,7 @@ NukedSc55::NukedSc55(const clap_plugin_t _plugin_class,
92100 log_init ();
93101
94102 path = plugin_path;
95- log (" Plugin path: %s" , path.c_str ());
103+ log (" Plugin path: %s" , path.string (). c_str ());
96104
97105 plugin_class = _plugin_class;
98106
@@ -107,62 +115,50 @@ const clap_plugin_t* NukedSc55::GetPluginClass()
107115 return &plugin_class;
108116}
109117
110- // Get the ROM directory from an environment variable if set to a non-empty
111- // value. The path must be an absolute directory path
112- std::filesystem::path NukedSc55::GetRomEnvDir ()
118+ // Get a list of potential ROM directories from an environment variable
119+ // if it is set to a non-empty value. The paths must be absolute directory paths.
120+ // Entries must be separated by the OS PATH separator
121+ std::vector<std::filesystem::path> NukedSc55::GetRomEnvDirs ()
113122{
114123 constexpr char env_rom_dir_name[] = " SOUNDCANVAS_ROM_DIR" ;
115- std::filesystem::path empty_path = {};
116-
117- std::string dir_name = get_env_var (env_rom_dir_name);
118-
119- if (dir_name.empty ()) {
120- return empty_path;
121- }
122-
123- std::filesystem::path env_path (dir_name);
124-
125- if (env_path.is_relative ()) {
126- return empty_path;
124+ std::vector<std::filesystem::path> paths = {};
125+ const auto env_dir_list = get_env_var (env_rom_dir_name);
126+ if (env_dir_list.empty ()) {
127+ return paths;
127128 }
128-
129- std::error_code ec ;
130- if (! std::filesystem::is_directory (env_path, ec )) {
131- if (ec) {
132- log ( " Error getting directory status: %s " , ec. message (). c_str ()) ;
129+ for ( const auto env_dir : std::views::split (env_dir_list, PathSeparator)) {
130+ auto dir = std::filesystem::path ( std::string (env_dir. data (), env_dir. size ())) ;
131+ if (dir. is_relative ( )) {
132+ log ( " Error: path is relative: %s " , dir. string (). c_str ());
133+ continue ;
133134 }
134- return empty_path;
135+ std::error_code ec;
136+ if (!std::filesystem::is_directory (dir, ec)) {
137+ if (ec) {
138+ log (" Error getting directory status: %s" , ec.message ().c_str ());
139+ }
140+ continue ;
141+ }
142+ paths.push_back (dir);
135143 }
136- return env_path ;
144+ return paths ;
137145}
138146
139- std::filesystem::path NukedSc55::GetRomBasePath ()
147+ std::vector<std:: filesystem::path> NukedSc55::GetRomBasePaths ()
140148{
141- auto env_rom_dir = GetRomEnvDir ();
142- if (!env_rom_dir.empty ()) {
143- log (" ROM base path from environment: %s" , env_rom_dir.c_str ());
144- return env_rom_dir;
145- }
149+ auto paths = GetRomEnvDirs ();
146150
147- const char * rom_dir = " ROMs" ;
151+ const char * default_rom_dir = " ROMs" ;
148152
149- #ifdef __APPLE__
150153 // Try the Resources folder inside the application bundle first on macOS
151- const auto bundle_rom_path = path / " Resources" / rom_dir;
152-
153- if (std::filesystem::exists (bundle_rom_path)) {
154- log (" Found ROM directory within application bundle, ROM base path: %s" ,
155- bundle_rom_path.c_str ());
156-
157- return bundle_rom_path;
158- }
154+ #ifdef __APPLE__
155+ paths.push_back (path / " Resources" / default_rom_dir);
159156#endif
160- const char * resources_dir = " Nuked-SC55-Resources" ;
161157
162- const auto rom_path = path. parent_path () / resources_dir / rom_dir ;
163- log ( " ROM base path: %s " , rom_path. c_str () );
158+ const char * resources_dir = " Nuked-SC55-Resources " ;
159+ paths. push_back ( path. parent_path () / resources_dir / default_rom_dir );
164160
165- return rom_path ;
161+ return paths ;
166162}
167163
168164bool NukedSc55::Init (const clap_plugin* _plugin_instance)
@@ -180,40 +176,43 @@ bool NukedSc55::Init(const clap_plugin* _plugin_instance)
180176 return false ;
181177 }
182178
183- auto rom_path = GetRomBasePath ();
184- auto romset = " mk1" ;
185-
186- switch (model) {
187- case Model::Sc55_v1_00: rom_path /= " SC-55-v1.00" ; break ;
188- case Model::Sc55_v1_20: rom_path /= " SC-55-v1.20" ; break ;
189- case Model::Sc55_v1_21: rom_path /= " SC-55-v1.21" ; break ;
190- case Model::Sc55_v2_00: rom_path /= " SC-55-v2.00" ; break ;
191- case Model::Sc55mk2_v1_01:
192- romset = " mk2" ;
193- rom_path /= " SC-55mk2-v1.01" ;
194- break ;
195- default : assert (false );
196- }
179+ auto rom_paths = GetRomBasePaths ();
180+ for (auto rom_path : rom_paths) {
181+ auto romset = " mk1" ;
182+
183+ switch (model) {
184+ case Model::Sc55_v1_00: rom_path /= " SC-55-v1.00" ; break ;
185+ case Model::Sc55_v1_20: rom_path /= " SC-55-v1.20" ; break ;
186+ case Model::Sc55_v1_21: rom_path /= " SC-55-v1.21" ; break ;
187+ case Model::Sc55_v2_00: rom_path /= " SC-55-v2.00" ; break ;
188+ case Model::Sc55mk2_v1_01:
189+ romset = " mk2" ;
190+ rom_path /= " SC-55mk2-v1.01" ;
191+ break ;
192+ default : assert (false );
193+ }
197194
198- log (" ROM dir: %s" , rom_path.c_str ());
195+ log (" Trying ROM dir: %s" , rom_path. string () .c_str ());
199196
200- AllRomsetInfo romset_info{};
201- common::LoadRomsetResult load_result{};
202- common::RomOverrides rom_overrides;
203- common::LoadRomsetError err = common::LoadRomset (romset_info, rom_path, romset, false , rom_overrides, load_result);
204- if (err != common::LoadRomsetError{}) {
205- log (" emu->LoadRomset failed" );
206- emu.reset (nullptr );
207- return false ;
208- }
209- RomLocationSet loaded{};
210- if (!emu->LoadRoms (load_result.romset , romset_info, &loaded)) {
211- log (" emu->LoadRoms failed" );
212- emu.reset (nullptr );
213- return false ;
214- }
215-
216- return true ;
197+ AllRomsetInfo romset_info = {};
198+ common::LoadRomsetResult load_result = {};
199+ common::RomOverrides rom_overrides;
200+ common::LoadRomsetError err = common::LoadRomset (romset_info, rom_path, romset, false , rom_overrides, load_result);
201+ if (err != common::LoadRomsetError{}) {
202+ log (" emu->LoadRomset failed. Trying next directory" );
203+ continue ;
204+ }
205+ RomLocationSet loaded = {};
206+ if (!emu->LoadRoms (load_result.romset , romset_info, &loaded)) {
207+ log (" emu->LoadRoms failed" );
208+ emu.reset (nullptr );
209+ return false ;
210+ }
211+ return true ;
212+ }
213+ log (" Init failed, tried all ROM directories" );
214+ emu.reset (nullptr );
215+ return false ;
217216}
218217
219218void NukedSc55::Shutdown ()
0 commit comments