All,
Please find below version 1.0 of the ADSREnvelope wrapper class.
This class is designed to emulate a simple ADSR envelope and write it to the instrument envelopes which are now available to Lua with Renoise 2.8. It works with Renoise 2.8 beta 2 and will be maintained through the beta and release candidate period.
The code is self contained and can just be placed within it’s own file and 'require’d from your main tool code. It has error checking built in and will stop script execution and deliver a helpful message explaining any errors during use.
It’s free to use and well documented so you can fully understand how it works.
Enjoy!
Click to view contents
--------------------------------------------------------------------------------
-- ADSR Envelope Class
--
-- Copyright 2011 Martin Bealby
--
-- Free to use in any project
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Documentation
--------------------------------------------------------------------------------
--[[
The ADSR envelope class (ADSREnvelope()) is designed to present a simple ADSR
interface to the envelope objects available in Renoise 2.8.
The ADSREnvelope class presents the following API:
ADSREnvelope() - Create a new blank class instance
ADSREnvelope:set_attack(ticks) - Set the attack time (in ticks)
ADSREnvelope:set_decay(ticks) - Set the decay time (in ticks)
ADSREnvelope:set_sustain(level) - Set the sustain level (0 to 1)
ADSREnvelope:set_release(ticks) - Set the release time (in ticks)
ADSREnvelope:get_settings_string() - Retrieves all settings as a parameter
string
ADSREnvelope:load_settings_string(settings_string)
- Loads settings from a well-formed
parameter string
ADSREnvelope:copy_to(envelope) - Copies the ADSR envelope parameters into
the specified InstrumentMixerEnvelope or
InstrumentFilterEnvelope
The ADSREnvelope class takes care of automatically enabling / disabling the
sustain point depending upon the sustain value.
]]--
--------------------------------------------------------------------------------
-- Changelog
--------------------------------------------------------------------------------
-- Version 1.0 - Initial release based upon Renoise 2.8 Beta 2
--------------------------------------------------------------------------------
-- Class Preamble
--------------------------------------------------------------------------------
class "ADSREnvelope"
--------------------------------------------------------------------------------
-- Class Functions
--------------------------------------------------------------------------------
function ADSREnvelope:__init()
-- Initialise the class to defaults
self.attack_ticks = 6
self.decay_ticks = 6
self.sustain_level = 0.5
self.release_ticks = 6
end
function ADSREnvelope:set_attack(ticks)
-- Sets a new attack value
assert(type(ticks) == "number", "ADSREnvelope:set_attack() - ticks must be"..
" specified as a number")
assert(math.floor(ticks) >= 0 , "ADSREnvelope:set_attack() - ticks must be"..
" a positive number")
assert(math.floor(ticks) <= 127, "ADSREnvelope:set_attack() - ticks must be"..
" a number less than 128")
self.attack_ticks = math.floor(ticks)
end
function ADSREnvelope:set_decay(ticks)
-- Sets a new decay value
assert(type(ticks) == "number", "ADSREnvelope:set_decay() - ticks must be"..
" specified as a number")
assert(math.floor(ticks) >= 0 , "ADSREnvelope:set_decay() - ticks must be"..
" a positive number")
assert(math.floor(ticks) <= 127, "ADSREnvelope:set_decay() - ticks must be"..
" a number less than 128")
self.decay_ticks = math.floor(ticks)
end
function ADSREnvelope:set_sustain(level)
-- Sets a new sustain level
assert(type(ticks) == "number", "ADSREnvelope:set_sustain() - level must be"..
" specified as a number")
assert(level >= 0, "ADSREnvelope:set_sustain() - level must be between 0"..
" and 1")
assert(level <= 1, "ADSREnvelope:set_sustain() - level must be between 0"..
" and 1")
self.sustain_level = level
end
function ADSREnvelope:set_release(ticks)
-- Sets a new decay value
assert(type(ticks) == "number", "ADSREnvelope:set_release() - ticks must be"..
" specified as a number")
assert(math.floor(ticks) >= 0 , "ADSREnvelope:set_release() - ticks must be"..
" a positive number")
assert(math.floor(ticks) <= 127, "ADSREnvelope:set_release() - ticks must"..
" be a number less than 128")
self.release_ticks = math.floor(ticks)
end
function ADSREnvelope:get_settings_string()
-- Returns all ADSR settings as a string with header
return string.format("ADSR1:%d:%d:%f:%d",
self.attack_ticks,
self.decay_ticks,
self.sustain_level,
self.release_ticks)
end
function ADSREnvelope:load_settings_string(settings_string)
-- Verifies a settings string and loads all parameters from within
assert(type(settings_string) == "string", "ADSREnvelope:load_settings_string"..
" - settings string must be a"..
" string")
-- Split string into parameters
local param_table = {}
local from = 1
local delim_from, delim_to = string.find(settings_string, ":", from)
while delim_from do
table.insert(param_table, string.sub(settings_string, from, delim_from-1))
from = delim_to + 1
delim_from, delim_to = string.find(settings_string, ":", from)
end
table.insert(param_table, string.sub(settings_string, from))
assert(#param_table == 5, "ADSREnvelope:load_settings_string - settings"..
" string has incorrect number of parameters")
assert(param_table[1] == "ADSR1", "ADSREnvelope:load_settings_string -"..
" settings string header check failed")
-- Seems ok, set parameters
self.attack_ticks = tonumber(param_table[2])
self.decay_ticks = tonumber(param_table[3])
self.sustain_level = tonumber(param_table[4])
self.release_ticks = tonumber(param_table[5])
end
function ADSREnvelope:copy_to(envelope)
-- Copies the ADSR curve to the specified envelope object
if (type(envelope) == "InstrumentMixerEnvelope") or
(type(envelope) == "InstrumentFilterEnvelope") then
-- supported envelope type
-- clear existing envelope
envelope:clear_points()
-- add attack points
if self.attack_ticks > 0 then
envelope:add_point_at(1, 0)
envelope:add_point_at(1 + self.attack_ticks, 1)
else
envelope:add_point_at(1, 1)
end
-- add decay points
envelope:add_point_at(1 + self.attack_ticks + self.decay_ticks,
self.sustain_level)
-- add sustain / release points
if self.sustain_level ~= 0 then
if self.release_ticks > 0 then
envelope:add_point_at(1 + self.attack_ticks + self.decay_ticks
+ self.release_ticks, 0)
else
envelope:add_point_at(1 + self.attack_ticks + self.decay_ticks
+ 1, 0)
end
envelope.sustain_position = self.attack_ticks + self.decay_ticks + 1
envelope.sustain_enabled = true
else
envelope.sustain_enabled = false
end
envelope.enabled = true
else
-- unsupported envelope type
assert(false, "ADSREnvelope:copy_to(envelope) - envelope must be of type"..
" InstrumentMixerEnvelope or InstrumentFilterEnvelope")
end
end