/
protocols.clj
50 lines (41 loc) · 2.79 KB
/
protocols.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
(ns overtone.protocols)
; This is a holding ground for working on protocols...
; One goal of defining protocols is to clearly delineate various groups of functionality
; so we can improve the composability of the Overtone building blocks. Our current synths
; and instruments grew out of a desire to make things easy to use, but we need to refactor them
; split-up unneccessarily bound aspects of functionality, and then create new "easy" APIs using
; these refactored elements.
; Synths:
; * synth definition
; * filling of default parameter settings from atoms
; * mixed argument handling (in-order and/or keyword)
; * implements trigger, ctl and kill for single synth instances
; * places synth nodes in a default synth group
; Instruments:
; * allocates an output bus for all instances of the synth
; * appends the out ugen to automatically use the correct bus
; * allocates groups:
; - inst container group
; - instance group
; - fx group
; - mixer group
; * implements ctl and kill for all instances
; This bundling of functionality has led to two issues that demonstrate some of the problems:
; * Many synth designs are very general purpose, and with different settings they can sound like completely different instruments. Currently the only way to use the same instrument multiple times in Overtone with different parameter settings is to copy/paste the definst and give it a new name. Instead we need a way to build a "voice" given a synth design and a set of parameters.
; * Audio samples and the memory buffers they get loaded into can be single or multi-channel, but a synth design must have a fixed number of channels. We need to define a protocol for triggering synths so we can implement higher level "meta-synths" that can actually use multiple underlying synths depending on the number of channels of the input buffer. Many other kinds of meta-synths could exist that either generate synth definitions on the fly, or choose the most appropriate for the task.
; To begin lets try to isolate this functionality into simpler units:
; * synth definition
; * mixed argument handling
; * stored default parameters
; * trigger, control and kill
; * bus allocation and automatic append of out ugen
; * automatic instance placement
; * group allocation and fx/mixer setup
(defprotocol ISynthBuffer
(info [this] "Returns a map containing the properties of this buffer (e.g. size, n-channels...)")
(sample-array [this] [this start len] "Returns a float array with values read from this buffer.")
(write! [this data] [this start-idx data] "Write float values into the buffer.")
(set-value! [this idx value] "Set a single value in the buffer.")
(get-value [this idx] "Get a single value in the buffer."))
(defprotocol ISaveable
(save [this] [this path] [this path options] "Save to a default location"))