// title: hamma // author: hamma // description: // a go at making something like metaphysical function from NI reaktor in SC // // original instrument design by mike daliot // // based on ScopeView helpfile and // // https://www.youtube.com/watch?v=l-uuPlAk_FY // code: a go at making something like metaphysical function from NI reaktor in SC original instrument design by mike daliot based on ScopeView helpfile and https://www.youtube.com/watch?v=l-uuPlAk_FY how to use: this instrument generates harsh drones and visuals. use with caution! protect your hearing! dist goes loud! 1. add a little spin with spin t1, t2 and/or fine 2. detune one of the oscillators using tune/fine a and b is a bank of 4 sine oscs and 2 pulse oscs with pw 0.5 and 0.2 ( var w, ctr = IdentityDictionary[], gui = IdentityDictionary[]; var syn, scopeSyn, scope, func, bus, buffer; w = Window("Scope", Rect(0, 0, 800, 500)); ctr[\defaultfreqs] = 60 ! 6; ctr[\defaultfine] = 0.0 ! 6; ctr[\defaultamps] = [-12] ++ (-120 ! 5); gui[\views] = [\topBar, \scopeView, \zoomView, \lowBar]; gui[\basicView] = { View().background_(Color.gray).layout_(HLayout()) }; gui[\views].do({ |view| gui[view] = gui[\basicView].value }); [\a, \b].do({ |ab| [\Top, \Mid, \Low].do({ |tier| gui[(ab++tier).asSymbol] = gui[\basicView].value; }) }); func = { arg view, synarg, spec, contr, defaults, i; var sl, values; sl = Slider(gui[view]).action_({ values = ctr[contr].collect({|sl| spec.asSpec.map(sl.value)}); syn.setn(synarg, values); //values.postln }); sl.value_(spec.asSpec.unmap(ctr[defaults][i])) }; // lazy labels [StaticText(gui[\topBar]).string_("a tune / fine / amp\t\t alvl"), View(gui[\topBar]).minWidth_(450), StaticText(gui[\topBar]).string_("blvl\t\t b tune / fine / amp")]; [View(gui[\lowBar]).maxWidth_(163), StaticText(gui[\lowBar], Rect(200, 0, 200, 20)).string_( "a+b zoom spin t1 t2 fine fb dist a*b")]; // the 2 groups of 3 * 6 controls for a and b ctr[\atune] = {|i| func.(\aTop, \afreqs, [5, 125, \lin, 1 ], \atune, \defaultfreqs, i)} !6; ctr[\btune] = {|i| func.(\bTop, \bfreqs, [5, 125, \lin, 1 ], \btune, \defaultfreqs, i)} !6; ctr[\afine] = {|i| func.(\aMid, \afine, [-1, 1], \afine, \defaultfine, i)} !6; ctr[\bfine] = {|i| func.(\bMid, \bfine, [-1, 1], \bfine, \defaultfine, i)} !6; ctr[\aamp] = {|i| func.(\aLow, \aamps, [-120, -4, \exp], \aamp, \defaultamps, i)} ! 6; ctr[\bamp] = {|i| func.(\bLow, \bamps, [-120, -4, \exp], \bamp, \defaultamps, i)} ! 6; gui[\layout] = VLayout( gui[\topBar], HLayout( VLayout( gui[\aTop], gui[\aMid], gui[\aLow], ), VLayout( gui[\scopeView], gui[\zoomView].maxHeight_(100), ), VLayout( gui[\bTop], gui[\bMid], gui[\bLow], ), ), gui[\lowBar] ); SynthDef("scope", { var sig; sig = In.ar(\in.kr(0), 2); // ScopeOut2 writes the audio to the buffer // IMPORTANT - ScopeOut2, not ScopeOut ScopeOut2.ar(sig, \bufnum.kr(0)); Out.ar(0, sig*0.1); }).add; SynthDef("test3", { var a, b, f, sig; var afreqs, bfreqs, aamps, bamps; afreqs = \afreqs.kr(ctr[\defaultfreqs]) + \afine.kr(ctr[\defaultfine]); bfreqs = \bfreqs.kr(ctr[\defaultfreqs]) + \bfine.kr(ctr[\defaultfine]); aamps = \aamps.kr(ctr[\defaultamps]); bamps = \bamps.kr(ctr[\defaultamps]); a = SinOsc.ar(afreqs[0..3].midicps, 0.0, aamps[0..3].dbamp); b = SinOsc.ar(bfreqs[0..3].midicps, 0.0, bamps[0..3].dbamp); a = a + Pulse.ar(afreqs[4..].midicps, [0.5, 0.2], aamps[4..].dbamp); b = b + Pulse.ar(bfreqs[4..].midicps, [0.5, 0.2], bamps[4..].dbamp); sig = ((a+b) * \absum.kr(0.5)) + ((a*b) * \abmul.kr(0.5)); sig = (sig * \dist.kr(1.0)).tanh; f = LocalIn.ar(2, 0); f = f * \fb.kr(0.0); a = DelayL.ar(sig+f[0], 2, \aspin.kr(0.0, 0.1)); b = DelayL.ar(sig+f[1], 2, \bspin.kr(0.0, 0.1) + \finespin.kr(0.0, 0.2)); LocalOut.ar([a, b]); a = a * \alvl.kr(0.5); b = b * \blvl.kr(0.5); Out.ar(\out.kr(0), [a, b]); }).add; // scope view with lvl controls Slider(gui[\scopeView]).action_({|sl| syn.set(\alvl, [0.0, 1.0].asSpec.map(sl.value))}).value_(0.5); scope = ScopeView(gui[\scopeView], Rect(0,0,380,380)); // this is SCScope Slider(gui[\scopeView]).action_({|sl| syn.set(\blvl, [0.0, 1.0].asSpec.map(sl.value))}).value_(0.5); // controls below scope Knob(gui[\zoomView]).action_({|sl| syn.set(\absum, [0.0, 1.0].asSpec.map(sl.value))}).value_(0.5); Slider(gui[\zoomView]).action_({|sl| scope.yZoom = ([0.125, 20, \exp, 1/8, 1].asSpec.map(sl.value))}).valueAction_(0.0); Slider(gui[\zoomView]).action_({|sl| syn.set(\aspin, [0.0, 0.49].asSpec.map(sl.value))}).value_(0.0); Slider(gui[\zoomView]).action_({|sl| syn.set(\bspin, [0.0, 0.49].asSpec.map(sl.value))}).value_(0.0); Slider(gui[\zoomView]).action_({|sl| syn.set(\finespin, [0.0, 0.1, \lin, 0.001].asSpec.map(sl.value))}).value_(0.0); Slider(gui[\zoomView]).action_({|sl| syn.set(\fb, [-0.2, 0.2].asSpec.map(sl.value))}).value_(0.5); Slider(gui[\zoomView]).action_({|sl| syn.set(\dist, [1, 50].asSpec.map(sl.value))}).value_(0.0); Knob(gui[\zoomView]).action_({|sl| syn.set(\abmul, [0.0, 1.0].asSpec.map(sl.value))}).value_(0.5); buffer = Buffer.alloc(s, 1024,2); bus = Bus.audio(s, 1); // why 1? scope.bufnum = buffer.bufnum; scope.style = 2; ​ // IMPORTANT scope.server = s; scopeSyn = Synth.tail(RootNode(s), "scope", [\in, bus.index, \bufnum, buffer.bufnum]); syn = Synth("test3", [\out, bus.index]); scope.start; w.onClose = { syn.free; scopeSyn.free; buffer.free; bus.free; syn = scopeSyn = scope = func = buffer = bus = nil }; CmdPeriod.doOnce({w.close}); w.layout = gui[\layout]; w.front; )