Here is a simple player class that should hopefully work in most cases.
I’ve included all that it needed (including the duplex oscclient) but nothing more. If you make a tool out of it, it will play a Cmaj7 chord for 3 seconds, extremely pleasing to your ears.
In Rauls’ case this might not be needed, since I’m guessing he’ll just start and stop on button press / button release. Then it would be sufficient to use the OscClient class only.
Click to view contents
-- Simple OSC voice player supporting duration
-- client: OscClient object
-- voices: table (!) of voices, one voice being { instrument_index, track_index, note_value, velocity }
-- duration: play duration in milliseconds
-- no_autoplay: if false, voices will play automatically when object is created
class 'OscPlayer'
function OscPlayer:__init(client, voices, duration, no_autoplay)
self.client = client
self.voices = voices
self.duration = duration
self._playing_voices = { }
self._release_func = function() self:stop() end
-- don't autoplay if true
if not no_autoplay then
self:play()
end
end
-- bloating the syntax for dubious legibility
function OscPlayer:get_parameters(voice_index)
local params = self._playing_voices[voice_index]
return params[1], params[2], params[3], params[4]
end
function OscPlayer:play()
-- cut notes if already playing
if (#self._playing_voices > 0) then self:stop() end
-- play and memorize voices
for k = 1, #self.voices do
local voice = self.voices[k]
self._playing_voices[k] = table.rcopy(self.voices[k])
self.client:trigger_instrument(true, self:get_parameters(k))
end
-- add "release" timer
renoise.tool():add_timer(self._release_func, self.duration)
end
function OscPlayer:stop()
-- remove the "release" timer
if renoise.tool():has_timer(self._release_func) then
renoise.tool():remove_timer(self._release_func)
end
-- send note-offs
for k = 1, #self._playing_voices do
local voice = self._playing_voices[k]
self.client:trigger_instrument(false, self:get_parameters(k))
end
self._playing_voices = { }
end
--[[============================================================================
-- Duplex.OscClient
============================================================================]]--
--[[--
OscClient is a simple OSC client that connect to the built-in OSC server in Renoise, producing realtime messages that trigger notes or send MIDI messages
--]]
--==============================================================================
class 'OscClient'
--------------------------------------------------------------------------------
--- Initialize the OscClient class
-- @param osc_host (string) the host-address name (can be an IP address)
-- @param osc_port (int) the host port
function OscClient:__init(osc_host,osc_port, protocol)
-- the socket connection, nil if not established
self._connection = nil
local client, socket_error = renoise.Socket.create_client(osc_host, osc_port, protocol)
if (socket_error) then
renoise.app():show_warning("Warning: Chord Tracker failed to start the internal OSC client")
self._connection = nil
else
self._connection = client
end
end
--------------------------------------------------------------------------------
--- Trigger instrument-note
-- @param note_on (bool), true when note-on and false when note-off
-- @param instr (int), the Renoise instrument index
-- @param track (int) the Renoise track index
-- @param note (int), the desired pitch, 0-120
-- @param velocity (int), the desired velocity, 0-127
function OscClient:trigger_instrument(note_on,instr,track,note,velocity)
-- TRACE("OscClient:trigger_instrument()",note_on,instr,track,note,velocity)
if not self._connection then
return false
end
local osc_vars = { }
osc_vars[1] = {tag = "i",value = instr}
osc_vars[2] = {tag = "i",value = track}
osc_vars[3] = {tag = "i",value = note}
local header = nil
if (note_on) then
header = "/renoise/trigger/note_on"
osc_vars[4] = {tag = "i",value = velocity}
else
header = "/renoise/trigger/note_off"
end
self._connection:send(renoise.Osc.Message(header,osc_vars))
return true
end
--------------------------------------------------------------------------------
--- END OF CLASSES. TESTING CODE BELOW
local my_osc_client = OscClient("127.0.0.1", 8000, 2)
local voices = {
{ 1, 1, 60, 100 },
{ 1, 1, 64, 100 },
{ 1, 1, 67, 100 },
{ 1, 1, 71, 100 }
}
local my_player = OscPlayer(my_osc_client, voices, 3000)
my_player:stop()
my_player:play() -- a bit of stress testing
my_player:stop()
my_player:play()