Hey all. I’m building a formant synthesiser and i’m looking to automate/animate the XY Pad.
I’m using an XYPad to interpolate smoothly between different formant sounds ‘oo’ ‘ee’ ‘aa’ etc… this works great! I also implemented a button called ‘AutoVowel’ that when clicked, should override the manual setting of XYPad and have the little circle parameter of XYPad move in a circle within the pad bounds.
The effect itself is actually working and toggling fine, I can hear all the interpolations between phonemes occurring smoothly when AutoVowel is activated, but I can’t see the parameter moving, I haven’t been able to trigger the GUI update.
One issue I foresee, upon reading https://cabbageaudio.com/docs/identchannels/, is that i’m not using Ident Channels. This is only because I can’t use them at the same time as guiMode(“queue”), which i’m using. Is that a deal breaker or is there a workaround?
Here is the instrument for the XYPad:
instr XYPad
kx chnget "xCoordinate"
ky chnget "yCoordinate"
kTune chnget "tune"
kFineTune chnget "fineTune"
kNormTune = (kTune + 24) / 48
; Define formant values for MidRange vowels
iF1_i_Mid = 270
iF2_i_Mid = 2300
iF3_i_Mid = 3000
iF1_u_Mid = 300
iF2_u_Mid = 870
iF3_u_Mid = 2240
iF1_e_Mid = 390
iF2_e_Mid = 2000
iF3_e_Mid = 2800
iF1_o_Mid = 460
iF2_o_Mid = 920
iF3_o_Mid = 2420
iF1_a_Mid = 730
iF2_a_Mid = 1090
iF3_a_Mid = 2440
; Calculate the mean frequency for all vowels to derive the central, or "Mid", formant frequencies
iF1_Mid = (iF1_i_Mid + iF1_u_Mid + iF1_e_Mid + iF1_o_Mid + iF1_a_Mid) / 5
iF2_Mid = (iF2_i_Mid + iF2_u_Mid + iF2_e_Mid + iF2_o_Mid + iF2_a_Mid) / 5
iF3_Mid = (iF3_i_Mid + iF3_u_Mid + iF3_e_Mid + iF3_o_Mid + iF3_a_Mid) / 5
; Adjust formants based on normalized tuning. This interpolates between the Mid value and the specific vowel formant
kF1_i = iF1_i_Mid + (iF1_Mid - iF1_i_Mid) * kNormTune
kF2_i = iF2_i_Mid + (iF2_Mid - iF2_i_Mid) * kNormTune
kF3_i = iF3_i_Mid + (iF3_Mid - iF3_i_Mid) * kNormTune
kF1_u = iF1_u_Mid + (iF1_Mid - iF1_u_Mid) * kNormTune
kF2_u = iF2_u_Mid + (iF2_Mid - iF2_u_Mid) * kNormTune
kF3_u = iF3_u_Mid + (iF3_Mid - iF3_u_Mid) * kNormTune
kF1_e = iF1_e_Mid + (iF1_Mid - iF1_e_Mid) * kNormTune
kF2_e = iF2_e_Mid + (iF2_Mid - iF2_e_Mid) * kNormTune
kF3_e = iF3_e_Mid + (iF3_Mid - iF3_e_Mid) * kNormTune
kF1_o = iF1_o_Mid + (iF1_Mid - iF1_o_Mid) * kNormTune
kF2_o = iF2_o_Mid + (iF2_Mid - iF2_o_Mid) * kNormTune
kF3_o = iF3_o_Mid + (iF3_Mid - iF3_o_Mid) * kNormTune
; 2D Interpolation: Interpolate formants based on ky (Y coordinate) between 'i' and 'u' and between 'e' and 'o'
kF1_i_u = kF1_i + (kF1_u - kF1_i) * ky
kF2_i_u = kF2_i + (kF2_u - kF2_i) * ky
kF3_i_u = kF3_i + (kF3_u - kF3_i) * ky
kF1_e_o = kF1_e + (kF1_o - kF1_e) * ky
kF2_e_o = kF2_e + (kF2_o - kF2_e) * ky
kF3_e_o = kF3_e + (kF3_o - kF3_e) * ky
; Interpolate between the two previously interpolated sets based on kx (X coordinate)
kF1 = kF1_i_u + (kF1_e_o - kF1_i_u) * kx + (iF1_a_Mid - kF1_i_u) * (1-abs(2*kx-1)) * (1-abs(2*ky-1))
kF2 = kF2_i_u + (kF2_e_o - kF2_i_u) * kx + (iF2_a_Mid - kF2_i_u) * (1-abs(2*kx-1)) * (1-abs(2*ky-1))
kF3 = kF3_i_u + (kF3_e_o - kF3_i_u) * kx + (iF3_a_Mid - kF3_i_u) * (1-abs(2*kx-1)) * (1-abs(2*ky-1))
kF1 = kF1 * pow(2, kTune/12 + kFineTune/100)
kF2 = kF2 * pow(2, kTune/12 + kFineTune/100)
kF3 = kF3 * pow(2, kTune/12 + kFineTune/100)
cabbageSetValue "kFreq1", kF1
cabbageSetValue "kFreq2", kF2
cabbageSetValue "kFreq3", kF3
; Get the status of the automation toggle
kActivate chnget "autoVowel"
if kActivate == 1 then
; Circular motion for X and Y coordinates
kTheta phasor 0.1
kx = 0.5 + 0.5*cos(kTheta*2*$M_PI)
ky = 0.5 + 0.5*sin(kTheta*2*$M_PI)
; Update X and Y coordinate channels with newly computed values
chnset kx, "xCoordinate"
chnset ky, "yCoordinate"
else
; If not in automation mode, simply retrieve the manually set X and Y coordinates
kx chnget "xCoordinate"
ky chnget "yCoordinate"
endif
endin
Here are the relevant Cabbage elements:
button bounds(325, 140, 80, 25), channel(“autoVowel”), text(“AutoVowel”)
plant(“XYPad”) {
groupbox bounds(315, 170, 220, 190), text(“XYPad”), colour(200, 200, 200)
xypad bounds(325, 190, 200, 160), channel(“xCoordinate”, “yCoordinate”)
}
Here is the CsScore:
The only relevant one is i"XYPad" 0 z, the rest are for other functionalities
f0 z
f 10 0 4096 10 1
f 1 0 4096 10 1
i"UpdateGUI" 0 z
i"Chorus" 0 z 0.8
i"MIDI_Listener" 0 z
i"UpdateDisplay" 0 z
i"XYPad" 0 z
Thank you for your time!