412 lines
13 KiB
Plaintext
412 lines
13 KiB
Plaintext
#include "audio_paths.nvgt"
|
|
|
|
funcdef void learn_sounds_speak_callback(const string& in message, bool interrupt);
|
|
funcdef void learn_sounds_tick_callback();
|
|
funcdef void learn_sounds_setup_callback();
|
|
|
|
learn_sounds_speak_callback @learnSoundsSpeakCallback = null;
|
|
learn_sounds_tick_callback @learnSoundsTickCallback = null;
|
|
learn_sounds_setup_callback @learnSoundsSetupCallback = null;
|
|
|
|
string[] learnSoundsSkipList;
|
|
string[] learnSoundsDescriptionPaths;
|
|
string[] learnSoundsDescriptionTexts;
|
|
|
|
string learnSoundsRootDir = "sounds";
|
|
string learnSoundsMenuSoundDir = "sounds/menu";
|
|
bool learnSoundsWrap = true;
|
|
bool learnSoundsPlaySelectSound = true;
|
|
bool learnSoundsSetupApplied = false;
|
|
|
|
sound learnSoundsPreviewSound;
|
|
sound learnSoundsMoveSound;
|
|
sound learnSoundsSelectSound;
|
|
|
|
void learn_sounds_set_speak_callback(learn_sounds_speak_callback @callback) {
|
|
@learnSoundsSpeakCallback = @callback;
|
|
}
|
|
|
|
void learn_sounds_set_tick_callback(learn_sounds_tick_callback @callback) {
|
|
@learnSoundsTickCallback = @callback;
|
|
}
|
|
|
|
void learn_sounds_set_setup_callback(learn_sounds_setup_callback @callback) {
|
|
@learnSoundsSetupCallback = @callback;
|
|
learnSoundsSetupApplied = false;
|
|
}
|
|
|
|
void learn_sounds_set_root_dir(const string rootDir) {
|
|
learnSoundsRootDir = rootDir;
|
|
}
|
|
|
|
void learn_sounds_set_menu_sound_dir(const string menuSoundDir) {
|
|
learnSoundsMenuSoundDir = menuSoundDir;
|
|
}
|
|
|
|
void learn_sounds_set_wrap(bool wrap) {
|
|
learnSoundsWrap = wrap;
|
|
}
|
|
|
|
void learn_sounds_set_play_select_sound(bool playSelectSound) {
|
|
learnSoundsPlaySelectSound = playSelectSound;
|
|
}
|
|
|
|
void learn_sounds_clear_skip_entries() {
|
|
learnSoundsSkipList.resize(0);
|
|
}
|
|
|
|
void learn_sounds_add_skip_entry(const string entry) {
|
|
if (entry == "") {
|
|
return;
|
|
}
|
|
learnSoundsSkipList.insert_last(entry);
|
|
}
|
|
|
|
void learn_sounds_clear_descriptions() {
|
|
learnSoundsDescriptionPaths.resize(0);
|
|
learnSoundsDescriptionTexts.resize(0);
|
|
}
|
|
|
|
void learn_sounds_add_description(const string soundPath, const string description) {
|
|
if (soundPath == "") {
|
|
return;
|
|
}
|
|
learnSoundsDescriptionPaths.insert_last(soundPath);
|
|
learnSoundsDescriptionTexts.insert_last(description);
|
|
}
|
|
|
|
void learn_sounds_reset_configuration() {
|
|
learn_sounds_clear_skip_entries();
|
|
learn_sounds_clear_descriptions();
|
|
learnSoundsSetupApplied = false;
|
|
}
|
|
|
|
void learn_sounds_speak(const string& in message, bool interrupt) {
|
|
if (@learnSoundsSpeakCallback !is null) {
|
|
learnSoundsSpeakCallback(message, interrupt);
|
|
return;
|
|
}
|
|
screen_reader_speak(message, interrupt);
|
|
}
|
|
|
|
void learn_sounds_tick() {
|
|
if (@learnSoundsTickCallback !is null) {
|
|
learnSoundsTickCallback();
|
|
}
|
|
}
|
|
|
|
void learn_sounds_apply_setup_once() {
|
|
if (learnSoundsSetupApplied) {
|
|
return;
|
|
}
|
|
|
|
if (@learnSoundsSetupCallback !is null) {
|
|
learnSoundsSetupCallback();
|
|
}
|
|
|
|
learnSoundsSetupApplied = true;
|
|
}
|
|
|
|
string learn_sounds_normalize_path(const string& in path) {
|
|
return path.replace("\\", "/", true);
|
|
}
|
|
|
|
bool learn_sounds_is_directory_skip_entry(const string& in entry) {
|
|
if (entry.length() == 0)
|
|
return false;
|
|
if (entry.substr(entry.length() - 1) == "/")
|
|
return true;
|
|
return directory_exists(entry);
|
|
}
|
|
|
|
bool learn_sounds_should_skip_path(const string& in path) {
|
|
string normalizedPath = learn_sounds_normalize_path(path);
|
|
for (uint skipIndex = 0; skipIndex < learnSoundsSkipList.length(); skipIndex++) {
|
|
string entry = learn_sounds_normalize_path(learnSoundsSkipList[skipIndex]);
|
|
if (entry.length() == 0)
|
|
continue;
|
|
|
|
bool isDirectory = learn_sounds_is_directory_skip_entry(entry);
|
|
if (isDirectory) {
|
|
if (entry.substr(entry.length() - 1) != "/")
|
|
entry += "/";
|
|
if (normalizedPath.length() >= entry.length() && normalizedPath.substr(0, entry.length()) == entry) {
|
|
return true;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (normalizedPath == entry)
|
|
return true;
|
|
|
|
if (entry.find_first("/") < 0 && entry.find_first("\\") < 0) {
|
|
if (normalizedPath.length() >= entry.length() + 1 &&
|
|
normalizedPath.substr(normalizedPath.length() - entry.length()) == entry) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
string learn_sounds_get_description(const string& in path) {
|
|
string normalizedPath = learn_sounds_normalize_path(path);
|
|
uint descriptionCount = learnSoundsDescriptionPaths.length();
|
|
if (learnSoundsDescriptionTexts.length() < descriptionCount) {
|
|
descriptionCount = learnSoundsDescriptionTexts.length();
|
|
}
|
|
|
|
for (uint descriptionIndex = 0; descriptionIndex < descriptionCount; descriptionIndex++) {
|
|
if (learn_sounds_normalize_path(learnSoundsDescriptionPaths[descriptionIndex]) == normalizedPath) {
|
|
return learnSoundsDescriptionTexts[descriptionIndex];
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
bool learn_sounds_contains_path_ci(string[] @paths, const string& in path) {
|
|
string normalizedPath = learn_sounds_normalize_path(path).lower();
|
|
for (uint pathIndex = 0; pathIndex < paths.length(); pathIndex++) {
|
|
if (learn_sounds_normalize_path(paths[pathIndex]).lower() == normalizedPath) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void learn_sounds_add_path_if_missing(string[] @paths, const string& in path) {
|
|
if (learn_sounds_contains_path_ci(paths, path)) {
|
|
return;
|
|
}
|
|
paths.insert_last(path);
|
|
}
|
|
|
|
bool learn_sounds_has_audio_extension(const string& in path) {
|
|
string lowerPath = path.lower();
|
|
if (lowerPath.length() < 4)
|
|
return false;
|
|
string suffix = lowerPath.substr(lowerPath.length() - 4);
|
|
return suffix == ".ogg" || suffix == ".wav";
|
|
}
|
|
|
|
void learn_sounds_gather_files_from_pack(const string& in basePath, string[] @outFiles) {
|
|
pack @activePack = cast<pack @>(sound_default_pack);
|
|
if (@activePack is null)
|
|
return;
|
|
|
|
string[] @packFiles = activePack.list_files();
|
|
if (@packFiles is null)
|
|
return;
|
|
|
|
string normalizedBasePath = learn_sounds_normalize_path(basePath);
|
|
if (normalizedBasePath != "" && normalizedBasePath.substr(normalizedBasePath.length() - 1) != "/") {
|
|
normalizedBasePath += "/";
|
|
}
|
|
string normalizedBasePathLower = normalizedBasePath.lower();
|
|
|
|
for (uint fileIndex = 0; fileIndex < packFiles.length(); fileIndex++) {
|
|
string normalizedPath = learn_sounds_normalize_path(packFiles[fileIndex]);
|
|
if (normalizedPath.find("./") == 0) {
|
|
normalizedPath = normalizedPath.substr(2);
|
|
}
|
|
|
|
if (!learn_sounds_has_audio_extension(normalizedPath)) {
|
|
continue;
|
|
}
|
|
|
|
if (normalizedBasePathLower != "") {
|
|
if (normalizedPath.length() < normalizedBasePathLower.length()) {
|
|
continue;
|
|
}
|
|
if (normalizedPath.substr(0, normalizedBasePathLower.length()).lower() != normalizedBasePathLower) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
learn_sounds_add_path_if_missing(outFiles, normalizedPath);
|
|
}
|
|
}
|
|
|
|
void learn_sounds_gather_files_recursive(const string& in basePath, string[] @outFiles) {
|
|
string[] @oggFiles = find_files(basePath + "/*.ogg");
|
|
if (@oggFiles !is null) {
|
|
for (uint fileIndex = 0; fileIndex < oggFiles.length(); fileIndex++) {
|
|
learn_sounds_add_path_if_missing(outFiles, basePath + "/" + oggFiles[fileIndex]);
|
|
}
|
|
}
|
|
|
|
string[] @oggUpperFiles = find_files(basePath + "/*.OGG");
|
|
if (@oggUpperFiles !is null) {
|
|
for (uint fileIndex = 0; fileIndex < oggUpperFiles.length(); fileIndex++) {
|
|
learn_sounds_add_path_if_missing(outFiles, basePath + "/" + oggUpperFiles[fileIndex]);
|
|
}
|
|
}
|
|
|
|
string[] @wavFiles = find_files(basePath + "/*.wav");
|
|
if (@wavFiles !is null) {
|
|
for (uint fileIndex = 0; fileIndex < wavFiles.length(); fileIndex++) {
|
|
learn_sounds_add_path_if_missing(outFiles, basePath + "/" + wavFiles[fileIndex]);
|
|
}
|
|
}
|
|
|
|
string[] @wavUpperFiles = find_files(basePath + "/*.WAV");
|
|
if (@wavUpperFiles !is null) {
|
|
for (uint fileIndex = 0; fileIndex < wavUpperFiles.length(); fileIndex++) {
|
|
learn_sounds_add_path_if_missing(outFiles, basePath + "/" + wavUpperFiles[fileIndex]);
|
|
}
|
|
}
|
|
|
|
string[] @folders = find_directories(basePath + "/*");
|
|
if (@folders !is null) {
|
|
for (uint folderIndex = 0; folderIndex < folders.length(); folderIndex++) {
|
|
learn_sounds_gather_files_recursive(basePath + "/" + folders[folderIndex], outFiles);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool learn_sounds_sort_case_insensitive(const string& in a, const string& in b) {
|
|
return a.lower() < b.lower();
|
|
}
|
|
|
|
string learn_sounds_collapse_spaces(const string& in text) {
|
|
string result = text;
|
|
while (result.find_first(" ") > -1) {
|
|
result = result.replace(" ", " ", true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
string learn_sounds_label_from_path(const string& in soundPath) {
|
|
string normalizedPath = learn_sounds_normalize_path(soundPath);
|
|
int slashPos = normalizedPath.find_last_of("/");
|
|
string name = (slashPos >= 0) ? normalizedPath.substr(slashPos + 1) : normalizedPath;
|
|
|
|
string lowerName = name.lower();
|
|
if (lowerName.length() > 4 && lowerName.substr(lowerName.length() - 4) == ".ogg") {
|
|
name = name.substr(0, name.length() - 4);
|
|
} else if (lowerName.length() > 4 && lowerName.substr(lowerName.length() - 4) == ".wav") {
|
|
name = name.substr(0, name.length() - 4);
|
|
}
|
|
|
|
name = name.replace("_", " ", true);
|
|
name = name.replace("-", " ", true);
|
|
name = learn_sounds_collapse_spaces(name);
|
|
name = name.lower();
|
|
name.trim_whitespace_this();
|
|
|
|
if (name.length() == 0)
|
|
return "Sound";
|
|
return name;
|
|
}
|
|
|
|
void learn_sounds_collect_entries(string[] @labels, string[] @soundPaths) {
|
|
labels.resize(0);
|
|
soundPaths.resize(0);
|
|
|
|
string[] discoveredFiles;
|
|
if (directory_exists(learnSoundsRootDir)) {
|
|
learn_sounds_gather_files_recursive(learnSoundsRootDir, discoveredFiles);
|
|
}
|
|
learn_sounds_gather_files_from_pack(learnSoundsRootDir, discoveredFiles);
|
|
if (discoveredFiles.length() > 1) {
|
|
discoveredFiles.sort(learn_sounds_sort_case_insensitive);
|
|
}
|
|
|
|
for (uint fileIndex = 0; fileIndex < discoveredFiles.length(); fileIndex++) {
|
|
string soundPath = learn_sounds_normalize_path(discoveredFiles[fileIndex]);
|
|
if (learn_sounds_should_skip_path(soundPath)) {
|
|
continue;
|
|
}
|
|
|
|
string label = learn_sounds_label_from_path(soundPath);
|
|
string description = learn_sounds_get_description(soundPath);
|
|
if (description.length() > 0) {
|
|
label += " - " + description;
|
|
}
|
|
|
|
labels.insert_last(label);
|
|
soundPaths.insert_last(soundPath);
|
|
}
|
|
}
|
|
|
|
void learn_sounds_play_ui_sound(sound& inout soundObj, const string basePath) {
|
|
soundObj.close();
|
|
|
|
// Avoid file_exists()-only path checks so packaged Android assets can still load.
|
|
if (soundObj.load(basePath)) {
|
|
soundObj.play();
|
|
return;
|
|
}
|
|
|
|
if (soundObj.load(basePath + ".ogg")) {
|
|
soundObj.play();
|
|
return;
|
|
}
|
|
|
|
if (!soundObj.load(basePath + ".wav")) {
|
|
return;
|
|
}
|
|
|
|
soundObj.play();
|
|
}
|
|
|
|
void learn_sounds_run_menu() {
|
|
learn_sounds_apply_setup_once();
|
|
|
|
string[] labels;
|
|
string[] soundPaths;
|
|
learn_sounds_collect_entries(labels, soundPaths);
|
|
|
|
learn_sounds_speak("Learn sounds.", true);
|
|
if (labels.length() == 0) {
|
|
learn_sounds_speak("No sounds available.", true);
|
|
return;
|
|
}
|
|
|
|
int selection = 0;
|
|
learn_sounds_speak(labels[selection], true);
|
|
|
|
while (true) {
|
|
wait(5);
|
|
learn_sounds_tick();
|
|
|
|
if (key_pressed(KEY_ESCAPE)) {
|
|
learn_sounds_speak("Closed.", true);
|
|
return;
|
|
}
|
|
|
|
if (key_pressed(KEY_DOWN)) {
|
|
learn_sounds_play_ui_sound(learnSoundsMoveSound, learnSoundsMenuSoundDir + "/menu_move");
|
|
selection++;
|
|
if (selection >= int(labels.length())) {
|
|
selection = learnSoundsWrap ? 0 : int(labels.length()) - 1;
|
|
}
|
|
learn_sounds_speak(labels[selection], true);
|
|
}
|
|
|
|
if (key_pressed(KEY_UP)) {
|
|
learn_sounds_play_ui_sound(learnSoundsMoveSound, learnSoundsMenuSoundDir + "/menu_move");
|
|
selection--;
|
|
if (selection < 0) {
|
|
selection = learnSoundsWrap ? int(labels.length()) - 1 : 0;
|
|
}
|
|
learn_sounds_speak(labels[selection], true);
|
|
}
|
|
|
|
if (key_pressed(KEY_RETURN)) {
|
|
if (learnSoundsPlaySelectSound) {
|
|
learn_sounds_play_ui_sound(learnSoundsSelectSound, learnSoundsMenuSoundDir + "/menu_select");
|
|
}
|
|
string selectedPath = soundPaths[selection];
|
|
|
|
learnSoundsPreviewSound.close();
|
|
if (!learnSoundsPreviewSound.load(selectedPath)) {
|
|
learn_sounds_speak("Unable to load sound.", true);
|
|
continue;
|
|
}
|
|
learnSoundsPreviewSound.play();
|
|
}
|
|
}
|
|
}
|