Old 02-01-2018, 05:47 PM   #1
pipelineaudio
Mortal
 
pipelineaudio's Avatar
 
Join Date: Jan 2006
Location: Wickenburg, Arizona
Posts: 13,585
Default Sending a bypass on program change

I need to either send a CC 0 or a parameter bypass to all tracks whenever I recieve a program change message, can you think of any way to do this?
pipelineaudio is offline   Reply With Quote
Old 04-01-2018, 03:15 AM   #2
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default

I'm thinking of doing something similar:
Code:
- an action script that does this:
  1) Take one parameter, the track to enable
  2) Loop over all tracks, skipping master and folder tracks
     If a track is not the parameter track,
       SetMediaTrackInfo(track, "I_FXEN", 0)
     Else
       SetMediaTrackInfo(track, "I_FXEN", -1)

- set up your own ReaperOSC map so that when
  you send action/NNN/track/MMM,
  the "MMM" gets passed to your action script
Ideally, I'd have liked to do this on MIDI PgmChg but I don't think there's a way without resorting to the C++ API. (I spent yesterday failing with JSFX... I refused to believe what I was reading in the manual...) I don't even know if the above will work yet...
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.
pljones is offline   Reply With Quote
Old 04-01-2018, 06:47 AM   #3
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default

... And, having investigated further, you would need one script per track, as it's still not possible to read parameters passed via OSC.

-edit-
You can put the loop script into one function in a library script and require that into each of the track scripts, though, which keeps them simpler. The track script then looks something like this, for track 1.
Code:
require 'Scripts.toggleTrackEnable'
function run()
  toggleTrackEnable(1)
  reaper.defer(run)
end

reaper.defer(run)
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.

Last edited by pljones; 04-01-2018 at 07:59 AM. Reason: expand...
pljones is offline   Reply With Quote
Old 04-01-2018, 10:59 AM   #4
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default

v0.5 is a rather significant set of changes. I still wouldn't consider it 1.x...

I gave up on anything but the toggleTrackEnable{N}.lua approach. Right now, as I'm working on multiple computers, I have my scripts on a shared drive - so long as everything is in the same folder, the same magic in the toggleTrackEnable{N}.lua files works...

So here's the new toggleTrackEnable.lua - now with comments as it's rather specific to the use I'm putting it to.

{pathTo...}\Scripts\toggleTrackEnable.lua:
Code:
--[[
/**
 * ReaScript Name: toggleTrackEnable
 * Description: Toggle Track Enable
 * Instructions: Install this in user reaper scripts.
 * Author: pljones
 * Licence: GPL v3
 * Version: 0.5
 */
]]
function toggleTrackEnable()
  is_new,name,sec,cmd,rel,res,val = reaper.get_action_context()
  if not(is_new) then
    return
  end

  -- val is just boolean but we want -1, not the 1 that's passed by OSC
  if not(val == 0) then val = -1 end

  -- the only way to get info from the OSC input trigger... ugh, ugh, ugh...
  -- but it works more or less
  local tkNo = name:match([[toggleTrackEnable(%d*)%.lua$]])
  if (tkNo == nil) then
    return
  end

  -- OSC tkNo from above starts at 1
  -- Reaper GetTrack is zero based
  -- The ReaperOSC 
  -- TRACK_SELECT b/track/@/onOff
  -- mapping also maps OSC @=1 to Reaper GetTrack=0

  -- Unfortunately, because of the extra "Sound source parent SEND" Reaper track,
  -- in my project file, I need to do some magic...
  -- OSC tkNo 1 needs to map to Reaper GetTrack 1.
  
  -- Hence, the OSC mapping will have touched the wrong track, so turn it off.
  local track = reaper.GetTrack(0, tkNo - 1)
  if (track == nil) then
    return
  end
  reaper.SetTrackSelected(track, 0)

  -- And now, get the intended track
  track = reaper.GetTrack(0, tkNo)

  -- if this track is not a sound source (see below), ignore the request
  if not(canToggle(track)) then
    return
  end

  _toggleTrackEnableN(tkNo, track)

end

--[[
  A track can be toggled if it has MIDI In for All inputs.
  That's just how life is in my project file...
]]
function canToggle(track)
  local recInput = reaper.GetMediaTrackInfo_Value(track, "I_RECINPUT")
  -- Is this a MIDI track?
  if recInput & 4096 == 0 then
    return false
  end
  -- Is this receiving all inputs?
  return recInput & 31 == 0
end

function _toggleTrackEnableN(tkNo, track)
--  local isTkFxEnabled = reaper.GetMediaTrackInfo_Value(track, "I_FXEN")
--  reaper.ShowConsoleMsg("track " .. tkNo .. "; setting " .. val .. "; isTkFxEnabled " .. isTkFxEnabled .. "\n")
  local srTk = 0
  local search = reaper.GetTrack(0, srTk)
  local srVal = 0

  while not(search == nil) do
    if canToggle(search) then

      -- For the target track, apply the OSC val, otherwise, turn off
      if ((0 + srTk) == (0 + tkNo)) then srVal = val else srVal = 0 end
      reaper.SetMediaTrackInfo_Value(search, "I_FXEN", srVal)
      -- Trigger the ReaperOSC mapping for feedback
      -- See notes above for why the mess is needed...
      reaper.SetTrackSelected(reaper.GetTrack(0, srTk - 1), srVal)

    end
    srTk = srTk + 1
    search = reaper.GetTrack(0, srTk)
  end

end
Then, place multiple copies of the following (the "1" being the first - the "1" is important as it's used as the track number in the above) in the same folder as the main script. The script content is identical in each copy. (This hasn't changed since v0.1, I think.)
{pathTo...}\Scripts\toggleTrackEnable1.lua:
Code:
dofile(debug.getinfo(1,'S').source:match[[^@?(.*[\/])[^\/]-$]] .. 'toggleTrackEnable.lua')
reaper.defer(toggleTrackEnable)
Now... The reason for that "off by one" malarkey in the main script is because I had 80-odd copies of toggleTrackEnable{N}.lua already mapped up as actions and didn't want to have to remap everything. Of course, when I moved them to the shared folder, I had to remap everything (though a quick edit/replace-all sorted that) and maybe I could have fixed the issue there... Oh well...

So, bind each toggleTrackEnable{N}.lua to your controller - I'm sending "/track/{N}/onOff {val}" from mine.

v0.4 and later include support for feedback using the ReaperOSC mapping file and track selection. Create (and activate) a mapping with this content:
Code:
DEVICE_TRACK_COUNT 100
# Have a toggle button that sends this:
TRACK_SELECT b/track/@/onOff
Remember, this is a bi-directional mapping. So if you change the selected track in Reaper, Reaper emits the OSC command. But it does not run the script! So all of a sudden, your controller is out of sync with Reaper...

0.5 brings a big new feature. I've added two more buttons to my TouchOSC controller (I'll attach that, too). These let me toggle what I'm hearing between incoming audio from ReaNINJAM and Jamulus. That's why I've now got the "Sound source parent SEND" track mentioned in the main script above. All my sound sources route through that, that gets send to two output (ReaNINJAM outgoing and ReaRoute output to Jamulus) tracks; the input from these services each has its own track (ReaNINJAM input being direct from the output track as it's a "thru" plugin; and Jamulus ReaRoute audio in) which then route to the Master out. It's this final step - the send to Master - that's controlled.

Simple, huh?
Code:

--[[
/**
 * ReaScript Name: enableOnlineService
 * Description: Switches between two online services for monitoring purposes.
 * Instructions:
 *  # Install this in user reaper scripts
 *  # Ensure /{service}/onOff is bound to enableService-{service}.lua (because there's no way to look up the shortcut).
 *  # Ensure online service track receive exists, called {service} RECEIVE (and no others like that).
 * Currently there is no feedback as it's not possible to send OSC from a script (and I can't think how to fake it here).
 * Author: pljones
 * Licence: GPL v3
 * Version: 0.2
 */
]]
-- Put these two lines into enableService-{service}.lua for each {service}:
-- dofile(debug.getinfo(1,'S').source:match[[^@?(.*[\/])[^\/]-$]] .. 'enableOnlineService.lua')
-- reaper.defer(enableService)

function initService()
  if not(initServiceDone == nil) then
    return
  end

  hwMidiOut = nil
  SVC_ENABLE = 110 -- CC no for service controls

  local wantedMIDIOutputName = "TouchOSC Bridge"
  local numMIDIOutputs = reaper.GetNumMIDIOutputs()

  local midiOut = 0
  while midiOut < numMIDIOutputs
  do
    retval, nameout = reaper.GetMIDIOutputName(midiOut, "")
    if not(nameout == nil) and nameout == wantedMIDIOutputName then
      hwMidiOut = midiOut
      midiOut = numMIDIOutputs
    end
    midiOut = midiOut + 1
  end
--  reaper.ShowConsoleMsg("initService: " .. wantedMIDIOutputName .. " " .. hwMidiOut .. "\n")
  
  initServiceDone = true

end

function enableService()
  is_new,name,sec,cmd,rel,res,val = reaper.get_action_context()
  if not(is_new) then
    return
  end

  local service = name:match("^.+enableService%-?(.+)%.lua$")
  if (service == nil) then
    return
  end

  _enableService(service)
end

function _enableService(service)
--  reaper.ShowConsoleMsg("service " .. service .. "; val " .. val .. "\n")
  local serviceNo = 0

  local srTk = 0
  local search = reaper.GetTrack(0, srTk)
  while(not (search == nil))
  do

    local retVal, searchName = reaper.GetSetMediaTrackInfo_String(search, "P_NAME", "", false)
    if (not(searchName == nil)) then
      local receiveName = searchName:match("^(.+) RECEIVE$")
      if (not(receiveName == nil)) then

        -- it's a service receive
        local ret
        if (service == receiveName) then
          -- this is track we are looking for
--[[
          Previously this side simply set the value "on" (1) for both commands
          Now it reads and toggles
]]
          local val = reaper.GetMediaTrackInfo_Value(search, "B_MAINSEND")
          if not(val == 0) then val = 0 else val = 1 end
          ret = reaper.SetMediaTrackInfo_Value(search, "B_MAINSEND", val)
          reaper.StuffMIDIMessage(16 + hwMidiOut, 0xBF, SVC_ENABLE + serviceNo, val)
--[[
        else
          -- it's a service receive but a different one
          ret = reaper.SetMediaTrackInfo_Value(search, "B_MAINSEND", 0)
          reaper.StuffMIDIMessage(16 + hwMidiOut, 0xBF, SVC_ENABLE + serviceNo, 0)
]]
        end
        serviceNo = serviceNo + 1

      end
    end

    srTk = srTk + 1
    search = reaper.GetTrack(0, srTk)

  end

end

initService()
Yay for StuffMIDIMessage! This is what's known as a "nasty hack". The buttons send OSC and are not MIDI-enabled. Instead, I have an LED overlay that is MIDI-enabled. We also ensure this goes out the TouchOSC Bridge. The script relies on track names to find the desired input (i.e. "{service} RECEIVE" track is the one) and sets the track main send on or off appropriately. As I only want one in, it turns any other "... RECEIVE" tracks off.

The new buttons are down the bottom right on every tab, like this:

And that's created through the ns_kit7+NIAR+AD-muxed v4.touchosc file (I had to rename it to add .ZIP to allow it to be attached, so rename it back to remove the extra .ZIP before trying to open it in TouchOSC Editor).

I'd make the RPP available but it's 32Mb and probably not much use, directly... Instead, JamulusReaNINJAM.rpp is a mini demo that works with the scripts and the TouchOSC layout. You can add additional sound source tracks under the "Sound source parent SEND" and it should keep working (up to however many mapped OSC toggles you have).

Change Log
0.5 / 0.2: Minor update to the receive toggles not to be mutually exclusive any more - proved more harm than good in use
0.5: Significant rewrite plus enableOnlineService.lua script, Touch OSC mapping and sample Reaper project file
0.4: Add track selection to trigger OSC feedback (as there's no API for it directly)
0.3: Fix off by one error
0.2: Loop over all tracks and disable them if not the target track
0.1: Initial version
Attached Images
File Type: png ns_kit7+NIAR+AD-muxed v4.touchosc-tab1.png (61.8 KB, 102 views)
Attached Files
File Type: zip ns_kit7+NIAR+AD-muxed v4.touchosc.ZIP (6.7 KB, 9 views)
File Type: rpp JamulusReaNINJAM.rpp (6.0 KB, 11 views)
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.

Last edited by pljones; 02-07-2020 at 01:08 PM. Reason: v0.5 / v0.2
pljones is offline   Reply With Quote
Old 01-26-2019, 01:13 PM   #5
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default

I made some significant headway with feedback - by cheating. When I send the "/track/1/onOff n" message from my control surface by pressing a toggle switch, I've made the script deselect all tracks and then select a track where n is 1. With the ReaperOSC config above, this also then sends back to the control surface the OSC message "/track/x/onOff y" where x is all tracks and y is 0, turning off the toggle switch, this is then followed by "/track/1/onOff 1" which is already the control surface state so it does nothing.
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.
pljones is offline   Reply With Quote
Old 12-31-2019, 05:08 PM   #6
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default TouchOSC, Reaper, Track Control and feedback

Bit of a bump as I've done a v0.5, adding a new feature, along with the TouchOSC mapping and a sample Reaper RPP project file that uses the scripts.

One thing I'm considering is whether the FX enable method is the "right" one. It works for MIDI generated sounds. If you've an Audio In with no FXs, it doesn't really help - you want to toggle monitoring, too. So I might add that at some point.

I'm also thinking each server enable should be an independent toggle - despite a lot of the effort for the script having been to only have one enabled at a time...
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.

Last edited by pljones; 01-13-2020 at 03:13 PM.
pljones is offline   Reply With Quote
Old 02-07-2020, 01:09 PM   #7
pljones
Human being with feelings
 
pljones's Avatar
 
Join Date: Aug 2007
Location: London, UK
Posts: 657
Default

Bump for v0.2 of the service toggle script - it proved more useful to have to make the choice of one or both being active manually, rather than having the script enforce only one.

(And yes, if a mod fancies splitting this thread between #3 and #4, that would probably help...)
__________________
Quote:
Originally Posted by Tony Williams
...Playing fast around the drums is one thing. But to play with people for others, to listen to, that's something else. That's a whole other world.
pljones is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:09 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.