{
   "description" : "To start hearing something, raise the FbGain level above 0dB",
   "ancestor_list" : [],
   "author" : "gosub",
   "name" : "audrey II",
   "code" : "// patch name: Audrey II\r\n// patch date: 2026-02-06\r\n// patch desc: software Audrey II drone synthesizer (Synthux Academy / Fede Repic)\r\n//             feedback-driven self-oscillating drone machine\r\n//\r\n// signal flow:\r\n//   noise seed (-90dBFS) + fb_return -> KS resonator -> overdrive -> LPF -> HPF -> reverb\r\n//       ^                                                                            |\r\n//       +--- feedback delay (\"body\", 1-100ms, stereo decorrelated) <--- fb_gain <----+\r\n//                                                                                    |\r\n//                                                                              echo send\r\n//                                                                                    v\r\n//                                                                     echo delay (50ms-5s)\r\n//                                                                     BPF 800Hz -> tanh\r\n//                                                                        (tape degradation)\r\n//\r\n// no oscillator generates sound -- the feedback loop self-excites when gain > ~0 dB\r\n\r\n(\r\nSynthDef(\\audrey2, {\r\n\t|out=0, freq=48, fbGain= -20, body=0.01, lpf=12000, hpf=60,\r\n\t verbMix=0.3, verbDecay=0.5,\r\n\t echoSend=0, echoTime=0.3, echoFb=0.5,\r\n\t vol=0.3|\r\n\tvar seed, sigL, sigR, verbL, verbR;\r\n\tvar fbRetL, fbRetR, echoRetL, echoRetR;\r\n\tvar echoTapeL, echoTapeR, echoOutL, echoOutR;\r\n\tvar kFreq = Lag.kr(freq, 0.2).midicps;\r\n\tvar kBody = Lag.kr(body, 1.0);\r\n\tvar kFbAmp = Lag.kr(fbGain, 0.05).dbamp;\r\n\tvar kLpf = Lag.kr(lpf, 0.05);\r\n\tvar kHpf = Lag.kr(hpf, 0.05);\r\n\tvar kEchoTime = Lag.kr(echoTime, 0.5);\r\n\tvar kEchoSend = Lag.kr(echoSend, 0.05);\r\n\tvar kEchoFb = Lag.kr(echoFb, 0.05);\r\n\r\n\t// feedback return: 2 main fb + 2 echo fb\r\n\t#fbRetL, fbRetR, echoRetL, echoRetR = LocalIn.ar(4);\r\n\r\n\t// === MAIN FEEDBACK LOOP ===\r\n\r\n\t// white noise seed at -90 dBFS + feedback (independent L/R seeds)\r\n\tsigL = WhiteNoise.ar(-90.dbamp) + (fbRetL * kFbAmp);\r\n\tsigR = WhiteNoise.ar(-90.dbamp) + (fbRetR * kFbAmp);\r\n\r\n\t// karplus-strong resonator (tuned comb filter + brightness damping)\r\n\t// decay matches original's 0.8 damping factor: ~31 periods to -60dB\r\n\tsigL = OnePole.ar(CombL.ar(sigL, 0.2, kFreq.reciprocal, kFreq.reciprocal * 31), 0.98);\r\n\tsigR = OnePole.ar(CombL.ar(sigR, 0.2, kFreq.reciprocal, kFreq.reciprocal * 31), 0.98);\r\n\r\n\t// overdrive (soft clipping)\r\n\tsigL = (sigL * 1.5).tanh;\r\n\tsigR = (sigR * 1.5).tanh;\r\n\r\n\t// feedback loop filters + DC blocker\r\n\tsigL = LeakDC.ar(HPF.ar(LPF.ar(sigL, kLpf), kHpf));\r\n\tsigR = LeakDC.ar(HPF.ar(LPF.ar(sigR, kLpf), kHpf));\r\n\r\n\t// reverb (inside the feedback loop, as in original)\r\n\t#verbL, verbR = FreeVerb2.ar(sigL, sigR,\r\n\t\tLag.kr(verbMix, 0.05), Lag.kr(verbDecay, 0.05), 0.5);\r\n\r\n\t// === ECHO DELAY (outside the feedback loop) ===\r\n\t// tape-style: each repetition passes through BPF + soft clip,\r\n\t// progressively losing highs and lows (telephone-like degradation)\r\n\r\n\t// tape degradation on echo feedback return\r\n\techoTapeL = BPF.ar(echoRetL, 800, 1.0).tanh;\r\n\techoTapeR = BPF.ar(echoRetR, 800, 1.0).tanh;\r\n\r\n\t// mix echo input (dry send) with degraded feedback, then delay\r\n\techoOutL = DelayC.ar((verbL * kEchoSend) + (echoTapeL * kEchoFb), 5, kEchoTime);\r\n\techoOutR = DelayC.ar((verbR * kEchoSend) + (echoTapeR * kEchoFb), 5, kEchoTime);\r\n\r\n\t// write all feedback paths\r\n\tLocalOut.ar([\r\n\t\t// main feedback delay (\"body\") -- right offset by 4 samples for stereo\r\n\t\tDelayC.ar(verbL, 0.25, kBody),\r\n\t\tDelayC.ar(verbR, 0.25, max(SampleDur.ir, kBody - (4 * SampleDur.ir))),\r\n\t\t// echo delay feedback\r\n\t\techoOutL,\r\n\t\techoOutR\r\n\t]);\r\n\r\n\t// final mix: dry + echo wet, then limiter\r\n\tOut.ar(out, Limiter.ar([\r\n\t\tverbL + echoOutL,\r\n\t\tverbR + echoOutR\r\n\t] * 0.5 * Lag.kr(vol, 0.05), 0.7));\r\n}).add;\r\n)\r\n\r\n(\r\na = Synth(\\audrey2);\r\n\r\nw = Window.new(\"Audrey II\", Rect(200, 200, 460, 480)).layout_(\r\n\tVLayout(\r\n\t\tStaticText().string_(\"Audrey II -- feedback drone synthesizer\").align_(\\center),\r\n\t\tHLayout(\r\n\t\t\tVLayout(StaticText().string_(\"Freq\"),\r\n\t\t\t\tSlider().value_([16,72].asSpec.unmap(48))\r\n\t\t\t\t.action_({|x| a.set(\\freq, [16,72].asSpec.map(x.value))})),\r\n\t\t\tVLayout(StaticText().string_(\"Fb Gain\"),\r\n\t\t\t\tSlider().value_([-60,12].asSpec.unmap(-20))\r\n\t\t\t\t.action_({|x| a.set(\\fbGain, [-60,12].asSpec.map(x.value))})),\r\n\t\t\tVLayout(StaticText().string_(\"Body\"),\r\n\t\t\t\tSlider().value_([0.001,0.1,\\exp].asSpec.unmap(0.01))\r\n\t\t\t\t.action_({|x| a.set(\\body, [0.001,0.1,\\exp].asSpec.map(x.value))})),\r\n\t\t),\r\n\t\tHLayout(\r\n\t\t\tVLayout(StaticText().string_(\"LPF\"),\r\n\t\t\t\tSlider().value_([100,18000,\\exp].asSpec.unmap(12000))\r\n\t\t\t\t.action_({|x| a.set(\\lpf, [100,18000,\\exp].asSpec.map(x.value))})),\r\n\t\t\tVLayout(StaticText().string_(\"HPF\"),\r\n\t\t\t\tSlider().value_([10,4000,\\exp].asSpec.unmap(60))\r\n\t\t\t\t.action_({|x| a.set(\\hpf, [10,4000,\\exp].asSpec.map(x.value))})),\r\n\t\t),\r\n\t\tHLayout(\r\n\t\t\tVLayout(StaticText().string_(\"Verb Mix\"),\r\n\t\t\t\tSlider().value_(0.3)\r\n\t\t\t\t.action_({|x| a.set(\\verbMix, x.value)})),\r\n\t\t\tVLayout(StaticText().string_(\"Verb Decay\"),\r\n\t\t\t\tSlider().value_([0.2,1.0].asSpec.unmap(0.5))\r\n\t\t\t\t.action_({|x| a.set(\\verbDecay, [0.2,1.0].asSpec.map(x.value))})),\r\n\t\t),\r\n\t\tHLayout(\r\n\t\t\tVLayout(StaticText().string_(\"Echo Send\"),\r\n\t\t\t\tSlider().value_([0.001,1.0,\\exp].asSpec.unmap(0.001))\r\n\t\t\t\t.action_({|x| a.set(\\echoSend, [0.001,1.0,\\exp].asSpec.map(x.value))})),\r\n\t\t\tVLayout(StaticText().string_(\"Echo Time\"),\r\n\t\t\t\tSlider().value_([0.05,5.0,\\exp].asSpec.unmap(0.3))\r\n\t\t\t\t.action_({|x| a.set(\\echoTime, [0.05,5.0,\\exp].asSpec.map(x.value))})),\r\n\t\t\tVLayout(StaticText().string_(\"Echo Fb\"),\r\n\t\t\t\tSlider().value_([0.0,1.5].asSpec.unmap(0.5))\r\n\t\t\t\t.action_({|x| a.set(\\echoFb, [0.0,1.5].asSpec.map(x.value))})),\r\n\t\t),\r\n\t\tHLayout(\r\n\t\t\tVLayout(StaticText().string_(\"Volume\"),\r\n\t\t\t\tSlider().value_([0.001,1.0,\\exp].asSpec.unmap(0.3))\r\n\t\t\t\t.action_({|x| a.set(\\vol, [0.001,1.0,\\exp].asSpec.map(x.value))})),\r\n\t\t),\r\n\t)\r\n).front;\r\n)",
   "is_private" : null,
   "id" : "1-5iG",
   "labels" : [
      "feedback",
      "drone",
      "hardware",
      "audreyii",
      "selfoscillating"
   ]
}
