
( // run once to convert and resample wavetable files
var paths, file, data, n, newData, outFile;
paths = "/home/lcoogan/snd/wtables/AKWF/AKWF_0002/*.wav".pathMatch;
Routine({
	paths.do { |it i|
		// 'protect' guarantees the file objects will be closed in case of error
		protect {
			// Read original size of data
			file = SoundFile.openRead(paths[i]);
			data = Signal.newClear(file.numFrames);
			file.readData(data);
			0.1.wait;
			// Convert to n = some power of 2 samples.
			// n = data.size.nextPowerOfTwo;
			n = 4096;
			newData = data.resamp1(n);
			0.1.wait;
			// Convert the resampled signal into a Wavetable.
			// resamp1 outputs an Array, so we have to reconvert to Signal
			newData = newData.as(Signal).asWavetable;
			0.1.wait;

			// save to disk.
			outFile = SoundFile(paths[i] ++ "_4096.wtable")
			.headerFormat_("WAV")
			.sampleFormat_("float")
			.numChannels_(1)
			.sampleRate_(44100);
			if(outFile.openWrite.notNil) {
				outFile.writeData(newData);
				0.1.wait;
			} {
				"Couldn't write output file".warn;
			};
		} {
			file.close;
			if(outFile.notNil) { outFile.close };
		};

	}
}).play

)


(	// to be put to Platform.userConfigDir +/+ "startup.scd"

~serverBootFunc = { |server|

	var wtsize, wtpaths, wtbuffers;

	"-----------wavetables begin-----------".postln;


	wtsize = 4096;
wtpaths = "/home/lcoogan/snd/wtables/AKWF/AKWF_0002/*.wav_4096.wtable".pathMatch;
	[wtpaths].postln;
	wtbuffers = Buffer.allocConsecutive(wtpaths.size, s, wtsize * 2, 1, );
	wtpaths.do { |it i| wtbuffers[i].read(wtpaths[i])};


	~wtbufnums = List[];
	~wavetables = ();


	wtpaths.do { |it i|
		var name = wtbuffers[i].path.basename.findRegexp(".*\.wav")[0][1].splitext[0];
		var buffer = wtbuffers[i].bufnum;
		~wavetables[name.asSymbol] = buffer;
		~wtbufnums.add(buffer);
	};


	"-----------wavetables end-----------".postln;
};

ServerBoot.add(~serverBootFunc, \default);
)



(

Spec.add(\bufn, ControlSpec(~wtbufnums.minItem, ~wtbufnums.maxItem, 'linear', 1, 0, ""));

Spec.add(\wtmodbufn, \bufn);
Spec.add(\wtmodfreq,\widefreq);
Spec.add(\wtmodamp, [0,5]);

Spec.add(\fmod, \bipolar);
Spec.add(\fmodbufn, \bufn);
Spec.add(\fltRange, \freq);
Spec.add(\res, \unipolar);
Spec.add(\driveDB, [-40,40,\lin,0,0.01,"dB"]);
)

Ndef(\wtable_vosc_dual_t).edit

~wtbufnums.postln;


(
Ndef(\wtable_vosc_dual_t, {
	var env, freq;
	var wtbufnumRange = [ ~wtbufnums.minItem, ~wtbufnums.maxItem  ];
	var sig;
	// var trg = Dust.kr(2);
	var trg = Impulse.kr(0.5);
	// trg = trg.lag(TRand.kr(0.0,0.2,trg));


	env = EnvGen.ar(Env.perc(
		TRand.kr(0.2,1,trg),
		TRand.kr(0.2,2,trg)
	), gate:trg).lag(0.1);



	// env = XFade2.ar(env,env * LFDNoise3.ar(env * 20 + 1).range(0,1), env*2-1);

	freq = TExpRand.kr(80,500,trg);

	sig = VOsc.ar(
		(
			 VOsc.ar(\wtmodbufn.kr( rrand( wtbufnumRange[0],wtbufnumRange[1] ) ).lag(0.3), \wtmodfreq.kr(2), Rand(0,2pi), \wtmodamp.kr(1))
			+
			env.pow(1.4)
			+
			\bufn.ar( rrand( wtbufnumRange[0],wtbufnumRange[1] ) )
		) .lag(1.8) .mod( wtbufnumRange[1] - wtbufnumRange[0] ) + wtbufnumRange[0],
		freq
	)  * env;



	sig!2 * 0.2

}).play


)

(// low pass filtering the env
{
	[
		EnvGen.kr(Env.perc(0.02, 0.02)),
		EnvGen.kr(Env.perc(0.02, 0.02)).lag(0.1)
	]
}.plot(0.1)
)

({ // modulo plot
var a = Line.ar(8,150);
[
	a,
	a.mod(107-8) +8
]
}.plot(1))





Ndef(\wtable_vosc_dual_t_0).edit.nameView

(
Ndef(\wtable_vosc_dual_t_0, {| vel=1|
	var env, freq;
	var wtbufnumRange = [ ~wtbufnums.minItem, ~wtbufnums.maxItem  ];
	var sig;
	var fenv;
	var driveDB = \driveDB.kr(0);
	var direct = \direct.kr(0.5);
	// var trg = \trg.kr(1);
	// var trg = Dust.kr(2);
	var trg = Impulse.kr(1);


	env = EnvGen.ar(
		Env.adsr(
			TExpRand.kr(0.001, 0.1, trg),
			TExpRand.kr(0.001, 0.1, trg),
			TExpRand.kr(0.1, 0.6, trg),
			TExpRand.kr(1.5,4,trg),
			curve: TRand.kr(-5.0,4,trg)
		),
		gate:trg,
		doneAction:0
	).lag(0.1) * vel;


	env = XFade2.ar(env,LFDNoise3.ar(env * 20 + 1).range(0,1), env*2-1);

	// env = env * WhiteNoise.ar(MouseX.kr(0,1)!2).range(0,1.0);

	// fenv = env * LFNoise0.kr(TRand.kr(1,21, trg)).range(0.5,1.4).lag(TRand.kr(0.0001,0.1, trg));
	fenv = env * VOsc.ar(
		\fmodbufn.kr( rrand( wtbufnumRange[0],wtbufnumRange[1] ) ).lag(0.4),
		\fmodFreq.kr(11)
	).range(0.5,1.4)
	.lag(TRand.kr(0.0001,0.01, trg));


	// freq = \freq.kr(111).lag(0.1);
	// freq = LFNoise0.kr(1).exprange(80,1000).lag(0.1);
	freq = TExpRand.kr(80,1000,trg);

	sig = VOsc.ar(
		(
			VOsc.ar(\wtmodbufn.kr( rrand( wtbufnumRange[0],wtbufnumRange[1] ) ).lag(0.3), \wtmodfreq.kr(2), Rand(0,2pi), \wtmodamp.kr(1))
			+
			( env * [  Rand(0.5,1.5),  Rand(0.5,1.5) ])
			// ( env.pow(1.4) * [ LFNoise1.kr(3).range(1.5,9), LFNoise1.kr(3).range(1.5,9)] + 0.1)
			+
			\bufn.ar( rrand( wtbufnumRange[0],wtbufnumRange[1] ) )
		).lag(0.1).mod( wtbufnumRange[1] - wtbufnumRange[0] ) + wtbufnumRange[0],
		freq
	)  * env;

	sig = MoogVCF.ar(
		sig * driveDB.dbamp,
		XFade2.ar( env.pow(1.4), fenv.pow(1.4), \fmod.kr(0)) * \fltRange.kr(10000) + 50 ,
		\res.kr(0)
	);

	sig = sig * driveDB.neg.dbamp * 0.4; // compensate drive


	sig * direct;

}).play
)


(
SynthDef(\wtable_vosc_dual_t, {| vel=0.8|
	var env, freq;
	var wtbufnumRange = [ ~wtbufnums.minItem, ~wtbufnums.maxItem  ];
	var sig;
	var fenv;
	var driveDB = \driveDB.kr(0);
	var direct = \direct.kr(0.5).lag(0.2);
	// var trg = \trg.kr(1);
	var trg = Dust.kr(1);
	// var trg = Impulse.kr(2);


	env = EnvGen.ar(
		Env.adsr(
			TExpRand.kr(0.001, 0.1, trg),
			TExpRand.kr(0.001, 0.1, trg),
			TExpRand.kr(0.1, 0.6, trg),
			TExpRand.kr(0.5,4,trg),
			curve: TRand.kr(-5.0,4,trg)),
		gate:trg,
		doneAction:0
	).lag(0.1) * vel;


	env = XFade2.ar(env,env * LFDNoise3.ar(env * 20 + 1).range(0,1), env*2-1);

	// env = env * WhiteNoise.ar(MouseX.kr(0,1)!2).range(0,1.0);

	// fenv = env * LFNoise0.kr(TRand.kr(1,21, trg)).range(0.5,1.4).lag(TRand.kr(0.0001,0.1, trg));
	fenv = env * VOsc.ar(
		\fmodbufn.kr( rrand( wtbufnumRange[0],wtbufnumRange[1] ) ).lag(0.4),
		// TRand.kr(1,21, trg)
		\fmodFreq.kr(11)
	).range(0.5,1.4)
	.lag(TRand.kr(0.0001,0.01, trg));


	freq = \freq.kr(111).lag(0.1);
	// freq = LFNoise0.kr(1).exprange(80,1000).lag(0.1);
	// freq = TExpRand.kr(80,1000,trg);

	sig = VOsc.ar(
		(
			VOsc.ar(\wtmodbufn.kr( rrand( wtbufnumRange[0],wtbufnumRange[1] ) ).lag(0.3), \wtmodfreq.kr(2), Rand(0,2pi), \wtmodamp.kr(1))
			+
			// ( env * [  Rand(1.5,2),  Rand(1.5,2) ])
			( env.pow(1.4) * [ LFNoise1.kr(3).range(1.5,3), LFNoise1.kr(3).range(1.5,3)])
			+
			\bufn.ar( rrand( wtbufnumRange[0],wtbufnumRange[1] ) )
		).lag(0.1).mod( wtbufnumRange[1] - wtbufnumRange[0] ) + wtbufnumRange[0],
		freq
	)  * env;

	sig = MoogVCF.ar(
		sig * driveDB.dbamp,
		XFade2.ar( env.pow(1.4), fenv.pow(1.4), \fmod.kr(0)) * \fltRange.kr(10000) + 50 ,
		\res.kr(0)
	);

	sig = sig * driveDB.neg.dbamp * 0.4; // compensate drive


	Out.ar(\outBus.kr, sig * direct);
	Out.ar(\effBus.kr, sig * (1-direct))

	// }).play
}).add
)





~reverbBus = Bus.audio(s,2);





(
{
	var a;

	Ndef(\verb, {var a, n;
		a = In.ar(~reverbBus, 2);
		n = 8;
		n.collect { |i|
			a = AllpassC.ar(
				a,
				delaytime: LFNoise1.kr(0.03!2).range(0.01 , 0.02 * (i+1)),
				// decaytime: n-i
				decaytime: (i+1)
				// decaytime: (n / 2 -i).abs + 0.1
			).tanh
		}.mean;
		a
	}).play;


	a = [
		Synth(\wtable_vosc_dual_t, [\outBus, 0, \effBus, ~reverbBus, \bufn, ~wtbufnums.choose]),
		Synth(\wtable_vosc_dual_t, [\outBus, 0, \effBus, ~reverbBus, \bufn, ~wtbufnums.choose]),
		Synth(\wtable_vosc_dual_t, [\outBus, 0, \effBus, ~reverbBus, \bufn, ~wtbufnums.choose]),
		// Synth(\wtable_vosc_dual_t, [\outBus, 0, \effBus, ~reverbBus, \bufn, ~wtbufnums.choose]),
	];



	loop{
		a.choose.set(
			\freq,  ([0, 1, 2, 4, 5, 8, 11].choose + 60).midicps * 2.pow((-2..2).choose),
			\wtmodfreq, exprand(1, 20),
			// \wtmodamp, exprand(0.1,4).postln,
			\fmod, rrand(-1.0,1),
			// \fmodbufn, ~wtbufnums.choose,
			\fmodFreq, exprand(2,20),
			// \fltRange, rrand(1000,10000),
			\vel, rrand(0.1,0.9),
			\direct, rrand(0.1,0.6),
		);
		2.pow((-2..1).choose).wait;
	}

}.fork
)