|
|
|
(
|
|
|
|
var formatPatternData;
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~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;
|
|
|
|
|
|
|
|
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, 0.1))});
|
|
|
|
masterSig = Mix.ar(sigsPanned.drop(-1)) * NamedControl.kr(\masterVol, 1, 0.1) * NamedControl.kr(\masterMute, 1, 0.1);
|
|
|
|
|
|
|
|
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)])});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
|
|
|
|
sdAmpCurve = SynthDef(\amp_curve_ ++ ~hash, {arg amp = 1, dur = 0.1, bus = 0;
|
|
|
|
Out.kr(bus, amp.lag)
|
|
|
|
});
|
|
|
|
|
|
|
|
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) * amp * Latch.kr(In.kr(ampBus), Impulse.kr(0)) * EnvGen.kr(Env.asr(0.1, 1, 0.1), gate, doneAction: 2))
|
|
|
|
});
|
|
|
|
|
|
|
|
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))
|
|
|
|
});
|
|
|
|
|
|
|
|
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))
|
|
|
|
});
|
|
|
|
|
|
|
|
sdBass = SynthDef(\bass_mono_ ++ ~hash, {arg freq = 440, ampBus = 0, bus = 0;
|
|
|
|
Out.ar(bus, (SinOsc.ar(freq) * 0.5 * In.kr(ampBus)))
|
|
|
|
});
|
|
|
|
|
|
|
|
sdDiskOut = SynthDef(\disk_out_ ++ ~hash, {arg bufnum, inbus;
|
|
|
|
DiskOut.ar(bufnum, In.ar(inbus));
|
|
|
|
});
|
|
|
|
|
|
|
|
allSds = [sdPlayer, sdTransport, sdClick, sdAmpCurve, sdEns, sdAccomp, sdClip, sdBass, sdDiskOut];
|
|
|
|
allSds.do({arg sd; sd.add});
|
|
|
|
allSds
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// group data by measures for navigation
|
|
|
|
formatPatternData = {arg musData, measureLen;
|
|
|
|
var dataLen;
|
|
|
|
dataLen = musData[0][0].size;
|
|
|
|
musData.collect({arg partData;
|
|
|
|
var res;
|
|
|
|
res = partData.flop;
|
|
|
|
res = res.add(res[1]);
|
|
|
|
res[1] = (res[1].differentiate.drop(1) ++ [10]);
|
|
|
|
res = res.flop ++ measureLen.collect({arg measure; dataLen.collect({0}) ++ [measure * 16]});
|
|
|
|
res = res.sort({arg a, b; a.last < b.last}).flop;
|
|
|
|
res = res.insert(1, (res.last.differentiate.drop(1) ++ [10])).flop;
|
|
|
|
res = res.separate({arg a, b; (a.last / 16).trunc != (b.last / 16).trunc});
|
|
|
|
res.collect({arg measureData; measureData.flop})
|
|
|
|
}).flop
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~GENERATE PATTERNS~~~~~~~~~~~~
|
|
|
|
//this generates patterns grouped by measures except for bass data and amp curve data which are much higher resolution
|
|
|
|
//these are used to make playable patterns
|
|
|
|
~genPatterns = {arg ensData, accompData, bassData, ampData, sectionData, preampBusses, accompBusses, postampBusses;
|
|
|
|
var measureLen, ensDataFormatted, accompDataFormatted, bassDataFormatted, ampDataFormatted,
|
|
|
|
dUnit, section, subsection, patterns;
|
|
|
|
|
|
|
|
measureLen = ((
|
|
|
|
ensData.collect({arg partData; partData.last[1]}) ++
|
|
|
|
accompData.flatten.collect({arg partData; partData.last[1]})
|
|
|
|
).maxItem.ceil(16) / 16).asInteger + 1;
|
|
|
|
|
|
|
|
ensDataFormatted = formatPatternData.value(ensData, measureLen);
|
|
|
|
accompDataFormatted = formatPatternData.value(accompData.flatten, measureLen);
|
|
|
|
dUnit = 8.reciprocal;
|
|
|
|
|
|
|
|
patterns = measureLen.collect({arg measure;
|
|
|
|
if(sectionData[measure * 4] != nil, {
|
|
|
|
section = sectionData[measure * 4][2];
|
|
|
|
subsection = sectionData[measure * 4][3];
|
|
|
|
});
|
|
|
|
Ppar(
|
|
|
|
//check how amplitude is being handled
|
|
|
|
ensDataFormatted[measure].collect({arg musData, m;
|
|
|
|
Pbind(
|
|
|
|
\instrument, \ens_ ++ ~hash,
|
|
|
|
\freq, Pseq(musData[0].replace(0, Rest(0))),
|
|
|
|
\dur, Pseq(musData[1] * dUnit),
|
|
|
|
\sustain, Pseq(musData[2] * dUnit),
|
|
|
|
\amp, [1, 0.7, 0.5, 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);
|
|
|
|
\ampBus, preampBusses[0].index,
|
|
|
|
\bus, postampBusses[m].index
|
|
|
|
)
|
|
|
|
}) ++
|
|
|
|
//check how amplitude and attack are being handled
|
|
|
|
accompDataFormatted[measure].collect({arg musData, m;
|
|
|
|
Pbind(
|
|
|
|
\instrument, \accomp_ ++ ~hash,
|
|
|
|
\freq, Pseq(musData[0].replace(0, Rest(0))),
|
|
|
|
\dur, Pseq(musData[1] * dUnit),
|
|
|
|
\sustain, Pseq(musData[2] * dUnit),
|
|
|
|
\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}))
|
|
|
|
)
|
|
|
|
}) ++
|
|
|
|
[
|
|
|
|
Pbind(
|
|
|
|
\instrument, \transport_ ++ ~hash,
|
|
|
|
\measure, measure + 1,
|
|
|
|
\beat, Pseq([1, 2]),
|
|
|
|
\section, section,
|
|
|
|
\subsection, subsection,
|
|
|
|
\dur, 8 * dUnit
|
|
|
|
),
|
|
|
|
Pbind(
|
|
|
|
\instrument, \click_ ++ ~hash,
|
|
|
|
\beat, Pseq([1, 2]),
|
|
|
|
\dur, 8 * dUnit
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
});
|
|
|
|
[patterns, bassData, ampData]
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//this is a playable pattern based on start measure
|
|
|
|
~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
|
|
|
|
)
|
|
|
|
})
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//~~~~~~~~~~~~BOUNCE AUDIO~~~~~~~~~~~~
|
|
|
|
//this bounces the audio for use in another DAW or for practice
|
|
|
|
~bounceAudio = {arg seed;
|
|
|
|
var trackNames, basePath, server, buffers, recDur,
|
|
|
|
preampBusses, nextNode, accompBusses, postampBusses,
|
|
|
|
synths, prePatterns, playablePatterns, score;
|
|
|
|
|
|
|
|
trackNames = ["part_start", "part_III", "part_II", "part_I", "accomp_II", "accomp_I", "click"];
|
|
|
|
|
|
|
|
basePath = ~dir +/+ ".." +/+ "audio" +/+ "seed_" ++ seed;
|
|
|
|
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, 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);
|
|
|
|
|
|
|
|
recDur = (prePatterns[2][0].size / 8) + 10;
|
|
|
|
score = playablePatterns.asScore(duration: recDur, timeOffset: 0.001);
|
|
|
|
nextNode = score.score.slice(nil, 1).select({arg msg; msg[0] == 9}).slice(nil, 2).maxItem + 1;
|
|
|
|
|
|
|
|
synths.do({arg synth; score.add([0.0, [\d_recv, synth.asBytes]])});
|
|
|
|
|
|
|
|
4.collect({arg p;
|
|
|
|
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 +/+ "tkam_" ++ trackNames[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([recDur, [\n_free, nextNode]]);
|
|
|
|
score.add([recDur, [\b_close, track]]);
|
|
|
|
score.add([recDur, [\b_free, track]]);
|
|
|
|
nextNode = nextNode + 1;
|
|
|
|
});
|
|
|
|
|
|
|
|
score.sort;
|
|
|
|
|
|
|
|
score.recordNRT(
|
|
|
|
outputFilePath: basePath +/+ "tkam_all" ++ ".wav".standardizePath,
|
|
|
|
sampleRate: 44100,
|
|
|
|
headerFormat: "WAV",
|
|
|
|
sampleFormat: "int16",
|
|
|
|
options: server.options,
|
|
|
|
duration: recDur
|
|
|
|
);
|
|
|
|
|
|
|
|
server.remove;
|
|
|
|
}
|
|
|
|
)
|