Submit
Browse
Anonymous
Login
RSS
SuperCollider Code
Fork Code: beat repeat with gate and pitch increment
name
code content
//by Santi Vilanova //October 2024 //www.playmodes.com ( SynthDef(\beatrepeat, { arg in=0, out=0, bufferSize=4; var onoff=\go.kr(0), rate=\rate.kr(1); var reset=\reset.kr(0); // Reset parameter var amp=1; var recms=\repms.kr(1000); var gate=1-\gate.kr(1); var ratestep=\pitchstep.kr(0); var reverse=((1-\reverse.kr(0))*2)-1; var envtime; var input, buffer, playhead, output, loopOutput; var recTrig, recTime, playTrig, bufferEnd, isLooping; var fixedTimeGate, fixedTimeEnd; var numChannels = 2; var mixPhase, resetTrig; var declickEnv; var loopPhase; var mix, play, wetGate; var bufferPlayRate, actualPlayPos, loopDur, loopReset, phasor, combinedResetTrig; var declick = \declick.kr(0.005); // Declick time in seconds, default to 5ms var loopCount, currentRate; var onoffTrig; var mixedOutput; var transitionEnv; var ramp; // Create a local buffer buffer = LocalBuf(SampleRate.ir * bufferSize, numChannels).clear; // Input signal input = In.ar(in, numChannels); // Detect start of recording and create reset trigger onoffTrig = Trig1.kr(onoff); resetTrig = Trig1.kr(reset); recTrig = onoffTrig; // Combined reset trigger for both 'go' and 'reset' combinedResetTrig = Trig1.ar(K2A.ar(onoff) + K2A.ar(reset), ControlDur.ir); // Create a gate that closes after fixed time fixedTimeGate = EnvGen.kr(Env([0, 1, 0], [0, recms/1000], ['step', 'step']), recTrig); fixedTimeEnd = TDelay.kr(1 - fixedTimeGate, recms/1000); // Link mix to onoff, but delayed by recms mix = DelayN.kr(onoff, recms/1000, recms/1000); // Create a gate for the wet signal that opens after recms wetGate = DelayN.kr(onoff, recms/1000, recms/1000); // Link play to onoff with delay play = onoff; // Detect end of recording playTrig = Trig1.kr(fixedTimeEnd); // Determine buffer end and loop duration bufferEnd = recms / 1000; loopDur = bufferEnd; // Record to buffer RecordBuf.ar(input, buffer, loop: 0, trigger: recTrig); // Create a loop reset trigger using Phasor phasor = Phasor.ar(combinedResetTrig, 1 / (SampleRate.ir * loopDur), 0, 1); loopReset = (phasor - Delay1.ar(phasor) > 0).clip(0, 1); // Count loop cycles, resetting when either 'go' or 'reset' triggers loopCount = PulseCount.ar(loopReset, combinedResetTrig); // Calculate current rate based on ratestep (in semitones) currentRate = rate * (2 ** (ratestep * loopCount / 12)); // Calculate buffer play rate bufferPlayRate = currentRate * BufRateScale.kr(buffer); // Playhead for buffer playback playhead = Phasor.ar( trig: loopReset, rate: bufferPlayRate * reverse, start: 0, end: bufferEnd * SampleRate.ir, resetPos: 0 ); // Calculate actual play position, clamping for rates < 1 actualPlayPos = if( currentRate < 1, playhead.clip(0, bufferEnd * currentRate * SampleRate.ir), playhead % (bufferEnd * SampleRate.ir) ); // Create the envelope envtime = (recms/1000) - (2 * declick); declickEnv = EnvGen.ar( Env( levels: [0, 1, 1, 0], times: [declick, envtime-(envtime*gate), declick], curve: [\lin, \step, \lin] ), gate: loopReset, levelScale: 1, levelBias: 0, timeScale: 1 ); // Play from buffer only if we're looping loopOutput = BufRd.ar(numChannels, buffer, actualPlayPos, loop: 1) * play * declickEnv * wetGate; // Mix input and loop output mixedOutput = (input * (1 - mix)) + (loopOutput * mix); // Create a fast ramping envelope for smooth transitions transitionEnv = Env.asr(declick, 1, declick, 'sine'); ramp = EnvGen.ar(transitionEnv, K2A.ar(onoff)); // Use SelectX for smooth transition between dry and wet signals output = SelectX.ar(ramp, [input, mixedOutput]); Out.ar(out, output * amp); }).add(); )
code description
Use this synthdef as an effect and just make the \go parameter from 0 to 1 to activate. When you transition from 0 to 1, it will record a buffer of length \repms (in miliseconds) and will loop this recorded chunk for as long as \go=1. The \gate parameter controls how much silence is left at the end of the chunk, for a strong gate effect. \rate allows you to change the speed of the sampled chunk, without affecting the loop duration (it will omit part of the end of the loop for rates <1, and it will loop for rates>1, resyncing when \repms time has passed) \pitchstep will make that every new loop starts with an increment/decrement of semitones defiend by this parameter \declick...well... declicks.... and \reverse reverses the played chunk
use markdown for formating
category tags
comma separated, i.g. "wild, siren" (do not enter default SC class names, please)
ancestor(s)
comma separated identificators, i.g. "1-C,1-1,1-4M,1-x"
Private?
the code will be accessible by direct url and not visible in public activity
signup to submit public code without captcha
comment of change