Last active
September 17, 2023 14:58
-
-
Save schollz/f2878f41c644ffd20557f85d50784656 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
InstrumentSample { | |
var server; | |
var syns; | |
var <allNumbers; | |
var <allDynamics; | |
var <allRoundRobins; | |
*new { | |
arg argServer; | |
^super.new.init(argServer); | |
} | |
init { | |
arg argServer; | |
server = argServer; | |
allNumbers=Dictionary.new(); | |
allDynamics=Dictionary.new(); | |
allRoundRobins=Dictionary.new(); | |
syns = Dictionary.new(); | |
} | |
loadFolder { | |
arg folder; | |
var noteDynamics=Dictionary.new(); | |
var noteRoundRobins=Dictionary.new(); | |
var noteNumbers=Array.new(128); | |
PathName.new(folder).entries.do({ arg v; | |
var fileSplit=v.fileName.split($.); | |
var note,dyn,dyns,rr,rel; | |
if (fileSplit.last=="wav",{ | |
if (fileSplit.size==6,{ | |
note=fileSplit[0].asInteger; | |
dyn=fileSplit[1].asInteger; | |
dyns=fileSplit[2].asInteger; | |
rr=fileSplit[3].asInteger; | |
rel=fileSplit[4].asInteger; | |
if (rel==0,{ | |
if (noteDynamics.at(note).isNil,{ | |
noteDynamics.put(note,dyns); | |
noteNumbers.add(note); | |
}); | |
if (noteRoundRobins.at(note.asString++"."++dyn.asString).isNil,{ | |
noteRoundRobins.put(note.asString++"."++dyn.asString,rr); | |
},{ | |
if (rr>noteRoundRobins.at(note.asString++"."++dyn.asString),{ | |
noteRoundRobins.put(note.asString++"."++dyn.asString,rr); | |
}); | |
}); | |
}); | |
}); | |
}); | |
}); | |
noteNumbers=noteNumbers.sort; | |
allDynamics.put(folder,noteDynamics); | |
allNumbers.put(folder,noteNumbers); | |
allRoundRobins.put(folder,noteRoundRobins); | |
SynthDef("playx2",{ | |
arg out=0,pan=0,amp=1.0, | |
buf1,buf2,buf1mix=1, | |
t_trig=1,rate=1, | |
attack=0.01,decay=0.1,sustain=1.0,release=6,gate=1, | |
startPos=0; | |
var snd,snd2; | |
var frames1=BufFrames.ir(buf1); | |
var frames2=BufFrames.ir(buf2); | |
rate=rate*BufRateScale.ir(buf1); | |
snd=PlayBuf.ar(2,buf1,rate,t_trig,startPos:startPos*frames1,doneAction:Select.kr(frames1>frames2,[0,2])); | |
snd2=PlayBuf.ar(2,buf2,rate,t_trig,startPos:startPos*frames2,doneAction:Select.kr(frames2>frames1,[0,2])); | |
snd=(buf1mix*snd)+((1-buf1mix)*snd2);//SelectX.ar(buf1mix,[snd2,snd]); | |
snd=snd*EnvGen.ar(Env.adsr(attack,decay,sustain,release),gate,doneAction:2); | |
DetectSilence.ar(snd,0.0005,doneAction:2); | |
snd=Balance2.ar(snd[0],snd[1],pan,amp); | |
Out.ar(out,snd); | |
}).send(server); | |
SynthDef("playx1",{ | |
arg out=0,pan=0,amp=1.0, | |
buf1,buf2,buf1mix=1, | |
t_trig=1,rate=1, | |
attack=0.01,decay=0.1,sustain=1.0,release=6,gate=1, | |
startPos=0; | |
var snd,snd2; | |
var frames1=BufFrames.ir(buf1); | |
var frames2=BufFrames.ir(buf2); | |
rate=rate*BufRateScale.ir(buf1); | |
snd=PlayBuf.ar(1,buf1,rate,t_trig,startPos:startPos*frames1,doneAction:Select.kr(frames1>frames2,[0,2])); | |
snd2=PlayBuf.ar(1,buf2,rate,t_trig,startPos:startPos*frames2,doneAction:Select.kr(frames2>frames1,[0,2])); | |
snd=SelectX.ar(buf1mix,[snd2,snd]); | |
snd=snd*EnvGen.ar(Env.adsr(attack,decay,sustain,release),gate,doneAction:2); | |
DetectSilence.ar(snd,0.001,doneAction:2); | |
snd=Pan2.ar(snd,pan,amp); | |
Out.ar(out,snd); | |
}).send(server); | |
} | |
doPlay { | |
arg id,note,amp,buf1,buf2,buf1mix,rate; | |
var notename=1000000.rand; | |
var node; | |
[notename,note,amp,buf1,buf2,buf1mix,rate].postln; | |
if (syns.at(id).isNil,{ | |
syns.put(id,Dictionary.new()); | |
}); | |
if (syns.at(id).at(note).notNil,{ | |
if (syns.at(id).at(note).isRunning,{ | |
syns.at(id).at(note).set(\gate,0); | |
}); | |
}); | |
node=Synth.head(server,"playx"++buf1.numChannels,[ | |
\out,0, | |
\amp,amp, | |
\buf1,buf1, | |
\buf2,buf2, | |
\buf1mix,buf1mix, | |
\rate,rate, | |
]).onFree({ | |
buf1.free; | |
buf2.free; | |
}); | |
syns.at(id).put(note,node); | |
NodeWatcher.register(node,true); | |
} | |
playSample { | |
arg id, folder, note, velocity; | |
var noteDynamics = allDynamics.at(folder); | |
var noteRoundRobins = allRoundRobins.at(folder); | |
var noteNumbers = allNumbers.at(folder); | |
var noteOriginal=note; | |
var noteLoaded=note; | |
var noteClosest=noteNumbers[noteNumbers.indexIn(note)]; | |
var rate=1.0; | |
var rateLoaded=1.0; | |
var buf1mix=1.0; | |
var amp=1.0; | |
var file1,file2,fileLoaded; | |
var velIndex=0; | |
var velIndices; | |
var vels; | |
var dyns; | |
var noteNumbersLoadedDict=Dictionary.new(); | |
// first determine the rate to get the right note | |
while ({note<noteClosest},{ | |
note=note+12; | |
rate=rate*0.5; | |
}); | |
while ({note-noteClosest>11},{ | |
note=note-12; | |
rate=rate*2; | |
}); | |
rate=rate*Scale.chromatic.ratios[note-noteClosest]; | |
// determine the number of dynamics | |
dyns=noteDynamics.at(noteClosest); | |
if (dyns>1,{ | |
velIndices=Array.fill(dyns,{ arg i; | |
i*128/(dyns-1) | |
}); | |
velIndex=velIndices.indexOfGreaterThan(velocity)-1; | |
}); | |
// determine file 1 and 2 interpolation | |
file1=noteClosest.asInteger.asString++"."; | |
file2=noteClosest.asInteger.asString++"."; | |
if (dyns<2,{ | |
// simple playback using amp | |
amp=velocity/127.0; | |
file1=file1++"1.1."; | |
file2=file2++"1.1."; | |
// add round robin | |
file1=file1++(noteRoundRobins.at(noteClosest.asString++".1").rand+1).asString++".0.wav"; | |
file2=file2++(noteRoundRobins.at(noteClosest.asString++".1").rand+1).asString++".0.wav"; | |
},{ | |
var rr1,rr2; | |
amp=velocity/127.0/2+0.25; | |
// gather the velocity indices that are available | |
// TODO: make this specific to a single note? | |
vels=[velIndices[velIndex],velIndices[velIndex+1]]; | |
buf1mix=(1-((velocity-vels[0])/(vels[1]-vels[0]))); | |
// add dynamic | |
file1=file1++(velIndex+1).asInteger.asString++"."; | |
file2=file2++(velIndex+2).asInteger.asString++"."; | |
// add dynamic max | |
file1=file1++dyns.asString++"."; | |
file2=file2++dyns.asString++"."; | |
// add round robin | |
rr1=noteRoundRobins.at(noteClosest.asString++"."++(velIndex+1).asString); | |
if (rr1.isNil,{ | |
rr1=1; | |
}); | |
file1=file1++(rr1.rand+1).asString++".0.wav"; | |
rr2=noteRoundRobins.at(noteClosest.asString++"."++(velIndex+2).asString); | |
if (rr2.isNil,{ | |
rr2=1; | |
}); | |
file2=file2++(rr2.rand+1).asString++".0.wav"; | |
}); | |
[file1,file2,amp,rate].postln; | |
Buffer.read(server,PathName(folder+/+file1).fullPath,action:{ arg b1; | |
b1.postln; | |
Buffer.read(server,PathName(folder+/+file2).fullPath,action:{ arg b2; | |
b2.postln; | |
this.doPlay(id,noteOriginal,amp,b1,b2,buf1mix,rate); | |
}); | |
}); | |
} | |
noteOff { | |
arg id, note; | |
if (syns.at(id).notNil,{ | |
if (syns.at(id).at(note).notNil,{ | |
if (syns.at(id).at(note).isRunning,{ | |
syns.at(id).at(note).set(\gate,0); | |
}); | |
}); | |
}); | |
} | |
noteOn { | |
arg id, folder, note, velocity; | |
if (allNumbers.at(folder).isNil,{ | |
this.loadFolder(folder); | |
}); | |
this.playSample(id, folder, note, velocity); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
( | |
s.waitForBoot({ | |
~velocity=Bus.control(s,1); | |
{ | |
Out.kr(~velocity,SinOsc.kr(1/LFNoise2.kr(1/5).range(5,6)).range(1,90)); | |
}.play; | |
~octave=Bus.control(s,1); | |
{ | |
Out.kr(~octave, | |
LinLin.kr(SinOsc.kr(1/7,mul:1.5)+SinOsc.kr(1/1.1,mul:0.5),2.neg,2,2.neg,2).round*12); | |
}.play; | |
~fx={ | |
var snd, freq, dur; | |
snd = In.ar(0,2); | |
freq = LFNoise2.kr(1/3).range(0.5,10); | |
dur = LFNoise2.kr(1/3).range(0.5,4); | |
snd = [GrainIn.ar( | |
numChannels: 1, | |
trigger: Impulse.kr(freq+0.1), | |
dur: dur/(freq+0.1), | |
in: snd[0], | |
maxGrains: 64, | |
),GrainIn.ar( | |
numChannels: 1, | |
trigger: Impulse.kr(freq+0.2), | |
dur: dur/(freq+0.2), | |
in: snd[1], | |
maxGrains: 64, | |
)]; | |
snd = SelectX.ar(LFNoise2.kr(1/5).range(0.1,0.25),[snd, | |
Fverb.ar(snd[0],snd[1],50, | |
tail_density: LFNoise2.kr(1/3).range(50,90), | |
decay: LFNoise2.kr(1/3).range(50,90), | |
) | |
]); | |
snd = snd * EnvGen.ar(Env.adsr(10,1,1,1)); | |
ReplaceOut.ar(0,snd * Lag.kr(\db.kr(0),30).dbamp); | |
}.play; | |
i=InstrumentSample.new(Server.default); | |
Routine { | |
inf.do{ | |
[2,2.5,1,1.5,2,0.5,0.25,1,1].choose.wait; | |
i.noteOn(1,"/home/zns/Documents/dronecore/samples/claus_piano", | |
[60,59,60,59,60,57].choose+(~octave.getSynchronous), | |
~velocity.getSynchronous | |
); | |
[0,0,2,2.5,3,1,1.5,2,0.5,0.25,1,1].choose.wait; | |
i.noteOn(1,"/home/zns/Documents/dronecore/samples/claus_piano", | |
[64,64,64,62,65].choose+(~octave.getSynchronous), | |
~velocity.getSynchronous | |
); | |
[0,0,2,2.5,3,0.125,1,1.5,2,0.5,0.25,1,1].choose.wait; | |
i.noteOn(1,"/home/zns/Documents/dronecore/samples/claus_piano", | |
[67,67,67,67,69,69,69,71,71].choose+(~octave.getSynchronous), | |
~velocity.getSynchronous | |
); | |
}; | |
}.play; | |
}); | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment