How to avoid the error: no note_column's are available

I am having big problems with a somewhat strange situation. I have searched the forums for a solution and I can not find anything.It is the following error:

*** std::logic_error: 'invalid note_column index '1'. no note_column's are available.'
*** stack traceback:
*** [C]: in function 'note_column'
*** main.lua:914: in function <main.lua:890>
*** [C]: in function 'add_track_to_group'

This error appears in the following scenario:

  1. A Function 1 with a notifier that requires continuous access to the selected note column. So changing column or track or group note, a value related to the column note is updated on a monitor, as the value of a note, or the value of the volume of that note…

  2. On the other hand, a simple Function 2 that includes a group and several tracks within that group, all in the same function.

When executing Function 2, the Function 1 is also executed by changing the track (When you insert new tracks, change the index).Then, by inserting a group, it generates this error:‘invalid note_column index ‘1’. no note_column’s are available.’

How can I avoid this error?

In the Function 1 I useif ( song.selected_track.type == renoise.Track.TRACK_TYPE_SEQUENCER ) thento prevent it from executing anything if the selected track is not a Sequencer Type (a group, master, send…, that do not include note columns).

It gives me the sensation that when adding several tracks and a group to later insert those tracks within the group, a specific scenario occurs with the index of the track that can “confuse” a group(group type) with a track (sequencer type)

The fact is that I want to have access to the information that contains the selected note column (notes, panning volume values, etc.) and that this is not a problem when adding tracks and groups in the same function.

Can anyone do some magic here with any idea?

Not sure Ive fully understood the situation but couldnt you just do something like below to catch it? (or modify the selected/ target note column if the test fails)

if note_column_index ~= 0 then

 do this code

end

from the API:

renoise.song().selected_note_column_index
-> [number, index or 0 (when an effect column is selected)]

Second reading, looks like your already doing the above by looking at track type.

Do you have a simple code snippet that can be run to illustrate the problem?

Are you keeping a reference to the track itself or it’s index? The index will change as tracks are added and removed, but the reference shouldn’t.

I guess we need that snippet :slight_smile:

Thanks Ledger and Danoise!!!

I already tried what Ledger says. But it does not work.But I suspect that Danoise has succeeded.The notifier I used was selected_track_observable but when executing the function that adds tracks and group at the same time, it does not seem to update the notifier when inserting the group, so that it generates the error.

The solution is to use selected_track_index_observable instead of selected_track_observable.I do not understand very well why. If someone wants to explain it to me…

Anyway, I still have to learn how to make sure to remove all the notifiers that refer to a tool window, when this window is closed.

You create a window with notifiers that are executed when you open that window. At all times they are in operation, such as a selected_track_index.How can I order remove all these notifiers when closing that window?

I think that there is no option in the available LUA API to be able to execute a function when giving the X button to close a window.Is there any way to do this even through dialog:close() or dialog.visible??

My main dialog:

function dialog_main()
  --Avoid showing the same window several times!
  if ( dialog and dialog.visible ) then dialog:show() return end
  
  --Load dialog ( with "title name", content and key_handler )
  dialog = renoise.app():show_custom_dialog( title, content, key_handler )
  
  --reload all dialog main() in new song
  if not renoise.tool().app_new_document_observable:has_notifier( dialog_main ) then
    renoise.tool().app_new_document_observable:add_notifier( dialog_main )
  end
end

Something like: if not dialog.visible then … remove the notifiers, the selected_track_index_observable and the rest.Where to put or invoke this code?

I have some logic that deals with opening/closing dialogs in vLib.

Check out the following lines:

https://github.com/renoise/vLib/blob/master/classes/vDialog.lua#L72

There’s some complexity there because it’s designed for dialogs that can appear when Renoise starts, but the principle should apply also for more simple setups

Glad you got it sorted Raul!

A couple of snippets that might be relevant aswell

This is how I generally deal with GUI [X] button closing; added to the top of your snippet. It can be added at the end if you still want the function to run first (or just remove the return to continue).

FORUM SIDENOTE: Just noticed if we choose sql as code type in forum formatting, we can get the lua comments showing in red, maybe this could be made forum default?

Added lines 3 -13:

function dialog_main()
    
      --HOUSEKEEPING -----remove timer when GUI is closed
      ---------------------------------
      if (my_dialog == nil) or (my_dialog.visible == false) then
      
        if renoise.tool():has_timer(dialog_main) then
          renoise.tool():remove_timer(dialog_main)
        end
        
        --remove all other notifiers and reset variables here if needed
        return
      end
    
      --Avoid showing the same window several times!
      if ( dialog and dialog.visible ) then dialog:show() return end
      
      --Load dialog ( with "title name", content and key_handler )
      dialog = renoise.app():show_custom_dialog( title, content, key_handler )
      
      --reload all dialog main() in new song
      if not renoise.tool().app_new_document_observable:has_notifier( dialog_main ) then
        renoise.tool().app_new_document_observable:add_notifier( dialog_main )
      end
    end

Also I often use a global variable to track the changing track index/ instrument index etc., which cuts down on observable checking/ attaching/ removing operations. This works well if there is only one timer function observing track changes but could be made that you have a global for each timer if you needed more. note: You also need to update the global on a new song being loaded.

--global stores initial track index --remove `local` if in a separate .lua file
    local global_track_index_holder = renoise.song().selected_track_index
    
    function my_timer_function()
      
      --check if track index changed
      if renoise.song().selected_track_index ~= global_track_index_holder then
        --update the global for next run
        global_track_index_holder = renoise.song().selected_track_index
        
            --do stuff for track change here--
      end
      
      --rest of function--
    end

edit: updated line 7 which was incorrect before.

Thanks Danoise and Ledger!

I think I already understand well how to master timers and notifiers with the use of open tool windows.The detail is to make sure to remove the notifier or the timer inside the function invoked with that notifier or timer respectively.Something like adding this inside the function, at the beginning:

--remove notifier
  if ( dialog and dialog.visible == false ) then
    if song.selected_pattern_index_observable:has_notifier( vpd_check_first_line_play ) then
      song.selected_pattern_index_observable:remove_notifier( vpd_check_first_line_play )
    end  
    print("stop line notifier 1")
    return
  end

or

--remove timer
  if ( dialog and dialog.visible == false ) then
    if ( renoise.tool():has_timer( vpd_check_current_line_play ) ) then
      renoise.tool():remove_timer( vpd_check_current_line_play )
    end
    print("stop line timer 2")
    return
  end

In my case, in the first line of my main.lua I have written: dialog = nil. So I have to write"if**( dialog and** dialog.visible == false ) then" instead of “if**( dialog == false ) or**(dialog.visible == false ) then”

The dialog_main() functionIt only runs once when the window tool is opened.Therefore, adding within this function the remove of notifiers/timers will not work.

The final conclusion is very specific: remove the timers or notifiers inside the functions that have invoked said timers or notifiers,for when there is a change of state (dialog.visible = false),in my case, inside the functionsvpd_check_first_line_play(),vpd_check_current_line_play()…

The caveat is that the notifier will stop when the function is activated again. For example, if it is selected_pattern_index_obserbable,the notifier will stop when changing the pattern (up or down).

It is possible to make sure to remove all the “junk” notifiers or timers when the tool window is closed (they are no longer useful), and make sure to activate them again from dialog_main() function, what is when dialog.visible = true.Use “print” to make sure everything works.

I think this topic is clear to me. At last!

Thank you very much for the help!!!

I change this topic as resolved…

Edit:By the way, this solution to stop the timers seems so obvious, but until you try it with trial and error, it’s not very clear. For some reason, mastering timers or notifiers is a bit “messy” or “confusing”. At least that’s what happened to me.

Yes timers and notifiers can be a bit confusing, but once you have a working method in your mind to catch/ manage them it becomes a lot easier.

In my case, in the first line of my main.lua I have written: dialog = nil. So I have to write"if**( dialog and** dialog.visible == false ) then" instead of “if**( dialog == false ) or**(dialog.visible == false ) then”

As a side note, Ive learnt to be very explicit with testing return values, otherwise I find Im bug hunting for nil vs false vs 0. It makes my code more verbose, but leaves more hair on my head! :slight_smile:

I use a lot of:

if X == false then
if X == nil then
if X == 0 then

rather than:

if X then
if not X then

nil vs false can certainly get a bit slippery if not careful: and in Lua zero being a true value
From Lua docs:

Like control structures, all logical operators consider false and nil as false and anything else as true.

It is possible to make sure to remove all the “junk” notifiers or timers when the tool window is closed (they are no longer useful), and make sure to activate them again from dialog_main() function, what is when dialog.visible = true.Use “print” to make sure everything works.

It`s a shame there is no API table of all the attached notifiers and timers to a tool,

you could then do something like this, and the same for renoise.tool().active_timers. (also rprint() them while debugging)

--imaginary code, will not work (in 2017 at least)!

for i = 1, #renoise.tool().active_notifiers do
  
  renoise.tool():remove_notifier(renoise.tool().active_notifiers[i])

end

Yes timers and notifiers can be a bit confusing, but once you have a working method in your mind to catch/ manage them it becomes a lot easier.

As a side note, Ive learnt to be very explicit with testing return values, otherwise I find Im bug hunting for nil vs false vs 0. It makes my code more verbose, but leaves more hair on my head! :slight_smile:

I use a lot of:

if X == false then
if X == nil then
if X == 0 then

rather than:

if X then
if not X then

nil vs false can certainly get a bit slippery if not careful: and in Lua zero being a true value
From Lua docs:

It`s a shame there is no API table of all the attached notifiers and timers to a tool,

you could then do something like this, and the same for renoise.tool().active_timers. (also rprint() them while debugging)

--imaginary code, will not work (in 2017 at least)!

for i = 1, #renoise.tool().active_notifiers do
  
renoise.tool():remove_notifier(renoise.tool().active_notifiers[i])

end

I would like to be able to execute a function when I do click on the X of the close button of the tool window.

In fact, I would like to have the total domain of the tool’s top bar (the title and the X button to close), leaving the space necessary to drag the window. Thus, the programmer has full control of what the user will do when handling the tool.

By pressing the X button, the programmer can not invoke another function, what a pity! It would be very useful to make sure to clean things that should not work, such as notifiers or timers, all collected in the same function.

I wish some requests could be grouped to be added in Renoise. It gives me the feeling that many things are easy to add under the hood of Renoise, but that they are not there because they have not been thought of or simply have not arrived there.

If you think about it, a “broom car” function also seems very obvious, since it allows you to clean the remains of the tool that are left over,ensuring that nothing is left running that consumes resources if the tool is not open, and in a window the ideal trigger is the X button to close…

Yes an [X] button notifier would be a good addition. Ive also thought recently that aroll window up` button next to the [X] would be useful, so if you have several tools open you can just minimize/ maximize them as you go.

I see that you did a bespoke version in one of your gifs of your orchestra tool, I will probably add something similar to my sequencer tool soon.

Yes an button notifier would be a good addition. Ive also thought recently that a roll window up` button next to the would be useful, so if you have several tools open you can just minimize/ maximize them as you go.

I see that you did a bespoke version in one of your gifs of your orchestra tool, I will probably add something similar to my sequencer tool soon.

Exact!That’s why I say that I would like to have full control of the top bar. I use a minimize/maximize button, but it is below the top bar.I’m always trying to create as compact windows as possible. A very large window becomes useless in Renoise, because it is usually necessary to have a large Renoise area in view at the same time you use the tool window.

Most “module windows” of my VPDpro tool have a “minimize” button, which turns the window into something much smaller.This is a very clear example (the button to the right of the button “ChEMP”):

[sharedmedia=core:attachments:7637]

Edit:to do this I always use the property :row { visible = false } or :column{ visible = false }calling from your id…