Needed this personally but was to lazy to make a full tool out of it. Maybe useful for someone else.
--[[----------------------------------------------------------------------------
Author : Alexander Stoica
Creation Date : 01/19/2012
Last modified : 01/20/2012
Renders a song separated by instrument.
----------------------------------------------------------------------------]]--
local render_options = {
sample_rate = 44100, -- 22050, 44100, 48000, 88200, 96000
bit_depth = 16, -- 16, 24, 32
interpolation = "cubic", -- cubic, sinc
priority = "high" -- realtime, low, high
}
--[[globals]]-------------------------------------------------------------]]--
local thread = nil
--[[functions]]-----------------------------------------------------------]]--
function render()
local output_path = renoise.app():prompt_for_path(
"Select the destination folder:"
)
if not io.exists(output_path) then
print("Error: Invalid output folder specified, aborting!")
return
end
local rs = renoise.song()
-- cache volume levels
local cache = table.create()
for i, instrument in ipairs(rs.instruments) do
cache:insert(i, table.create())
cache[i] = {
pv = instrument.plugin_properties.volume,
sv = table.create()
}
for s, sample in ipairs(instrument.samples) do
if sample.sample_buffer.has_sample_data then
cache[i].sv:insert(s, sample.volume)
end
end
if cache[i].sv:is_empty() and
not instrument.plugin_properties.plugin_loaded then
cache[i] = nil
end
end
-- loop through each instrument
for t, vt in pairs(cache) do
local current_instrument = rs:instrument(t)
-- set volume of all instruments and their samples to 0
for i, _ in pairs(cache) do
local instrument = rs:instrument(i)
if instrument.plugin_properties.plugin_loaded then
instrument.plugin_properties.volume = 0
end
if not cache[i].sv:is_empty() then
for s, _ in pairs(cache[i].sv) do
local sample = instrument:sample(s)
sample.volume = 0
end
end
end
-- restore volume of the current instrument to render
if current_instrument.plugin_properties.plugin_loaded then
current_instrument.plugin_properties.volume = vt.pv
end
if not vt.sv:is_empty() then
for s, _ in pairs(vt.sv) do
local sample = current_instrument:sample(s)
sample.volume = vt.sv[s]
end
end
-- start rendering
local output_filename = output_path ..
string.format("%03d", t - 1) ..
string.format(" %03dBPM ", rs.transport.bpm) ..
string.gsub(current_instrument.name, "[<>:\"/\\|?*]", "")
output_filename = output_filename:match("^(.*%S)")
print("Rendering file: " .. output_filename .. ".wav")
rs.transport:panic()
rs:render(render_options, output_filename, render_done)
-- wait for renoise to finish rendering
coroutine.yield()
end
-- restore all volume levels
for i, vi in pairs(cache) do
local instrument = rs:instrument(i)
if instrument.plugin_properties.plugin_loaded then
instrument.plugin_properties.volume = vi.pv
end
if not vi.sv:is_empty() then
for s, _ in pairs(vi.sv) do
local sample = instrument:sample(s)
sample.volume = vi.sv[s]
end
end
end
print("Rendering completed!")
end
function render_done()
-- resume rendering thread
print("... done")
coroutine.resume(thread)
end
--[[entry point]]---------------------------------------------------------]]--
thread = coroutine.create(render)
coroutine.resume(thread)
---------------------------------------------------------------------[[EOF]]--