It took me a minute to cook up this example, which is in the end very similar to the example in the PV_Control help file. Run the code then very slowly turn up the volume until the signal starts feeding back. Move the microphone around or adjust the EQ on in output signal and the whole thing should change. I am getting good results with this, but it took me a bit to figure the instrument out. Feedback is funny because every room is different. Every mic is different. Etc. I feel like it is different every time.
This won’t totally blow up, but do be careful with the volume when you first try it out. Don’t fry your ears!
Sam
(
var feedback_innards = {|in, buf, buf2, num_analyses, thresh, mulFactor, attackReleaseFrames, sustainZeroFrames, waitGoFrames, tripCount, tripBlockFrames, topBin, ampMin, qRatio|
var fft, windowStarts, vols, bandwidth, center;
in = Compander.ar(in, in, 0.5, 1, 0.5, 0.01, 0.01);
//calculate the fft
fft = FFT(buf, in);
//
fft = PV_Control(fft, buf2, thresh, mulFactor, attackReleaseFrames+Rand(-10,10), sustainZeroFrames+Rand(-10,10), waitGoFrames+Rand(-50,50), tripCount+Rand(-2,2), tripBlockFrames+Rand(-50,50), topBin);
//read the volumes from the pv_control fft buffer
vols = num_analyses.collect{|i|
BufRd.kr(1,buf2,i*2+2,0,0);
};
bandwidth = SampleRate.ir/2048;
//make a bunch of MidEQ filters - one per fft band
num_analyses.do{arg i;
var center = (i+1)*(bandwidth);
in = MidEQ.ar(in, center, qRatio*(bandwidth/center), vols[i].lincurve(0,1,ampMin,1,-4).ampdb);
};
in
};
SynthDef("feedback_control_example", {|inBus, speaker_outBus=0, sax_outBus = 4, volume=0.8, thresh=5, mulFactor=0.11, attackReleaseFrames=200, sustainZeroFrames=399, waitGoFrames=138, tripCount=20, tripBlockFrames=100, topBin=400, ampMin=0, qRatio=2|
var fx1, fx2;
var numBins = 2048;
var num_analyses = 300;
//make the 2 needed fft buffers
var buf = LocalBuf(numBins);
var buf2 = LocalBuf(numBins);
var sig = SoundIn.ar(inBus);
var env = Env.asr(0.1, 1, 0.1).kr(2, \gate.kr(1));
//lowPass
3.do{sig = LPF.ar(sig, 1000)};
sig = VSTPlugin.ar(sig.dup, 2, 0, id:\rr3_1);
sig = feedback_innards.(Mix(sig), buf, buf2, num_analyses, thresh, mulFactor, attackReleaseFrames, sustainZeroFrames, waitGoFrames, tripCount, tripBlockFrames, topBin, ampMin, qRatio);
//lots of verb is good
sig = FreeVerb.ar(sig, 1, 0.95);
//distiortion is necessary to amplify the signal and limit the output volume
sig = (sig*2).tanh*0.75;
Out.ar(speaker_outBus, sig.dup.flatten*volume);
}).load(s);
)
(
var input_channel = 0; //set your input channel here (probably 0)
(
s.waitForBoot({
a = Synth("feedback_control_example", [\inBus, input_channel]);
b = [
[\thresh, ControlSpec(0,10), 7, StaticText()],
[\mulFactor, ControlSpec(0,1), 0.11, StaticText()],
[\attackReleaseFrames, ControlSpec(10,500, 'lin', 1), 300, StaticText()],
[\sustainZeroFrames, ControlSpec(10,500, 'lin', 1), 399, StaticText()],
[\waitGoFrames, ControlSpec(0,300, 'lin', 1), 138, StaticText()],
[\tripCount, ControlSpec(0,20, 'lin', 1), 3, StaticText()],
[\tripBlockFrames, ControlSpec(0,500, 'lin', 1), 400, StaticText()],
[\topBin, ControlSpec(10,500, 'lin', 1), 400, StaticText()],
[\volume, ControlSpec(0,1), 0, StaticText()]
];
a.set(*b.collect{|item| [item[0], item[2]]}.flatten);
c = b.collect({|item| Slider().orientation_('horizontal')
.action_{|sl|
a.set(item[0], item[1].map(sl.value));
item[3].string_(item[1].map(sl.value).round(0.01).asString)
}});
c.do{|item, i| {item.valueAction_(b[i][1].unmap(b[i][2].postln))}.defer};
w = Window();
w.onClose = {a.set(\gate,0)};
w.layout_(
HLayout(
VLayout(*b.collect{|item| StaticText().string_(item[0])}),
VLayout(*c),
VLayout(*b.collect{|item| item[3]})
));
w.front;
});
)
)
Sam