Freeze Track Snippet

@esaruoho had a question and problem rendering a track, in order to “freeze” it.

Here’s a snippet on how this could work. Maybe this helps others too. I think this has been done in other tools as well:

-- Define render state (initialized when starting to render)
local render_context = {
  source_track = 0,
  target_track = 0,
  target_instrument = 0,
  temp_file_path = ""
}

-- Callback function to load the rendered file into a sample buffer
-- of the first sample of the first instrument
function rendering_done_callback()
  local song = renoise.song()
  song:describe_undo("Freeze Track")
  
  local source_track = song:track(render_context.source_track)
  -- Turn All Render Track Note Columns to "Off"
  for i=1,source_track.max_note_columns do
    source_track:set_column_is_muted(i, true)
  end
  -- Collapse Render Track
  source_track.collapsed = true
  -- Unsolo Source Track
  source_track:solo()
    
  -- Insert New Track Next to Render Track
  local target_track = song:insert_track_at(render_context.target_track)
  song.selected_track_index = render_context.target_track

  -- Rename New Track using Render Track Name
  target_track.name = (render_context.source_track .. " Rendered")

  -- Insert C-4 + Rendered Instrument number to Rendered Track
  local target_pattern = song:pattern(1):track(render_context.target_track)
  local target_note_column = target_pattern:line(1):note_column(1)
  target_note_column.note_string = "C-4"
  target_note_column.instrument_value = render_context.target_instrument - 1
  
  -- Create New Instrument
  local target_instrument = song:insert_instrument_at(render_context.target_instrument)
  target_instrument.name = target_track.name
  -- Load the rendered audio file into the sample buffer
  local target_sample_buffer = target_instrument:insert_sample_at(1).sample_buffer
  target_sample_buffer:load_from(render_context.temp_file_path)
  os.remove(render_context.temp_file_path)
end

function freezeTrack()
  local song = renoise.song()
  song:describe_undo("Freeze Track")
  
  -- Set render context
  render_context.source_track = song.selected_track_index
  render_context.target_track = render_context.source_track + 1
  render_context.target_instrument = #song.instruments
  render_context.temp_file_path = os.tmpname(".wav")

  -- Solo Source Track
  local source_track = song.tracks[render_context.source_track]
  if not source_track.solo_state then
    source_track:solo()
  end
  
  -- Render Selected Track
  local render_options = {
    sample_rate = 44100,
    bit_depth = 32,
    interpolation = "precise",    
    priority = "high",
  }
  -- Start rendering with the correct function call
  local success, error_message = song:render(
    render_options, render_context.temp_file_path, rendering_done_callback)
  -- Handle possible errors during the render initiation
  if not success then
    renoise.app():show_error("Rendering failed: " .. error_message)
  end
  -- Rest is done when rendering finished
end

freezeTrack()
3 Likes

thanks for introducing the temp_path for OS, this means i can get my version working with Windows, Linux and macOS in one go. i’ll incorporate bits from your snippet, and make the samplerate + bitrate configurable within Paketti. and still work in the #line-in detection for realtime vs high.

i appreciate you taking the time to incorporate the OS detection into the mix, as that was what i was looking forward to doing the least.

1 Like