// title: audio transitions // author: 56228375 // description: // Code used in the blog article about audio transitions https://technogems.blogspot.be/2017/08/audio-transitions-in-supercollider.html // The program proposes a few ways to gradually switch between 2 sounds that go further than simple crossfading. Can you think of other ways? // code: ( s.waitForBoot({ var synthGroup = Group.new; var transitionGroup = Group.after(synthGroup); if ((~b1.notNil), { ~b1.free; ~b2.free; }); ~b1 = Bus.audio(s, 2); ~b2 = Bus.audio(s, 2); SynthDef(\sound1, { | out=0 | var sig = SinOsc.ar(LFNoise0.ar(4, 400, 450), 0, 0.2); Out.ar(out, sig!2); }).add; SynthDef(\sound2, { | out = 0 | var sig = VarSaw.ar(freq:LFPulse.kr(3, 0, 0.3, 200, 200), iphase:0, width:LFTri.kr(1.0).range(0,1), mul:0.1); Out.ar(out, sig!2); }).add; SynthDef(\transitionCut, { // direct cut, no smooth transition | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, Select.ar(testPos.linlin(-1,1,0,1), [sig1, sig2])); }).add; SynthDef(\transitionCrossFadeEqualGain, { // cross fade linearly | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]).plot, doneAction:2); Out.ar(outBus, (testPos.linlin(-1,1,0,1)*sig1) + (testPos.linlin(-1,1,1,0)*sig2)); }).add; SynthDef(\transitionCrossFadeEqualPower, { // cross fade according to square root law | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, ((((1+testPos).sqrt)/2)*sig1) + ((((1-testPos).sqrt)/2)*sig2) ); }).add; SynthDef(\transitionSpectralCurtainHPF, { // wipe using sweeping hpf filter | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, (HPF.ar(sig1, testPos.linexp(-1,1,2,20000)) + HPF.ar(sig2, testPos.linexp(-1,1,20000,2)))); }).add; SynthDef(\transitionSpectralCurtainLPF, { // wipe using sweeping lpf filter | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, (LPF.ar(sig1, testPos.linexp(-1,1,20000,2)) + LPF.ar(sig2, testPos.linexp(-1,1,2,20000)))); }).add; SynthDef(\transitionReverbWash, { // blur out | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, (testPos.linlin(-1,1,1,0)*FreeVerb.ar(in:sig1, mix:testPos.linlin(-1,1,0,1), room:15, damp:0.01)) + (testPos.linlin(-1,1,0,1)*FreeVerb.ar(in:sig2, mix:testPos.linlin(-1,1,1,0), room:15, damp:0.01))); }).add; SynthDef(\transitionPulseTrain, { // "pixelate" | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); var pulsefreq = 15; // do some waveshaping with an Env: generate 0,1,2 but stay 10x longer in 1 than in 0 and 2. // the generated value will be used in a Select UGen var mapper = Env.new([0,0,1,1,2,2],[0.1,0.01,1,0.01,0.1].normalizeSum); var mappedTestPos = IEnvGen.ar(mapper, testPos.linlin(-1,1,0,1)); Out.ar(outBus, Select.ar(mappedTestPos, [testPos.linlin(-1,1,1,0)*sig1, LeakDC.ar(((testPos.linlin(-1,1,1,0)*(LFPulse.kr(pulsefreq, 0, testPos.linlin(-1,1,1,0))*sig1)) + (testPos.linlin(-1,1,0,1)*(LFPulse.kr(pulsefreq, 1, testPos.linlin(-1,1,0,1))*sig2)))), testPos.linlin(-1,1,0,1)*sig2])); }).add; SynthDef(\transitionPanLR, { // shift LR | inBusA, inBusB, outBus=0, pos= -1 | var sig1 = In.ar(inBusA, 2); var sig2 = In.ar(inBusB, 2); //var testPos = pos; var testPos = EnvGen.kr(Env.new(levels:[-1,-1,1,1,-1,-1], times:[5,5,5,5,5]), doneAction:2); Out.ar(outBus, Balance2.ar(sig1[0], sig1[1], testPos.linlin(-1,1,-1,0), testPos.linlin(-1,1,0,1)) + Balance2.ar(sig2[0], sig2[1], testPos.linlin(-1,1,0,1), testPos.linlin(-1,1,1,0)) ); }).add; s.sync; fork { var s1 = Synth(\sound1, [\out, ~b1], synthGroup); var s2 = Synth(\sound2, [\out, ~b2], synthGroup); [//\transitionCut, // boring \transitionCrossFadeEqualGain, \transitionCrossFadeEqualPower, \transitionSpectralCurtainHPF, \transitionSpectralCurtainLPF, \transitionReverbWash, \transitionPulseTrain, \transitionPanLR ].do({ | item , idx | ("Now switching to transition "++item).postln; Synth(item, [\inBusA, ~b1, \inBusB, ~b2], transitionGroup); 25.wait; }); } }); )