Cabbage Logo
Back to Cabbage Site

Suggestions for envelope UDO truncating synth notes?

Hey everyone! I’m looking for some help/ideas on reaching a goal. I’ve banged my head against this for a little bit already, to no avail… so I feel like I’m missing something either obvious or elegant… maybe even both.

I have a cabbage synth that’s realtime midi controlled. It calls a UDO that returns an A/K rate variable to be used as an ADSR envelope by the synth. The UDO already calls madsr to make an envelope, but I would like to be able to choose a different envelope mode via combobox that will truncates the parent note, basically implementing a sort of “max time” for the envelope’s synth note before it goes straight into the release phase.

A caveat, I know that I could just have the envelope drop to and remain at 0, letting the note continue for whatever duration… but I’d really prefer to terminate processing the note as soon as possible to help maintain as much processing power for real time polyphony as possible.

I have a feeling the answer lies with turnoff2… but I can’t piece it together for some reason. Any help or hints would be huge, thanks!

Just so I’m clear, you want to terminate a note at any time, and in doing so trigger its release phase? I’m not sure how this would work. Here’s an example that uses channels to notify an instrument to turn off. But if if are holding a MIDI note a new note will start anyway? I’m pretty confused, so if my code ticks any of your boxes it’ll be time to crack open the champagne :laughing:

endADSR.csd (1.1 KB)

Thanks for the example Rory! I don’t think it’s quite what I was looking for (or maybe I didn’t understand how to apply it to my problem), but it’s also possible that I’m trying too hard to reach my goal via a specific route and overly complicating the problem in the process. It is definitely helping me to think of alternate methods to get there rather than tunnel-vision focusing on how to reach my goal this one particular way.

Not quite, but sort of… here’s a try at restating the problem: I’m trying to have a UDO that acts as an envelope generator with a mode selected via combobox. If that combobox is set to this second mode, a maximum note length is enforced that is user definable via rslider. Any notes calling this UDO that exceed that max length are turned off and forced to enter the release phase, if they hadn’t already. That way if this envelope UDO were used in a very processing heavy synth, it could cut held notes off after their desired envelope time rather than leaving them processing in silence until the key is released.

For portability, I would like this timing/turnoff processing to happen in the UDO, not the synth itself. If the UDO itself could call turnoff once it’s duration exceeds the value in the rslider, turning off the parent instrument… that would be ideal, and (I think) what I was trying to achieve.

This is a simplified working example, other than the segfault when turnoff condition is reached. This represents the way I’ve been trying to get this working, but perhaps another route would be better. I’ll keep thinking on ideas tonight.

Just in case it behaves different for you, this is being tested on OSX 10.13.6, with csound 6.13. I had issues with changes to string/channel behavior in 6.14, and haven’t had the time to figure out a good solution to that.

endADSR2.csd (1.3 KB)

Hopefully the example helps and this is a little more clear than my first description? Thanks again!

A simple fix is to notify the main instrument that is should turn off, as shown below. I’ll now try to see why that segfault it happening…

opcode MyADSR,ak,0
    iMode  = 2;chnget "mode"
    iMaxTime = 3; chnget "maxtime"
    ; counts 0 to 1 (and beyond!) over duration of "maxtime"
    kTimer linseg 0, iMaxTime, 1
    kEnd = 0;
    iAtt = .1
    iDec = .2
    iSus = .6
    iRel = 1
    aEnv madsr iAtt, iDec, iSus, iRel

    ; once kTimer has been reached "1" and mode is "2", turnoff sounding note
    if(iMode==2 && kTimer==1) then
        kEnd = 1

    xout aEnv, kEnd

;instrument will be triggered by keyboard widget
instr 1
    aEnv, kEnd MyADSR
    aOut vco2 p5, p4
    aOut *= aEnv

    if changed(kEnd) ==1 then
    outs aOut, aOut

Looks like a bug with turnoff. I think the solution above is probably the best option for now.

Yeah, this is pretty similar to where I ended up as a possible workaround too… but since the goal is encapsulation/portability as part of an imported widget group, I’d like to keep the UDO’s usage as short and simple as possible.

I’ll try to design as if it will eventually work as intended, but comment out the segfaults and for now I will look at using a workaround . Should I submit any info about this, or is a bug already open about it etc?

No bug is issues yet. This is the minimal code I was using to demo it:

ksmps = 32
nchnls = 2
0dbfs = 1
opcode MyUDO,a,0
    kTimer linseg 0, 5, 5
    if(kTimer > 1) then
    xout a(1)
instr 1
    a1 MyUDO
i1 0 8

I don’t have my Csound dev machine set up at the moment, but once I get it up and running I’ll run this through the debugger and see what I can see.

1 Like

So, when this special mode is selected, and the maximum time (set by a slider) is reached, you want the notes to just truncate immediately, likely causing a click? Or you want the note to go into release mode?

Do you need to set it up so that notes that are already playing can be switched to a different mode in the middle of the note?

EDIT: one thing i didn’t know for the longest time when I started out with Csound was that an instrument’s code can alter its own p3 (duration). This even works with midi-triggered notes, i believe. So adding
p3 = 1.5
to the instrument means every note you trigger will be 1.5 seconds long, even if you just tap the key, or even if you hold down the key forever. If there is also an opcode such as madsr that creates a release stage, then the note will last for 1.5 seconds and then enter the release stage.
So maybe your opcode could contain something like
imode chnget "mode_selection"
if (imode==1) then
p3 chnget "maxtime"
Not sure if this is the behavior you want. It means any given note’s mode is set when the note is triggered and can’t be changed in the middle of the note.

For what it’s worth, this bug has been fixed in the Csound dev branch :wink:

I didn’t know that. Might be quite handy in certain contexts.

Its very handy, because it basically lets you make instruments that do have absolutely no midi-specific code, and just use midi as a way to trigger note events. i use it a lot when i want to use midi to audition an instrument as i develop it, but the code im developing is intended to eventually be something other than a midi instrument.

That’s a nice tip!

I think the test I posted showed it ending in a click, but that was just to make the segfault bug clear… but my end goal is to basically have a typical madsr envelope, that works perfectly normal most of the time, it holds the notes until released etc.

But when this other mode is enabled, it will only hold a note as long as this max time setting, forcing a release phase and then termination of the note completely, regardless of if the key is still being held. For example, a=1, d=1, r=1… if maxtime is 1 and you hold a note, the decay phase would be skipped because the note terminates due to “turnoff”, moving straight to release phase of the envelope.

It’s similar to changing length with p3, but I don’t want to lengthen shorter notes, only cut off longer ones. Setting p3 would result in all notes having the same length, which isn’t my goal either.

Rory is right tho, the underlying bug of using turnoff from a UDO has been fixed upstream. I can’t build new binaries, so I’m waiting for the next release to really complete and test my envelope UDO and widgets… assuming I still don’t run into all the string issues that have already kept me back a version :wink:

Hi @csound1734 I’m just trying this now and I can’t get my MIDI triggered notes to last for p3 if I release them early :thinking:

If I do this for example, and release the note early I get a click:

instr 1
    p3 = 10
    a1 expon p5, p3, 0.001
    a2 oscili a1, p4, -1
    outs a2, a2