Cabbage Logo
Back to Cabbage Site

Noob question

Hi all,

I am about three weeks new to Csound and cabbage. I am currently in the stage of building my first instrument - a simple 4 operator FM synth.

I am wondering if it is possible to sync the values of the operator envelopes to the BPM of the host DAW. For example if I set the attack to 3, it will map to 3 beats defined by the host DAW BPM as opposed to seconds.

I have managed to sync the operators when being used as LFOs using the reserved channel HOST_BPM, but when I try with the envelopes, I am unable to due to the input arguments of madsr being i-rate.

Sorry if an obvious question, any help or direction would be appreciated :slight_smile:


I’m not quite sure I follow. You wish to have the operator envelopes re-triggered on each beat, irrespective of the overall ADSR? If you find yourself wanting k-rate parameters for an ADSR, it usually means you need to rethink your design. I’ve been there :joy:

Sorry, as I’m teaching myself I’ve probably not explained it well - a lot of the concepts are still quite hazy for me.

I have no doubt my instrument is a little bit ‘odd’ :joy:.

Basically, if I set attack to 3 and hold a note, the volume will move from 0 to set amplitude in 3 seconds (or three quarter notes at 60 bpm)

So if I open as a plugin in Reaper at 120 bpm, I know an attack value of 3 will move from 0 to set amplitude over a length of 6 quarter notes, and so on.

How could I ‘tempo sync’ this, so that an attack value of ‘3’ will mean a length of three quarter notes across any tempo set in the DAW?

It would be nice to have this level of control and predictability at any tempo set within the DAW. Is this possible?

Hopefully I’m making sense :joy:

Ok, now I get it. I believe what you want to do is multiply the rise time by 60/BPM? So if the BPM is 120, you want a rise time of 1.5 seconds, i.e., 3 * 60/120 = 1.5? Sound right?

Yes, correct :slight_smile:

I used an attack value of three as an example.

So I could change BPM in the DAW, and it will adjust the envelopes so that a value of ‘1’ second on any adsr control will be equal 1 ‘beat’.

Sounds like the simplest solution is to change your krate to equal your irate.

Thank you for the suggestion

How would I do that?

I am getting very confused by i, k, and a-rates. I have a basic understanding from the FLOSS manual.

As I understand it, a-rate and k-rate are set in the orchestra header?

Where abouts is i-rate determined?

You can’t change k-rate to equal i-rate, but you can cast one rate to another. But you don’t need to in this case. If you want a rise time of one beat set it to be 60/BPM

Thank you for your patient responses Rory.

I understand what you are saying. I managed to do something similar with LFOs like such:

gkbpm chnget "HOST_BPM

----------------------------------- ; then within the FM instrument block:

klfo1select chnget “LFO1Sync” ; control for lfo rhythm select

kFreq1 chnget “ModFreq1” ; Operator 1 modulation rate

; Operator 1 lfo rhythm selection conditionals. If set to anything other that ‘0’ then ModFreq1 GUI control bypassed.

if (klfo1select == 0) then
kFreq1 = kFreq1 ; Mod Freq1 rslider engaged. If on any other value then rslider bypassed.
elseif (klfo1select == 1) then
kFreq1 = gkbpm/240 ; whole note: 0.5hz
elseif (klfo1select == 2) then
kFreq1 = gkbpm/120 ; half notes: 1hz
elseif (klfo1select == 3) then
kFreq1 = gkbpm/60 ; quarter notes: 2hz
elseif (klfo1select == 4) then
kFreq1 = gkbpm/30 ; 8th notes: 4hz
elseif (klfo1select == 5) then
kFreq1 = gkbpm/15 ; 16th notes: 8hz
elseif (klfo1select == 6) then
kFreq1 = gkbpm/7.5 ; 32nd notes: 16hz
elseif (klfo1select == 7) then
kFreq1 = gkbpm/179.910044977511244 ; dotted half note: 0.667hz
elseif (klfo1select == 8) then
kFreq1 = gkbpm/90.022505626406602 ; dotted quarter note: 1.333hz
elseif (klfo1select == 9) then
kFreq1 = gkbpm/44.99437570303712 ; dotted 8th note: 2.667hz
elseif (klfo1select == 10) then
kFreq1 = gkbpm/22.501406337896119 ; dotted 16th note: 5.333hz
elseif (klfo1select == 11) then
kFreq1 = gkbpm/11.249648448485985 ; dotted 32nd note: 10.667hz
elseif (klfo1select == 12) then
kFreq1 = gkbpm/80 ; half note triplets: 1.5hz
elseif (klfo1select == 13) then
kFreq1 = gkbpm/40 ; quarter note triplets: 3hz
elseif (klfo1select == 14) then
kFreq1 = gkbpm/20 ; 8th note triplets: 6hz
elseif (klfo1select == 15) then
kFreq1 = gkbpm/10 ; 16th note triplets: 12hz
elseif (klfo1select == 16) then
kFreq1 = gkbpm/5 ; 32nd note triplets: 24hz

kMod1Env madsr iop1ampattack, iop1ampdecay, iop1ampsustain, iop1amprelease
kMod2Env madsr iop2ampattack, iop2ampdecay, iop2ampsustain, iop2amprelease
kMod3Env madsr iop3ampattack, iop3ampdecay, iop3ampsustain, iop3amprelease
aEnv madsr iattack, idecay, isustain, irelease
aMod1 oscilikt kAmp1kMod1Env, kFreq1, kOp1WaveShape
aMod2 oscilikt kAmp2
kMod2Env, kFreq2, kOp2WaveShape
aMod3 oscilikt kAmp3kMod3Env, kFreq3, kOp3WaveShape
aCar oscilikt kamp, kfreq+aMod1+aMod2+aMod3, kCarrierWaveShape
aBPfil butterbp aCar, kBPcutoff, kBwidth
outs aBPfil
aEnv, aBPfil*aEnv

(I haven’t included the whole code - just the relevant parts)

This enables me to load the plugin into Reaper, and no matter how many times I change the BPM setting in Reaper, the LFOs will return the same rhythms synced in time.

So what I would like is for something similar with the Envelopes - so values of ‘seconds’ will automatically adjust to values of ‘beats’ whatever BPM I arbitrarily decide to set.

This is where my knowledge falls short.

so something like:

aEnv madsr iattack*(60/gkbpm), idecay*(60/gkbpm), isustain*(60/gkbpm), irelease*(60/gkbpm)

Obviously this is wrong (I’m completely guessing) - and the output shows the following.

error: Unable to find opcode entry for ‘madsr’ with matching argument types:
Found: a madsr kkkk

I assume this has something to do with i-rate and k-rate.

Thanks agin.

Cast gkbpm as i-rate: i(60/gkbpm)
That should do it.

Where abouts do I put this in the code? In the initialisation block of the instrument?

I’ve tried a couple of things but get back:

error: syntax error, unexpected T_OPCODEB (token “i”) from file /Users/jackobrien/Library/Caches/Cabbage/temp_3582e8be.csoundCabbageCsdText (1)
line 74:

i <<<
Parsing failed due to invalid input!


aEnv madsr iattack*(60/i(gkbpm)), idecay*(60/i(gkbpm)), isustain*(60/i(gkbpm)), irelease*(60/i(gkbpm))

or else just create new i-rate variable and assign the value of gkbpm, and use that…

iBPM = i(gkbpm)
aEnv madsr iattack*(60/iBPM), idecay*(60/iBPM), isustain*(60/iBPM), irelease*(60/iBPM)

Brilliant - it worked!

Thanks for the advice, and a handy trick to know for the future :slight_smile: