Cabbage Logo
Back to Cabbage Site

Keyboard latching

How can one check whether a particular key is pressed on the standard keyboard, the note on and off message (0 and 1) of that key ?

You mean the ascii keyboard, or the midi keyboard?

1 Like

Yes, on the screen.
The virtual midi keyboard.

Using midiin and disabling the normal MIDI triggering is useful for this sort of thing. The following provides a 1 or 0 if middle C (C3) is pressed:

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

massign 0,0 ; disable instrument triggering

instr 1
iNote  =    60 ; note to test
kFlag  init 0  ; flag to indicate whether chosen not is on or off

kstatus,kchan,kdata1,kdata2 midiin

if changed:k(kstatus)==1 then
 if kstatus==144 && kdata1==60 then ; if note is on
  kFlag = 1
 elseif kstatus==128 && kdata1==60 then ; if note is off
  kFlag = 0
 endif
endif

printk2 kFlag

; audio indicator
a1 poscil kFlag/10,440
outs a1,a1

endin


</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
i 1 0 z
</CsScore>
</CsoundSynthesizer>
1 Like

I see,

I’ll have to try this out.
For now what I get is:
Why is it specifically 144 and 128 values for kstatus ? kchan and kdata2 seemingly aren’t used.

Would you recommend this for the entire keyboard ?
An additional route might be to make a keyboard starting from buttons, but I suppose putting in order the midi functionality will be the hassle in this one.

Thx!

144 and 128 are the status bytes for MIDI events which correspond to note on and note off. In the example they are used to determine when kFlag should be 1 or zero.

kchan is the MIDI channel, in the example I just ignored it but if it is important, include it in the conditional. kdata2 is key velocity and again, I decided to ignore it in the example.

Below is another approach in which flags for all notes played and held are written into an array in which the location corresponds to the note played. This might be more efficient if you intend to interrogate the status of many notes.

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

massign 0,1 ; ensure all MIDI note events sent to instr 1


gkNoteOnOffs[] init 128 ; array to store on/off flags for all notes

instr 1
iNum  notnum ; read in note number
kRel  release ; release flag. 0 while note is held, 1 when note is released
gkNoteOnOffs[iNum] = 1-kRel ; invert logic of kRel and write to array in a location corresponding to the note number played
endin

instr 2
kFlag  =  gkNoteOnOffs[60] ; read status (1 or zero) of middle C
printk2 kFlag
; audio indicator
a1 poscil kFlag/10, 440
   outs   a1, a1

endin


</CsInstruments>
<CsScore>
i 2 0 z
</CsScore>
</CsoundSynthesizer>
2 Likes

Wow, that looks great.

Is there a particular reason for dividing kFlag by 10 ?

The thing is that I needed the data of the note actions controlled from a midi keyboard for other means than sound production (visuals etc.).
So regular sound production and additonal actions.

I’ll try this out and keep this post updated.

Thanks again !

The divide-by-10 was simply because I was using it to control amplitude. I didn’t want to deafen myself!

I see, you’re just using these as switches.

If you need the keyboard presses - press-release - to toggle some value, i.e. you don’t want to hold the key to keep the value at 1, you can try this UDO through which you pass kFlag.

; UnlatchedToLatched
; ------------------
; Converts an unlatched trigger signal to a latched one
;
; kTrigOut  UnlatchedToLatched  kTrigIn
;
; Performance
; -----------
; kTrigIn  --  input trigger

opcode   UnlatchedToLatched,k,k
   kTrigIn      xin                    ; READ IN INPUT ARGUMENT 
   kTrigOut   init   0                 ; INITIALISE OUTPUT TRIGGER VALUE
   kcross      trigger   kTrigIn,0,2   ; IF INPUT TRIGGER CHANGES FROM ZERO OR BACK TO ZERO SWITCH THE OUTPUT TRIGGER VALUE ACCORDING TO ITS CURRENT VALUE
   if kcross==1 then                   ; IF INPUT TRIGGER HAS CHANGED FROM ZERO OR BACK TO ZERO...
    kTrigOut   =   abs(kTrigOut-1)     ; FLIP THE OUTPUT TRIGGER FROM 0 TO 1 OR FROM 1 TO 0 (DEPENDING UPON WHAT ITS CURRENT VALUE IS)
   endif                               ; END OF CONDITIONAL BRANCH
         xout   kTrigOut               ; SEND OUTPUT TRIGGER BACK TO CALLER INSTRUMENT
endop
2 Likes

I tried out your previous approach for a while and for:
“printk2 kFlag”
this doesn’t print very consistently.
Should print 1 at the attack, 0 at release.

Prints 1 of following:

  • the above (as it should)
  • 1 and 0 seemingly at attack
  • 1 and 0 somewhere along the way
  • 1 and 0 at the release

I seem to get reliable behaviour from both methods. Ultimately it’s the value of kFlag that matters. In the video I’m using kFlag to drive a button widget, which is easier to follow than the ones and zeroes in the terminal.

The basic script like this works fine, but once I put it in my code…

form caption(“Untitled”) size(400, 300), guiMode(“queue”), pluginId(“def1”)
keyboard bounds(8, 158, 381, 95)



-n -dm0 -+rtmidi=NULL -M0 --midi-key-cps=4 --midi-velocity-amp=5


; Initialize the global variables.
ksmps = 32
nchnls = 2
0dbfs = 1

massign 0,1 ; ensure all MIDI note events sent to instr 1

gkNoteOnOffs[] init 128 ; array to store on/off flags for all notes

opcode getNoteOn, k, 0

iNum notnum ; read in note number
kRel release ; release flag. 0 while note is held, 1 when note is released
gkNoteOnOffs[iNum] = 1-kRel ; invert logic of kRel and write to array in a location corresponding to the note number played

kFlag = gkNoteOnOffs[iNum] ; read status (1 or zero) of current note

xout kFlag

endop

instr 1

xtratim 5

kFlag getNoteOn
printk2 kFlag
; audio indicator
icps cpsmidi
a1 poscil kFlag/10, icps
outs a1, a1

endin

f0z

I also have xtratim going on and both the sound block and GUI managing block still rely on p4 and p5.

All works from now on.
Now have to check the functioning of multiple notes (ASCI keyboard or midi keyboard).

1 Like