diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d8dd753 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.wav diff --git a/supercollider/tkam_gui.scd b/supercollider/tkam_gui.scd index 4e46e2a..a754beb 100644 --- a/supercollider/tkam_gui.scd +++ b/supercollider/tkam_gui.scd @@ -82,10 +82,12 @@ updateSubsection = {arg mod, clock, metronome, sectionDisplay, refresh = true; currentSection, currentSubsection ); }); - }, {updateSection.value(mod, clock, metronome, sectionDisplay, refresh)}) + }, { + updateSection.value(mod, clock, metronome, sectionDisplay, refresh) + }) }; -buildTransport = {arg win, view, clock, metronome; +buildTransport = {arg win, view, clock, metronome, preampBusses, accompBusses, postampBusses; var sec, subsec, sectionDisplay, layout, player; sectionDisplay = StaticText(win).string_("section: 1.1").font_(Font("Liberation Mono", 70)); @@ -111,27 +113,7 @@ buildTransport = {arg win, view, clock, metronome; if(pState.value == 1, { player = { var startMeasure = ~sectionNavDict[[currentSection, currentSubsection]] - 1; - ~patternProxy.source = Ppar( - [Pseq(~patterns[0][startMeasure..], 1)] ++ - - ~patterns[2].collect({arg pattern, p; - Pmono(\amp_curve_ ++ ~hash, - \amp, Pseg(Pseq(pattern.slice(nil, 0)[(startMeasure * 16)..], 1), 1 * ~dUnit, \cub), - \dur, 1 * ~dUnit, - \bus, ~preampBusses[p].index - ) - }) ++ - - ~patterns[1].collect({arg pattern, p; - Pmono(\bass_mono_ ++ ~hash, - \freq, Pseq(pattern.slice(nil, 0)[(startMeasure * 16)..], 1), - \dur, 1 * ~dUnit, - \ampBus, ~preampBusses[p + 1].index, - \bus, ~postampBusses[4].index - ) - }) - - ); + ~patternProxy.source = ~genPlayablePatterns.value(startMeasure, ~patterns, preampBusses, accompBusses, postampBusses); Pbind(\instrument, \click_ ++ ~hash, \beat, Pseq([1, 2, 1, 2]), \dur, 1).play(~tempoClock, quant: 0); [1, 2, 1, 2].do({arg beat; { @@ -210,13 +192,13 @@ buildTrackFader = {arg view, name, index, initVal; }; -masterView = {arg win; +masterView = {arg win, preampBusses, accompBusses, postampBusses; var view, generatorLayout, clock, metronome, metronomeLayout, transportLayout, auxControlsLayout, countOff, ranSeed, order, tempo, sectionDisplay, address; view = View(win); generatorLayout = buildGenerator.value(view); # clock, metronome, metronomeLayout = buildMetronome.value(win); - # sectionDisplay, transportLayout = buildTransport.value(win, view, clock, metronome); + # sectionDisplay, transportLayout = buildTransport.value(win, view, clock, metronome, preampBusses, accompBusses, postampBusses); auxControlsLayout = buildAuxControls.value(view); view.layout_( @@ -263,7 +245,7 @@ faderView = {arg win; }; -~generateGUI = { +~generateGUI = {arg preampBusses, accompBusses, postampBusses; var win, tabButtonReset, transportButton, mixerButton, helpButton, tabs; win = Window("to kill a monarch", Rect(500, 500, 1100, 575), false).front; tabButtonReset = {transportButton.value = 1; mixerButton.value = 1; helpButton.value = 1}; @@ -281,7 +263,7 @@ faderView = {arg win; helpButton = Button().states_([["help", Color.white, Color.grey], ["help", Color.black]]).action_( {tabButtonReset.value; helpButton.value = 0; tabs.index = 2 }.inEnvir).value_(1) ), - tabs = StackLayout(masterView.value(win), faderView.value(win)/*, helpView.value*/)); + tabs = StackLayout(masterView.value(win, preampBusses, accompBusses, postampBusses), faderView.value(win)/*, helpView.value*/)); }; //~generateGUI.value ) diff --git a/supercollider/tkam_main.scd b/supercollider/tkam_main.scd index 73dfe8c..b80a86c 100644 --- a/supercollider/tkam_main.scd +++ b/supercollider/tkam_main.scd @@ -8,6 +8,7 @@ appEnvironment = Environment.make; appEnvironment.push; s.waitForBoot({ + var preampBusses, accompBusses, postampBusses; ~hash = Date.getDate.hash.asString; ~cRes = 1; @@ -18,12 +19,16 @@ s.waitForBoot({ "tkam_gui.scd".loadRelative; "tkam_transcriber.scd".loadRelative; + # preampBusses, accompBusses, postampBusses = ~allocBusses.value(s); + ~defineSynths.value(s, preampBusses, accompBusses, postampBusses); + ~genAll = {arg seed; ~dUnit = 8.reciprocal; ~musicData = ~genMusicData.value(seed); ~scoreData = ~genScoreData.value(~musicData[0]); ~sectionData = ~musicData[4]; - ~patterns = ~genPatterns.value(~musicData[0], ~musicData[1], ~musicData[2], ~musicData[3], ~sectionData); + ~patterns = ~genPatterns.value(~musicData[0], ~musicData[1], ~musicData[2], ~musicData[3], ~sectionData, + preampBusses, accompBusses, postampBusses); ~sectionNavDict = ~musicData[5]; ~isPlaying = false; }; @@ -35,8 +40,8 @@ s.waitForBoot({ "loading app".postln; ~genAll.value(19800725); ~play = Synth.new(\masterPlayerControl_ ++ ~hash); - 4.collect({arg p; Synth.new(\clip_ ++ ~hash, [\bin, ~accompBusses[p].index, \bus, ~postampBusses[5].index])}); - ~generateGUI.value; + 4.collect({arg p; Synth.new(\clip_ ++ ~hash, [\bin, accompBusses[p].index, \bus, postampBusses[5].index])}); + ~generateGUI.value(preampBusses, accompBusses, postampBusses); "ready".postln; }); appEnvironment.pop; diff --git a/supercollider/tkam_musical_data_generator.scd b/supercollider/tkam_musical_data_generator.scd index 4c9c8e4..b7926ef 100644 --- a/supercollider/tkam_musical_data_generator.scd +++ b/supercollider/tkam_musical_data_generator.scd @@ -38,7 +38,7 @@ frNearestInList = {arg frComp, frDict; frDict.reject({arg item; (item[\root][0] == frComp[1]) || (item[\fr] == frComp[1]) - }).keys.do({arg fr; + }).keys.asList.sort({arg a, b; a.asString < b.asString}).do({arg fr; var diff = abs(frToFloat.value(fr) - frToFloat.value(frComp[0])); if(diff < diffNearest, {diffNearest = diff; frNearest = fr}); }); @@ -82,9 +82,10 @@ hdChoose = {arg mode, exp = 1, weights = [1, 1, 1, 1, 1, 1, 1]; mode.wchoose(probs.normalizeSum) }; +//!!!!this is not returning the same thing when if randseed is set. the issue is the array as key and sorting. wchooseDict = {arg dict, exp = 1, limit = 0; var keyList, probs; - keyList = dict.keys.asList; + keyList = dict.keys.asList.sort({arg a, b; a.asString < b.asString}); probs = keyList.collect({arg key; var count = dict[key][\count]; if(count < limit, {0}, {count}) @@ -93,7 +94,9 @@ wchooseDict = {arg dict, exp = 1, limit = 0; keyList.wchoose(probs.normalizeSum) }; -collectRoots = {arg dict; dict.keys.collect({arg fr; dict[fr][\root][0]})}; +collectRoots = {arg dict; dict.keys.collect({arg fr; + dict[fr][\root][0]}).asList.sort({arg a, b; a.asString < b.asString}) +}; //~~~~~~~~~~~~GENERATE MODE SEQUENCE~~~~~~~~~~~~ @@ -434,7 +437,7 @@ genAmpCurve = {arg temporalData1, temporalData2, offset1, offset2, type; sectionCount, subsectionCount, lastRoots, roots, ampDataTmp; - thisThread.randSeed = seed; + thisThread.randSeed = seed.postln; # totalDur, section1Dur, dUnit, curLen, cadence, ultimate = [6 * 60, 2 * 60, 8.reciprocal, 0, false, false]; # totalLen, section1Len = [(totalDur / dUnit).round(16), (section1Dur / dUnit).round(16)]; @@ -500,8 +503,8 @@ genAmpCurve = {arg temporalData1, temporalData2, offset1, offset2, type; bassData[1] = bassData[1] ++ genBassPart.value(collectRoots.value(lastCadenceState).asList[0], ampDataTmp, false); }); - sectionData.add(((curLen - temporalData[0].size).postln / 4).asInteger-> - sectionData[((curLen - temporalData[0].size).postln / 4).asInteger].put(5, true)); + sectionData.add(((curLen - temporalData[0].size) / 4).asInteger-> + sectionData[((curLen - temporalData[0].size) / 4).asInteger].put(5, true)); # sectionCount, subsectionCount = [sectionCount + 1, 1]; # lastCadenceTemporalData, lastCadenceState, lastSectionPoint = [temporalData, modeState, curLen]; cadence = true; @@ -518,6 +521,7 @@ genAmpCurve = {arg temporalData1, temporalData2, offset1, offset2, type; [ensData, accompData, bassData, ampData, sectionData, sectionNavDict] }; -~genMusicData.value(100) + +//~genMusicData.value(100) ) diff --git a/supercollider/tkam_sonifier.scd b/supercollider/tkam_sonifier.scd index a177ec6..949f040 100644 --- a/supercollider/tkam_sonifier.scd +++ b/supercollider/tkam_sonifier.scd @@ -1,63 +1,81 @@ ( var formatPatternData; -//busses +//~~~~~~~~~~~~ALLOCATE BUSSES~~~~~~~~~~~~ +~allocBusses = {arg server; + var preampBusses, accompBusses, postampBusses; + preampBusses = 3.collect({Bus.audio(server, 1)}); + accompBusses = 4.collect({Bus.audio(server, 1)}); + postampBusses = 7.collect({Bus.audio(server, 1)}); + [preampBusses, accompBusses, postampBusses]; +}; + +//~~~~~~~~~~~~DEFINE SYNTHS~~~~~~~~~~~~ +~defineSynths = {arg server, preampBusses, accompBusses, postampBusses; + var sdPlayer, sdTransport, sdClick, sdAmpCurve, sdEns, sdAccomp, sdClip, sdBass, sdDiskOut, allSds; -~postampBusses = 7.collect({Bus.audio(s, 1)}); -~preampBusses = 3.collect({Bus.audio(s, 1)}); -~accompBusses = 4.collect({Bus.audio(s, 1)}); + //~postampBusses = 7.collect({Bus.audio(server, 1)}); + //~preampBusses = 3.collect({Bus.audio(server, 1)}); + //~accompBusses = 4.collect({Bus.audio(server, 1)}); -SynthDef(\masterPlayerControl_ ++ ~hash, { - var sigs, sigsPanned, masterSig, imp; + sdPlayer = SynthDef(\masterPlayerControl_ ++ ~hash, { + var sigs, sigsPanned, masterSig, imp; - sigs = ~postampBusses.collect({arg bus, i; In.ar(bus) * NamedControl.kr(\vol_ ++ i, 1, 0.1)}); - sigsPanned = sigs.collect({arg sig, i; Pan2.ar(sig * NamedControl.kr(\mute_ ++ i, 1, 0.1), NamedControl.kr(\pan_ ++ i, 0.5, 0.1))}); - masterSig = Mix.ar(sigsPanned.drop(-1)) * NamedControl.kr("vol_master" ++ i, 1, 0.1) * NamedControl.kr("mute_master" ++ i, 1, 0.1); + sigs = postampBusses.collect({arg bus, i; In.ar(bus) * NamedControl.kr(\vol_ ++ i, 1, 0.1)}); + sigsPanned = sigs.collect({arg sig, i; Pan2.ar(sig * NamedControl.kr(\mute_ ++ i, 1, 0.1), NamedControl.kr(\pan_ ++ i, 0.5, 0.1))}); + masterSig = Mix.ar(sigsPanned.drop(-1)) * NamedControl.kr("vol_master" ++ i, 1, 0.1) * NamedControl.kr("mute_master" ++ i, 1, 0.1); - Out.ar(0, masterSig); - Out.ar(2, sigsPanned.last); //change this if you want the click to go somewhere else + Out.ar(0, masterSig); + Out.ar(2, sigsPanned.last); //change this if you want the click to go somewhere else - imp = Impulse.kr(10); - SendReply.kr(imp, '/masterLevels_' ++ ~hash, values: [Amplitude.kr(masterSig)]); - sigs.collect({arg sig, i; SendReply.kr(imp, '/trackLevel_' ++ i ++ "_" ++ ~hash, values: [Amplitude.kr(sig)])}); -}).add; + imp = Impulse.kr(10); + SendReply.kr(imp, '/masterLevels_' ++ ~hash, values: [Amplitude.kr(masterSig)]); + sigs.collect({arg sig, i; SendReply.kr(imp, '/trackLevel_' ++ i ++ "_" ++ ~hash, values: [Amplitude.kr(sig)])}); + }).add; -SynthDef(\transport_ ++ ~hash, {arg measure = 0, beat = 0, section = 0, subsection = 0, gate = 1, dur = 1; - SendReply.kr(Impulse.kr(0) * (measure > 0) * (beat > 0),'/measureClock_' ++ ~hash, values: [measure, beat, section, subsection]); - //SendReply.kr(Impulse.kr(0),'/nextSubsection_' ++ ~hash); - EnvGen.kr(Env.sine(dur), gate, doneAction: 2); -}).add; + sdTransport = SynthDef(\transport_ ++ ~hash, {arg measure = 0, beat = 0, section = 0, subsection = 0, gate = 1, dur = 1; + SendReply.kr(Impulse.kr(0) * (measure > 0) * (beat > 0),'/measureClock_' ++ ~hash, values: [measure, beat, section, subsection]); + //SendReply.kr(Impulse.kr(0),'/nextSubsection_' ++ ~hash); + EnvGen.kr(Env.sine(dur), gate, doneAction: 2); + }).add; -SynthDef(\click_ ++ ~hash, {arg beat = 0, gate = 1, dur = 1; - Out.ar(~postampBusses[6], 10 * BPF.ar(WhiteNoise.ar * EnvGen.kr(Env.perc(0.01, 0.1), gate), 440 * ((beat <= 1) + 1), 0.02)); - EnvGen.kr(Env.sine(dur), gate, doneAction: 2); -}).add; + sdClick = SynthDef(\click_ ++ ~hash, {arg beat = 0, gate = 1, dur = 1; + Out.ar(postampBusses[6], 10 * BPF.ar(WhiteNoise.ar * EnvGen.kr(Env.perc(0.01, 0.1), gate), 440 * ((beat <= 1) + 1), 0.02)); + EnvGen.kr(Env.sine(dur), gate, doneAction: 2); + }).add; + sdAmpCurve = SynthDef(\amp_curve_ ++ ~hash, {arg amp = 0, dur = 0.1, gate = 1, bus = 0; + Out.kr(bus, amp) + }).add; -//~~~~~~~~~~~~DEFINE SYNTHS~~~~~~~~~~~~ -SynthDef(\amp_curve_ ++ ~hash, {arg amp = 0, dur = 0.1, gate = 1, bus = 0; - Out.kr(bus, amp) -}).add; + sdEns = SynthDef(\ens_ ++ ~hash, {arg freq = 440, amp = 1, dur = 1, gate = 1, bus = 0, ampBus = 0; + Out.ar(bus, SinOsc.ar(freq, 2pi.rand, 0.1) * Latch.kr(In.kr(ampBus), Impulse.kr(0)) * EnvGen.kr(Env.asr(0.1, 1, 0.1), gate, doneAction: 2)) + }).add; -SynthDef(\ens_ ++ ~hash, {arg freq = 440, amp = 1, dur = 1, gate = 1, bus = 0, ampBus = 0; - Out.ar(bus, SinOsc.ar(freq, 2pi.rand, 0.1) * Latch.kr(In.kr(ampBus), Impulse.kr(0)) * EnvGen.kr(Env.asr(0.1, 1, 0.1), gate, doneAction: 2)) -}).add; + sdAccomp = SynthDef(\accomp_ ++ ~hash, {arg freq = 440, amp = 1, attack = 1, dur = 1, gate = 1, bout = 0, ampBus = 0; + Out.ar(bout, SinOsc.ar(freq, 2pi.rand, 1) * 0.01 * amp * Latch.kr(In.kr(ampBus), Impulse.kr(0)) * EnvGen.kr(Env.asr(attack, 1, 0.01), gate, doneAction: 2)) + }).add; -SynthDef(\accomp_ ++ ~hash, {arg freq = 440, amp = 1, attack = 1, dur = 1, gate = 1, bout = 0, ampBus = 0; - Out.ar(bout, SinOsc.ar(freq, 2pi.rand, 1) * 0.01 * amp * Latch.kr(In.kr(ampBus), Impulse.kr(0)) * EnvGen.kr(Env.asr(attack, 1, 0.01), gate, doneAction: 2)) -}).add; + sdClip = SynthDef(\clip_ ++ ~hash, {arg dur = 1, gate = 1, bin = 0, bus = 0; + //Out.ar([0, 1], (In.ar(bin)).clip(0, 1) * pow(Line.kr(0, 1, 240), 2)) + Out.ar(bus, (In.ar(bin)).clip(0, 1) * 50 * pow(Line.kr(0, 1, 10), 2)) + }).add; -SynthDef(\clip_ ++ ~hash, {arg dur = 1, gate = 1, bin = 0, bus = 0; - //Out.ar([0, 1], (In.ar(bin)).clip(0, 1) * pow(Line.kr(0, 1, 240), 2)) - Out.ar(bus, (In.ar(bin)).clip(0, 1) * 50 * pow(Line.kr(0, 1, 10), 2)) -}).add; + sdBass = SynthDef(\bass_mono_ ++ ~hash, {arg freq = 440, ampBus = 0, bus = 0; + Poll.kr(Changed.kr(In.kr(ampBus)), In.kr(ampBus)); + Out.ar(bus, (SinOsc.ar(freq) * 0.4 * In.kr(ampBus))) + }).add; -SynthDef(\bass_mono_ ++ ~hash, {arg freq = 440, ampBus = 0, bus = 0; - Poll.kr(Changed.kr(In.kr(ampBus)), In.kr(ampBus)); - Out.ar(bus, (SinOsc.ar(freq) * 0.4 * In.kr(ampBus))) -}).add; + sdDiskOut = SynthDef(\disk_out_ ++ ~hash, {arg bufnum, inbus; + DiskOut.ar(bufnum, In.ar(inbus)); + }).add; + + allSds = [sdPlayer, sdTransport, sdClick, sdAmpCurve, sdEns, sdAccomp, sdClip, sdBass, sdDiskOut]; + allSds.do({arg sd; sd.add}); + allSds +}; // group data by measures for navigation @@ -79,7 +97,7 @@ formatPatternData = {arg musData, measureLen; //~~~~~~~~~~~~GENERATE PATTERNS~~~~~~~~~~~~ -~genPatterns = {arg ensData, accompData, bassData, ampData, sectionData; +~genPatterns = {arg ensData, accompData, bassData, ampData, sectionData, preampBusses, accompBusses, postampBusses; var measureLen, ensDataFormatted, accompDataFormatted, bassDataFormatted, ampDataFormatted, dUnit, section, subsection, patterns; @@ -109,8 +127,8 @@ formatPatternData = {arg musData, measureLen; \amp, [0.5, 0.3, 0.3, 0.3][m], //\amp, Pseq(musData[2].collect({arg item; [0, 0.25, 0.5, 0.75][item]}) * [1, 0.5, 0.25, 0.1][m] * 16); // * musData[3].collect({arg val; if(val < 0.25, {0}, {0.5})})) - \ampBus, ~preampBusses[0].index, - \bus, ~postampBusses[m].index + \ampBus, preampBusses[0].index, + \bus, postampBusses[m].index ) }) ++ accompDataFormatted[measure].collect({arg musData, m; @@ -122,8 +140,8 @@ formatPatternData = {arg musData, measureLen; \amp, Pseq(musData[3].collect({arg item; [0, 2, 4, 8][item]}) * 0.0125 * 1), //\attack, Pseq(musData[1] * abs(musData[3].clip(0, 0.25) * 2 - 1) * dUnit), \attack, Pseq(musData[2] * 1 * dUnit), - \ampBus, ~preampBusses[0].index, - \bout, Pseq(musData[4].collect({arg index; ~accompBusses[index].index})) + \ampBus, preampBusses[0].index, + \bout, Pseq(musData[4].collect({arg index; accompBusses[index].index})) ) }) ++ [ @@ -146,4 +164,92 @@ formatPatternData = {arg musData, measureLen; [patterns, bassData, ampData] }; -) \ No newline at end of file +~genPlayablePatterns = {arg startMeasure, patterns, preampBusses, accompBusses, postampBusses; + Ppar( + [Pseq(patterns[0][startMeasure..], 1)] ++ + + patterns[2].collect({arg pattern, p; + Pmono(\amp_curve_ ++ ~hash, + \amp, Pseg(Pseq(pattern.slice(nil, 0)[(startMeasure * 16)..], 1), 1 * ~dUnit, \cub), + \dur, 1 * ~dUnit, + \bus, preampBusses[p].index + ) + }) ++ + patterns[1].collect({arg pattern, p; + Pmono(\bass_mono_ ++ ~hash, + \freq, Pseq(pattern.slice(nil, 0)[(startMeasure * 16)..], 1), + \dur, 1 * ~dUnit, + \ampBus, preampBusses[p + 1].index, + \bus, postampBusses[4].index + ) + }) + ); +}; + + +~bounceAudio = { + var basePath, server, buffers, preampBusses, nextNode, accompBusses, postampBusses, synths, prePatterns, playablePatterns, score; + + //dir = thisProcess.nowExecutingPath.dirname; + basePath = ~dir +/+ ".." +/+ "audio"; + basePath.mkdir; + + server = Server(\nrt_ ++ ~hash, + options: ServerOptions.new + .numOutputBusChannels_(7) + .numInputBusChannels_(0) + ); + + # preampBusses, accompBusses, postampBusses = ~allocBusses.value(s); + postampBusses = 7.collect({arg index; Bus.new(rate: 'audio', index: index.postln, numChannels: 1, server: server)}); + synths = ~defineSynths.value(s, preampBusses, accompBusses, postampBusses); + + prePatterns = ~genPatterns.value(~musicData[0], ~musicData[1], ~musicData[2], ~musicData[3], ~sectionData, + preampBusses, accompBusses, postampBusses); + + playablePatterns = ~genPlayablePatterns.value(0, prePatterns, preampBusses, accompBusses, postampBusses); + + score = playablePatterns.asScore(duration: 120, timeOffset: 0.001); + + nextNode = score.score.slice(nil, 1).select({arg msg; msg[0] == 9}).slice(nil, 2).maxItem + 1; + + score.score[2].postln; + nextNode.postln; + + synths.do({arg synth; score.add([0.0, [\d_recv, synth.asBytes]])}); + + 4.collect({arg p; + //Synth.new(\clip_ ++ ~hash, [\bin, accompBusses[p].index, \bus, postampBusses[5].index]) + score.add([0.0, [\s_new, \clip_ ++ ~hash, nextNode, 1, 1, \bin, accompBusses[p].index, \bus, postampBusses[5].index]]); + nextNode = nextNode + 1; + }); + + buffers = 7.do({arg track; + + score.add([0.0, [\b_alloc, track, 65536, 1]]); + score.add([0.0, [\b_write, track, basePath +/+ "test_" ++ track ++ ".wav".standardizePath, "WAV", "int16", 0, 0, 1]]); + score.add([0.0, [\s_new, \disk_out_ ++ ~hash, nextNode, 1, 1, \bufnum, track, \inbus, track]]); + + score.add([120.0, [\n_free, nextNode]]); + score.add([120.0, [\b_close, track]]); + score.add([120.0, [\b_free, track]]); + nextNode = nextNode + 1; + }); + + score.sort; + + score.recordNRT( + outputFilePath: basePath +/+ "test_all" ++ ".wav".standardizePath, + sampleRate: 44100, + headerFormat: "WAV", + sampleFormat: "int16", + options: server.options, + duration: 120 + ); + + server.remove; +} + +) + +//~bounceAudio.value \ No newline at end of file