How to implement a "Run" button
This is a repost from the internal Reason dev forum, in case somebody here knows the answer...
I want to implement a button that behaves exactly like the Run button found in devices like Dr Rex or Chord Sequencer:
1) the user can press the Run button, to toggle play/stop
2) the user can use the transport Play/Stop button to also toggle the Run button
I just don't know how to implement such a behavior:
If the user can interact with the button directly, then it has to be tied to a document_owner property (and for the rendering, a toggle_button widget should do the trick)
But because the transport can dictate the state as well, that means the real time code, which is the one receiving the transport information, needs to update the property. Which means the property needs to be rt_owner property.
Since a property cannot belong to 2 different owners, I am not sure how to do this. Can somebody explain the trick to make it work?
Thank you
I want to implement a button that behaves exactly like the Run button found in devices like Dr Rex or Chord Sequencer:
1) the user can press the Run button, to toggle play/stop
2) the user can use the transport Play/Stop button to also toggle the Run button
I just don't know how to implement such a behavior:
If the user can interact with the button directly, then it has to be tied to a document_owner property (and for the rendering, a toggle_button widget should do the trick)
But because the transport can dictate the state as well, that means the real time code, which is the one receiving the transport information, needs to update the property. Which means the property needs to be rt_owner property.
Since a property cannot belong to 2 different owners, I am not sure how to do this. Can somebody explain the trick to make it work?
Thank you
The trick is to implement the Run button as a custom display.
You can hide that fact either by drawing fairly realistic display graphics (the RS approach) or by covering up the display with static decorations that change based on visibility switches (the Robotic Bean approach).
As you've already concluded, you have to use a realtime property to keep track of the "is_running" state, which is calculated in the realtime code by looking at the transport state in combination with various other internal states depending on the requirements of the device.
For the player devices that I wrote (Euclidean, Sequences, Beatmap, Pattern Mutator and Bassline Generator), I have a custom boolean property to indicate whether the Run button is being pressed. When that property turns true it means that the user wants to toggle whatever playback state is active right now, and the realtime code acts accordingly.
Apart from the Reason transport and pressing the Run button, some devices also trigger Run on note on or a pulse on a CV input, so the logic can get pretty complicated.![Smile :-)](./images/smilies/icon_e_smile.gif)
I created a Transport class that manages all these inputs and either follows the Reason song clock, or generates its own clock, depending on the situation.
I hope this helps!
You can hide that fact either by drawing fairly realistic display graphics (the RS approach) or by covering up the display with static decorations that change based on visibility switches (the Robotic Bean approach).
As you've already concluded, you have to use a realtime property to keep track of the "is_running" state, which is calculated in the realtime code by looking at the transport state in combination with various other internal states depending on the requirements of the device.
For the player devices that I wrote (Euclidean, Sequences, Beatmap, Pattern Mutator and Bassline Generator), I have a custom boolean property to indicate whether the Run button is being pressed. When that property turns true it means that the user wants to toggle whatever playback state is active right now, and the realtime code acts accordingly.
Apart from the Reason transport and pressing the Run button, some devices also trigger Run on note on or a pulse on a CV input, so the logic can get pretty complicated.
![Smile :-)](./images/smilies/icon_e_smile.gif)
I created a Transport class that manages all these inputs and either follows the Reason song clock, or generates its own clock, depending on the situation.
I hope this helps!
Thank you @buddard. The description makes a lot of sense. I wished we didn't have to jump through hoops to implement what seems to be a trivial behavior.
Reading your description, I realized I ended up doing something similar for my AB12 switch (I guess I am getting old, not even remembering what I did a few years ago), in particular for the A and B button and I used your approach.
Reading your description, I realized I ended up doing something similar for my AB12 switch (I guess I am getting old, not even remembering what I did a few years ago), in particular for the A and B button and I used your approach.
You guys saved me creating a new topic thanks!pongasoft wrote: ↑09 Apr 2023Thank you @buddard. The description makes a lot of sense. I wished we didn't have to jump through hoops to implement what seems to be a trivial behavior.
Reading your description, I realized I ended up doing something similar for my AB12 switch (I guess I am getting old, not even remembering what I did a few years ago), in particular for the A and B button and I used your approach.
I need to implement a mixer "solo" button that turns the "mute" on all other channels on, and I guess this is exactly the way it needs to be done
![Smile :)](./images/smilies/icon_e_smile.gif)
Murf
Guys I am having trouble with this but I am pretty sure I have implemented it properly.
Here is my hdguid_2D.lua entry:
Here is my motherboard_def.lua entries:
Here is my display.lua entries (Similar to what Yan used in AB switch:
And finally my renderBatch code
The idea here is when the button gets tapped it returns the rt as true in display.lua then the renderbatch sets the document_owner custom display with that value.
Nothing happen though...
in renderBatch the "fCH1_Knob_SoloSelected" var is not receiving the changes returned by the handleSwitchTap function in display.lua?
I have even logged handleSwitchTap to see if it changes in the cpp code when the button is tapped and it doesnt
Any insights would be appreciated!
Murf
Here is my hdguid_2D.lua entry:
Code: Select all
-- CH1_SOLO_PB
front_widgets[#front_widgets + 1] = jbox.custom_display {
graphics = { node = "CH1_SOLO_PB" },
background = jbox.image{ path = "solo_off" },
display_width_pixels = 50,
display_height_pixels = 50,
draw_function = "drawSwitch",
gesture_function = "SwitchGesture",
values = { "/custom_properties/ch1_solo_pb", "/custom_properties/ch1_solo_pb_rt" }
}
Code: Select all
custom_properties = jbox.property_set{
document_owner = {
properties = {
ch1_solo_pb=jbox.boolean{default=false,ui_name=ui_text_ch1_solo_pb,ui_type=ui_selecter_switch,},
}
},
rt_owner = {
properties = {
ch1_solo_pb_rt=jbox.boolean{default=false,ui_name=ui_text_ch1_solo_pb,ui_type=ui_selecter_switch,},
}
},
Code: Select all
function handleSwitchTap(props)
local changes = {}
changes[1] = not props[1];
return { gesture_ui_name = jbox.ui_text("ch1_solo_pb"),property_changes = changes }
end
function drawSwitch(props, di, dr)
local sw = props[2] -- rt version
local switchRect = { left = 0, top = 0, right = di.width, bottom = di.height }
if (sw) then
jbox_display.draw_rect(switchRect, colorOn)
else
jbox_display.draw_rect(switchRect, colorOff)
end
end
Code: Select all
.h def:
fCH1_Knob_Solo_PropertyRef = JBox_MakePropertyRef(fCustomProperties, "ch1_solo_pb");
fCH1_Knob_Solo_RT_PropertyRef = JBox_MakePropertyRef(fCustomProperties, "ch1_solo_pb_rt");
.cpp (renderBatch):
fCH1_Knob_SoloSelected = JBox_GetBoolean(JBox_LoadMOMProperty(fCH1_Knob_Solo_PropertyRef)); //BM t or f
JBox_StoreMOMProperty(fCH1_Knob_Solo_RT_PropertyRef,JBox_MakeBoolean(fCH1_Knob_SoloSelected));
Nothing happen though...
in renderBatch the "fCH1_Knob_SoloSelected" var is not receiving the changes returned by the handleSwitchTap function in display.lua?
I have even logged handleSwitchTap to see if it changes in the cpp code when the button is tapped and it doesnt
Any insights would be appreciated!
Murf
What does the code in SwitchGesture look like, does it delegate properly to handleSwitchTap?Murf wrote: ↑11 Aug 2023
The idea here is when the button gets tapped it returns the rt as true in display.lua then the renderbatch sets the document_owner custom display with that value.
Nothing happen though...
in renderBatch the "fCH1_Knob_SoloSelected" var is not receiving the changes returned by the handleSwitchTap function in display.lua?
I have even logged handleSwitchTap to see if it changes in the cpp code when the button is tapped and it doesnt
Any insights would be appreciated!
Murf
I would probably add some traces in both the display code and the realtime code to see how far you get.
Code: Select all
--------------- Definition ----------------------
function gestureFunction(handlers)
return function(props, di, sp)
local gesture_definition = {
custom_data = {},
handlers = handlers
}
return gesture_definition
end
end
SwitchGesture = gestureFunction{ on_tap = "SwitchTap" }
SwitchTap = switchTapFunction()
NOTE: If I look at the document proprty in the draw function rather than the RT one then clicking the button performs the draw function fine.
The only problem here is I need to "light up" the buttons from renderBatch, not display code.
Actually... If I put all the "which other buttons do what logic when others are pressed" code in the display.lua instead of renderBatch that may work....
Ok I am almost there, I have the switches (buttons) logic working in display.lua, and the buttons turn on and off properly when I click them.
I am not using an RT property anymore, just the doc ones for the UI elements (custom display buttons)
The only problem is.... renderBatch is not seeing the properties change!!!
I have 8 channels each with a solo button, the hdgui_2D.lua is like this (just showing the ch1 here)
Motherboard is as before ( x 8)
display.lua:
and this renderBatch code does not log anything when any of the first 3 channel solo buttons are pressed:
Sorry for such a big post, I think I am missing something simple here...
Murf.
I am not using an RT property anymore, just the doc ones for the UI elements (custom display buttons)
The only problem is.... renderBatch is not seeing the properties change!!!
I have 8 channels each with a solo button, the hdgui_2D.lua is like this (just showing the ch1 here)
Code: Select all
-- CH1_SOLO_PB
front_widgets[#front_widgets + 1] = jbox.custom_display {
graphics = { node = "CH1_SOLO_PB" },
background = jbox.image{ path = "solo_off" },
display_width_pixels = 50,
display_height_pixels = 50,
draw_function = "SwitchDraw1",
gesture_function = "SwitchGesture1",
values = { "/custom_properties/ch1_solo_pb",
"/custom_properties/ch2_solo_pb",
"/custom_properties/ch3_solo_pb",
"/custom_properties/ch4_solo_pb",
"/custom_properties/ch5_solo_pb",
"/custom_properties/ch6_solo_pb",
"/custom_properties/ch7_solo_pb",
"/custom_properties/ch8_solo_pb"
}
}
Code: Select all
custom_properties = jbox.property_set{
document_owner = {
properties = {
ch1_solo_pb=jbox.boolean{default=false,ui_name=ui_text_ch1_solo_pb,ui_type=ui_selecter_switch,},
Code: Select all
format_version = "1.0"
--------------- Definition ----------------------
function gestureFunction(handlers)
return function(props, di, sp)
local gesture_definition = {
custom_data = {},
handlers = handlers
}
return gesture_definition
end
end
function switchTapFunction(input)
return function(props, di, gi, cd) return handleSwitchTap(props,input) end
end
function switchDrawFunction(input)
return function(props, di, dr) return handleSwitchDraw(props,di,input) end
end
SwitchGesture1 = gestureFunction{ on_tap = "SwitchTap1" }
SwitchTap1 = switchTapFunction(1)
SwitchDraw1 = switchDrawFunction(1)
SwitchGesture2 = gestureFunction{ on_tap = "SwitchTap2" }
SwitchTap2 = switchTapFunction(2)
SwitchDraw2 = switchDrawFunction(2)
SwitchGesture3 = gestureFunction{ on_tap = "SwitchTap3" }
SwitchTap3 = switchTapFunction(3)
SwitchDraw3 = switchDrawFunction(3)
SwitchGesture4 = gestureFunction{ on_tap = "SwitchTap4" }
SwitchTap4 = switchTapFunction(4)
SwitchDraw4 = switchDrawFunction(4)
SwitchGesture5 = gestureFunction{ on_tap = "SwitchTap5" }
SwitchTap5 = switchTapFunction(5)
SwitchDraw5 = switchDrawFunction(5)
SwitchGesture6 = gestureFunction{ on_tap = "SwitchTap6" }
SwitchTap6 = switchTapFunction(6)
SwitchDraw6 = switchDrawFunction(6)
SwitchGesture7 = gestureFunction{ on_tap = "SwitchTap7" }
SwitchTap7 = switchTapFunction(7)
SwitchDraw7 = switchDrawFunction(7)
SwitchGesture8 = gestureFunction{ on_tap = "SwitchTap8" }
SwitchTap8 = switchTapFunction(8)
SwitchDraw8 = switchDrawFunction(8)
local colorOn = { r = 0, g = 255, b = 0, a = 200 }
local colorOff = { r = 0, g = 0, b = 0, a = 0 }
function handleSwitchTap(props,input)
local changes = {}
changes[input] = not props[input]
return { gesture_ui_name = jbox.ui_text("ch1_solo_pb"),property_changes = changes }
end
function handleSwitchDraw(props,di, input)
local switchRect = { left = 0, top = 0, right = di.width, bottom = di.height }
if (props[input]) then
jbox_display.draw_rect(switchRect, colorOn)
else
jbox_display.draw_rect(switchRect, colorOff)
end
end
-- nothing to do
NoOpDraw = function(props, di, dr)
end
Code: Select all
fCH1_Knob_SoloSelected = JBox_GetBoolean(JBox_LoadMOMProperty(fCH1_Knob_Solo_PropertyRef)); //BM t or f ( x8)
if (fCH1_Knob_SoloSelected || fCH2_Knob_SoloSelected || fCH3_Knob_SoloSelected ) {
TJBox_Value aVal = JBox_MakeNumber(fCH1_Knob_SoloSelected);
TJBox_Value bVal = JBox_MakeNumber(fCH2_Knob_SoloSelected);
TJBox_Value cVal = JBox_MakeNumber(fCH3_Knob_SoloSelected);
TJBox_Value values[] = {aVal,bVal,cVal};
JBOX_TRACEVALUES("fCH1_Knob_SoloSelected: ^0,fCH2_Knob_SoloSelected: ^1,fCH3_Knob_SoloSelected: ^2", values, 3);
}
Murf.
Ok.. so this apparently doesnt work!:
fCH1_Knob_SoloSelected = JBox_GetBoolean(JBox_LoadMOMProperty(fCH1_Knob_Solo_PropertyRef)); //BM t or f
when I cast to a float everything works![Smile :)](./images/smilies/icon_e_smile.gif)
fCH1_Knob_SoloSelected = JBox_GetBoolean(JBox_LoadMOMProperty(fCH1_Knob_Solo_PropertyRef)); //BM t or f
when I cast to a float everything works
![Smile :)](./images/smilies/icon_e_smile.gif)
I'm not sure why that wouldn't work? I use GetBoolean all the time... But I'm glad you found a way forward!
Ah, I see! Haha, yes, that's a classic, I've been there too a couple of times.
![Laughing :lol:](./images/smilies/icon_lol.gif)
-
- Information
-
Who is online
Users browsing this forum: No registered users and 1 guest