aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Runge <dave@sleepmap.de>2020-12-30 01:14:51 +0100
committerDavid Runge <dave@sleepmap.de>2020-12-30 01:14:51 +0100
commit57050ba42967df9fa159dbb257f58c27216c8db3 (patch)
tree9610ab4cd2869ec664b5bfc9104a54e2f06c6998
parent8d943f2513085f540e3bcf8ac345ea8a391730cc (diff)
downloadzzz-57050ba42967df9fa159dbb257f58c27216c8db3.tar.gz
zzz-57050ba42967df9fa159dbb257f58c27216c8db3.tar.bz2
zzz-57050ba42967df9fa159dbb257f58c27216c8db3.tar.xz
zzz-57050ba42967df9fa159dbb257f58c27216c8db3.zip
Add classes for Error and Device
classes/ZZZError.sc: Add a simple Error class. classes/ZZZDevice.sc: Add a generic class to make the device-specific ZZZES3 class obsolete. This class utilizes all new and improved SynthDefs of ZZZ.
-rw-r--r--classes/ZZZDevice.sc334
-rw-r--r--classes/ZZZError.sc3
2 files changed, 337 insertions, 0 deletions
diff --git a/classes/ZZZDevice.sc b/classes/ZZZDevice.sc
new file mode 100644
index 0000000..b10a6b0
--- /dev/null
+++ b/classes/ZZZDevice.sc
@@ -0,0 +1,334 @@
+ZZZDevice : ZZZ{
+
+ classvar < clockTypes = #[\zeroFive, \minusFiveFive, \korgZeroFive, \korgMinusFiveFive];
+ classvar < playTypes = #[\beat, \bar];
+ var < outs,
+ < tempoBusses,
+ < clocks,
+ < deviceGroup,
+ < gateBusses,
+ < gates,
+ < tempos,
+ clocksTempoMap;
+
+ *new{
+ arg channels, server;
+ if(channels.isNil, {
+ ZZZError("ZZZDevice: Initialized without setting channels parameter!").throw;
+ });
+ if(server.isNil, {
+ ZZZError("ZZZDevice: Initialized without setting server parameter!").throw;
+ });
+ ^super.newCopyArgs(channels, server).init;
+ }
+
+ init{
+ ("Initializing ZZZDevice...").postln;
+ clocks = Dictionary();
+ gates = Dictionary();
+ gateBusses = Dictionary();
+ outs = Dictionary();
+ tempos = Dictionary();
+ tempoBusses = Dictionary();
+ clocksTempoMap = Dictionary();
+ (1..super.channels.size).do({|item, i|
+ outs.add(item -> super.channels[i]);
+ });
+ // add Group for all Synths used by ZZZDevice instance
+ super.server.doWhenBooted({deviceGroup = Group.new()});
+ }
+
+ outputOnHardware{ |output|
+ if(output.isNil || output.isInteger.not,{
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(output < 1 || output > outs.size,{
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1, <"++outs.size++").").throw;
+ });
+ ^outs.at(output);
+ }
+
+ addTempo{|slot, tempo|
+ if(slot.isNil || slot.isInteger.not, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(slot < 1, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(tempo.isNil || tempo.isFloat.not, {
+ ZZZError("ZZZDevice: The provided tempo is not valid (needs to be >= 0.0).").throw;
+ });
+ if(tempo < 0.0, {
+ ZZZError("ZZZDevice: The provided tempo is not valid (needs to be >= 0.0).").throw;
+ });
+
+ if(tempos.at(slot).isNil, {
+ ("Create new TempoBusClock in slot "++ slot++" with tempo "++tempo).postln;
+ tempoBusses.add(slot -> Bus.control());
+ tempoBusses.at(slot).setSynchronous(tempo);
+ tempos.add(slot -> TempoBusClock.new(control: tempoBusses.at(slot)));
+ },{
+ ZZZError("ZZZDevice: Cannot add tempo "++ tempo ++" in slot "++ slot ++". There is a TempoBusClock already.").throw;
+ });
+ }
+
+ removeTempo{|slot, playType = \beat, quant = 1|
+ var removeFunc;
+ if(slot.isNil || slot.isInteger.not, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(slot < 1, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+
+ clocksTempoMap.keysValuesDo({|key, value|
+ if(value == slot, {
+ this.removeClock(output: key, playType: playType, quant: quant);
+ });
+ });
+ removeFunc = {
+ tempos.at(slot).clear;
+ tempos.at(slot).stop;
+ tempos.removeAt(slot);
+ tempoBusses.at(slot).free;
+ tempoBusses.removeAt(slot);
+ };
+ if(playType == \beat, {
+ tempos.at(slot).play(removeFunc, quant: quant);
+ });
+ if(playType == \bar, {
+ tempos.at(slot).playNextBar(removeFunc);
+ });
+ }
+
+ setTempo{|slot, tempo|
+ if(slot.isNil || slot.isInteger.not || slot < 1, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(tempo.isNil || tempo.isFloat.not || tempo < 0.0, {
+ ZZZError("ZZZDevice: The provided tempo is not valid (needs to be >= 0.0).").throw;
+ });
+ if(tempos.at(slot).isNil, {
+ ZZZError("ZZZDevice: Cannot set tempo "++ tempo ++" at slot "++ slot ++". There is no TempoBusClock.").throw;
+ });
+
+ tempoBusses.at(slot).setSynchronous(tempo);
+ }
+
+ addClock{ |output, slot, type = \zeroFive, playType = \beat, quant = 1, replace = false|
+ var clockFunc, synthName, synthArgs;
+ if(slot.isNil || slot.isInteger.not || slot < 1, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(slot < 1, {
+ ZZZError("ZZZDevice: The provided slot number is not valid (needs to be >= 1).").throw;
+ });
+ if(tempos.at(slot).isNil, {
+ ZZZError("ZZZDevice: There is no tempo at slot "++slot).throw;
+ });
+ if(output.isNil || output.isInteger.not || output < 1, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(output < 1, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(clockTypes.includes(type).not, {
+ ZZZError("ZZZDevice: Unrecognized clock type "++ type ++". Only the following are understood: "++ clockTypes).throw;
+ });
+ if(playTypes.includes(playType).not, {
+ ZZZError("ZZZDevice: Unrecognized playType "++ type ++". Only the following are understood: "++ playTypes).throw;
+ });
+ if(clocks.at(output).notNil && replace.not, {
+ ZZZError("Cannot add clock on output "++ output ++". There is a "++clocks.at(output).defName++" playing and replacement was not requested.").throw;
+ });
+ if(clocks.at(output).isNil && replace, {
+ ZZZError("Cannot replace clock on output "++ output ++". There is no clock playing.").throw;
+ });
+ // add \ZZZClock Synth to add clocking for various standards
+ // the standard (derived from MIDI SYNC) uses 24 pulses per quarter note
+ if(type == \zeroFive, {
+ synthName = \ZZZClock;
+ synthArgs = [\out, this.outputOnHardware(output: output), \bus, tempoBusses.at(slot), \mul, 0.5];
+ });
+ // some devices react to the range of minus five to plus five
+ if(type == \minusFiveFive, {
+ synthName = \ZZZClock;
+ synthArgs = [\out, this.outputOnHardware(output: output), \bus, tempoBusses.at(slot), \add, -0.5];
+ });
+ // Korg uses 48 pulses per quarter note
+ if(type == \korgZeroFive, {
+ synthName = \ZZZClockKorg;
+ synthArgs = [\out, this.outputOnHardware(output: output), \bus, tempoBusses.at(slot), \mul, 0.5];
+ });
+ // some devices react to the range of minus five to plus five
+ if(type == \korgMinusFiveFive, {
+ synthName = \ZZZClockKorg;
+ synthArgs = [\out, this.outputOnHardware(output: output), \bus, tempoBusses.at(slot), \add, -0.5];
+ });
+
+ clockFunc = {
+ var synth;
+ if(replace, {
+ synth = Synth.replace(clocks.at(output), synthName, synthArgs, sameID: true).onFree({
+ clocks.removeAt(output);
+ clocksTempoMap.removeAt(output);
+ });
+ },{
+ synth = Synth(synthName, synthArgs, target: this.deviceGroup).onFree({
+ clocks.removeAt(output);
+ clocksTempoMap.removeAt(output);
+ });
+ });
+ clocks.add(output -> synth);
+ clocksTempoMap.add(output -> slot);
+ };
+ // add Synth on next beat
+ if(playType == \beat, {
+ tempos.at(slot).play(clockFunc, quant: quant);
+ });
+ // add Synth on next bar
+ if(playType == \bar, {
+ tempos.at(slot).playNextBar(clockFunc);
+ });
+ }
+
+ removeClock{ |output, playType = \beat, quant = 1|
+ var removeFunc;
+ if(output.isNil || output.isInteger.not || output < 1, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(clocks.at(output).isNil, {
+ ZZZError("ZZZDevice: There is no clock at output "++output++" to remove.").throw;
+ });
+
+ if(playType == \beat, {
+ tempos.at(clocksTempoMap.at(output)).play({clocks.at(output).free}, quant: quant);
+ });
+ if(playType == \bar, {
+ tempos.at(clocksTempoMap.at(output)).playNextBar({clocks.at(output).free});
+ });
+ }
+
+ setClockTempo{ |output, slot, playType = \beat, quant = 1, type = \zeroFive|
+ this.addClock(output: output, slot: slot, playType: playType, quant: quant, replace: true, type: type);
+ }
+
+ addGate{ |output, input = 0.9|
+ if(output.isNil || output.isInteger.not, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(output < 1, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(input.isNil || input.isFloat.not, {
+ ZZZError("ZZZDevice: The provided value for input is not valid (needs to be 0.0 < input <= 1.0).").throw;
+ });
+ if(input < 0.0 || input > 1.0, {
+ ZZZError("ZZZDevice: The provided value for input is not valid (needs to be 0.0 < input <= 1.0).").throw;
+ });
+ if(gates.at(output).notNil, {
+ ZZZError("ZZZDevice: Cannot add gate on output "++ output ++". There is a "++gates.at(output).defName++" already.").throw;
+ });
+
+ gateBusses.add(output -> Bus.control());
+ gateBusses.at(output).setSynchronous(input);
+ gates.add(
+ output -> Synth(\ZZZGate, [\out, this.outputOnHardware(output: output), \bus, gateBusses.at(output)]).onFree({
+ gateBusses.removeAt(output);
+ gates.removeAt(output);
+ })
+ );
+ }
+
+ removeGate{ |output|
+ if(output.isNil || output.isInteger.not, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(output < 1, {
+ ZZZError("ZZZDevice: The provided output number is not valid (needs to be >= 1).").throw;
+ });
+ if(gates.at(output).isNil, {
+ ZZZError("ZZZDevice: There is no gate at the provided output "++output).throw;
+ });
+
+ gates.at(output).free;
+ }
+
+ postAll{
+ this.postClocks;
+ this.postGates;
+ this.postOuts;
+ this.postTempos;
+ }
+
+ postClocks{
+ ("Clocks").postln;
+ ("------").postln;
+ ("output -> tempo slot (value)").postln;
+ clocks.keysValuesDo({|key, value|
+ if(value.isRunning, {
+ if(super.server.hasShmInterface,{
+ (key.asString++" -> "++clocksTempoMap.at(key)++" ("++tempoBusses.at(clocksTempoMap.at(key)).getSynchronous++")").postln;
+ },{
+ tempoBusses.at(clocksTempoMap.at(key)).get({ |values|
+ (key.asString++" -> "++clocksTempoMap.at(key)++" ("++values++")").postln;
+ });
+ });
+ },{
+ (key.asString++" -> "++clocksTempoMap.at(key)++" ("++Nil++")").postln;
+ });
+ });
+ ("------").postln;
+ }
+
+ postGates{
+ ("Gates").postln;
+ ("-----").postln;
+ ("output -> value").postln;
+ gates.keysValuesDo({|key, value|
+ if(value.isRunning, {
+ if(super.server.hasShmInterface,{
+ (key.asString++" -> "++gateBusses.at(key).getSynchronous).postln;
+ },{
+ gateBusses.at(key).get({ |values|
+ (key.asString++" -> "++values).postln;
+ });
+ });
+ },{
+ (key.asString++" -> "++Nil).postln;
+ });
+ });
+ ("-----").postln;
+ }
+
+ postOuts{
+ ("Outputs").postln;
+ ("-------").postln;
+ ("hardware channel -> server output bus channel").postln;
+ outs.keysValuesDo({|key, value|
+ (key.asString++" -> "++value.asString).postln;
+ });
+ ("-------").postln;
+ }
+
+ postTempos{
+ ("Tempos").postln;
+ ("------").postln;
+ ("slot -> speed").postln;
+ tempos.keysValuesDo({|key, value|
+ if(value.isRunning, {
+ if(super.server.hasShmInterface,{
+ (key.asString++" -> "++tempoBusses.at(key).getSynchronous).postln;
+ },{
+ tempoBusses.at(key).get({ |values|
+ (key.asString++" -> "++values).postln;
+ });
+ });
+ },{
+ (key.asString++" -> "++Nil).postln;
+ });
+ });
+ ("------").postln;
+ }
+
+}
diff --git a/classes/ZZZError.sc b/classes/ZZZError.sc
new file mode 100644
index 0000000..670619f
--- /dev/null
+++ b/classes/ZZZError.sc
@@ -0,0 +1,3 @@
+ZZZError : Error{
+
+}