-
Notifications
You must be signed in to change notification settings - Fork 0
/
Chain.ts
212 lines (179 loc) · 10.1 KB
/
Chain.ts
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import { DisconnectedNode, Node, NodeConnectFunc, FBNode, FBTargetNode, INode, OP, IParamAny, IParam, IParam2, IParam3, IParam4, ParamType, PulseAction, Paramable } from './Types'
import { Guid } from 'guid-typescript'
import { none, fromNullable } from 'fp-ts/lib/Option';
const assert = {
ok: (res, str) => {if(!res){throw new Error(str)}},
equal: (a, b, str = 'something went wrong') => {if(a !== b){ throw new Error(str); }}
}
// Ops
// const op = <T extends OP>(type: OP) => (optype: string, params: { [name: string] : IParamAny}) : OpTree<T> => {
// if (type === "DAT"){}
// return new OpTree<T>({family: type, type: optype + type, params: params, connections: []}, [])
// }
// New chain mechanism
export const constructNodeFromDefault = (n: any): INode =>
Object.assign({unique: none, text: none, connections: [], params: {}, actions: []}, n)
const op = <T extends OP>(type: T) =>
(ty: string, params: { [name: string] : Paramable} = {}, actions: PulseAction[] = [], unique: string = null, text: string = null) =>
new DisconnectedNode<T>(
(inputs: Node<T>[]) =>
new Node({
type: ty + type,
family:type,
actions,
params,
connections: inputs.map(n => n.node),
unique: fromNullable(unique),
text: fromNullable(text)
})
)
export const top = op<"TOP">("TOP")
export const tope = (optype: string) => op<"TOP">("TOP")(optype, {})
export const dat = op<"DAT">("DAT")
export const date = (optype: string) => op<"DAT">("DAT")(optype, {})
export const chop = op<"CHOP">("CHOP")
export const chope = (optype: string) => op<"CHOP">("CHOP")(optype, {})
export const sop = op<"SOP">("SOP")
export const sope = (optype: string) => op<"SOP">("SOP")(optype, {})
export const mat = op<"MAT">("MAT")
export const mate = (optype: string) => op<"MAT">("MAT")(optype, {})
export const comp = op<"COMP">("COMP")
export const compe = (optype: string) => op<"COMP">("COMP")(optype, {})
// export const replacetop = new ReplaceTree<"TOP">(tope("null").value, [])
// export const replacechop = new ReplaceTree<"CHOP">(chope("null").value, [])
// export const replacedat = new ReplaceTree<"DAT">(date("null").value, [])
// export const replacesop = new ReplaceTree<"SOP">(sope("null").value, [])
// export const replacemat = new ReplaceTree<"MAT">(mate("null").value, [])
// export const cc = <T extends OP>(handlef: (self: OpTree<T>, n: OpTree<T>) => OpTree<T>, root: OpTree<T>) => {
// new CustomConnectOpTree<T>(handlef, root.value, root.forest as OpTree<T>[]);
// }
export const cc = <T extends OP>(func: NodeConnectFunc<T>) => {
return new DisconnectedNode(func);
}
export const insertconn = <T extends OP>(dn: DisconnectedNode<T>, before: Node<T>[], after: Node<T>[]) => {
return cc<T>((inputs) => dn.run(before.concat(inputs, after)))
}
export const node = <T extends OP, R extends INode>(n: R) => {
return new Node<T>(n)
}
export const feedbacktop = (): DisconnectedNode<"TOP"> => {
return cc((inputs) => node(constructNodeFromDefault({ family: "TOP", type: "feedbackTOP", special: "FB", id: Guid.create(), unique: none, actions: [], connections: inputs.map(i => i.out()), params: {}})))
}
export const feedbacktarget = (fbg: Guid, optype: string, params: {[name: string] : IParamAny}) : DisconnectedNode<"TOP"> => {
return cc((inputs) => node(constructNodeFromDefault({special: "FBT", selects: [fbg], unique: none, actions: [], connections: inputs.map(i => i.out()), params: params, type: optype + "TOP", family: "TOP"})))
}
export const feedbackChain = (middle: DisconnectedNode<"TOP">) : DisconnectedNode<"TOP"> => {
return cc<"TOP">((inputs) => {
let fbt = feedbacktop()
let baseop = (id: Guid) => cc<"TOP">((inputs) => {
let basemiddle = middle.run(inputs).out()
return node(constructNodeFromDefault({special: "FBT", selects: [id], unique: none, actions: [], connections: basemiddle.connections, params: middle.run(inputs).out().params, type: middle.out().type, family: "TOP"}))
})
return fbt.connect(cc((inputs) => baseop((inputs[0].node as FBNode).id).run(inputs))).run(inputs)
})
}
export const fp = (v: number) : IParam<"float"> => {
assert.ok(typeof v === 'number', "float param only takes numbers");
return { type: "float", value0: [String(v)] }
}
export const ip = (v: number) : IParam<"number"> => {
assert.ok(Number.isSafeInteger(v), "integer param only takes integers");
return { type: "number", value0: [String(v)] }
}
export const sp = (v: string) : IParam<"string"> => {
assert.equal(typeof v, "string")
return ({ type: "string", value0: ['"' + v + '"'] })
}
export const tp = (v: boolean) : IParam<"toggle"> => {
assert.ok(typeof v === 'boolean', "boolean param only takes booleans");
return { type: "toggle", value0: [String(v ? 1 : 0)] }
}
export const mp = (v: number) : IParam<"menu"> => {
assert.ok(Number.isSafeInteger(v), "menu param only takes integers");
return { type: "menu", value0: [String(v)] }
}
export const xyp = (v0: IParam<"float" | "number">, v1: IParam<"float" | "number">) : IParam2<"xy"> => {
assert.ok((v0.type == "float" || v0.type === "number") && (v1.type == "float" || v1.type === "number"), "xy requires float params")
return ({ type: "xy", value0: v0.value0, value1: v1.value0 })
}
export const xyzp = (v0: IParam<"float" | "number">, v1: IParam<"float" | "number">, v2: IParam<"float" | "number">) : IParam3<"xyz"> => {
assert.ok(v0.type == "float" || v0.type == "number", "xyz requires float params")
assert.ok(v1.type == "float" || v1.type == "number", "xyz requires float params")
assert.ok(v2.type == "float" || v2.type == "number", "xyz requires float params")
return ({ type: "xyz", value0: v0.value0, value1: v1.value0, value2: v2.value0 })
}
export const rgbp = (v0: IParam<"float" | "number">, v1: IParam<"float" | "number">, v2: IParam<"float" | "number">) : IParam3<"rgb"> => {
assert.ok(v0.type == "float" || v0.type == "number", "rgb requires float params")
assert.ok(v1.type == "float" || v1.type == "number", "rgb requires float params")
assert.ok(v2.type == "float" || v2.type == "number", "rgb requires float params")
return ({ type: "rgb", value0: v0.value0, value1: v1.value0, value2: v2.value0 })
}
export const xyzwp = (v0: IParam<"float" | "number">, v1: IParam<"float" | "number">, v2: IParam<"float" | "number">, v3: IParam<"float" | "number">) : IParam4<"xyzw"> => {
assert.ok(v0.type == "float" || v0.type == "number", "xyzw requires float params")
assert.ok(v1.type == "float" || v1.type == "number", "xyzw requires float params")
assert.ok(v2.type == "float" || v2.type == "number", "xyzw requires float params")
assert.ok(v3.type == "float" || v3.type == "number", "xyzw requires float params")
return ({ type: "xyzw", value0: v0.value0, value1: v1.value0, value2: v2.value0, value3: v3.value0 })
}
export const whp = (v0: IParam<"number">, v1: IParam<"number">) : IParam2<"wh"> => {
assert.ok(v0.type == "number" && v1.type == "number", "wh requires number params")
return ({ type: "wh", value0: v0.value0, value1: v1.value0 })
}
const cast = <T extends ParamType>(ty: T, op: string) => (v: IParam<ParamType>): IParam<T> => ({
type: ty,
value0: ([op, "("] as (string | INode)[]).concat(v.value0, [")"])
})
export const casti = cast("number", "int")
export const castt = cast("toggle", "bool")
export const castf = cast("float", "float")
export const casts = cast("string", "str")
export const castp = cast("pulse", "int")
const opp = <T extends OP>(type: T) =>
(n: (Node<T> | DisconnectedNode<T>)[] | (Node<T> | DisconnectedNode<T>)) => {
assert.equal(type, (Array.isArray(n) ? n[0] : n).out().family, "param and op family must match")
return { type: type, value0: (['\"'] as (string | INode)[]).concat(n instanceof Array ? n.map(n => n.runT().out()) : [n.out()], ['\"']) }
}
export const topp = opp("TOP")
export const datp = opp("DAT")
export const chopp = opp("CHOP")
export const sopp = opp("SOP")
export const matp = opp("MAT")
export const compp = opp("COMP")
export const chan = (i: IParam<"number" | "string">, v: Node<"CHOP"> | DisconnectedNode<"CHOP">): IParam<"float"> => {
let out = v.out()
assert.equal("CHOP", out.family, "param and op family must match")
assert.ok("number" === i.type || "string" === i.type, "chan needs integer or string param index")
return ({ type: "float", value0: ['op(\"', v.out(), '\")['].concat(i.value0, [']'])})
}
export const chan0 = (chop) => chan(ip(0), chop)
export const mathopp = <T extends ("number" | "float")>(t: string) => (a: IParam<T>, b: IParam<T>): IParam<T> => {
assert.ok("float" === a.type || "number" === b.type, t + "is a float or integer op")
assert.equal(a.type, b.type, t + " ops match")
return { type: a.type, value0: (["( "] as Array<string | INode>).concat(a.value0, [ " " + t + " " ], b.value0, [" )"])}
}
export const multp = mathopp("*")
export const addp = mathopp("+")
export const subp = mathopp("-")
export const divp = mathopp("/")
export const modp = mathopp("%")
export const powp = mathopp("**")
export const funcp = (b: string) => (a: IParam<"float" | "number">) => {
return { type: "float", value0: ([b, "("] as Array<string | INode>).concat(a.value0, [")"])} as IParam<"float">;
}
export const funcp2 = (f: string) => (a: IParam<"float" | "number">, b: IParam<"float" | "number">) => {
return { type: "float", value0: ([f, "("] as Array<string | INode>).concat(a.value0, [", "], b.value0, [")"])} as IParam<"float">;
}
export const absp = funcp("abs")
export const clampp = funcp2("clamp")
export const floorp = funcp("math.floor")
export const sinp = funcp("math.sin")
export const cosp = funcp("math.cos")
export const tanp = funcp("math.tan")
export const x4p = (v0: IParam<"float">) : IParam4<"xyzw"> => {
assert.ok(v0.type == "float", "xyzw requires float params")
let undef = { type: "float", value0: [] }
return ({ type: "xyzw", value0: v0.value0, value1: [], value2: [], value3: [] })
}
export const seconds = { type: "float", value0: ["absTime.seconds"]} as IParam<"float">
export const frames = { type: "float", value0: ["absTime.frame"]} as IParam<"float">
export const sampleIndex = { type: "number", value0: ["sampleIndex"]} as IParam<"number">