From ccda7bb639a70fdb42a2b70e349fb1b7cde2b382 Mon Sep 17 00:00:00 2001 From: esaruoho Date: Sat, 5 Sep 2026 22:04:21 +0300 Subject: [PATCH 1/2] Sononymph v1.11: fix Windows similarity search and Sononym-update breakage Reported on the Renoise forum: after updating Sononym, the tool reported "invalid paths" after Detect, "Open Path" crashed the notifier, and a similarity search from Renoise was refused by Sononym itself. - do_search / do_browse: convert the argument handed to the Sononym executable to native separators. On Windows we passed the temp file as "C:/Users/.../Renoise_TmpFile.flac" and Sononym answered "Indexing error - Unable to resolve location". Adds App.native_path(). - do_search: quote the file argument (a user or temp folder containing a space broke the launch) and drop duplicated locals. - AppUI Detect: with 2+ Sononym versions installed the button only filled the dropdown and relied on its notifier, which does not fire when the picked index is already the current one - and it starts at index 1. So picking the newest version applied nothing and left ConfigPath unset. Apply the newest immediately, keep the dropdown for older versions. - OpenConfigPath: guard an unset ConfigPath and accept windows separators (this is the reported "attempt to concatenate local 'directory_path' (a nil value)"), and fix the Linux branch assigning its command to os_name instead of command. - check_paths: self-heal a stale ConfigPath. Sononym stores query.json in a version-named folder, so every Sononym update leaves the tool pointing at a file that no longer exists. Adopt the newest detected version. - Persist AppPath / ConfigPath when they are set. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WzMBd9wYDRk4Pu341ggkSv --- Tools/com.renoise.Sononymph.xrnx/App.lua | 113 ++++++++++++++---- Tools/com.renoise.Sononymph.xrnx/AppUI.lua | 25 +++- Tools/com.renoise.Sononymph.xrnx/changelog.md | 10 ++ Tools/com.renoise.Sononymph.xrnx/main.lua | 2 +- Tools/com.renoise.Sononymph.xrnx/manifest.xml | 2 +- 5 files changed, 125 insertions(+), 27 deletions(-) diff --git a/Tools/com.renoise.Sononymph.xrnx/App.lua b/Tools/com.renoise.Sononymph.xrnx/App.lua index 53359d7e..ea99d9c8 100644 --- a/Tools/com.renoise.Sononymph.xrnx/App.lua +++ b/Tools/com.renoise.Sononymph.xrnx/App.lua @@ -203,6 +203,23 @@ end --------------------------------------------------------------------------------------------------- -- check paths and update "paths_are_valid" with result +-- persist the preferences to disk. +-- setting a value on the document only keeps it in memory until Renoise shuts +-- down cleanly - writing it out immediately means a configured path also +-- survives a crash. + +function App:save_preferences() + local ok,err = pcall(function() + self.prefs:save_as("preferences.xml") + end) + if not ok then + LOG("Sononymph: could not save preferences:",err) + end +end + +--------------------------------------------------------------------------------------------------- +-- check paths and update "paths_are_valid" with result + function App:check_paths() TRACE("App:check_paths()") @@ -216,6 +233,29 @@ function App:check_paths() local path = self.prefs.path_to_config.value local success,err = App.check_path(path) + if not success then + -- The stored query.json is gone. This happens every time Sononym updates + -- itself, because the configuration lives in a version-named folder: + -- .../Sononym/1.6.2/query.json becomes .../Sononym/1.6.14/query.json + -- Adopt the newest detected version instead of only reporting "invalid paths". + if not self._healing_config_path then + self._healing_config_path = true + local versions = App.find_sononym_versions() + local newest = versions and versions[1] + if newest and (newest.path ~= path) then + LOG("check_paths: stored ConfigPath is gone ("..tostring(path) + ..") - switching to detected Sononym "..newest.version..": "..newest.path) + self.prefs.path_to_config.value = cFilesystem.unixslashes(newest.path) + self:save_preferences() + path = self.prefs.path_to_config.value + success,err = App.check_path(path) + if success then + renoise.app():show_status("Sononymph: ConfigPath updated to Sononym "..newest.version) + end + end + self._healing_config_path = false + end + end if not success then self.invalid_path_observable.value = path self.paths_are_valid_observable.value = false @@ -317,6 +357,7 @@ function App:set_path_to_exe(file_path) file_path = cFilesystem.unixslashes(file_path) self.prefs.path_to_exe.value = file_path + self:save_preferences() local success,err = App.check_path(file_path) if not success then self:stop_monitoring() @@ -348,6 +389,7 @@ function App:set_path_to_config(file_path) file_path = cFilesystem.unixslashes(file_path) self.prefs.path_to_config.value = file_path + self:save_preferences() local success,err = App.check_path(file_path) if not success then self:stop_monitoring() @@ -752,16 +794,17 @@ function App:do_search() return false,"Unable to Launch Search: " .. err end -local path_to_exe=cFilesystem.unixslashes(self.prefs.path_to_exe.value) -local tmp_path=cFilesystem.unixslashes(tmp_path) - - local path_to_exe = cFilesystem.unixslashes(self.prefs.path_to_exe.value) - local cmd = string.format('"%s" %s',path_to_exe,cFilesystem.unixslashes(tmp_path)) -print (cmd) - local code = os.execute(cmd .. " &") + tmp_path = cFilesystem.unixslashes(tmp_path) + + -- quote both arguments: the temp folder and/or the user folder can contain + -- spaces. the file argument needs native separators, or Sononym reports + -- "Indexing error - Unable to resolve location" on Windows. + local cmd = string.format('"%s" "%s"',path_to_exe,App.native_path(tmp_path)) + LOG("do_search:",cmd) + os.execute(cmd .. " &") -return true + return true end --------------------------------------------------------------------------------------------------- @@ -782,7 +825,8 @@ function App:do_browse() end local path_to_exe = cFilesystem.unixslashes(self.prefs.path_to_exe.value) - local browse_path = cFilesystem.unixslashes(folder_path) + -- native separators: Sononym's crawler cannot resolve "C:/..." on Windows + local browse_path = App.native_path(cFilesystem.unixslashes(folder_path)) -- Launch Sononym with the folder path to enter browse mode local cmd = string.format('"%s" "%s"', path_to_exe, browse_path) @@ -1244,6 +1288,23 @@ function App.parse_config(path) end +--------------------------------------------------------------------------------------------------- +-- Convert a path to the separator style the host OS expects. +-- Paths are kept internally in unix style (cFilesystem.unixslashes), but +-- Sononym's crawler on Windows cannot resolve "C:/Users/.../file.flac" and +-- answers with "Indexing error - Unable to resolve location". Any path handed +-- to the Sononym executable as an argument has to use native separators. +-- @param file_path (string) +-- @return string + +function App.native_path(file_path) + if not file_path then return file_path end + if (os.platform() == "WINDOWS") then + return (string.gsub(file_path,"/","\\")) + end + return file_path +end + --------------------------------------------------------------------------------------------------- -- check if path is valid and existing -- @return boolean @@ -1522,21 +1583,33 @@ renoise.tool().preferences = prefs function OpenConfigPath() ---print (prefs.path_to_config) -local config_path = renoise.tool().preferences.path_to_config.value -local directory_path = config_path:match("(.*/)") -oprint(os.platform()) -oprint(directory_path) -oprint(config_path) + local config_path = renoise.tool().preferences.path_to_config.value + + if not config_path or (config_path == "") then + renoise.app():show_status("Sononymph: no ConfigPath is set yet - use Detect or Browse first.") + return + end + + -- accept both unix and windows separators: the path can be typed in by hand + local directory_path = config_path:match("(.*[/\\])") + if not directory_path then + renoise.app():show_status("Sononymph: ConfigPath does not look like a file path: "..config_path) + return + end + + local os_name = os.platform() local command -local os_name = os.platform() + if os_name == "WINDOWS" then + command = 'start "" "' .. App.native_path(directory_path) .. '"' + elseif os_name == "MACINTOSH" then + command = 'open "' .. directory_path .. '"' + else + command = 'xdg-open "' .. directory_path .. '"' + end - if os_name == "WINDOWS" then command = 'start "" "' .. directory_path .. '"' - elseif os_name == "MACINTOSH" then command = 'open "' .. directory_path .. '"' - else os_name = 'xdg-open "' .. directory_path .. '"' end + LOG("OpenConfigPath:",os_name,config_path,command) os.execute(command .. " &") - end diff --git a/Tools/com.renoise.Sononymph.xrnx/AppUI.lua b/Tools/com.renoise.Sononymph.xrnx/AppUI.lua index b8427069..dea67baa 100644 --- a/Tools/com.renoise.Sononymph.xrnx/AppUI.lua +++ b/Tools/com.renoise.Sononymph.xrnx/AppUI.lua @@ -420,21 +420,36 @@ function AppUI:create_dialog() renoise.app():show_warning(err or "Failed to set ConfigPath") end else - -- Multiple versions found - show dropdown for selection + -- Multiple versions found - apply the newest one right away and + -- offer the dropdown in case an older one is wanted. + -- Do NOT rely on the popup notifier to apply the first entry: + -- a popup does not fire its notifier when the picked index is + -- already the current one, and the popup starts at index 1. So + -- picking "the newest" - the obvious choice - would silently + -- leave ConfigPath untouched and the tool stuck on "invalid paths". self.config_paths = versions - + + local newest = versions[1] + local success, err = self.owner:set_path_to_config(newest.path) + if not success then + renoise.app():show_warning(err or "Failed to set ConfigPath") + end + vb.views["path_to_config"].text = newest.path + -- Build dropdown items local dropdown_items = {} for i, version_info in ipairs(versions) do table.insert(dropdown_items, "Sononym " .. version_info.version .. " (" .. version_info.path .. ")") end - - -- Populate the popup menu + + -- Populate the popup menu, pre-selecting the version just applied vb.views["config_path_popup"].items = dropdown_items + vb.views["config_path_popup"].value = 1 -- Show the popup and hide the textfield vb.views["config_path_popup"].visible = true vb.views["path_to_config"].visible = false - renoise.app():show_status("Multiple versions found - please select one") + renoise.app():show_status("ConfigPath set to newest: " .. newest.path + .. " (" .. #versions .. " versions found - pick another from the list if needed)") end end end diff --git a/Tools/com.renoise.Sononymph.xrnx/changelog.md b/Tools/com.renoise.Sononymph.xrnx/changelog.md index b0421531..e77a4ef7 100644 --- a/Tools/com.renoise.Sononymph.xrnx/changelog.md +++ b/Tools/com.renoise.Sononymph.xrnx/changelog.md @@ -1,5 +1,15 @@ # Changelog +## 1.11 + +### Fixes +- **Similarity search now works on Windows**: Sononym answered every search launched from Renoise with `Indexing error - Reason: Unable to resolve location`. The temporary sample file was passed with forward slashes (`C:/Users/.../Renoise_TmpFile.flac`), which Sononym's crawler cannot resolve. Arguments handed to the Sononym executable are now converted to native separators (`App.native_path()`); the same applies to Browse Folder in Sononym. +- **Quoted the search argument**: the temp file path was passed unquoted, so a user or temp folder containing a space broke the launch. +- **"Detect" applied nothing when several Sononym versions were installed**: with 2+ versions the button only populated the dropdown and relied on its notifier. A popup does not fire its notifier when the picked index is already the current one, and it starts at index 1 - so choosing the newest version, the obvious choice, silently left ConfigPath unset and the tool stuck on "invalid paths". Detect now applies the newest version immediately and keeps the dropdown for picking an older one. +- **"Open Path" crashed when ConfigPath was unset**: `App.lua:1521: attempt to concatenate local 'directory_path' (a nil value)`, which Renoise reports as the tool failing in one of its notifiers. Empty and non-matching paths are now reported in the status bar, and both unix and windows separators are accepted. The Linux branch of the same function assigned its command to `os_name` instead of `command`, so Open Path threw there too. +- **A Sononym update no longer breaks the configuration**: Sononym keeps `query.json` in a version-named folder, so `.../Sononym/1.6.2/query.json` becomes `.../Sononym/1.6.14/query.json` as soon as Sononym updates itself. The tool was left pointing at a file that no longer existed and simply reported "invalid paths". It now adopts the newest version it can find and says which one in the status bar. +- **AppPath and ConfigPath are written to disk when set**, rather than only being held in memory until Renoise shuts down cleanly. + ## 1.10 ### New Features diff --git a/Tools/com.renoise.Sononymph.xrnx/main.lua b/Tools/com.renoise.Sononymph.xrnx/main.lua index e5d2e9ba..a1940796 100644 --- a/Tools/com.renoise.Sononymph.xrnx/main.lua +++ b/Tools/com.renoise.Sononymph.xrnx/main.lua @@ -79,7 +79,7 @@ require ('App') -- local variables & initialization --------------------------------------------------------------------------------------------------- local TOOL_NAME = "Sononymph" -local TOOL_VERSION = "1.10" +local TOOL_VERSION = "1.11" local prefs = AppPrefs() renoise.tool().preferences = prefs diff --git a/Tools/com.renoise.Sononymph.xrnx/manifest.xml b/Tools/com.renoise.Sononymph.xrnx/manifest.xml index c18033f9..a38e9525 100644 --- a/Tools/com.renoise.Sononymph.xrnx/manifest.xml +++ b/Tools/com.renoise.Sononymph.xrnx/manifest.xml @@ -2,7 +2,7 @@ Sononymph com.renoise.Sononymph - 1.10 + 1.11 6 danoise & esaruoho false From e5b9bb138db6f388ead70fdadf8753e61bc091b9 Mon Sep 17 00:00:00 2001 From: esaruoho Date: Mon, 7 Sep 2026 20:03:56 +0300 Subject: [PATCH 2/2] Sononymph: address review - no manual preference saving, use open_path() - Renoise persists tool preferences by itself, so App:save_preferences() and its three call sites are removed. - OpenConfigPath checks that the config folder exists and says so when it does not, instead of reporting the path shape, and opens the folder with renoise.app():open_path() rather than a per-platform shell command. This also removes the Linux branch that assigned to os_name instead of command. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01WzMBd9wYDRk4Pu341ggkSv --- Tools/com.renoise.Sononymph.xrnx/App.lua | 38 ++----------------- Tools/com.renoise.Sononymph.xrnx/changelog.md | 3 +- 2 files changed, 5 insertions(+), 36 deletions(-) diff --git a/Tools/com.renoise.Sononymph.xrnx/App.lua b/Tools/com.renoise.Sononymph.xrnx/App.lua index ea99d9c8..a0c27801 100644 --- a/Tools/com.renoise.Sononymph.xrnx/App.lua +++ b/Tools/com.renoise.Sononymph.xrnx/App.lua @@ -203,23 +203,6 @@ end --------------------------------------------------------------------------------------------------- -- check paths and update "paths_are_valid" with result --- persist the preferences to disk. --- setting a value on the document only keeps it in memory until Renoise shuts --- down cleanly - writing it out immediately means a configured path also --- survives a crash. - -function App:save_preferences() - local ok,err = pcall(function() - self.prefs:save_as("preferences.xml") - end) - if not ok then - LOG("Sononymph: could not save preferences:",err) - end -end - ---------------------------------------------------------------------------------------------------- --- check paths and update "paths_are_valid" with result - function App:check_paths() TRACE("App:check_paths()") @@ -246,7 +229,6 @@ function App:check_paths() LOG("check_paths: stored ConfigPath is gone ("..tostring(path) ..") - switching to detected Sononym "..newest.version..": "..newest.path) self.prefs.path_to_config.value = cFilesystem.unixslashes(newest.path) - self:save_preferences() path = self.prefs.path_to_config.value success,err = App.check_path(path) if success then @@ -357,7 +339,6 @@ function App:set_path_to_exe(file_path) file_path = cFilesystem.unixslashes(file_path) self.prefs.path_to_exe.value = file_path - self:save_preferences() local success,err = App.check_path(file_path) if not success then self:stop_monitoring() @@ -389,7 +370,6 @@ function App:set_path_to_config(file_path) file_path = cFilesystem.unixslashes(file_path) self.prefs.path_to_config.value = file_path - self:save_preferences() local success,err = App.check_path(file_path) if not success then self:stop_monitoring() @@ -1592,23 +1572,13 @@ function OpenConfigPath() -- accept both unix and windows separators: the path can be typed in by hand local directory_path = config_path:match("(.*[/\\])") - if not directory_path then - renoise.app():show_status("Sononymph: ConfigPath does not look like a file path: "..config_path) + if not directory_path or not io.exists(directory_path) then + renoise.app():show_status("Sononymph: the ConfigPath folder does not exist: "..config_path) return end - local os_name = os.platform() - local command - if os_name == "WINDOWS" then - command = 'start "" "' .. App.native_path(directory_path) .. '"' - elseif os_name == "MACINTOSH" then - command = 'open "' .. directory_path .. '"' - else - command = 'xdg-open "' .. directory_path .. '"' - end - - LOG("OpenConfigPath:",os_name,config_path,command) - os.execute(command .. " &") + LOG("OpenConfigPath:",directory_path) + renoise.app():open_path(directory_path) end diff --git a/Tools/com.renoise.Sononymph.xrnx/changelog.md b/Tools/com.renoise.Sononymph.xrnx/changelog.md index e77a4ef7..d7563ba4 100644 --- a/Tools/com.renoise.Sononymph.xrnx/changelog.md +++ b/Tools/com.renoise.Sononymph.xrnx/changelog.md @@ -6,9 +6,8 @@ - **Similarity search now works on Windows**: Sononym answered every search launched from Renoise with `Indexing error - Reason: Unable to resolve location`. The temporary sample file was passed with forward slashes (`C:/Users/.../Renoise_TmpFile.flac`), which Sononym's crawler cannot resolve. Arguments handed to the Sononym executable are now converted to native separators (`App.native_path()`); the same applies to Browse Folder in Sononym. - **Quoted the search argument**: the temp file path was passed unquoted, so a user or temp folder containing a space broke the launch. - **"Detect" applied nothing when several Sononym versions were installed**: with 2+ versions the button only populated the dropdown and relied on its notifier. A popup does not fire its notifier when the picked index is already the current one, and it starts at index 1 - so choosing the newest version, the obvious choice, silently left ConfigPath unset and the tool stuck on "invalid paths". Detect now applies the newest version immediately and keeps the dropdown for picking an older one. -- **"Open Path" crashed when ConfigPath was unset**: `App.lua:1521: attempt to concatenate local 'directory_path' (a nil value)`, which Renoise reports as the tool failing in one of its notifiers. Empty and non-matching paths are now reported in the status bar, and both unix and windows separators are accepted. The Linux branch of the same function assigned its command to `os_name` instead of `command`, so Open Path threw there too. +- **"Open Path" crashed when ConfigPath was unset**: `App.lua:1521: attempt to concatenate local 'directory_path' (a nil value)`, which Renoise reports as the tool failing in one of its notifiers. Empty and non-matching paths are now reported in the status bar, and both unix and windows separators are accepted. The folder is now opened with `renoise.app():open_path()` instead of a hand-rolled per-platform shell command, which also fixes Linux, where the branch assigned its command to `os_name` instead of `command` and threw. - **A Sononym update no longer breaks the configuration**: Sononym keeps `query.json` in a version-named folder, so `.../Sononym/1.6.2/query.json` becomes `.../Sononym/1.6.14/query.json` as soon as Sononym updates itself. The tool was left pointing at a file that no longer existed and simply reported "invalid paths". It now adopts the newest version it can find and says which one in the status bar. -- **AppPath and ConfigPath are written to disk when set**, rather than only being held in memory until Renoise shuts down cleanly. ## 1.10