; FrequencyShifter.csd
; Iain McCurdy, 2013.
;
; Frequency shifting using the hilbert filter
;
; CONTROLS
; --------
; Input -- Choose audio input: Live, sine tone or pink noise
; Polarity -- 3 options: 'Positive' = multiply 'Freq.' by 1, 'Negative' = multiply 'Freq.' by -1, 'Dual' = sum of 'Positive' and 'Negative' outputs
; Mix -- Dry/Wet mix control
; Freq. -- Principle frequency of the shifting frequency (before modulation by other controls)
; Mult. -- multipler of shifting frequency. Can be useful for finer control of shifting frequency around zero.
; Feedback -- Amount of frequency shifter that is fed back into its input
; Level -- Output level
; Dual Mono / Stereo -- 'Dual Mono' = both channels treated in the same way. 'Stereo' = right channel 180 degrees out of phase with respect to the left
; Stereo mode most apparent if shifting frequency is close to zero
; zero freq -- set 'Freq.' to zero
; [LFO~]
; Modulate Frequency -- Switch to activate LFO modulation of shifting frequency
; Shape -- Shape of the LFO: sine / triangle / square / random sample and hold / random splines
; Rate -- Rate of LFO (in hertz)
; Min -- Minimum frequency of the LFO modulation
; Max -- Maximum frequency of the LFO modulation
; Pan Mod -- Amount of panning modulation (strictly speaking, stereo balance modulation). Rate of modulation governed also by 'Rate'
; Sync LFO -- Restart LFO. Can be useful if 'random spline' modulation becomes 'stuck' at a low frequency
form caption("Frequency Shifter") size(560,180), pluginid("fshi")
image bounds( 0, 0, 560,180), colour("darkslategrey"), outlinecolour("silver"), outlinethickness(6), shape("rounded")
label bounds(15, 7, 70, 11), text("INPUT"), fontcolour("white")
combobox bounds(15, 18, 70, 20), channel("input"), value(1), text("Live","Tone","Noise")
label bounds(15, 42, 70, 11), text("POLARITY"), fontcolour("white")
combobox bounds(15, 53, 70, 20), channel("polarity"), value(1), text("Positive","Negative","Dual")
rslider bounds( 80, 10, 70, 70), text("Mix"), channel("mix"), range(0, 1.00, 0.5), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
rslider bounds(150, 10, 70, 70), text("Freq."), channel("freq"), range(-4000, 4000, -50), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
rslider bounds(220, 10, 70, 70), text("Mult."), channel("mult"), range(-1, 1.00, 0.1), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
rslider bounds(285, 15, 60, 60), text("Port."), channel("port"), range(0, 30.00, 0.1), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
rslider bounds(340, 10, 70, 70), text("Feedback"), channel("fback"), range(0, 0.75, 0.6), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
rslider bounds(410, 10, 70, 70), text("Level"), channel("level"), range(0, 1.00, 1), colour(27,59,59), textcolour("white"), trackercolour(255,255,100)
checkbox bounds(480, 20, 12, 12), channel("r1") fontcolour("white") colour(yellow) value(1)
checkbox bounds(480, 32, 12, 12), channel("r2") fontcolour("white") colour(yellow)
label bounds(493, 21, 55, 9), text("DUAL MONO"), fontcolour("white")
label bounds(492, 33, 40, 9), text("STEREO"), fontcolour("white")
button bounds(480, 50, 65, 20), colour("Green"), text("Zero Freq", "Zero Freq"), channel("Zerofreq"), value(0), latched(0)
;----
line bounds( 10, 90, 540, 2), colour("Grey")
;----
checkbox bounds( 40,100,150, 20), channel("ModOnOff") text("LFO Modulate Freq."), fontcolour("white") colour(lime) value(0)
label bounds( 53,127, 45, 11), text("SHAPE"), fontcolour("white")
combobox bounds( 40,138, 85, 20), channel("LFOShape"), value(7), text("Sine","Triangle","Square","Saw Up","Saw Down","Rand.S&H","Rand.Spline")
rslider bounds( 175,100, 70, 70), text("Rate"), channel("LFORate"), range(0, 30, 1.5, 0.5, 0.001), colour("lightslategrey"), textcolour("white"), trackercolour(255,255,100)
rslider bounds( 245,100, 70, 70), text("Min"), channel("LFOMin"), range(-2000, 2000, -600), colour("lightslategrey"), textcolour("white"), trackercolour(255,255,100)
rslider bounds( 315,100, 70, 70), text("Max"), channel("LFOMax"), range(-2000, 2000, 600), colour("lightslategrey"), textcolour("white"), trackercolour(255,255,100)
rslider bounds( 385,100, 70, 70), text("Pan Mod."), channel("PanSpread"),range(0, 1.00, 1), colour("lightslategrey"), textcolour("white"), trackercolour(255,255,100)
button bounds(455,100, 65, 20), colour("Green"), text("Sync LFO", "Sync LFO"), channel("SyncLFO"), value(0), latched(0)
-d -n -+rtmidi=NULL -M0
sr = 48000
ksmps = 32
nchnls = 2
0dbfs = 1
;Iain McCurdy, 2012
;http://iainmccurdy.org/csound.html
;Frequency shifter effect based around the hilbert filter.
gisine ftgen 0,0,4096,10,1 ;A SINE WAVE SHAPE
gicos ftgen 0,0,4096,11,1 ;A COSINE WAVE SHAPE
gishapes ftgen 0,0,8,-2,0,1,2,4,5
opcode FreqShifter,a,akkki
adry,kmix,kfshift,kfback,ifn xin ;READ IN INPUT ARGUMENTS
kWet limit kmix*2,0,1
kDry limit (1-kmix)*2,0,1
aFS init 0 ;INITILISE FEEDBACK SIGNAL (FOR FIRST K-PASS)
ain = adry + (aFS * kfback) ;ADD FEEDBACK SIGNAL TO INPUT (AMOUNT OF FEEDBACK CONTROLLED BY 'Feedback Gain' SLIDER)
areal, aimag hilbert ain ;HILBERT OPCODE OUTPUTS TWO PHASE SHIFTED SIGNALS, EACH 90 OUT OF PHASE WITH EACH OTHER
;QUADRATURE OSCILLATORS. I.E. 90 OUT OF PHASE WITH RESPECT TO EACH OTHER
;OUTUTS OPCODE AMPLITUDE | FREQ. | FUNCTION_TABLE | INITIAL_PHASE (OPTIONAL;DEFAULTS TO ZERO)
asin oscili 1, kfshift, ifn, 0
acos oscili 1, kfshift, ifn, 0.25
;RING MODULATE EACH SIGNAL USING THE QUADRATURE OSCILLATORS AS MODULATORS
amod1 = areal * acos
amod2 = aimag * asin
;UPSHIFTING OUTPUT
aFS = (amod1 - amod2)
aout sum aFS*kWet, adry*kDry ;CREATE WET/DRY MIX
xout aout ;SEND AUDIO BACK TO CALLER INSTRUMENT
endop
opcode CabbageRadio2,k,SS ; change opcode name and number is string variable inputs
S1,S2 xin ; add string inputs for the required number of inputs
kon = 0
koff = 0
ksum = 0
ktrigsum = 0
#define READ_CHANGES(NAME) #
k$NAME chnget $NAME
ksum = ksum + k$NAME
kon$NAME trigger k$NAME,0.5,0
ktrigsum = ktrigsum + kon$NAME#
#define WRITE_CHANGES(NAME'COUNT) #
if kon$NAME!=1 then
chnset koff,$NAME
else
kval = $COUNT
endif#
$READ_CHANGES(S1)
$READ_CHANGES(S2) ; add macro expansions for the required number of radio buttons
if ktrigsum>0 then
$WRITE_CHANGES(S1'1)
$WRITE_CHANGES(S2'2) ; add macro expansions for the required number of radio buttons
endif
kval = (ksum=0?0:kval)
xout kval
endop
instr 1
kporttime linseg 0,0.001,1
koff = 0
kmix chnget "mix" ; read input widgets
kfreq chnget "freq"
kmult chnget "mult"
kport chnget "port"
kfshift portk kfreq*kmult,kporttime*kport
kfback chnget "fback"
klevel chnget "level"
kpolarity chnget "polarity"
kStereoMode CabbageRadio2 "r1","r2" ; call UDO
kZeroFreq chnget "Zerofreq"
ktrig changed kZeroFreq
if ktrig=1 then
chnset koff,"freq"
endif
kModOnOff chnget "ModOnOff"
kLFOShape chnget "LFOShape"
kLFORate chnget "LFORate"
kLFOMin chnget "LFOMin"
kLFOMax chnget "LFOMax"
kPanSpread chnget "PanSpread"
kSyncLFO chnget "SyncLFO"
/* INPUT */
kinput chnget "input"
if kinput=1 then
a1,a2 ins
elseif kinput=2 then
a1 oscils 0.2, 300, 0
a2 = a1
else
a1 pinkish 0.2
a2 pinkish 0.2
endif
/* LFO */
if kModOnOff=1 then
ktrig changed kLFOShape,kSyncLFO
if ktrig==1 then
reinit RESTART_LFO
endif
RESTART_LFO:
if i(kLFOShape)=6 then
kLFOFreq randomh kLFOMin,kLFOMax,kLFORate
elseif i(kLFOShape)=7 then ; random spline
;kLFOFreq randomi kLFOMin,kLFOMax,kLFORate,1
;kLFOFreq portk kLFOFreq,1/kLFORate
kLFOFreq rspline kLFOMin,kLFOMax,kLFORate,kLFORate*2
else
ishape table i(kLFOShape)-1,gishapes
kLFOFreq lfo 1,kLFORate,ishape
kLFOFreq scale (kLFOFreq*0.5)+0.5,kLFOMin,kLFOMax
endif
rireturn
endif
kfshift = kfshift+kLFOFreq
/* FREQUENCY SHIFTERS */
ktrig changed kStereoMode
if ktrig=1 then
reinit RESTART_FREQUENCY_SHIFTERS
endif
RESTART_FREQUENCY_SHIFTERS:
if kpolarity=1 then ; polarity is positive...
a1 FreqShifter a1,kmix,kfshift,kfback,gisine
if i(kStereoMode)=2 then
a2 FreqShifter a2,kmix,kfshift,kfback,gicos ; cosine version
else
a2 FreqShifter a2,kmix,kfshift,kfback,gisine
endif
elseif kpolarity=2 then ; polarity is negative...
a1 FreqShifter a1,kmix,-kfshift,kfback,gisine
if i(kStereoMode)=2 then
a2 FreqShifter a2,kmix,-kfshift,kfback,gicos ; cosine version
else
a2 FreqShifter a2,kmix,-kfshift,kfback,gisine
endif
else ; polarity is dual...
aa FreqShifter a1,kmix,kfshift,kfback,gisine ; positive
if i(kStereoMode)=2 then
ab FreqShifter a2,kmix,kfshift,kfback,gicos ; cosine version
else
ab FreqShifter a2,kmix,kfshift,kfback,gisine
endif
ac FreqShifter a1,kmix,-kfshift,kfback,gisine ; negative
if i(kStereoMode)=2 then
ad FreqShifter a2,kmix,-kfshift,kfback,gicos ; cosine version
else
ad FreqShifter a2,kmix,-kfshift,kfback,gisine
endif
rireturn
a1 = (aa+ac)*0.5 ; sum positive and negative and attenuate
a2 = (ab+ad)*0.5
endif
/* PANNING */
if kModOnOff=1 then
kpan randomi 0.5-(kPanSpread*0.5),0.5+(kPanSpread*0.5),kLFORate,1
kpan portk kpan,1/kLFORate
a1 = a1 * sin(kpan*$M_PI_2)
a2 = a2 * cos(kpan*$M_PI_2)
;a1 = a1*kpan
;a2 = a2*(1-kpan)
endif
a1 = a1 * klevel ; scale using level control
a2 = a2 * klevel
outs a1,a2
endin
i 1 0 [60*60*24*7]