osara
osara copied to clipboard
Enable or Disable Report changes made via control surfaces actions
Would it be possible not to have the names of the following 2 actions stated by OSARA when they are triggered: OSARA: Disable Report changes made via control surfaces OSARA: Enable Report changes made via control surfaces These 2 actions must remain silent for it to be usable. In some very complex script or in CSI, I need to mutate the next message from Osara and disable feedback from control surfaces. Once the script work is complete, I re-enable everything before the script out. The problem is that these 2 actions make NVDA speaking. So, this is very complicated to manage. But at the same time, I would find it a shame not to have feedback on these 2 actions in other circumstances. Or, maybe create 2 other actions that would completely mutate OSARA and one that would activate it. Thanks to consider this request.
Does calling ID _OSARA_MUTENEXTMESSAGE first silence the report?
Sometimes it gets the job done but sometimes CSI has to run multiple tasks consecutively and then NVDA speaks gibberish and nothing can stop it except Ctrl or the end of his message. For some reason, in certain circumstances OSARA: Mute next message from OSARA is not sufficient, I have to add the action 3 times in a row. It's really not easy because I have to try all the formulas in order to find the right one. Sometimes I have to trigger the action at the beginning of the code, sometimes in the middle or at the end, it's never the same twice. I really think that 2 actions that could completely mutate OSARA while the code is running would be perfect, but again I'm not sure, I have to test it. But at the moment I can't do the tests I would like because I have no way to completely disable OSARA while the code is running.
The idea is that you should run OSARA: Mute next message before any action that might normally provide feedback. If you're running two actions that might provide feedback, you need OSARA: Mute next message before each one; i.e. Mute next message, action1, Mute next message, action2. If you're seeing cases where that doesn't work, please provide specific steps to reproduce and we can look into it.
Here is a lua script that is problematic. This script selects the last track in the folder only if the parent or child folder track is selected. The script works perfectly if the parent or child track of a folder is selected. But if I select a track that is not in a track folder, the script is supposed to speak the message "Selected track is not in a folder." But he cannot state that message because OSARA must state "OSARA: Enable Report changes made via control surfaces" However, reactivating control surface feedback is completely at the end of the script. This script is very simple, now imagine in CSI code. I waste a lot of time finding the right formula for each piece of code. Thanks for your help guys. Here is the script:
-- OSARA: Disable Report changes made via control surfaces reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_CONFIG_reportSurfaceChanges_DISABLE"), 0, 0)
-- Function to open track folder if necessary function openFolderIfClosed(track) local folderDepth = reaper.GetMediaTrackInfo_Value(track, "I_FOLDERDEPTH")
-- If the folder is closed, open it
if folderDepth == 1 then
reaper.SetMediaTrackInfo_Value(track, "I_FOLDERCOMPACT", 0)
end
end
-- Function to select the last track in the track folder relative to the currently selected track function getLastTrackInFolder() -- Get the currently selected track local selectedTrack = reaper.GetSelectedTrack(0, 0)
if selectedTrack ~= nil then
-- Open track folder if necessary
openFolderIfClosed(selectedTrack)
-- Check if the selected track is itself a folder track
local isFolderTrack = reaper.GetMediaTrackInfo_Value(selectedTrack, "I_FOLDERDEPTH") == 1
if isFolderTrack then
-- If the selected track is a folder, find the last track in that folder
local numTracksInFolder = reaper.CountTracks(0)
local lastTrackInFolder = nil
-- Traverse tracks in reverse order to find the last track in the folder
for i = numTracksInFolder, 1, -1 do
local track = reaper.GetTrack(0, i - 1)
if track ~= nil and reaper.GetParentTrack(track) == selectedTrack then
-- Track found in the folder
lastTrackInFolder = track
break
end
end
if lastTrackInFolder == nil then
-- If no track is found, select the folder itself
lastTrackInFolder = selectedTrack
end
-- Output message to indicate end of folder
reaper.osara_outputMessage("End of folder.")
-- Select the last track in the folder
reaper.SetOnlyTrackSelected(lastTrackInFolder)
reaper.TrackList_AdjustWindows(false)
reaper.UpdateArrange()
-- Speak out the name of the last selected track
local _, trackName = reaper.GetTrackName(lastTrackInFolder)
reaper.osara_outputMessage("Last track in folder: " .. trackName)
else
-- If the selected track is not a folder, look into the parent folder
local folderTrack = reaper.GetParentTrack(selectedTrack)
if folderTrack ~= nil then
local numTracksInFolder = reaper.CountTracks(0)
local lastTrackInFolder = nil
-- Traverse tracks in reverse order to find the last track in the folder
for i = numTracksInFolder, 1, -1 do
local track = reaper.GetTrack(0, i - 1)
if track ~= nil and reaper.GetParentTrack(track) == folderTrack then
-- Track found in the folder
lastTrackInFolder = track
break
end
end
if lastTrackInFolder == nil then
-- If no track is found, select the folder itself
lastTrackInFolder = folderTrack
end
-- Output message to indicate end of folder
reaper.osara_outputMessage("End of folder.")
-- OSARA: Mute next message from OSARA
reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_MUTENEXTMESSAGE"), 0, 0)
-- Select the last track in the folder
reaper.SetOnlyTrackSelected(lastTrackInFolder)
reaper.TrackList_AdjustWindows(false)
reaper.UpdateArrange()
-- Speak out the name of the last selected track
local _, trackName = reaper.GetTrackName(lastTrackInFolder)
reaper.osara_outputMessage("Last track in folder: " .. trackName)
else
reaper.osara_outputMessage("Selected track is not in a folder.")
end
end
else
reaper.osara_outputMessage("No track selected.")
end
end
-- Execute the function getLastTrackInFolder()
-- OSARA: Re-enable next messages from OSARA reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_CONFIG_reportSurfaceChanges_ENABLE"), 0, 0)
Looking at this code, you're calling mute next message in one place only: before calling reaper.SetOnlyTrackSelected. But reaper.SetOnlyTrackSelected isn't going to report anything, so you don't want to call it there. I would be calling mute next message only before the other Main_OnCommandEx calls.
So something like this:
-- OSARA: Disable Report changes made via control surfaces
reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_MUTENEXTMESSAGE"), 0, 0)
reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_CONFIG_reportSurfaceChanges_DISABLE"), 0, 0)
-- Function to open track folder if necessary
... other code here ...
-- Execute the function
getLastTrackInFolder()
-- OSARA: Re-enable next messages from OSARA
reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_MUTENEXTMESSAGE"), 0, 0)
reaper.Main_OnCommandEx(reaper.NamedCommandLookup("_OSARA_CONFIG_reportSurfaceChanges_ENABLE"), 0, 0)
Nice, indeed, it works. But between the moment the script is triggered and the message spoken, there is often unnecessary gibberish spoken by NVDA. It's perfectly functional but could be cleaner. Here is another example: This script opens and closes all FX windows for all tracks in a track folder to expose all parameters to Reaper. It works perfectly but while the code is running, NVDA speaks gibberish for 2 seconds. I would have liked to be able to re-enable OSARA when opening the dialog only.
-- Function to open the FX window of a track local function openFXWindow(track) reaper.TrackFX_Show(track, 0, 3) -- Open the FX window (0 represents the first effect on the track) end
-- Function to output message via OSARA local function osaraOutputMessage(message) reaper.osara_outputMessage(message) end
-- Execute the SWS_SELCHILDREN action reaper.Main_OnCommand(reaper.NamedCommandLookup("_SWS_SELCHILDREN"), 0)
-- Get the selected track local selectedTrack = reaper.GetSelectedTrack(0, 0)
-- Check if a track is selected if selectedTrack then -- Get the track folder of the selected track local folderTrack = reaper.GetMediaTrackInfo_Value(selectedTrack, "P_PARTRACK")
-- Check if the track is in a folder
if folderTrack ~= 0 then
-- Get the number of tracks in the folder
local numTracksInFolder = reaper.CountTracks(0)
-- Iterate through all tracks in the folder
for i = 0, numTracksInFolder - 1 do
local trackInFolder = reaper.GetTrack(0, i)
-- Mute OSARA and output the message via OSARA before opening the dialog box
reaper.Main_OnCommand(reaper.NamedCommandLookup("_OSARA_MUTENEXTMESSAGE"), 0)
osaraOutputMessage("All parameters are now available. Press Space to close this window. OK Button")
-- Open the FX window of the track
openFXWindow(trackInFolder)
end
-- Show the message via a dialog box
local result = reaper.ShowMessageBox("All parameters are now available. Press Space to close this window.", "Message", 1)
-- If the user clicks the OK button (result == 1), trigger the S&M_WNCLS3 action
if result == 1 then
reaper.Main_OnCommand(reaper.NamedCommandLookup("_S&M_WNCLS3"), 0)
end
else
-- Show the error message via a dialog box
reaper.ShowMessageBox("The selected track is not in a folder.", "Error", 0)
end
else -- Show the error message via a dialog box reaper.ShowMessageBox("You must select the track folder and trigger this script again.", "Error", 0) end
I don't really understand what this code is doing. But I think you're still missing a key point here, which is that you should only call mute next message before an action which causes OSARA to report something. In this code, you're calling it before outputMessage, which doesn't make sense.
Note also that muting OSARA isn't going to silence other speech from your screen reader. For example, opening a dialog, closing a dialog or focusing a control all cause speech output, but that output does not come from OSARA and thus muting OSARA will not (and cannot) prevent it.
During code execution, NVDA tries to say lots of things but all at the same time so it's gibberish. Opening the dialog box happens later. I know that when opening or closing a dialog box, it is NVDA which states, it is not always OSARA. But here I'm only talking about what OSARA says during code execution in a script. Wouldn't it be simpler to be able to decide exactly when we want to disable and re-enable OSARA? Thanks.
I think it'd be helpful if you could provide a speech history log of what's being said.
Having mute and unmute commands is risky. Putting aside the simple possibility that someone just forgets to unmute, you could also fail to unmute if you returned early from a function or loop or similar. That screws the user pretty badly.
But honestly, the rule is fairly straightforward. If you're going to call Main_OnCommand or friends and that action is one of the actions OSARA supports (per the readme), call mute next message first.
The other thing to keep in mind is that a global mute command would also mute outputMessage, which is, as I understand it, not what you want.
I just realised one thing I haven't accounted for here is surface feedback. In that case, mute next message (or even a mute all action) isn't going to help because the point at which surface messages are sent is somewhat unpredictable. So you probably want to disable surface feedback before tweaking any parameters in the API.