Cabbage Logo
Back to Cabbage Site

Ascii midi keyboard control

I’m still not sure I follow the problem. This instrument will notify you of the instrument instance when the note is released. It uses lastcycle rather than released, but it effectively behaves the same way.

<Cabbage>
form caption("Untitled") size(400, 300), guiMode("queue"), pluginId("def1")
keyboard bounds(8, 158, 381, 95)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 --midi-key-cps=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1

;instrument will be triggered by keyboard widget
instr 1
    id = rnd(1000)
    prints sprintf("Instance ID:%d", id)
    kEnv madsr .1, .2, .6, .4
    aOut vco2 p5, p4
    outs aOut*kEnv, aOut*kEnv
 
    if lastcycle() == 1 then
        printks "Release ID %d\n", 0, id
    endif 
endin

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
</CsScore>
</CsoundSynthesizer>

I don’t think this is going to work either for the same reason, because i’m sending more than 1 note through the instrument. I could send 6 notes on the same frequency on a different string gauge through the same instrument. An opcode that takes no arguments and just looks at the instrument number i think will not distinguish between those notes at once.

Not if you assign a unique id to each instance. In terms of how Csound processes instruments, each instance is unique.

How, precisely ?
Does that require to work with event statements ?
Because I don’t use those. I could use them, they needed less note state information; but then i also have to swap my visuals into separate instruments, i wonder if that will work. There shouldn’t be a difference in calling an opcode vs an instrument, right ?

The example I posted gives each instance a unique id(*), and doesn’t use any event opcodes.

* not entirely true, but could be built to do so without much pain.

1 Like

Alright, I’ll try that

1 Like

Right now I have “xtratim” going on, which makes sure my note state information triggers run after I release the key. The “release” opcode signaled when I lifted the key.

When I use “lastcycle”, it signals the release; but only after xtratim is completed. And since I use this signal for the other note state information to trigger (the release), the end of the note state information doesn’t complete.

Is there a way to send that note-off at the onset of the release (just like the release opcode) ? Or an xtratim without extra time ?

Other than that, the multiple key registration thing works as I had in mind.

Why do you need ‘xtratim’. All notes will enter a release phase, regardless of xtratim.

I’m not sure I follow, are you spawning your own notes here? What would really help would be a stripped down minimal example of what you’re trying to do.

The velocity curve is essentially an exponential function following “kt” ,a time variable, starting from 0 each time:
exp(-kt)
This curve is different for each frequency of the timbre and also depends on the p5, p4 and so on.

“xtratim”, I used just for extra time after I lift the keys for extra flexibility in playing.
I guess with “linsegr”, lastcycles will also report after the release ?

multiple keys release test.csd (754 Bytes)

Does seem to work, by just swapping “lastcycle” for “release”. I then removed the envelope filter.
I didn’t know release also worked writing it like that, as there are no examples or different syntax mentioned in the reference manual.

lastcycle will report after linsegr has completed its release phase. release() will trigger when the release stage starts. I’d use one of the r family of envelopes in this context. Would be easier than rolling your own.

Here is a modified version of your code, minus the xtratim:

instr 1

    id = rnd(1000)
    prints sprintf("Instance ID:%d\n", id)
    kEnv madsr .1, .2, .6, 1
    aOut vco2 p5, p4
    outs aOut, aOut
    
    kRel init 0
    if release() == 1 && kRel == 0 then
        printks "Release started: %d\n", 0, id
        kRel = 1
    endif 
    
    if lastcycle() == 1 then
        printks "Last cycle: %d\n", 0, id
    endif 
endin

I was mistaken,
In the end it doesn’t work any better than “kflag release”.
While the sound does work internally as it should, there seems no way to relate the release to anything else to write it down and control values that way, even with the id.

I’m not really following the problem. Right now you can start a unique instance of a note, and be notified when that unique instance has been triggered to stop, and also when it has stopped. I thought this was what you were looking for?

Not really,

I have a counter which keeps track of all my strings (6).
Each string triggers on a certain condition.
I’m now going the event / score route, where I trigger the strings separately.
If I have a way now to transfer the “p3” to the separate instruments, I can use the “release” and “lastcycle” in those instruments.
Here, a snippet of what I’m trying to make work:

form caption("Note State Example") size(300, 200), guiMode("queue"), pluginId("def1") keyboard bounds(10, 10, 280, 100), channel("noteState") -n -d -+rtmidi=NULL -M0 -dm0 --midi-key-cps=4 --midi-velocity-amp=5

sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1

gkCounter init 0 ; will only iterate through the strings

instr 1

ktime times

kdur = 2
idur = 2

;xtratim idur + .001

iTun = 0
kStringFrequency = p4 / 2 * cent(iTun*100)
kAmp1 = -(10^(-p5))+1.1

ktrigger changed p5

if ktrigger == 1 then
gkCounter += 1

endif

/if giCounter > 6 then
giCounter = 1
endif
/

kStringE init 0
kStringA init 0
kStringD init 0
kStringG init 0
kStringB init 0
kStringe init 0

kS1 init 0
kS2 init 0
kS3 init 0
kS4 init 0
kS5 init 0
kS6 init 0

if kStringE == 0 && kStringA == 0 && kStringD == 0 && kStringG == 0 && kStringB == 0 && kStringe == 0 then
kSTrigE trigger gkCounter == 1 ? 1 : 0, 0, 0
endif

/if kStringE == 1 then
kSTrigE init 0
endif
/

if kSTrigE == 1 then
konsetE = p2
kStringE = 1
kStringFrequencyE = kStringFrequency
endif

schedkwhen kSTrigE, 0, 1, 4, 0, .001, p4, p5

kInstr4E active 4 ;[,iopt [,inorel]]

;printk2 kStringE
;printk2 kInstr4E

kTrigInstr4E trigger kInstr4E, 1, 1

if kTrigInstr4E == 1 then
kStringE = 0
if gkCounter != 1 then
kSTrigE = ktrigger
endif
gkCounter -= 1
endif

/*if kStringE == 1 then
kdurE = konsetE + p3
iE = rnd(1000)
if release() == 1 then
kS6 = 1
endif
kReleaseE trigger kS6, 0, 0
if kdur > .1 then
kSTrigE1 trighold kReleaseE, kdur - .1 ; kA = trigger segment ;kRelease;kSTrigE1;kA;kTrigRelE;
k6A trigger kSTrigE1, 1, 1 ; trigger
kTrigRelE trighold k6A, .1
kSTrigE12 trigger kTrigRelE, 1, 1 ; trigger
;kSTrigE12 trighold kSTrigE12, .1
;kSTrigE22 trigger kSTrigE12, 1, 1
if kReleaseE == 1 || kSTrigE1 == 1 || k6A == 1 || kTrigRelE == 1 then
k6Q = 1
else
k6Q = 0
endif
else
kSTrigE1 = kS6
k6A = kReleaseE
kTrigRelE trighold kReleaseE, .1 ; kRelease = trigger segment = kA ;kRelease;kTrigRelE;
kSTrigE12 trigger kTrigRelE, 1, 1
;kSTrigE12 trighold kSTrigE12, .1
;kSTrigE22 trigger kSTrigE12, 1, 1
if kReleaseE == 1 || kTrigRelE == 1 then
k6Q = 1
else
k6Q = 0
endif
endif
endif
if kSTrigE12 == 1 then
gkCounter -= 1
kStringE = 0
kS6 init 0
kSTrigE12 init 0
endif

if kStringE == 0 then
if gkCounter != 0 then ; the counter conditon takes all possibilities other than "kSTrigE trigger giCounter == 1 ? 1 : 0, 0, 0 … "
kSTrigE = ktrigger
endif
endif*/

if kStringE == 1 && kStringA == 0 && kStringD == 0 && kStringG == 0 && kStringB == 0 && kStringe == 0 then
kSTrigA trigger gkCounter == 2 ? 1 : 0, 0, 0
endif
if kSTrigA == 1 then
kdurA = p3
kStringA = 1
kStringFrequencyA = kStringFrequency
turnoff2 3, 0, .01
event “i”, 3, 0, 5, p4, p5
endif

kInstr3A active 3

kTrigInstr3A trigger kInstr3A, 1, 1

if kTrigInstr3A == 1 then
kStringA = 0
if gkCounter != 1 then
kSTrigA = ktrigger
endif
gkCounter -= 1
endif
/if kStringA == 1 then
iA = rnd(1000)
if release() == 1 then
kS5 = 1
endif
kReleaseA trigger kS5, 0, 0
if kdur > .1 then
kSTrigA1 trighold kReleaseA, kdur - .1
k5A trigger kSTrigA1, 1, 1
kTrigRelA trighold k5A, .1
kSTrigA12 trigger kTrigRelA, 1, 1
if kReleaseA == 1 || kSTrigA1 == 1 || k5A == 1 || kTrigRelA == 1 then
k5Q = 1
else
k5Q = 0
endif
else
kSTrigA1 = kS5
k5A = kReleaseA
kTrigRelA trighold kReleaseA, .1
kSTrigA12 trigger kTrigRelA, 1, 1
if kReleaseA == 1 || kTrigRelA == 1 then
k5Q = 1
else
k5Q = 0
endif
endif
endif
if kSTrigA12 == 1 then
gkCounter -= 1
kStringA = 0
kS5 init 0
kSTrigA12 init 0
endif
if kStringA == 0 then
if gkCounter != 1 && kStringE == 1 then
kSTrigA = ktrigger
endif
endif
/

if kStringE == 1 && kStringA == 1 && kStringD == 0 && kStringG == 0 && kStringB == 0 && kStringe == 0 then
kSTrigD trigger gkCounter == 3 ? 1 : 0, 0, 0
endif
if kSTrigD == 1 then
kStringD = 1
kAmpD = kAmp1
kStringFrequencyD = kStringFrequency
kNoteNumD = round((69 + (12 * log2(kStringFrequencyD / 440))) + 12)
turnoff2 2, 0, .01
event “i”, 2, 0, p3 + kdur, p4, p5
endif

kInstr2D active 2

kTrigInstr2D trigger kInstr2D, 1, 1

if kTrigInstr2D == 1 then
kStringD = 0
if gkCounter != 1 then
kSTrigD = ktrigger
endif
gkCounter -= 1
endif

/if kStringD == 1 then
iD = rnd(1000)
if release() == 1 then
kS4 = 1
endif
kReleaseD trigger kS4, 1, 1
if kdur > .1 then
kSTrigD1 trighold kReleaseD, kdur - .1
k4A trigger kSTrigD1, 1, 1
kTrigRelD trighold k4A, .1
kSTrigD12 trigger kTrigRelD, 1, 1
if kReleaseD == 1 || kSTrigD1 == 1 || k4A == 1 || kTrigRelD == 1 then
k4Q = 1
else
k4Q = 0
endif
else
kSTrigD1 = kS4
k4A = kReleaseD
kTrigRelD trighold kReleaseD, .1
kSTrigD12 trigger kTrigRelD, 1, 1
if kReleaseD == 1 || kTrigRelD == 1 then
k4Q = 1
else
k4Q = 0
endif
endif
endif
if kSTrigD12 == 1 then
gkCounter -= 1
kStringD = 0
kS4 init 0
kSTrigD12 init 0
endif
if kStringD == 0 then
if gkCounter != 2 && kStringE == 1 && kStringA == 1 then
kSTrigD = ktrigger
endif
endif
/

;printk2 kSTrigE

kCounterConsole = kStringE + kStringA + kStringD + kStringG + kStringB + kStringe

;printk2 kStringE
;printk2 kSTrigE
;printk2 kS6
;printk2 kReleaseE
;printk2 kSTrigE1
;printk2 kSTrigE12
;printk2 gkCounter
;printk2 kStringFrequencyE
;printk2 k6Q

;printk2 kSTrigA12
;printk2 kStringA
;printk2 kSTrigA
;printk2 kS5
;printk2 kS
;printk2 kdurE

;printk2 kStringD

endin

instr 2 ; D-string
a1 vco2 p5, p4
outs a1, a1
endin

instr 3 ; A-string
a1 vco2 p5, p4
outs a1, a1
endin

instr 4 ; E-string

;xtratim 5

if release() == 1 then
kSE = 1
else
kSE = 0
endif

if lastcycle() == 1 then
kaap = 1
else
kaap=0
endif

printk2 kSE
printk2 kaap

a1 vco2 p5, p4
outs a1, a1
endin

f 0 z ;i4 0 z

The commented out was the previous way I tried without separate instruments;
But now:
~ schedkwhen kSTrigE, 0, 1, 4, 0, … , p4, p5
or
~ event “i”, 2, 0, … , p4, p5

I could use the “lastcycle()” in each instrument in a global variable to trigger the end of it in the main instrument.

Can you format the code properly please. I’m almost at the point now where I’m ready to stop offering help to users who can’t format code properly :rofl: So, hit the edit button, select the code you wish to format and then hit the </> button in the text editor toolbar. Then I’ll be able to copy and paste the code, offer further help. Right now I would need to spend some considerable time reformatting everything. I just don’t have that time to do that.

i never understood that formatting:
aaaa.csd (6.3 KB)

Can you reduce the problem to a simplified .csd file? In as few lines as possible? Every time you use an event opcode you set a p3 for the instruments duration? Anyhow, send me on a barebones example and I’ll take a look. I don’t have time to parse through all of the instrument you posted.

aaaa2.csd (1.8 KB)

I intentionally wrote “…” where I need a fix.
I’m thinking there isn’t an “instrument section event statement” with performance defined duration right ?

And what do I need to do to see the problem?

I would like a real-time defined p3 instead of an initially set p3 on the spot of the “…”, if possible