I’ve coded myself into a dead end and I’m feeling a bit hopeless. Hopefully when I wake up tomorrow someone will have solved this for me? Pretty please?
The code (doesn’t do anything useful yet…)
Click to view contents
--[[Globals]]--
local my_interface = nil
local vb = nil
local gridpie_idx = nil
local x_pos = 1
local y_pos = 1
--[[Future]]--
local matrix_width = 4
local matrix_height = 4
local matrix_cells = table.create{}
local matrix_view = nil
--------------------------------------------------------------------------------
-- Keyboard input
--------------------------------------------------------------------------------
function key_handler(dialog, key)
if (key.name == "esc") then
dialog:close()
else
return key
end
end
--------------------------------------------------------------------------------
-- Build GUI Interface
--------------------------------------------------------------------------------
function build_interface()
-- Init VB
vb = renoise.ViewBuilder()
-- Buttons
local button_view = vb:row {
vb:text {
text = "x:",
font = "mono",
},
vb:valuebox {
min = 1,
value = x_pos,
notifier = function(val)
x_pos = val
adjust_grid()
end
},
vb:text {
text = " y:",
font = "mono",
},
vb:valuebox {
min = 1,
value = y_pos,
notifier = function(val)
y_pos = val
adjust_grid()
end
},
}
-- Checkmark Matrix
local matrix_view = vb:row { }
for x = 1, matrix_width do
local column = vb:column { margin = 2, spacing = 2, }
matrix_cells[x] = table.create()
for y = 1, matrix_height do
matrix_cells[x][y] = vb:checkbox {
value = false,
notifier = function(val)
toggler(x, y, val)
end
}
column:add_child(matrix_cells[x][y])
end
matrix_view:add_child(column)
end
-- Racks
local rack = vb:column {
id = "my_interface",
uniform = true,
margin = renoise.ViewBuilder.DEFAULT_DIALOG_MARGIN,
spacing = renoise.ViewBuilder.DEFAULT_CONTROL_SPACING,
vb:column {
vb:horizontal_aligner {
mode = "center",
button_view,
},
},
vb:space { height = 10 },
vb:column {
vb:horizontal_aligner {
mode = "center",
matrix_view,
},
},
}
-- Show dialog
my_interface = renoise.app():show_custom_dialog("Grid Pie", rack, key_handler)
end
--------------------------------------------------------------------------------
-- Abort
--------------------------------------------------------------------------------
function abort()
print("TODO: Abort!")
end
--------------------------------------------------------------------------------
-- Access a cell in the matrix view
--------------------------------------------------------------------------------
function matrix_cell(x, y)
if (matrix_cells[x] ~= nil) then
return matrix_cells[x][y]
else
return nil
end
end
--------------------------------------------------------------------------------
-- Initialize PM
--------------------------------------------------------------------------------
function init_pm()
local rns = renoise.song()
local tracks = rns.tracks
local sequencer = rns.sequencer
local total_tracks = #tracks
local total_sequence = #sequencer.pattern_sequence
for x = 1, total_tracks do
if
tracks[x].type ~= renoise.Track.TRACK_TYPE_MASTER and
tracks[x].type ~= renoise.Track.TRACK_TYPE_SEND
then
for y = 1, total_sequence do
renoise.song().sequencer:set_track_sequence_slot_is_muted(x , y, true)
end
end
end
end
--------------------------------------------------------------------------------
-- Initialize Grid Pie Pattern
--------------------------------------------------------------------------------
function init_gp_pattern()
local rns = renoise.song()
local tracks = rns.tracks
local total_tracks = #tracks
local sequencer = rns.sequencer
local total_sequence = #sequencer.pattern_sequence
local last_pattern = rns.sequencer:pattern(total_sequence)
if rns.patterns[last_pattern].name ~= "__GRID_PIE__" then
-- Create new pattern
local new_pattern = rns.sequencer:insert_new_pattern_at(total_sequence + 1)
rns.patterns[new_pattern].name = "__GRID_PIE__"
gridpie_idx = new_pattern
else
-- Clear pattern, unmute slot
rns.patterns[last_pattern]:clear()
rns.patterns[last_pattern].name = "__GRID_PIE__"
for x = 1, total_tracks do
renoise.song().sequencer:set_track_sequence_slot_is_muted(x , total_sequence, false)
end
gridpie_idx = last_pattern
end
-- Cleanup any other pattern named __GRID_PIE__
for x = 1, total_sequence - 1 do
local tmp = rns.sequencer:pattern(x)
if rns.patterns[tmp].name == "__GRID_PIE__" then
rns.patterns[tmp].name = ""
end
end
-- Move playhead to last pattern
rns.selected_sequence_index = #sequencer.pattern_sequence
rns.transport.follow_player = false
rns.transport.loop_pattern = true
-- Set Observables
if not (rns.transport.follow_player_observable:has_notifier(abort)) then
rns.transport.follow_player_observable:add_notifier(abort)
end
if not (rns.transport.loop_pattern_observable:has_notifier(abort)) then
rns.transport.loop_pattern_observable:add_notifier(abort)
end
-- Start playback
rns.transport:start(renoise.Transport.PLAYMODE_RESTART_PATTERN)
end
--------------------------------------------------------------------------------
-- Is garbage PM position?
--------------------------------------------------------------------------------
function is_garbage_pos(x, y)
-- Garbage position?
local rns = renoise.song()
local sequencer = rns.sequencer
local total_sequence = #sequencer.pattern_sequence
local last_pattern = rns.sequencer:pattern(total_sequence)
if rns.sequencer.pattern_sequence[y] == nil then
return true
elseif rns.tracks[x] == nil then
return true
elseif last_pattern == y then
return true
else
return false
end
end
--------------------------------------------------------------------------------
-- Adjust grid
--------------------------------------------------------------------------------
function adjust_grid()
-- TODO: How do I avoid?
-- 'notifier feedback loop detected. do not change values you are listening to within your notifiers.'
local rns = renoise.song()
local cell = nil
for x = x_pos, matrix_height + x_pos - 1 do
for y = y_pos, matrix_width + y_pos - 1 do
cell = matrix_cell(x - x_pos + 1, y - y_pos + 1)
if cell ~= nil and not is_garbage_pos(x, y) then
local val = rns.sequencer:track_sequence_slot_is_muted(x, y)
cell.value = (not val)
end
end
end
end
--------------------------------------------------------------------------------
-- Toggler
--------------------------------------------------------------------------------
function toggler(x, y, val)
local rns = renoise.song()
x = x + (x_pos - 1)
y = y + (y_pos - 1)
-- Change PM
for i = 1, matrix_height do
if not is_garbage_pos(x, i) then
if i == y and val == true then
rns.sequencer:set_track_sequence_slot_is_muted(x , i, false)
else
rns.sequencer:set_track_sequence_slot_is_muted(x , i, true)
end
end
end
adjust_grid()
-- TODO: Copy to gridpie_idx!
end
--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------
function main()
if (not my_interface or not my_interface.visible) then
build_interface()
init_pm()
init_gp_pattern()
end
run()
end
--------------------------------------------------------------------------------
-- Idler
--------------------------------------------------------------------------------
function idler()
if (not my_interface or not my_interface.visible) then
stop()
return
end
end
--------------------------------------------------------------------------------
-- Bootsauce
--------------------------------------------------------------------------------
function run()
if not (renoise.tool().app_idle_observable:has_notifier(idler)) then
renoise.tool().app_idle_observable:add_notifier(idler)
end
end
function stop()
if (renoise.tool().app_idle_observable:has_notifier(idler)) then
renoise.tool().app_idle_observable:remove_notifier(idler)
end
if (renoise.song().transport.follow_player_observable:has_notifier(abort)) then
renoise.song().transport.follow_player_observable:remove_notifier(abort)
end
if (renoise.song().transport.loop_pattern_observable:has_notifier(abort)) then
renoise.song().transport.loop_pattern_observable:remove_notifier(abort)
end
vb = nil -- Destroy vb
end
--------------------------------------------------------------------------------
-- Menu Registration
--------------------------------------------------------------------------------
renoise.tool():add_menu_entry {
name = "Main Menu:Tools:GridPie...",
invoke = main
}
The problem:
*** std::runtime_error: 'notifier feedback loop detected. do not change values you are listening to within your notifiers.'
*** stack traceback:
*** [C]: ?
*** [C]: in function '__newindex'
*** [string "do..."]:22: in function
*** main.lua:259: in function 'adjust_grid'
*** main.lua:289: in function 'toggler'
*** main.lua:80: in function <79><br>
*** [C]: ?<br>
*** [C]: in function '__newindex'<br>
*** [string "do..."]:22: in function <br>
*** main.lua:259: in function 'adjust_grid'<br>
*** main.lua:289: in function 'toggler'<br>
*** main.lua:80: in function <79><br>
<br>```
<br>
<br>
Basically, it's a matrix of checkmarks that controls the PM mute states. What need to happen. <br>
<br>
* Unlimited checkmarks on the X (horizontal) axis.<br>
* Only 1 checkmark on the Y (vertical) axis.<br>
<br>
Problem is that when when I change the values on the Y axis, it goes into the above feedback loop.<br>
<br>
I don't know how to solve this problem. I've been at it for hours and am stumped.<br>
<br>
Help!</79></79>