Jump to content


Photo

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

play stop sample code play sample preview sample play stop note preview note play note instrument

  • Please log in to reply
26 replies to this topic

#1 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 19 December 2016 - 01:54

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

Edited by Raul (ulneiz), 21 December 2016 - 13:33.

:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#2 toblerpone

toblerpone

    Guruh Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPip
  • 904 posts
  • Gender:Not Telling
  • Location::c

Posted 19 December 2016 - 02:34

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.



#3 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 19 December 2016 - 03:08

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 internal OSC server to trigger notes with a tool"?

 

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. 


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#4 toblerpone

toblerpone

    Guruh Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPip
  • 904 posts
  • Gender:Not Telling
  • Location::c

Posted 19 December 2016 - 03:36

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

Edited by toblerpone, 19 December 2016 - 03:42.


#5 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 19 December 2016 - 08:39

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



#6 afta8

afta8

    Big Super GrandMasta Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPip
  • 709 posts
  • Gender:Male
  • Location:London

Posted 19 December 2016 - 11:37

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



#7 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 19 December 2016 - 11:52

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



#8 afta8

afta8

    Big Super GrandMasta Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPip
  • 709 posts
  • Gender:Male
  • Location:London

Posted 19 December 2016 - 12:21

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 



#9 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 19 December 2016 - 13:08

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.


Edited by joule, 19 December 2016 - 14:28.

  • afta8 likes this

#10 danoise

danoise

    Probably More God or Borg Than Human Member

  • Renoise Team
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 6419 posts
  • Gender:Male
  • Location:Berlin
  • Interests:wildlife + urban trekking

Posted 19 December 2016 - 13:25

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 the xVoiceManager class


  • afta8 likes this

Tracking with Stuff. API wishlist | Soundcloud


#11 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 19 December 2016 - 18:04

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.

Spoiler

Edited by joule, 19 December 2016 - 18:13.

  • Raul (ulneiz) likes this

#12 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 19 December 2016 - 20:57

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?

 


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#13 danoise

danoise

    Probably More God or Borg Than Human Member

  • Renoise Team
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 6419 posts
  • Gender:Male
  • Location:Berlin
  • Interests:wildlife + urban trekking

Posted 19 December 2016 - 21:25

@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?")

 

2. 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). 


Tracking with Stuff. API wishlist | Soundcloud


#14 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 19 December 2016 - 21:47

@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.


Edited by joule, 19 December 2016 - 21:47.


#15 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 04:00

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?")

 

2. 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?

2) 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):

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?


Edited by Raul (ulneiz), 20 December 2016 - 04:14.

:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#16 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 04:21

@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.


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#17 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 20 December 2016 - 08:38

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


Edited by joule, 20 December 2016 - 09:48.


#18 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 09:56

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?

 


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#19 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 20 December 2016 - 10:10

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.


Edited by joule, 20 December 2016 - 10:28.


#20 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 10:29

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, 40I'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.


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#21 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 20 December 2016 - 10:49

It should flash, very briefly, since it's temporarily switching off edit_mode to prevent recording any notes. If edit_mode was on before, it should be on after.

 

The reason why you're getting a strange behavior is likely due to the dubious structure of your code, specifically the way you handle the player object (rather creating two separate objects for pressed/released, which is not optimal).

 

Create one player object (with no_autoplay = true) in the scope above the button creation, then call my_player:play() and my_player.stop() from the pressed/released notifiers.

 

I think (!) it is enough if the workaround goes inside the OscPlayer:play() function. IIRC "orphan" note-offs won't get recorded anyway.


Edited by joule, 20 December 2016 - 10:58.


#22 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 11:00

I true this:

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  


----delay edit_mode 40ms 
  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
end

Keep writing one note (or two notes, depending the timer), when press the mouse.

 

What exactly happens (in slow process):

  1. Pressing click: write note A in note column 01
  2. Releasing click: write note B (the same note A) in note column 02

That is, as the gif shows.


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#23 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 20 December 2016 - 11:18

This seems to work perfectly fine here...
    local button = vb:button {
      text = tostring(note_value),
      pressed = function()
          local stored_edit_mode = renoise.song().transport.edit_mode
          if stored_edit_mode then
              renoise.song().transport.edit_mode = false
          end
      
          osc_client:trigger_instrument(true, instrument, track, note_value, velocity)
  
          if stored_edit_mode then
            local timer_func
            timer_func = function()
                renoise.song().transport.edit_mode = true
                renoise.tool():remove_timer(timer_func)
              end
            renoise.tool():add_timer(timer_func, 40)
          end      
        end,
      released = function()
          osc_client:trigger_instrument(false, instrument, track, note_value, velocity)
        end,
    }
A practical example is attached.

Attached File  joule.no0b.testpad.xrnx   1.56KB   54 downloads

Edited by joule, 20 December 2016 - 11:20.

  • Raul (ulneiz) likes this

#24 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1009 posts
  • Gender:Male
  • Location:Spain

Posted 20 December 2016 - 12:20

This seems to work perfectly fine here...

    local button = vb:button {
      text = tostring(note_value),
      pressed = function()
          local stored_edit_mode = renoise.song().transport.edit_mode
          if stored_edit_mode then
              renoise.song().transport.edit_mode = false
          end
      
          osc_client:trigger_instrument(true, instrument, track, note_value, velocity)
  
          if stored_edit_mode then
            local timer_func
            timer_func = function()
                renoise.song().transport.edit_mode = true
                renoise.tool():remove_timer(timer_func)
              end
            renoise.tool():add_timer(timer_func, 40)
          end      
        end,
      released = function()
          osc_client:trigger_instrument(false, instrument, track, note_value, velocity)
        end,
    }
A practical example is attached.

attachicon.gifjoule.no0b.testpad.xrnx

 

 

Is there a problem with setting the value "15" or "10" or "5" instead of 40? Why 40? With value <16 edit_mode not blinking, but I do not know if it depends on the hardware.

 

The "left click repeat rate" in preferences/Keys/Mouse Wheel has something to do?

 

I'll try to build a new piano based on your code, even if it means starting over. I want the tool to work as fine as possible.    I believe that with all this I can move forward. I also have another option in mind, edit the notes without using edit_mode. In this case, osc server would be canceled, and the notes would not sound if active edit_mode. As I have my code, I have a separate configuration for each button. I think I understand all your code, and I can use it to compress it to the maximum (within my possibilities).

 

Thank you very much for all this! I think it's the best solution for this case.

 

...with my_player:play() and my_player.stop(), I had an error in the terminal, by using them separately in "pressed" and "released" of the button. I was doing something wrong.

 

I will continue to build, and when I have something fine I will comment here, maybe this weekend.


:excl: Development of my tool: GT16-Colors

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#25 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1491 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 20 December 2016 - 12:37

Yeah, I could use 10ms to avoid any noticable flickering, but that's on an I7 processor. To be safe on slower computers, I would guess that 40ms would be OK. I'd suggest making a stress test in 1 core mode while using a couple of heavy VST/VSTi:s.