[Solved] Help, code for play/stop specific note of a instrument, is po

Each instrument consists of multiple samples, and each note can be associated with a particular sample, or all notes (120) associated to one sample only…

It is possible through the LUA API play and stop “a note” associated with a concrete sample?Sound the note!

I have a button , with " notifier", " pressed" and " released", and a instrument: “instrument 00”. The API allows this? :

WMP_KEY_00 = vb:button {
  id = 'WMP_KEY_00',
  tooltip = 'play/stop note C-0',
  width = 14,
  height = 50,
  color = { 0xFF,0xFF,0xFF },
  notifier = the function of notifier
  pressed = the function of play note C-0 of the selected "instrument 00" with specific volume <--???
  released = the function of stop note C-0... <--???
}

The note would sound while holding down the button with the mouse and it stops when the mouse release the button.It’s possible?Is there a way to do it?

I have built a complete virtual piano for editing with the mouse. But it would be great to play the notes with the mouse, using buttons. I have been looking at “Renoise.Song.API.lua” but I can not find a command to play stop the note.Most of the related has to do with the pattern editor or the sample editor.

Please help!

Thanks!

Related:

Button Properties:

– Valid in the construction table only: set up a click notifier.

button.pressed

-> [function()]

– Valid in the construction table only: set up a click release notifier.

button.released

-> [function()]

– synonymous for ‘button.released’.

button.notifier

-> [function()]

– Add/remove button hit/release notifier functions.

– When a “pressed” notifier is set, the release notifier is guaranteed to be

– called as soon as the mouse is released, either over your button or anywhere

– else. When a “release” notifier is set, it is only called when the mouse

– button is pressed !and! released over your button.

button:add_pressed_notifier(function or {object, function} or {object, function})

button:add_released_notifier(function or {object, function} or {object, function})

button:remove_pressed_notifier(function or {object, function} or {object, function})

button:remove_released_notifier(function or {object, function} or {object, function})

Inventing:

renoise.song().instruments[].samples[].play ???

renoise.song().instruments[].samples[].stop ???

renoise.song().instruments[…“instrument 00”…].notes[…“C-0”…].play???Is not there something like that? :huh:

renoise.song().instruments[].notes[].stop ???

The following code is related to Keyzones?


– renoise.SampleMapping


– General remarks: Sample mappings of sliced samples are read-only: can not be

– modified. See sample_mappings[].read_only

-------- Properties

– True for sliced instruments. No sample mapping properties are allowed to

– be modified, but can be read.

renoise.song().instruments[].sample_mappings[].read_only

-> [read-only, boolean]

– Linked sample.

renoise.song().instruments[].sample_mappings[].sample

-> [renoise.Sample object]

– Mapping’s layer (triggered via Note-Ons or Note-Offs?).

renoise.song().instruments[].sample_mappings[].layer, _observable

-> [enum = renoise.Instrument.LAYER]

– Mappings velocity->volume and key->pitch options.

renoise.song().instruments[].sample_mappings[].map_ velocity_to_volume , _observable

-> [boolean]

renoise.song().instruments[].sample_mappings[].map_key_to_pitch, _observable

-> [boolean]

– Mappings base-note. Final pitch of the played sample is:

– played_note - mapping.base_note + sample.transpose + sample.finetune

renoise.song().instruments[].sample_mappings[].base_note, _observable

-> [number (0-119, c-4=48)]

– Note range the mapping is triggered for.

renoise.song().instruments[].sample_mappings[].note_range, _observable

-> [table with two numbers ( 0-119 , c-4=48)]

– Velocity range the mapping is triggered for.

renoise.song().instruments[].sample_mappings[].velocity_range, _observable

-> [table with two numbers (0-127)]

I don’t remember if there was a way to access the note preview function through the API, but it is possible and was the common way of doing things, to use the internal OSC server to trigger notes with a tool.

I don’t remember if there was a way to access the note preview function through the API, but it is possible and was the common way of doing things, to use the internal OSC server to trigger notes with a tool.

With the API you can play any sequence within the pattern editor, for example.There are the written notes, and they reproduce.But reproduce directly a note of an instrument, without going through the pattern editor, is a different path.

I’m looking for references in the API, but I find nothing. “use the internalOSCserverto trigger notes with a tool”?

7141 mouse-piano-01.png

This is a new tool module that I am building.All the keys already work, they write the notes and it is possible to modify some values of a global form.But I am looking to sound the keys.I am also experimenting with colors.

Sound and colors… What I need are reference codes to experiment with, on the basis of a button.

This is a global tool, which includes up to 8 more modules.When I’m finished, I’ll share.I am very excited about this tool. She is solving many things that I miss, that Renoise does not include.The code of this module I wrote of the pull this last Saturday.But the same thing always happens to me. A wall with a certain characteristic, which slows me down…

Using logic it should be possible to play a note with a simple button.

With the API you can play any sequence within the pattern editor, for example.There are the written notes, and they reproduce.But reproduce directly a note of an instrument, without going through the pattern editor, is a different path.

I understand that. I was talking about the Preview sample function, but it doesn’t seem to be accessible via the api, now that I checked.

So OSC is your only option for playing the note without writing anything to a pattern. The osc documentation is in Renoise.OSC.API.lua, check the code snippet folder as well, you’ll end up in the GlobalOscActions.lua eventually and will look for

---- Realtime Messages

/renoise/trigger/midi(message(u/int32/64))

/renoise/trigger/note_on(instr(int32/64), track(int32/64),
 note(int32/64), velocity(int32/64))

/renoise/trigger/note_off(instr(int32/64), track(int32/64),
 note(int32/64))

The super simple way of doing OSC note triggering from a tool is to snatch “OscClient.lua” from the Duplex tool.

Interested in this also… don’t you need a device plugged in to generate the midi/osc note?

Interested in this also… don’t you need a device plugged in to generate the midi/osc note?

Hmm… No. The user must enable the OSC server in the Renoise preferences. When that is done, it’s quite simple sending notes to the server from a script.

I don’t know if my way is the pretties, but I use “OscClient.lua” which provides a very simple syntax. One simple line for initializing a “connection” object (client), and then one simple line for sending a note value. It’s documented quite clearly in the file mentioned so it should be difficult to go wrong with it.

The “tricky” part when implementing it is that you have to keep a table of active notes, because they have to be note-offed with a separate transmission, of course depending on for how long you want to hold your note(s). So you might need to use some timers and tailor-made scheme for triggering the following note-off… However, I strongly suspect there might even be a better class available, providing a “duration” parameter when triggering notes. I haven’t looked that deep into what’s available.

(Danoise?)

Hmm so in theory you could build a sequencer using just the scripting side of things and not rely on writing notes to the pattern editor?

Will have a look at the code you mentioned, I had a few tool ideas that never went anywhere because I didn’t think you could do this

Hmm so in theory you could build a sequencer using just the scripting side of things and not rely on writing notes to the pattern editor?

Will have a look at the code you mentioned, I had a few tool ideas that never went anywhere because I didn’t think you could do this

I suggest checking the accuracy of the renoise.app() timer. I can’t find the forum thread now, but IIRC taktik stated somewhere that the timer only roughly guarantees an accuracy of XYZ milliseconds. That’s probably why it’s best to rely on the native playback. Perhaps it could at least be “good enough” for previewing a sequence, though…

EDIT, PS: Except for what’s mentioned above, I have noticed that there might be some small additional irregular timing factor with OSC, on a millisecond(s) level. Possibly due to network latency, even when it’s local? It was noticable in a function that 1) turns off edit mode, 2) sends OSC, 3) turns on edit mode. (notes could get recorded). So, a little bit of timer management might also be needed if you want to prevent recording by this scheme.

Hmm so in theory you could build a sequencer using just the scripting side of things and not rely on writing notes to the pattern editor?

Will have a look at the code you mentioned, I had a few tool ideas that never went anywhere because I didn’t think you could do this

In theory, yes. It would be wonky like hell, due to the reasons mentioned by joule.

But definitely good enough for something like a preview… something like a chord navigator hint

I don’t know if my way is the pretties, but I use “OscClient.lua” which provides a very simple syntax. One simple line for initializing a “connection” object (client), and then one simple line for sending a note value. It’s documented quite clearly in the file mentioned so it should be difficult to go wrong with it.

The “tricky” part when implementing it is that you have to keep a table of active notes, because they have to be note-offed with a separate transmission, of course depending on for how long you want to hold your note(s). So you might need to use some timers and tailor-made scheme for triggering the following note-off… However, I strongly suspect there might even be a better class available, providing a “duration” parameter when triggering notes. I haven’t looked that deep into what’s available.

(Danoise?)

That’s right, today I would use the xOscClient(part of xLib).

Also, to keep track of active voices you could use thexVoiceManagerclass

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()

Ok Joule,I am using the upper code provided.For now, I can shoot the note from the button. And stop.

The steps I’ve taken:

I used the whole code, canceling the following lines:

...
...

--- 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()

Then I add the functions in the button:

--The button

-------------------------------(1)
presd()
  OscPlayer(my_osc_client, { { 1, 1, 60, 50 }, }, 3000) --<<----- 3000??? (delete duration)
end

-------------------------------(2)
reled()
  stop()
end

-------------------------------(the button)
WMP_KEY_00 = vb:button {
  id = 'WMP_KEY_00',
  width = 14,
  height = 50,
  pressed = function() presd() end, --(1)
  notifier = function() reled() end, --(2)  
--released = function() end, --released is similar to notifier
}

Now I have to look if I can eliminate time.And fix the code to use the selected instrument at any time.I have to find a way to not repeat the same code for the 120 buttons.

@Danoise. If something should be added in the API are the functions that will allow all this, without having to activate the OSC Server.Maybe it’s not available, it’s because it’s hard to implement.But apparently, I am not the only interested. Many things can be done with this.

To all, thank you very much!

If I have more doubts about this I will ask here.This is the first time I use the OSC Server.

Attached a code for a timer, in case it serves anything.:

function amic_CH04_4A() --This loop will stop itself after 1.5 seconds. Use a clock
  local starttime = os.clock()
  print("I'm about to spam you horribly for 1.5 seconds")
  while os.clock() - starttime < 1.5 do
  print("SPAM!")
  end
  print("All done :P")
end

One last question:

Is it possible to remove the automatic color selection or marked?For example, pressing a button lights up a color related to the skin of Renoise.Is it possible to replace it?

@Danoise. If something should be added in the API are the functions that will allow all this, without having to activate the OSC Server.Maybe it’s not available, it’s because it’s hard to implement.

It’s rarely the case that something is too hard to implement. More critical is,does it make sense to do so?

In this case, I think it would be nice. Perhaps not for the obvious reason (I’ve worked a lot with the current implementation and think it’s great - you can route messages to specific instrument, tracks, etc.) but rather, for these two reasons:

  1. We don’t actually have a way in the API to check if the OSC server is enabled, and at which port it is listening. So right now, as a tool author, you basically need to display a one-time message to the user that (s)he needs to enable the OSC server in Renoise.

And obviously, being able to control the OSC server via scripting would then be a first step… no need to display this message. But even this would have to be done carefully, because the OSC server allows you to send messages to containing lua code, which Renoise will then evaluate. I think Renoise will sandbox the code, protecting you against running certain methods (so you can’t wipe someones harddisk through the network!!), but it’s still something to be aware of. So I would basically still want to display a warning (“you’re going to enable the OSC server, are you sure you want to continue?”)

  1. The note that you create is a “note proper”. As a result, it might end up getting recorded somewhere in the project. This is not necessarily what you want. Workaround? Temporarily disable edit-mode if it was enabled, and re-enable after note has been triggered (ugly, but that should work).

@Raul,

Are you just gonna play and stop on pressed/release? In that case you don’t need the intermediate player I did. That was just for duration support.

Otherwise you can simply do something like:

local audition_client = OscClient("127.0.0.1", 8000, 2)

function create_button(instrument, note_value, velocity)

    local button = vb:button {
        text = "my_button",
        pressed = audition_client:trigger_instrument(
            true, instrument, note_value, velocity),
        released = audition_client:trigger_instrument(
            false, instrument, note_value, velocity)
    }
    
    return button
end

function create_row()

    local instrument = 1
    local velocity = 100

    local row = vb:row { }
    
    for note_value = 1, 10 do
        row:add_child(
            create_button(instrument, note_value, velocity)
        )
    end

    -- do what you want with the row here
    
end

I made the example a bit extensive since your approach seemed a little bit strange.

It’s rarely the case that something is too hard to implement. More critical is,does it make sense to do so?

In this case, I think it would be nice. Perhaps not for the obvious reason (I’ve worked a lot with the current implementation and think it’s great - you can route messages to specific instrument, tracks, etc.) but rather, for these two reasons:

  1. We don’t actually have a way in the API to check if the OSC server is enabled, and at which port it is listening. So right now, as a tool author, you basically need to display a one-time message to the user that (s)he needs to enable the OSC server in Renoise.

And obviously, being able to control the OSC server via scripting would then be a first step… no need to display this message. But even this would have to be done carefully, because the OSC server allows you to send messages to containing lua code, which Renoise will then evaluate. I think Renoise will sandbox the code, protecting you against running certain methods (so you can’t wipe someones harddisk through the network!!), but it’s still something to be aware of. So I would basically still want to display a warning (“you’re going to enable the OSC server, are you sure you want to continue?”)

  1. The note that you create is a “note proper”. As a result, it might end up getting recorded somewhere in the project. This is not necessarily what you want. Workaround? Temporarily disable edit-mode if it was enabled, and re-enable after note has been triggered (ugly, but that should work).

1)Maybe a checkbox (activate/deactivate) would suffice → Active OSC Server [v], with tooltip: “warning, bla bla bla”.What would be the function to activate?

  1. Wooow this has been a disappointment.!!! :blush:This is creating me problems. I need the edit-mode activated, to write the notes in the pattern editor while the note is being played.

At the point where I am, everything works:

  • Timer deleted. OK!
  • Note associated with each button (each key of virtual piano), with play/stop, OK!
  • Track selection, OK! (in pattern editor)
  • Instrument selection, OK! (in instruments box)
  • Volume control with a valuebox OK! (in tool)
  • edit-mode activated writte the notes in pattern editor with keys of virtual piano OK!
  • edit-mode activated with OSC activate, writte notes also, NOT OK! ← problem!!!

I just need to avoid your point 2 (to prevent notes being written to the pattern editor when playing the notes):

7144 osc-write-notes.gif

This should not happen(should not write any notes, should only sound the associated sample of the selected instrument).In the gif image capture, my functions about write notes in the pattern editor are disabled.It is caused by OSC related functions.

Is there any way to avoid this?

@Raul,

Are you just gonna play and stop on pressed/release? In that case you don’t need the intermediate player I did. That was just for duration support.

Otherwise you can simply do something like:

local audition_client = OscClient("127.0.0.1", 8000, 2)

function create_button(instrument, note_value, velocity)

local button = vb:button {
text = "my_button",
pressed = audition_client:trigger_instrument(
true, instrument, note_value, velocity),
released = audition_client:trigger_instrument(
false, instrument, note_value, velocity)
}
    
return button
end

function create_row()

local instrument = 1
local velocity = 100

local row = vb:row { }
    
for note_value = 1, 10 do
row:add_child(
create_button(instrument, note_value, velocity)
)
end

-- do what you want with the row here
    
end

I made the example a bit extensive since your approach seemed a little bit strange.

Thanks joule!I have it organized differently, maybe I will change it. I will try to experiment with this code.The “track selection” is missing.It should also be.

As mentioned earlier in the thread, you have to prevent the recording the notes by using some workaround. It can be done with a one-shot timer, delaying edit_mode=on for maybe 40ms or so. (one-shot = timer self destructs after one run)

EDIT: Yeah I forgot the track parameter in the osc triggering. For you to correct :wink:

As mentioned earlier in the thread, you have to prevent the recording the notes by using some workaround. It can be done with a one-shot timer, delaying edit_mode=on for maybe 40ms or so. (one-shot = timer self destructs after one run)

I do not know how to add it. I am attaching the code I currently use (the note duration timer is off, overridden lines):

--------------------------------------------------------------------------------
-- OSC SERVER
--------------------------------------------------------------------------------
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

class 'OscClient' --Initialize the OscClient class
  -- osc_host (string) the host-address name (can be an IP address)
  -- 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
--- note_on (bool), true when note-on and false when note-off
--- instr (int), the Renoise instrument index 1-254
--- track (int), the Renoise track index 
--- note (int), the desired pitch, 0-120
--- velocity (int), the desired velocity, 0-127
function 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 } --wmp_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
local my_osc_client = OscClient( "127.0.0.1", 8000, 2 )

--my_player = OscPlayer( my_osc_client, { { 1, 1, 60, 50 } }, 10000 )
--my_player:stop()

function wmp_instr( song, instr )
  song = renoise.song()
  instr = song.selected_instrument_index
  return instr
end

function wmp_track( song, track )
  song = renoise.song()
  track = song.selected_track_index
  return track
end

--function wmp_note() end

function wmp_vel( vel )
  vel = vb.views['WMP_CTRL_VEL'].value
  return vel
end

--------------------------------------------------------------------------------
-- A BUTTON: (C-0)
--------------------------------------------------------------------------------

function wmp_fn_key_00_pre()
  OscPlayer( my_osc_client, { { wmp_instr(), wmp_track(), 0, wmp_vel() } } ) --0 is the note
end
function wmp_fn_key_00_rel()
  OscPlayer( my_osc_client, { { wmp_instr(), wmp_track(), 0, wmp_vel() } } ):stop()
end
function wmp_fn_key_00( song, spi, sti, sli, snci ) --To write parameters in the pattern editor
  song = renoise.song()
  spi, sti, sli, snci = song.selected_pattern_index, song.selected_track_index, song.selected_line_index, song.selected_note_column_index
  if ( song.transport.edit_mode == true and song.selected_note_column ) then --condition for edit_mode == true
    song.patterns[spi].tracks[sti].lines[sli].note_columns[snci].note_value = 0 --note
    ins_inst()
    ins_vol()
    ins_pan()
    ins_dly()
    step_length()    
  end
end

--the vb:button (C-0 note)

WMP_KEY_00 = vb:button {
  id = 'WMP_KEY_00',
  tooltip = '',
  width = 14,
  height = 50,
  color = { 0xFF,0xFF,0xFF },
  pressed = function() wmp_fn_key_00_pre() end,
  --notifier = function() wmp_fn_key_00() end, --<----Disabled to test the OSC server in isolation
  released = function() wmp_fn_key_00_rel() end,
  bitmap = 'icons/c-0.png',
}

How do I add the “one_short timer” as you mention?

Hmm… I can’t verify my code now, but the principle looks pretty much like this:

local stored_edit_mode = renoise.song().transport.edit_mode

-- we only need the workaround if recording mode was on. let's not clutter memory/cpu otherwise ;)
if stored_edit_mode then
 renoise.song().transport.edit_mode = false
end
 
-- put playing trigger here!

-- reset to edit_mode = true after some delay
if stored_edit_mode then
 local timer_func
 timer_func = function()
   renoise.song().transport.edit_mode = true
   renoise.tool():remove_timer(timer_func) -- works?
  end

 renoise.tool():add_timer(timer_func, 40)
end

Not sure if it would fire an error if you press the key repeatedly very fast, but I don’t think so. Try it and we’ll work it out.

PS. Do you really need duration support? If not, ditch the OscPlayer class and use OscClient:trigger_instrument directly.

Where do I put the code exactly?

I’ve pasted it inside the function "function OscPlayer:__init( client, voices, duration, no_autoplay )"But the effect is strange. The red frame of the edit_mode flashes, and if very fast pulse ends off.

in,renoise.tool():add_timer(timer_func, 40)I’ve tested it with 10, 20, 40, 60, 80, and I keep typing values.

However, it does not return any errors, even shredding the mouse.