Skip to content

Commit b95b1f4

Browse files
shermpjohnnovak
authored andcommitted
Allow trying to load ROMs from multiple directories
This includes expanding a list of directories from the env variable
1 parent 8ade3d9 commit b95b1f4

File tree

3 files changed

+83
-78
lines changed

3 files changed

+83
-78
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,23 @@ Nuked-SC55-Resources
6666

6767
On macOS, you can also put the `ROMs` folder in the `Resources` folder inside the `Nuked-SC55.clap` application bundle.
6868

69-
As an alternative to creating the `Nuked-SC55-Resources` directory in the plugin location, you may set the `SOUNDCANVAS_ROM_DIR` environment variable to the absolute directory of where the ROM directories can be found. Eg:
69+
As an alternative to creating the `Nuked-SC55-Resources` directory in the plugin location, you may set the `SOUNDCANVAS_ROM_DIR` environment variable to a list of absolute directories of where to look for ROM's. The OS PATH separator is used as a list delimiter Eg:
7070

7171
```pwsh
7272
$Env:SOUNDCANVAS_ROM_DIR = "C:\path\to\ROM\dir"
7373
```
74+
```pwsh
75+
$Env:SOUNDCANVAS_ROM_DIR = "C:\path\to\ROM\dir;Z:\alt\path\to\dir"
76+
```
7477

7578
or
7679

7780
```sh
7881
export SOUNDCANVAS_ROM_DIR=/path/to/ROM/dir
7982
```
83+
```sh
84+
export SOUNDCANVAS_ROM_DIR=/path/to/ROM/dir:/alt/path/to/rom/dir
85+
```
8086

8187
Here is the list of required files for each supported model and their SHA1 hashes. Lookup is performed by filename, so make sure the names match exactly.
8288

src/nuked_sc55.cpp

Lines changed: 74 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
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+
8795
extern std::string plugin_path;
8896

8997
NukedSc55::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

168164
bool 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

219218
void NukedSc55::Shutdown()

src/nuked_sc55.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ class NukedSc55 {
5757
double resample_ratio = 0.0f;
5858

5959
// Methods
60-
std::filesystem::path GetRomEnvDir();
61-
std::filesystem::path GetRomBasePath();
60+
std::vector<std::filesystem::path> GetRomEnvDirs();
61+
std::vector<std::filesystem::path> GetRomBasePaths();
6262

6363
void ProcessEvent(const clap_event_header_t* event);
6464

0 commit comments

Comments
 (0)