Add a `/renoise/trigger/note` OSC endpoint

OK, maybe this is a bit of a niche feature, but I’m going for it anyway.

Renoise is a crazy cool sound engine, and lately I’ve been trying to use it a backend to Tidal Cycles.

It kind of works, but I faced one major block. In renoise, like in MIDI, there is one event to trigger a note (note_on), and one event to release a note (note_off). From the point of view of a keyboard player, it makes sense: when you press a key to play a note, you don’t necessarily know for how long you will play it.

Things are a bit different in Tidal (and maybe other live coding environments). There, the note’s length is known from the start, so the event triggering the note contains the note’s duration, so the note_off event is moot. It may look like a minor difference, but it has quite a few implications (for example in Tidal each note is independant and “stateless”, which is not the case with note_on/off).

Anyway, here is the idea:

/renoise/trigger/note(instrument, track, note, velocity, duration)

That OSC endpoint would trigger a note like note_on, and attach a scheduled note_off event to that specific note.

I’ve tried to do it in lua, but I had some ugly lags. I guess there is a reason for /renoise/trigger/note_(on|off) to be hardcoded in renoise …

3 Likes

Let me elaborate on the subject.

The Tidal sequencer is built with polyphony in mind: you can trigger as many notes in parallel - you can even layer the same note multiple times if you want. As the length of the note is defined when triggered, the sequencer has full control over when each note stops.

Renoise is perfectly fine with polyphony - in fact you can also trigger the same note from the same instrument multiple times. But the API exposing note_on and note_off (either MIDI or OSC) is less expressive because a note_off event is not attached to a note_on event, but to a track+instrument+note.

It makes sense to do it this way because that’s how it is done with MIDI, but I think the interest of OSC is to go beyond MIDI limitations and build more expressive APIs.

OK I’ll stop ranting now, thanks for your time, and thanks for this wonderful piece of software! :wink:

1 Like

I just started to study this tidal cycles software, and I also thought a lot to try interaction with Renoise. now we are 1.5 people))

the problem with note on|off is relevant not only with tidal cycles, but also with other software

1 Like

Wow, +50% people interested in this in a month! at that rate we will soon be legions! :smiley:

1 Like

)))) Greetin!

Today I tried to connect Renoise + Tidal Cycles and everything seems to be fine, but for some reason the velocity does not work.

And the main ambush is that I can not write just an audio stream if it is a source of midi notes comes from another application.

Did you use that redirt thing I made, for tidal to renoise communication?

If so, the documentation says that tidal’s gain maps to renoise’s velocity, but I think that part is buggy and you should use the velocity function instead, with a 0-127 range.

1 Like

Nope! I just used renoise midi in/out. But thnx for information.

I’m still a beginner armed with a google translator, but I’m very interested and determined to study this software very seriously. many years of renoise practice, I want to integrate this experience. so I will ask stupid questions from time to time. for example, now I do not understand well how to connect Renoise via the Osc protocol. )))

Bless

That’s cool, tidal is quite wonderful, and could turn into a great live sequencer for renoise.

If you have any questions about tidal, may I suggest you to join the forum https://club.tidalcycles.org/ ? it’s a very nice and beginner-friendly community.

1 Like

it’s true! at the moment of meeting my hands were shaking.) for which day I have been exploring the possibilities. I already read the forum and study the presented examples

About OSC

@petitvolcan. It is possible to affirm that a key has 4 states:

  1. Without pressing
  2. Press
  3. Hold down
  4. Release

Keeping this in mind, do not forget that in addition to the Renoise API you have the LUA code 5.1, which is quite powerful and “simple” to program, together with MIDI input.

In this way, you can create three different note trigger systems, at least:

  1. The first is using note_on and note_off from OSC obeying the “press” (4 arguments) and “release” (3 arguments) of a key, always directed to a track, instrument and note (velocity for the note_on).
  2. But you can also use a second system, which triggers the note_off from a timer (the timer starts running when you press). In this way, you can set the duration of the note, and you only depend on the “act of pressing”.
  3. Use note_on and note_off only by pressing. This option will ignore the act of releasing.

The last two cases you can also use with release the key, so you can actually have 5 systems or methods.

If you want to go even further, all this allows you to build step sequencers, getting the sound through OSC. But it will be quite difficult to synchronize it with, for example, the playback of a pattern.

Keep in mind that note_on and note_off have associated writing the note (or note-off) in the pattern editor if it is in the foreground and with the edit mode activated.

By the way, the playback of note_on, note_off is in real time. If you experience any lag, it is probably caused by the sound card (or the network?). Personally, I have used OSC in a multitude of my own tools and it works perfectly. You may have experienced a “lost port” ever, but nothing else. To control the notes and their sound is fine.

hey, thanks for your input, but I’m not sure to follow everything here.

method 1 is basically what I’m doing right now - actually, I’m only note_on events and configuring my instruments as one-shot, so it works well for sequencing drums, but not for sequencing synths.

I considered that, namely adding a custom OSC endpoint that will recieve a note event from Tidal, send a /renoise/trigger/note_on event, and schedule a /renoise/trigger/note_off event, but it fell short for the following reasons:

  1. the scheduled note_off will be associated to (track,instrument,note) and will turn off any note associated to this tuple. So if I play a 1sec long C4 and play it again 500ms after, the note_off event scheduled by the first note will be applied to the second note, cutting it in half.
  2. the code I wrote to expose a custom endpoint to do just that gave me those weird lags - but maybe my code was just poor.

Sorry I don’t understand what you mean.

hitting those endpoints directly works perfectly. But having a custom endpoint that translates and reroute tidal events to those endpoints worked poorly for me.

Just to be clear, my aim here is not to gain full control over renoise from tidal. Right now I just want to trigger notes from instruments and control their macro parameters…

Hey, I’ve given this another try. Here is an endpoint I added to GlobalOscActions.lua.

TLDR:

  1. create a new endpoint /note (instr,track,note,velocity,duration)
  2. when an event arrive, send a OSC event /renoise/trigger/note_on (instr,track,note,velocity)
  3. …then create a OSC event /renoise/trigger/note_off (instr, track, note) but wrap it inside a bundle with a timetag shifted by duration.

Unfortunately, it looks like renoise is ignoring OSC bundle’s timetag, so this won’t work. Also, lua does not have sleep-like functions, and if it did, I don’t know if renoise is running the handler inside a separate thread (if not, sleeping here would freeze the application).

-- /note

local client, socket_error = renoise.Socket.create_client(
  "localhost", 8000, renoise.Socket.PROTOCOL_UDP
)

if (socket_error) then
  renoise.app():show_warning("failed to start the UDP client")
else
  add_global_action {
    pattern = "/note",
    description = "like /trigger/note_on but with duration",
    arguments = {
    	argument("instrument_index", "number"),
    	argument("track_index", "number"),
    	argument("note", "number"),
    	argument("velocity", "number"),
    	argument("duration", "number"),
    },
    handler = function(instrument_index, track_index, note, velocity, duration)
    	-- send note_on
    	local on = renoise.Osc.Message(
      	"/renoise/trigger/note_on",
      	{
        	{tag="i", value=instrument_index},
        	{tag="i", value=track_index},
        	{tag="i", value=note},
        	{tag="i", value=velocity},
      	}
    	)
    	client:send(on)
    	-- wait before sending note_off
    	local off = renoise.Osc.Message(
      	"/renoise/trigger/note_off",
      	{
        	{tag="i", value=instrument_index},
        	{tag="i", value=track_index},
        	{tag="i", value=note},
      	}
    	)
    	client:send(
    		renoise.Osc.Bundle(os.clock()+duration, off)
    	)
    end,
  }
end
1 Like

Greetings!
Could you write more detailed instructions for connecting renoise to tidalcycles?

thnx!

right now it is not very usable through OSC because of two things:

  1. OSC bundle timestamps are unsupported by renoise
  2. the lack of note + duration endpoint, even though it can be mitigated by sending note_off events manually

As suggested by Tidal Cycle’s author, right now the best way to do it is with superdirt’s MIDI instrument, which sends note_off events at the end of duration.

1 Like

Yes, I also drew on this problem with turning off the note. plus in some places renoise did not play other notes except the first one. in general, I’m satisfied with the midi connection, but how to disable the internal switching of octaves in renoise?