Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable or Disable Report changes made via control surfaces actions #1054

Open
reaperaccessible opened this issue Apr 17, 2024 · 12 comments
Open

Comments

@reaperaccessible
Copy link

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.

@ScottChesworth
Copy link
Collaborator

Does calling ID _OSARA_MUTENEXTMESSAGE first silence the report?

@reaperaccessible
Copy link
Author

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.

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

@reaperaccessible
Copy link
Author

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)

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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)

@reaperaccessible
Copy link
Author

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

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

@reaperaccessible
Copy link
Author

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.

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

@jcsteh
Copy link
Owner

jcsteh commented Apr 17, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants