I installedre.dread’sdBatchProcess which is a GUI frontend for sox that has presets for various audio processing effects.
I’m not experienced with lua but I was able to figure out how to create custom presets, which are in a file called presets.lua, separate from the main.lua file.
The custom presets that I created work fine but they aren’t properly sortedin the popup menu. I’d like to keep similar commands, ie “Normalize -3db”, “Normalize -6db”, next to each other so that the list isn’t such a mess and the items are easier to locate.
Does anybody have an example on how to sort the popup list either alphabetically or by the order that the presets appear in the presets.lua file?
Here is the code for the 2 files…
main.lua
Click to view contents
– dBatchProcess
–
– …
– © 2014 re.dread
–[[ TODO:
]]–
require ‘process_slicer’
require ‘presets’
local TOOLTIPS = true
local tool_id = “dBatchProcess”
local tool_version = “0.1”
local dialog = nil
local vb = nil
local opt = renoise.Document.create(“ScriptingToolPreferences”) {
path = [[c:\Program Files (x86)\sox-14-4-1]],
cmd = [[sox in_file out_file silence 1 0.1 1% reverse silence 1 0.1 1% reverse]],
– 1 = instrument, 2 = samples
delete_source = 1,
}
renoise.tool().preferences = opt
– add menu entries
–[[
renoise.tool():add_menu_entry {
name = “Instrument Box: Batch process …”,
invoke = function() show_dialog(true) end
}
]]
renoise.tool():add_menu_entry {
name = “Sample Editor: Batch process …”,
invoke = function() show_dialog(true) end
}
renoise.tool():add_menu_entry {
name = “Sample Navigator: Batch process …”,
invoke = function() show_dialog(true) end
}
function quote(string)
return ((os.platform() == “WINDOWS”) and “”" … string … “”" or string)
end
function os.capture(cmd, raw)
local f = assert(io.popen(cmd, ‘r’))
local s = assert(f:read(’*a’))
f:close()
if raw then return s end
s = string.gsub(s, ‘^%s+’, ‘’)
s = string.gsub(s, ‘%s+$’, ‘’)
s = string.gsub(s, ‘[\n\r]+’, ’ ')
return s
end
local vol
function process_sample(sample, analyze)
if not sample then return end
local buffer = sample.sample_buffer
if not buffer.has_sample_data then return end
– save sample to temp location
local file_in = os.tmpname(“wav”)
buffer:save_as(file_in, “wav”)
– prepare output file
local file_out = os.tmpname(“wav”)
– substitute sample paths
local cmd = string.gsub(opt.cmd.value, “@in”, quote(file_in))
local cmd = string.gsub(cmd, “@out”, quote(file_out))
– kindof dirty, but seems to work
cmd = quote(opt.path.value) … cmd … " 2>&1 "
print(cmd)
– execute command
local cmd_output = os.capture(quote(cmd))
rprint(cmd_output)
local vol_find = string.find(cmd_output, “%d+%.%d+$”)
if vol_find then
local vol_tmp = tonumber(string.sub(cmd_output, vol_find))
if vol then
vol = (vol_tmp < vol) and vol_tmp or vol
else – first sample
vol = vol_tmp
end
end
if vol then
print(“Sample volume: -” … vol …“db”)
end
– reload sample
local output_file = io.exists(file_out)
if not output_file then
renoise.app():show_status(
analyze and “dBatchProcess: analyzing sample volumes” or
"dBatchProcess: WARNING: No output file produced, loading input file … ")
end
buffer:load_from(output_file and file_out or file_in)
end
function update_progress(sample_i, samples)
vb.views.process_all_btn.text = sample_i … " / " … samples
if sample_i == samples then
vb.views.process_all_btn.text = “Process all!”
end
end
function process_all_()
vol = nil
local instr = renoise.song().selected_instrument
local normalize = false
if opt.cmd.value == “@normalize” then
opt.cmd.value = “sox @in -n stat -v”
normalize = true
end
for sample_i, sample in ipairs(instr.samples) do
process_sample(sample, true)
update_progress(sample_i, #instr.samples)
coroutine:yield()
end
if normalize then
opt.cmd.value = (“sox -v %f @in @out”):format(vol - 0.01)
for sample_i, sample in ipairs(instr.samples) do
process_sample(sample)
update_progress(sample_i, #instr.samples)
coroutine:yield()
end
opt.cmd.value = “@normalize”
end
end
local process
function process_all()
process = ProcessSlicer(process_all_, update_progress)
process:start()
–process_all_(update_progress)
end
function cancel()
if process and process:running() then
process:stop()
end
end
– ze gui
function show_dialog(instr)
if dialog and dialog.visible then
dialog:show()
return
end
vb = renoise.ViewBuilder()
local DEFAULT_DIALOG_MARGIN =
renoise.ViewBuilder.DEFAULT_DIALOG_MARGIN
local DEFAULT_CONTROL_SPACING =
renoise.ViewBuilder.DEFAULT_CONTROL_SPACING
local DEFAULT_BUTTON_HEIGHT =
renoise.ViewBuilder.DEFAULT_DIALOG_BUTTON_HEIGHT
– dialog content
local dialog_content = vb:column {
style = “body”,
margin = DEFAULT_DIALOG_MARGIN,
spacing = DEFAULT_CONTROL_SPACING,
uniform = true,
vb:horizontal_aligner {
–visible = false,
mode = “justify”,
vb:text { text = “Process samples”, font = “bold” },
},
vb:space { height = 5 },
vb:row {
style = “border”,
margin = DEFAULT_DIALOG_MARGIN,
spacing = DEFAULT_CONTROL_SPACING,
vb:column {
vb:text { text = "PATH " },
vb:text { text = "CMD " },
vb:text { text = "Presets: " },
},
vb:column {
spacing = DEFAULT_CONTROL_SPACING,
vb:horizontal_aligner {
mode = “justify”,
vb:textfield {
id = “path_txt”,
bind = opt.path,
width = 280,
},
vb:button {
id = “select_path”,
text = “*”,
notifier = function()
local new_path = renoise.app():prompt_for_path(“Executable path …”)
if new_path and new_path ~= “” then
opt.path.value = new_path
end
end,
},
},
vb:textfield {
id = “cmd_txt”,
bind = opt.cmd,
width = 300,
},
vb:popup {
items = table.keys(presets),
width = 300,
notifier = function(i)
vb.views.desc_txt.text = table.values(presets)[i].desc
opt.cmd.value = table.values(presets)[i].cmd
end
},
vb:multiline_textfield {
id = “desc_txt”,
width = 300,
height = 55,
text = “”
},
},
},
–vb:space { height = 5 },
vb:horizontal_aligner {
visible = false,
vb:checkbox {
bind = opt.delete_source_sample
},
vb:text { text = " delete source sample(s)" },
},
–vb:space { height = 10 },
vb:horizontal_aligner {
mode = “distribute”,
spacing = DEFAULT_CONTROL_SPACING,
margin = 5,
vb:button {
id = “process_btn”,
text = “Process sample!”,
notifier = function()
process_sample(renoise.song().selected_sample)
end
},
vb:button {
id = “process_all_btn”,
text = “Process all!”,
notifier = process_all,
},
vb:button {
text = “Cancel!”,
notifier = cancel,
},
},
}
– key_handler
local function key_handler(dialog, key)
– ignore held keys
if (key.repeated) then
return
end
if (key.name == “esc”) then
dialog:close()
end
end
– show
dialog = renoise.app():show_custom_dialog(
tool_id … " " … tool_version, dialog_content, key_handler)
end
presets.lua
Click to view contents
– presets:
presets = {
[“SoX: Normalize (Relative)”] =
{
cmd = “@normalize”,
desc = [[Normalize all samples relative to the loudest sample.]],
},
[“SoX: Trim silence (start/end)”] =
{
cmd = “sox @in @out silence 1 0.1 0.1% reverse silence 1 0.1 0.1% reverse”,
desc = [[Trim silence from start and end of the sample.
0.1% is the threshold value.]],
},
[“SoX: Change sample speed”] =
{
cmd = “sox @in @out speed 1200c”,
desc = [[Speeds up the sample with an amount of cents, setting it to 1200 is like shifting the octave.]],
},
[“SoX: Contrast”] =
{
cmd = “sox @in @out contrast 50”,
desc = [[Comparable with compression, this effect modifies an audio signal to make it sound louder. enhancement-amount controls the amount of the enhancement and is a number in the range 0−100. Note that enhancement-amount = 0 still gives a significant contrast enhancement.]],
},
[“SoX: Change sampling rate”] =
{
cmd = “sox @in -r 22k @out”,
desc = [[Change the sampleing rate. Here 22k]],
},
[“SoX: Echo (Short metallic)”] =
{
cmd = [[sox @in @out echo 0.8 0.88 6 0.4]],
desc = [[echo gain-in gain-out
Add echoing to the audio. Echoes are reflected sound and can occur naturally amongst mountains (and sometimes large buildings) when talking or shouting; digital echo effects emulate this behaviour and are often used to help fill out the sound of a single instrument or vocal. The time difference between the original signal and the reflection is the ‘delay’ (time), and the loudness of the reflected signal is the ‘decay’. Multiple echoes can have different delays and decays.]],
},
[“SoX: Fade in/out”] =
{
cmd = [[sox @in @out fade 0.01 0 0.01]],
desc = [[fade [type] fade-in-length [stop-time [fade-out-length]]
Apply a fade effect to the beginning, end, or both of the audio.
An optional type can be specified to select the shape of the fade curve: q for quarter of a sine wave, h for half a sine wave, t for linear (‘triangular’) slope, l for logarithmic, and p for inverted parabola. The default is logarithmic.
A fade-in starts from the first sample and ramps the signal level from 0 to full volume over fade-in-length seconds. Specify 0 seconds if no fade-in is wanted.
For fade-outs, the audio will be truncated at stop-time and the signal level will be ramped from full volume down to 0 starting at fade-out-length seconds before the stop-time. If fade-out-length is not specified, it defaults to the same value as fade-in-length. No fade-out is performed if stop-time is not specified. If the file length can be determined from the input file header and length-changing effects are not in effect, then 0 may be specified for stop-time to indicate the usual case of a fade-out that ends at the end of the input audio stream.
All times can be specified in either periods of time or sample counts. To specify time periods use the format hh:mm:ss.frac format. To specify using sample counts, specify the number of samples and append the letter ‘s’ to the sample count (for example ‘8000s’).]],
},
[“SoX: Normalize”] =
{
cmd = [[sox @in @out norm 0.01]],
desc = [[norm [dB-level]
Normalise the audio. norm is just an alias for gain −n; see the gain effect for details.]],
},
[“SoX: Reverb”] =
{
cmd = [[sox @in @out pad 0 3 reverb]],
desc = [[reverb [−w|−−wet-only] [reverberance (50%) [HF-damping (50%)
[room-scale (100%) [stereo-depth (100%)
[pre-delay (0ms) [wet-gain (0dB)]]]]]]
Add reverberation to the audio using the ‘freeverb’ algorithm. A reverberation effect is sometimes desirable for concert halls that are too small or contain so many people that the hall’s natural reverberance is diminished. Applying a small amount of stereo reverb to a (dry) mono signal will usually make it sound more natural. See [3] for a detailed description of reverberation.]],
},
}
Thanks.