[Solved] phrase keymap assing mapping.note_range whitout overlap

Hi!Yesterday I was trying to build a function to configure the keymap of the selected phrase, with a specific range of notes, returned by two valueboxes:

function pht_phrase_keymap()
  local song = renoise.song()  
  if ( rna.window.active_middle_frame ~= renoise.ApplicationWindow.MIDDLE_FRAME_INSTRUMENT_PHRASE_EDITOR ) or
     ( song.selected_instrument.phrase_editor_visible == false ) or
     ( song.selected_instrument.phrase_playback_mode ~= renoise.Instrument.PHRASES_PLAY_KEYMAP ) then
     pht_show_phrase_editor_keymap()
     return
  else
    local value_a = vws["PHT_VB_MAP_FIRST_NOTE"].value --VALUEBOX 1
    local value_b = vws["PHT_VB_MAP_LAST_NOTE"].value --VALUEBOX 2
    local ins = song.selected_instrument
    local id_ph_map = #ins.phrase_mappings + 1
    local sph = song.selected_phrase
    local sphi = song.selected_phrase_index

    --delete all phrases
    --for i = #song.selected_instrument.phrase_mappings, 1, -1 do
    -- song.selected_instrument:delete_phrase_mapping_at( i )
    --end

    print("id_ph_map", id_ph_map )
    print("sphi", sphi )

    --check if the index of keymap is free to insert a new map
    if ( ins:can_insert_phrase_mapping_at( id_ph_map ) == true ) then
      
      --check if the selected phrase is not mapped
      if ( sph.mapping == nil ) then
        --map the selected frase inside the index of keymap
        ins:insert_phrase_mapping_at( id_ph_map, sph )

        --assign the note range of the selected phrase with two valueboxes --<----------------- RETURN ERROR of overlap
        sph.mapping.note_range = { value_a, value_b }
        
        --asign the base note of the selected phrase
        sph.mapping.base_note = value_a
        
        --autoseek & shuffle of the selected phrase
        sph.autoseek = vws["PHT_PHRASE_AUTOSEEK"].value 
        sph.shuffle = vws["PHT_PHRASE_SHUFFLE"].value / 100
      end
    end
  end
end

This line:

sph.mapping.note_range = { value_a, value_b }

use two valueboxes to return value_a and value_b , with range of 0 to 119 , and always value_b >= value_a.The problem is that if there are already other phrases that occupy a certain and random range within the keymap, how to avoid overlap?I should put some condition that proves that the assigned range is free. It’s possible?

The typical error message is this:

*** std::logic_error: 'phrase mappings may not overlap. prev. phrase mapping's end is '56'. this mappings start must be bigger than that.'
*** stack traceback:
*** [C]: ?
*** [C]: in function '__newindex'
*** [string "do..."]:22: in function <[string "do..."]:9>
***.\lua/miscellaneous.lua:141: in function 'pht_phrase_keymap'
***.\lua/miscellaneous.lua:233: in function <.\lua/miscellaneous.lua:233>

How to avoid this error?

The intention is to be able to select a random phrase and assign a random range of mapping inside keymap mode.

Thanks!!! :slight_smile:

I think you’ll find the methodxPhraseManager.get_available_slot in xLib handy

https://github.com/renoise/xLib/blob/master/classes/xPhraseManager.lua

Just copy-paste if you don’t want to include the whole class… smile.png

I think you’ll find the methodxPhraseManager.get_available_slot in xLib handy

https://github.com/renoise/xLib/blob/master/classes/xPhraseManager.lua

Just copy-paste if you don’t want to include the whole class… smile.png

Thanks Danoise!I’ll review it, to understand how that function works :lol:

Finally, I have chosen to rewrite my entire function, with a little more flexibility, so that it allows selecting the initial phrase, the initial note and the range of notes. As the editor of phrases already allows to drag and drop, I have preferred to do a more global function, so as not to complicate it too much and that it is easy to configure the keymap quickly.

Finally, the function that I have built is the following:

function pht_auto_keymap()
  local song = renoise.song()  
  local ins = song.selected_instrument
  if ( rna.window.active_middle_frame ~= renoise.ApplicationWindow.MIDDLE_FRAME_INSTRUMENT_PHRASE_EDITOR ) or
     ( ins.phrase_editor_visible == false ) or
     ( ins.phrase_playback_mode ~= renoise.Instrument.PHRASES_PLAY_KEYMAP ) then
     pht_show_phrase_editor_keymap()
     return
  else
    local value_a = vws["PHT_VB_MAP_FIRST_NOTE"].value - 1
    local value_b = vws["PHT_VB_MAP_RANGE_NOTE"].value - 1
    local value_c = song.selected_phrase_index - 1
    --delete all phrases
    for i = #ins.phrase_mappings, 1, -1 do
      ins:delete_phrase_mapping_at( i )
    end
    --insert all phrases
    for i = 1, #ins.phrases do
      if ( value_a + i * vws["PHT_VB_MAP_RANGE_NOTE"].value <= 119 ) and ( i + value_c <= #ins.phrases ) then
        if ( ins:can_insert_phrase_mapping_at( i ) ) then
          local ph = ins:phrase( i + value_c )
          ins:insert_phrase_mapping_at( i, ph )
          if ( i == 1 ) then
            ph.mapping.note_range = { i + value_a, i + value_a + value_b }
          else
            ph.mapping.note_range = { ph.mapping.note_range[1], ph.mapping.note_range[1] + value_b }
          end
          ph.mapping.base_note = ph.mapping.note_range[1]
          ph.shuffle = vws["PHT_PHRASE_SHUFFLE"].value / 100
          ph.autoseek = vws["PHT_PHRASE_AUTOSEEK"].value 
          ph.mapping.looping = vws["PHT_PHRASE_LOOP"].value
          pht_change_status( "AutoKeymap has been executed successfully." )
        end
      end
    end
    if ( #ins.phrase_mappings == 0 ) then
      pht_change_status( "AutoKeymap is not possible. Reconfigure it!" )
    end
  end
end

“PHT_VB_MAP_FIRST_NOTE” is the id of a valuebox of range 0 to 119, “PHT_VB_MAP_RANGE_NOTE”, is the id of other valuebox of range 1 to 24.After manually setting these values, you trigger the function with a button and you’re done.

The reason for this choice is because, apparently, .insert_phrase_mapping_at covers every last note (119), and when you add a phrase to the left of an existing one, it will always overlap. Maybe it would be easier for the programmer that .insert_phrase_mapping_at only cover only a note, and then expand it after with .mapping.note_range.

Anyway, I’m very happy with this new function.It works fine with all the limits.