Panning Value is set to "--" - how to automatically set to 32

Hi, I’m working on modifying my delay-script (shortcut for adding +1, +10 or removing -1 or -10 from it via keyboard shortcuts) to also work for panning.

I’ve gotten it to start from “00” and go to “80”. I’ve gotten it set up so that when I am below 00 it will go back to --. But then it starts looping back to 80 if i go -1 -1 -1 from 01 to 00 to – and loops back to 80.

What I’m hoping to accomplish is this: if I input any change to a panning value that has “–” currently, the value will start subtracting/adding from from 40.

This is what I have thus far, and it doesn’t seem to work.

-- Set Panning +1 / -1 / +10 / -10 on current_row, display delay column
function panning(chg)
 local p = renoise.song().selected_note_column.panning_value
 local nc = renoise.song().selected_note_column
 local currTrak = renoise.song().selected_track_index

if nc.panning_string==".." then nc.panning_value=40 else end
 renoise.song().tracks[currTrak].panning_column_visible=true
 nc.panning_value = math.max(0, math.min(128, p + chg))
 if p < 1 then nc.panning_string=".." else end
 --end
end

Hi, I’m working on modifying my delay-script (shortcut for adding +1, +10 or removing -1 or -10 from it via keyboard shortcuts) to also work for panning.

I’ve gotten it to start from “00” and go to “80”. I’ve gotten it set up so that when I am below 00 it will go back to --. But then it starts looping back to 80 if i go -1 -1 -1 from 01 to 00 to – and loops back to 80.

What I’m hoping to accomplish is this: if I input any change to a panning value that has “–” currently, the value will start subtracting/adding from from 40.

This is what I have thus far, and it doesn’t seem to work.

-- Set Panning +1 / -1 / +10 / -10 on current_row, display delay column
function panning(chg)
local p = renoise.song().selected_note_column.panning_value
local nc = renoise.song().selected_note_column
local currTrak = renoise.song().selected_track_index

if nc.panning_string==".." then nc.panning_value=40 else end
renoise.song().tracks[currTrak].panning_column_visible=true
nc.panning_value = math.max(0, math.min(128, p + chg))
if p < 1 then nc.panning_string=".." else end
--end
end
function panning( chg, song, nc, pan )
  song = renoise.song()
  nc = song.selected_note_column
  pan = song.selected_note_column.panning_value
  if ( song.selected_track.panning_column_visible == false ) then
    song.selected_track.panning_column_visible = true
  end
  if ( nc.panning_string == ".." ) then
    nc.panning_value = 40
  end
  nc.panning_value = math.max( 0, math.min( 128, pan + chg ) )
  if ( nc.panning_value < 1 ) then
    nc.panning_string = ".."
  end
end

Try this function. I have not tried it, but it still approaches the solution.

renoise.song().patterns[].tracks[].lines[].note_columns[].panning_value
  -> [number, 0-127, 255==Empty when column value is <= 0x80 or is 0xFF,
              i.e. is used to specify pan]
     [number, 0-65535 in the form 0x0000xxyy where
              xx=effect char 1 and yy=effect char 2,
              when column value is > 0x80, i.e. is used to specify an effect]

( nc.panning_value < 1 ) -------------> panning_value = 0 is LEFT!Are you sure you want to do that? … 127 is RIGHT, 255 is empty.

( nc.panning_value < 1 ) -------------> panning_value = 0 is LEFT!Are you sure you want to do that? … 127 is RIGHT, 255 is empty.

Well, since I operate with +1/-1/+10/-10 it would be good to go from 0 to empty (–), and from empty to middle (40). i don’t believe there’s a usecase where “getting to 40 means go to “–””. I would rather get to 0 (which is where we go) and then go directly from 0 to – and then start adding/subtracting from 40

if nc.panning_string==".." then nc.panning_value = 40 else end

 nc.panning_value = math.max(0, math.min(128, columns[thing] + chg))
 if nc.panning_value < 1 then nc.panning_string=".." else end

this seems to result in not what i would like to happen, which is a bit weird. i mean, it feels like the first if should do what it needs to do, i.e. if you are starting from “…” then switch to “value” and then start doing the work?

if nc.panning_string==".." then nc.panning_value = 40 else end

nc.panning_value = math.max(0, math.min(128, columns[thing] + chg))
if nc.panning_value < 1 then nc.panning_string=".." else end

this seems to result in not what i would like to happen, which is a bit weird. i mean, it feels like the first if should do what it needs to do, i.e. if you are starting from “…” then switch to “value” and then start doing the work?

I do not know what you intend to build. But your first two lines do not make sense. You are defining the same value twice. Isolate the first two lines:

  1. if nc.panning_string ==“…” then nc.panning_value = 40 else end
  2. nc.panning_value = math.max(0, math.min(128, columns[thing] + chg))

The second line will always modify the first. Therefore, the first one is unnecessary.In the first line you say:nc.panning_value = 40 (else leftover).And in the second line you come back to definenc.panning_value = other number

That the mathematical operation (math.max(0, math.min(128, columns[thing] + chg))) will return negative values?Otherwise this does not make sense: if nc.panning_value < 1 then nc.panning_string=“…” else end there it is as if you were putting. if A == B then A = B end

renoise.song().patterns[].tracks[].lines[].note_columns[].panning_value -> [number, 0-127, 255==Empty 

renoise.song().patterns[].tracks[].lines[].note_columns[].panning_string -> [string, '00'-'FF' or '..']

Both lines are used to modify the same value in the pattern editor…

hmm… what i’m attempting to do is this:

if the user has never set a single panning_column value, the panning_column is empty. If the user starts setting panning_column amounts, start from “40” (middle, center) instead of from “00”. This allows for, say, going to row1 and saying “+3 pan” and it is 43 - then going to row 2 and saying “-3 pan” and it is 3D. but if the user goes below 0 in panning, the panning column is wiped (edited to “…”). if the user then starts adding pan or removing pan, they start from 40.

that’s why i’m setting “if panning is “–”, go to 40” on line 1, then on line2 i go "actually here’s some math to carry on from.

do you see what i’m going for?

the chg is +1 -1 +10 -10, and that is used to modify the panning column content. i just want to make sure that when starting from empty panning column data, and one starts the process of adding, subtracting from panning column, that it starts from 40. and returns to “empty” if you get below 0, and then starts from 40.

think of “below 0 to “…”” as “reset to center”, and then the next “oh there’s a “…”, i’m jumping to 40 because that’s center where the number counting starts” as the method for continuing instead of forcing the user to start from hard left pan (00). it’s much more convenient to the workflow.

I do not know what you intend to build. But your first two lines do not make sense. You are defining the same value twice. Isolate the first two lines:

  1. if nc.panning_string ==“…” then nc.panning_value = 40 else end
  2. nc.panning_value = math.max(0, math.min(128, columns[thing] + chg))

The second line will always modify the first. Therefore, the first one is unnecessary.In the first line you say:nc.panning_value = 40 (else leftover).And in the second line you come back to definenc.panning_value = other number

That the mathematical operation (math.max(0, math.min(128, columns[thing] + chg))) will return negative values?Otherwise this does not make sense: if nc.panning_value < 1 then nc.panning_string=“…” else end there it is as if you were putting. if A == B then A = B end

renoise.song().patterns[].tracks[].lines[].note_columns[].panning_value -> [number, 0-127, 255==Empty 

renoise.song().patterns[].tracks[].lines[].note_columns[].panning_string -> [string, '00'-'FF' or '..']

Both lines are used to modify the same value in the pattern editor…

I was able to solve this (need to set to 40 when going to “…”) by this:

elseif thing == 2 then
--panning column
local pancount=nil
 sst.panning_column_visible=true
   if nc.panning_string==".." then nc.panning_value = 64 return end
   pancount = math.max(-20, math.min(128, columns[thing] + chg))
   if pancount < 0 then nc.panning_string = ".." else nc.panning_value = pancount end

now when I go “below 0”, it will go to “…” but then when i input another -1 or +1, it starts from 40.

well, the return solved it after a fashion, but now the first time I ever input +1/-1/-10/+10 does not actually do anything, since the first time it is set to 40 only :frowning:

Hey esa, the snippet below should do it:

Couple of notes:

-In renoise the panning values are hexadecimal, so you have to account for that with the numbers in Lua. You need to prepend the number with (zero + x) “0x” i.e. 35 as written in the renoise columns becomes 0x35 written in Lua. You can then use all other hexadecimal values as numbers including 0x3A, 0x3B etc…

-Just a small one: With an **if** statement, where nothing is done when the if test fails, then you don`t need to write the else.
The two following expressions will give you the same outcome:

if nc.panning_value < 1 then nc.panning_string=".." else end

if nc.panning_value < 1 then nc.panning_string=".." end
-- Set Panning +1 / -1 / +10 / -10 on current_row, display delay column
function panning(chg)
 
  local nc = renoise.song().selected_note_column
  local currTrak = renoise.song().selected_track_index
  
  --make panning column visible
  renoise.song().tracks[currTrak].panning_column_visible = true

  -- default to 40 if empty (0x40 as renoise panning values are hexadecimal)
  if nc.panning_string == ".." then
    nc.panning_value = 0x40
  end
  
  --check bounds. If value will be less than 0 or greater than 0x80 then reset panning to ".."
  --else update to new value
  if (nc.panning_value + chg < 0) or (nc.panning_value + chg > 0x80) then
    nc.panning_string = ".."
  else
    nc.panning_value = nc.panning_value + chg
  end
  
  --clear panning to ".." if we are back at 0x40
  if nc.panning_value == 0x40 then
    nc.panning_string = ".." 
  end
end

--run function with a test value of 12
panning(12)

This snippet would probably be a bit more efficient if you calculate nc.panning_value + chg just once with:

local new_value = nc.panning_value + chg

and then replace it in the subsequent statements with new_value. I just did it this way to make the code a bit clearer for the example. Also not too significant if just part of a one-shot shortcut vs. some heavy looping.

hmm… what i’m attempting to do is this:

if the user has never set a single panning_column value, the panning_column is empty. If the user starts setting panning_column amounts, start from “40” (middle, center) instead of from “00”. This allows for, say, going to row1 and saying “+3 pan” and it is 43 - then going to row 2 and saying “-3 pan” and it is 3D. but if the user goes below 0 in panning, the panning column is wiped (edited to “…”). if the user then starts adding pan or removing pan, they start from 40.

that’s why i’m setting “if panning is “–”, go to 40” on line 1, then on line2 i go "actually here’s some math to carry on from.

do you see what i’m going for?

the chg is +1 -1 +10 -10, and that is used to modify the panning column content. i just want to make sure that when starting from empty panning column data, and one starts the process of adding, subtracting from panning column, that it starts from 40. and returns to “empty” if you get below 0, and then starts from 40.

think of “below 0 to “…”” as “reset to center”, and then the next “oh there’s a “…”, i’m jumping to 40 because that’s center where the number counting starts” as the method for continuing instead of forcing the user to start from hard left pan (00). it’s much more convenient to the workflow.

Ok I understand. Perhaps the best way to do all this is to create two functions, one to add, and another to subtract, and each one will work with a specific keyboard command.

After creating each function, make sure that the command repeats the function, establishing the limits within that function.

Forget the panning_string and focus your attention on the panning value. The panning sub-column accepts values greater than 127, and one of them is 255 (empty).Here is a suggestion and I have not tried the code, but I think it’s fine:

--renoise.song().tracks[].panning_column_visible
--renoise.song().patterns[].tracks[].lines[].note_columns[].panning_value

function panning_up( chg, song, pan )
  song = renoise.song()

  if ( song.selected_track.panning_column_visible == false ) then
    song.selected_track.panning_column_visible = true
  end

  if ( song.selected_line.selected_note_column.panning_value > 127 or song.selected_line.selected_note_column.panning_value ~= 40 ) then
    song.selected_line.selected_note_column.panning_value = 40
  end

  pan = song.selected_line.selected_note_column.panning_value

  if ( pan + chg <= 127 ) then
    song.selected_line.selected_note_column.panning_value = pan + chg
  end
end

function panning_down( chg, song, pan )
  song = renoise.song()

  if ( song.selected_track.panning_column_visible == false ) then
    song.selected_track.panning_column_visible = true
  end

  if ( song.selected_line.selected_note_column.panning_value > 127 or song.selected_line.selected_note_column.panning_value ~= 40 ) then
    song.selected_line.selected_note_column.panning_value = 40
  end

  pan = song.selected_line.selected_note_column.panning_value

  if ( pan - chg >= 0 ) then
    song.selected_line.selected_note_column.panning_value = pan - chg
  end
end

You will have to define the “chg” number somewhere, for example, from a valuebox…You can try all these things and choose what you like most.Personally, I would prefer not to jump to 40 when the value is less than 0. I would leave the value at 0 (maximum left).The same with 127.

If you only want to use a keyboard command for both cases and that the value “chg” is positive or negative, you only have to “merge” both functions into one and adapt it to this value.Sometimes, seeing things separately helps you move forward.

Edit:Remember to shield the function to avoid errors (in a group/master/send this will not work).

Hi Raul, why did you pass song and pan as parameters, rather than declare as local variables? They are assigned in the function before use so no need to have in parameter list.

The second part (line 10) shows with locals:

--passed and then re-assigned?

function panning_up( chg, song, pan )
  
  song = renoise.song()
  pan = song.selected_line.selected_note_column.panning_value

end

--local variables

function panning_up( chg )
  
  local song = renoise.song()
  local pan = song.selected_line.selected_note_column.panning_value

end

Hi Raul, why did you pass song and pan as parameters, rather than declare as local variables? They are assigned in the function before use so no need to have in parameter list.

The second part (line 10) shows with locals:

--passed and then re-assigned?

function panning_up( chg, song, pan )
  
song = renoise.song()
pan = song.selected_line.selected_note_column.panning_value

end

--local variables

function panning_up( chg )
  
local song = renoise.song()
local pan = song.selected_line.selected_note_column.panning_value

end

It is possible to define the local above without passing it. You just have to make sure you do not pass it in your position. That’s why chg is first.If you want to pass more variables, put them first, then you can define the local one above, and not have to type “local” all the time.

function panning_up( chg, song, pan )
  
  song = renoise.song()
  pan = song.selected_line.selected_note_column.panning_value

end
  1. position 1: chg, variable passed
  2. position 2: song, not passed, is a local
  3. position 3: pan, not passed, is other local

Pass more variables:

function panning_up( chg1, chg2, chg3, song, pan, dly )
  
  song = renoise.song()
  pan = song.selected_line.selected_note_column.panning_value
  dly = song.selected_line.selected_note_column.delay_value

end
  1. position 1: chg1, variable passed
  2. position 2: chg2, variable passed
  3. position 3: chg3, variable passed
  4. position 4: song, not passed, is a local
  5. position 5: pan, not passed, is other local
  6. position 6: dly, not passed, is other local
  7. etc
  8. etc

Personally, I only use “local” when I use one function within another.

But you can do it in both ways…

Yes it is a question if style in that case, just a bit less explicit using the parameter list.

Personally, I would prefer not to jump to 40 when the value is less than 0. I would leave the value at 0 (maximum left).The same with 127.

Perhaps it is not such a bad idea to do so if, in any case, you reach the maximum or minimum value, that is, after the operation, you must reach 0 or 127 before repeating the operation to return to 40. , panning_value can take any value and “chg” too.

Yes it is a question if style in that case, just a bit less explicit using the parameter list.

As long as the programmer knows what he is doing, there is no problem.Personally, I do not like having to define “local” hundreds of times. And there are also many functions that do not use passed variables, all are “local”.

Anyway, the function is very clear, unless it is very long and difficult to read. If there is no equality that defines it within the function, it is not a local one, is a passed variable (or simply define a name as a local, without equaling anything).

nc.panning_value = 0x40

Hi Ledger, I decided to bite the bullet and just make a “wipe current row note column’s pan column content” - so far seems to work ok

renoise.tool():add_keybinding{name="Pattern Editor:Paketti:Reset Panning in Current Column",invoke=function()
local s=renoise.song()
local nc=s.selected_note_column
s.selected_track.panning_column_visible=true
nc.panning_value = 0xFF
end}

Am hoping to then see if can “hard-code” 00 to stay 00 and not go below 00, and then if get to 0x40 get to 0xFF and then if get to 0x80 then do nothing too. Could be useful.

Most of these I’m working from the point of view of using a numpad so the middle number (I guess that’s 5) will wipe something - from the point of view of 4 and 6 being panning and 8 and 2 being delay.

Nice idea for the numberpad!

A quick modification of the earlier function that stops at the limits (0 and 0x80) rather than re-centering the pan, if it helps:

line 15 to 27 is the new stuff. In this version I also did what I mentioned earlier with saving the calculation of nc.panning_value + chg in the local variable target_pan_value on line 15:

-- Set Panning +1 / -1 / +10 / -10 on current_row, display delay column
function panning(chg)
 
  local nc = renoise.song().selected_note_column
  local currTrak = renoise.song().selected_track_index
  
  --make panning column visible
  renoise.song().tracks[currTrak].panning_column_visible = true
  
  --default to 40 if empty (0x40 as renoise panning values are hexadecimal)
  if nc.panning_string == ".." then
    nc.panning_value = 0x40
  end
 
  local target_pan_value = nc.panning_value + chg 
  
  --set the panning value
  if target_pan_value <= 0 then
    --set to zero (left pan)
    nc.panning_value = 0
  elseif target_pan_value >= 0x80 then
    --set to 0x80 (right pan)
    nc.panning_value = 0x80
  else
    --any value in between (0 to 0x80)  
    nc.panning_value = target_pan_value
  end
  
  --clear panning to ".." if we are back at 0x40
  if nc.panning_value == 0x40 then
    nc.panning_string = ".." 
  end
end
 
--run function with a test value of 10
panning(10)

A quick modification (…)

Last night I was doodling my own response to esa’s problem here.

It’s actually kind of amazing how close your own solution is to the one I came up with.

Great minds think alike I guess :slight_smile:

-- Set Panning +1 / -1 / +10 / -10 on current_row and display panning column
function panning(chg, center_out_of_bounds)

  -- Set the behaviour when going out of bounds.
  -- If centering then pan < 0 or > 0x80 will reset the new value back to center.
  -- Else just clip to the valid pan range 0x00 to 0x80. (Default behaviour)
  center_out_of_bounds = center_out_of_bounds or false
 
  -- Local reference to the song.
  local song = renoise.song()
  
  -- Local reference to the selected note column.
  local note_column = song.selected_note_column
  
  -- If no valid note column is selected...
  if note_column == nil then
  
    -- Nothing to do!
    return false
    
  end
  
  -- Show the panning column.
  song.selected_track.panning_column_visible = true
  
  -- Get the current pan value.
  local pan = note_column.panning_value
  
  -- If the pan value is empty...
  if pan == renoise.PatternLine.EMPTY_PANNING then
  
    -- Set the default center value.
    pan = 0x40

  end
  
  -- Apply the pan change.
  pan = pan + chg

  -- If wrapping to center and out of bounds...
  if center_out_of_bounds and (pan < 0x00 or pan > 0x80) then
    
    -- Reset to center.
    pan = 0x40
  
  -- Else...
  else
  
    -- Clip to valid pan range.
    pan = math.min(0x80, math.max(0x00, pan))    
    
  end
  
   -- If the final value ends up back at exact center...
  if pan == 0x40 then
    
    -- Show an empty panning column instead.
    pan = renoise.PatternLine.EMPTY_PANNING
    
  end  
  
  -- Finally shove the new value back into the note column.
  note_column.panning_value = pan

end

-- TEST

-- Wrap to center when going out of bounds.
local center_out_of_bounds = true

-- Apply pan change.
panning(10, center_out_of_bounds)

:slight_smile:

plus you `ve added a bit of extra polish, like

if note_column == nil then return

No excuses now esa! get copy pasting! :slight_smile:

No excuses now esa! get copy pasting! :slight_smile:

I’m actually kind of surprised esa hasn’t stumbled onto this hidden gem yet:

renoise.song().selected_sub_column_type

This guy tells you precisely where the cursor is, for maximum granularity.

For example:

-- Get the selected sub column type.
local sct = renoise.song().selected_sub_column_type

-- Do something cool with the note number.
if sct == renoise.Song.SUB_COLUMN_NOTE then

  -- Something cool.

-- Do something cool with the instrument number..
elseif sct == renoise.Song.SUB_COLUMN_INSTRUMENT then

  -- Something cool.

-- Do something cool with the volume.
elseif sct == renoise.Song.SUB_COLUMN_VOLUME then

  -- Something cool.

-- Do something cool with the panning.
elseif sct == renoise.Song.SUB_COLUMN_PANNING then

  -- Something cool.

-- Do something cool with the delay.
elseif sct == renoise.Song.SUB_COLUMN_DELAY then

  -- Something cool.

-- Do something cool with the sample effect number.
elseif sct == renoise.Song.SUB_COLUMN_SAMPLE_EFFECT_NUMBER then

  -- Something cool.

-- Do something cool with the sample effect amount.
elseif sct == renoise.Song.SUB_COLUMN_SAMPLE_EFFECT_AMOUNT then

  -- Something cool.

-- Do something cool with the effect number.
elseif sct == renoise.Song.SUB_COLUMN_EFFECT_NUMBER then

  -- Something cool.

-- Do something cool with the effect amount.
elseif sct == renoise.Song.SUB_COLUMN_EFFECT_AMOUNT then

  -- Something cool.

end

I’m actually kind of surprised esa hasn’t stumbled onto this hidden gem yet:

renoise.song().selected_sub_column_type

yaknow, dblue, i was told that there’s no granularity between effect column amount value and number value. i’m glad to be proven wrong, though!

and if i misunderstood what this is, then i’ll most certainly look at it close and try and figure out what i could do with it :slight_smile:

edit oh yeah, this can be read - but there’s no similar thing for writing to.

Am I in the right place thinking-wise if I muse that a notifier that detects that you’re in sub_column_type=9 could be used to trigger some certain functions?