at.atmosynth.module
Schema Diff
+55 -12
Compatibility Analysis
Breaking Changes Detected
8 breaking changes, 11 non-breaking changes.
Breaking Changes (8)
- KindChanged KindChanged { vertex_id: "at.atmosynth.module#breakpoint.value", old_kind: "unknown", new_kind: "string" }
- KindChanged KindChanged { vertex_id: "at.atmosynth.module#parameter.default", old_kind: "unknown", new_kind: "string" }
- KindChanged KindChanged { vertex_id: "at.atmosynth.module#range.max", old_kind: "unknown", new_kind: "string" }
- KindChanged KindChanged { vertex_id: "at.atmosynth.module#range.min", old_kind: "unknown", new_kind: "string" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.min", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#parameter.default", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.max", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#breakpoint.value", sort: "maxLength", value: "200" }
Non-Breaking Changes (11)
- AddedVertex AddedVertex { vertex_id: "at.atmosynth.module#parameter.scale" }
- AddedVertex AddedVertex { vertex_id: "at.atmosynth.module:body.noteOutputs" }
- AddedVertex AddedVertex { vertex_id: "at.atmosynth.module:body.noteOutputs:items" }
- AddedVertex AddedVertex { vertex_id: "at.atmosynth.module:body.noteSource" }
- AddedVertex AddedVertex { vertex_id: "at.atmosynth.module:body.patternSource" }
- AddedEdge AddedEdge { src: "at.atmosynth.module#parameter", tgt: "at.atmosynth.module#parameter.scale", kind: "prop", name: Some("scale") }
- AddedEdge AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.noteOutputs", kind: "prop", name: Some("noteOutputs") }
- AddedEdge AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.noteSource", kind: "prop", name: Some("noteSource") }
- AddedEdge AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.patternSource", kind: "prop", name: Some("patternSource") }
- AddedEdge AddedEdge { src: "at.atmosynth.module:body.noteOutputs", tgt: "at.atmosynth.module:body.noteOutputs:items", kind: "items", name: None }
- AddedEdge AddedEdge { src: "at.atmosynth.module:body.noteOutputs:items", tgt: "at.atmosynth.module#port", kind: "ref", name: None }
Migration Guidance
Added Elements
AddedVertex { vertex_id: "at.atmosynth.module#parameter.scale" }AddedVertex { vertex_id: "at.atmosynth.module:body.noteOutputs" }AddedVertex { vertex_id: "at.atmosynth.module:body.noteOutputs:items" }AddedVertex { vertex_id: "at.atmosynth.module:body.noteSource" }AddedVertex { vertex_id: "at.atmosynth.module:body.patternSource" }
Constraint Changes
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#parameter.default", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.min", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.max", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#breakpoint.value", sort: "maxLength", value: "200" }
Additional Notes
- Breaking: KindChanged { vertex_id: "at.atmosynth.module#breakpoint.value", old_kind: "unknown", new_kind: "string" }
- Breaking: KindChanged { vertex_id: "at.atmosynth.module#parameter.default", old_kind: "unknown", new_kind: "string" }
- Breaking: KindChanged { vertex_id: "at.atmosynth.module#range.max", old_kind: "unknown", new_kind: "string" }
- Breaking: KindChanged { vertex_id: "at.atmosynth.module#range.min", old_kind: "unknown", new_kind: "string" }
- Non-breaking: AddedEdge { src: "at.atmosynth.module#parameter", tgt: "at.atmosynth.module#parameter.scale", kind: "prop", name: Some("scale") }
- Non-breaking: AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.noteOutputs", kind: "prop", name: Some("noteOutputs") }
- Non-breaking: AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.noteSource", kind: "prop", name: Some("noteSource") }
- Non-breaking: AddedEdge { src: "at.atmosynth.module:body", tgt: "at.atmosynth.module:body.patternSource", kind: "prop", name: Some("patternSource") }
- Non-breaking: AddedEdge { src: "at.atmosynth.module:body.noteOutputs", tgt: "at.atmosynth.module:body.noteOutputs:items", kind: "items", name: None }
- Non-breaking: AddedEdge { src: "at.atmosynth.module:body.noteOutputs:items", tgt: "at.atmosynth.module#port", kind: "ref", name: None }
1
1
{
2
2
"$type": "com.atproto.lexicon.schema",
3
3
"defs": {
4
4
"automation": {
5
5
"description": "A breakpoint envelope scheduled onto an AudioParam. Breakpoints up to and including sustainAt are scheduled on note-on; those after it on note-off.",
6
6
"properties": {
7
7
"breakpoints": {
8
8
"items": {
9
9
"ref": "#breakpoint",
10
10
"type": "ref"
11
11
},
12
12
"minLength": 1,
13
13
"type": "array"
14
14
},
15
15
"id": {
16
16
"maxLength": 64,
17
17
"minLength": 1,
18
18
"type": "string"
19
19
},
20
20
"label": {
21
21
"maxLength": 200,
22
22
"type": "string"
23
23
},
24
24
"sustainAt": {
25
25
"description": "Index into breakpoints where the value holds while a note is held. Absent means a one-shot.",
26
26
"minimum": 0,
27
27
"type": "integer"
28
28
},
29
29
"target": {
30
30
"ref": "#paramTarget",
31
31
"type": "ref"
32
32
}
33
33
},
34
34
"required": [
35
35
"id",
36
36
"target",
37
37
"breakpoints"
38
38
],
39
39
"type": "object"
40
40
},
41
41
"breakpoint": {
42
42
"properties": {
43
43
"curve": {
44
44
"description": "How the value travels from the previous breakpoint.",
45
45
"knownValues": [
46
46
"step",
47
47
"linear",
48
48
"exponential"
49
49
],
50
50
"type": "string"
51
51
},
52
52
"time": {
53
53
"description": "Milliseconds from the trigger.",
54
54
"minimum": 0,
55
55
"type": "integer"
56
56
},
57
57
"value": {
58
-
"description": "The param's value at this instant. A number that is not a whole number is carried as its decimal string — \"0.5\", not 0.5 — because the ATproto data model has no floating-point type and a PDS refuses one. A whole number is an ordinary integer, and a reader turns such a string back into a number.",
59
-
"type": "unknown"
58
+
"description": "The param's value at this instant, as its decimal form — \"0.25\", \"1\" — because the ATproto data model has no floating-point type and a PDS refuses one. An automation is numeric by definition, so a reader turns it back into a number without asking anything else.",
59
+
"maxLength": 200,
60
+
"type": "string"
60
61
}
61
62
},
62
63
"required": [
63
64
"time",
64
65
"value"
65
66
],
66
67
"type": "object"
67
68
},
68
69
"connection": {
69
70
"description": "An audio connection from a node output to either an audio input or a named AudioParam.",
70
71
"properties": {
71
72
"from": {
72
73
"ref": "#source",
73
74
"type": "ref"
74
75
},
75
76
"to": {
76
77
"ref": "#target",
77
78
"type": "ref"
78
79
}
79
80
},
80
81
"required": [
81
82
"from",
82
83
"to"
83
84
],
84
85
"type": "object"
85
86
},
86
87
"lineage": {
87
88
"description": "The module this one was forked from, and its author.",
88
89
"properties": {
89
90
"authorDid": {
90
91
"format": "did",
91
92
"type": "string"
92
93
},
93
94
"moduleId": {
94
95
"maxLength": 128,
95
96
"type": "string"
96
97
},
97
98
"uri": {
98
99
"format": "at-uri",
99
100
"type": "string"
100
101
}
101
102
},
102
103
"required": [
103
104
"uri",
104
105
"authorDid"
105
106
],
106
107
"type": "object"
107
108
},
108
109
"main": {
109
110
"description": "A module, held in its author's own repository.",
110
111
"key": "tid",
111
112
"record": {
112
113
"properties": {
113
114
"audioInputs": {
114
115
"description": "Zero or more individually identified audio inputs.",
115
116
"items": {
116
117
"ref": "#port",
117
118
"type": "ref"
118
119
},
119
120
"type": "array"
120
121
},
121
122
"audioOutputs": {
122
123
"items": {
123
124
"ref": "#port",
124
125
"type": "ref"
125
126
},
126
127
"type": "array"
127
128
},
128
129
"automation": {
129
130
"description": "Scheduled AudioParam envelopes. Web Audio has no envelope node, so these are their own structure.",
130
131
"items": {
131
132
"ref": "#automation",
132
133
"type": "ref"
133
134
},
134
135
"type": "array"
135
136
},
136
137
"connections": {
137
138
"items": {
138
139
"ref": "#connection",
139
140
"type": "ref"
140
141
},
141
142
"type": "array"
142
143
},
143
144
"createdAt": {
144
145
"format": "datetime",
145
146
"type": "string"
146
147
},
147
148
"description": {
148
149
"maxLength": 3000,
149
150
"type": "string"
150
151
},
151
152
"descriptionVersion": {
152
153
"description": "Version of the module description this record follows. A reader accepts any version at or below its own.",
153
154
"minimum": 1,
154
155
"type": "integer"
155
156
},
156
157
"forkedFrom": {
157
158
"ref": "#lineage",
158
159
"type": "ref"
159
160
},
160
161
"midiInputs": {
162
+
"description": "Zero or more note inputs. A note input carries note events — what is played, and when — from any note source: a sequencer's note output, or the player, which is the on-screen keys, the computer keyboard and every MIDI device at once. \"MIDI\" is the historical name; nothing arriving here need have come from MIDI.",
161
163
"items": {
162
164
"ref": "#port",
163
165
"type": "ref"
164
166
},
165
167
"type": "array"
166
168
},
167
169
"moduleId": {
168
170
"description": "Stable identity shared by every published version of this module.",
169
171
"maxLength": 128,
170
172
"type": "string"
171
173
},
172
174
"name": {
173
175
"maxLength": 200,
174
176
"minLength": 1,
175
177
"type": "string"
176
178
},
177
179
"nodes": {
178
180
"items": {
179
181
"ref": "#node",
180
182
"type": "ref"
181
183
},
182
184
"type": "array"
183
185
},
186
+
"noteOutputs": {
187
+
"description": "Zero or more note outputs. A note output carries note events — what is played, and when — rather than a signal, so it is wired to another instance's note input (`midiInputs`) rather than to an audio input. A module that declares one is a source of what is played; a module that declares none is what plays it.",
188
+
"items": {
189
+
"ref": "#port",
190
+
"type": "ref"
191
+
},
192
+
"type": "array"
193
+
},
194
+
"noteSource": {
195
+
"description": "What this module emits notes by, where it is not made of Web Audio nodes at all. A note source has no `nodes` and no `connections`: it produces note events, and the behaviour that produces them is named here rather than described, because there is no vocabulary of nodes for a thing that makes no sound. `range` emits none of its own: it passes on the notes wired into its input that fall inside the range its instance names (`noteRange` on the patch's instance), each still the note of whatever played it. `transpose` and `assign` emit none of their own either: they pass on every note wired into their input at another pitch — moved by the semitones the instance names (`transpose`), or at the one note it names (`assignedNote`) — each still the note of whatever played it, and starting and stopping when it did. `oneshot` emits none of its own either: it passes on every note wired into its input lasting as many milliseconds as the instance names (`noteLength`), however long whatever played it held it — each still the note of whatever played it, at its own pitch, and starting when it did. A reader that does not know the named behaviour cannot run the module, and says so rather than guessing.",
196
+
"knownValues": [
197
+
"keyboard",
198
+
"sequencer",
199
+
"range",
200
+
"transpose",
201
+
"assign",
202
+
"oneshot"
203
+
],
204
+
"maxLength": 64,
205
+
"type": "string"
206
+
},
184
207
"parameters": {
185
208
"items": {
186
209
"ref": "#parameter",
187
210
"type": "ref"
188
211
},
189
212
"type": "array"
190
213
},
214
+
"patternSource": {
215
+
"description": "What this module chooses a sequencer's loops by, where it is not made of Web Audio nodes at all. A pattern source emits neither sound nor notes: it is wired to a sequencer's pattern input and decides which of that sequencer's loops is played, and when. Like a note source it has no `nodes` and no `connections`, and its behaviour is named here rather than described. A module is a note source or a pattern source, never both. A reader that does not know the named behaviour cannot run the module, and says so rather than guessing.",
216
+
"knownValues": [
217
+
"arranger",
218
+
"scenes"
219
+
],
220
+
"maxLength": 64,
221
+
"type": "string"
222
+
},
191
223
"sampleSlots": {
192
224
"items": {
193
225
"ref": "#sampleSlot",
194
226
"type": "ref"
195
227
},
196
228
"type": "array"
197
229
},
198
230
"versionKey": {
199
-
"description": "This record's own key within the series. Informational; the record key is authoritative.",
231
+
"description": "The record key this version is published under, repeated in the record so a reader holding only the record knows which version it is. A patch's `moduleRef.versionKey` is this value, and it is the record key a reader fetches: a record whose `versionKey` differs from its own key is pinned by the key and misdescribed by this field.",
200
232
"maxLength": 128,
201
233
"type": "string"
202
234
}
203
235
},
204
236
"required": [
205
237
"descriptionVersion",
206
238
"moduleId",
207
239
"name",
208
240
"description",
209
241
"audioInputs",
210
242
"audioOutputs",
211
243
"midiInputs",
212
244
"nodes",
213
245
"connections",
214
246
"createdAt"
215
247
],
216
248
"type": "object"
217
249
},
218
250
"type": "record"
219
251
},
220
252
"node": {
221
253
"description": "One Web Audio node. `kind` is drawn from a closed vocabulary; `options` are its construction-time settings, which are not AudioParams and cannot be modulated.",
222
254
"properties": {
223
255
"id": {
224
256
"maxLength": 64,
225
257
"minLength": 1,
226
258
"type": "string"
227
259
},
228
260
"kind": {
229
261
"maxLength": 64,
230
262
"minLength": 1,
231
263
"type": "string"
232
264
},
233
265
"options": {
234
-
"description": "The node's settings, as its kind defines them. A number that is not a whole number is carried as its decimal string — \"0.5\", not 0.5 — because the ATproto data model has no floating-point type and a PDS refuses one. A whole number is an ordinary integer, and a reader turns such a string back into a number.",
266
+
"description": "The node's settings, as its kind defines them. This is an object — which is the whole of what `unknown` means here — so the data model applies inside it: a whole number is an ordinary integer, and a number that is not a whole number is carried as its decimal string, \"0.5\" rather than 0.5, because the ATproto data model has no floating-point type and a PDS refuses one. That is the one difference from the fields this description types as strings, which have nowhere to put an integer.",
235
267
"type": "unknown"
236
268
}
237
269
},
238
270
"required": [
239
271
"id",
240
272
"kind"
241
273
],
242
274
"type": "object"
243
275
},
244
276
"paramTarget": {
245
277
"properties": {
246
278
"node": {
247
279
"maxLength": 64,
248
280
"minLength": 1,
249
281
"type": "string"
250
282
},
251
283
"param": {
252
284
"maxLength": 64,
253
285
"minLength": 1,
254
286
"type": "string"
255
287
}
256
288
},
257
289
"required": [
258
290
"node",
259
291
"param"
260
292
],
261
293
"type": "object"
262
294
},
263
295
"parameter": {
264
296
"description": "A parameter the module exposes for a patch to set. Each target reaches an AudioParam, a construction option, or one field of an automation breakpoint.",
265
297
"properties": {
266
298
"default": {
267
-
"description": "The value used where a patch sets none. A number that is not a whole number is carried as its decimal string — \"0.5\", not 0.5 — because the ATproto data model has no floating-point type and a PDS refuses one. A whole number is an ordinary integer, and a reader turns such a string back into a number. Where this parameter declares a closed value set, it is one of those strings.",
268
-
"type": "unknown"
299
+
"description": "The value used where a patch sets none, always as text. A number is its decimal form — \"0.5\", and \"2\" for a whole one — because the ATproto data model has no floating-point type and a string is the only type that carries both a number and a word. Where this parameter declares a closed value set, it is one of those strings instead, and a label that looks like a number stays the label it is.",
300
+
"maxLength": 200,
301
+
"type": "string"
269
302
},
270
303
"id": {
271
304
"maxLength": 64,
272
305
"minLength": 1,
273
306
"type": "string"
274
307
},
275
308
"label": {
276
309
"maxLength": 200,
277
310
"minLength": 1,
278
311
"type": "string"
279
312
},
280
313
"range": {
281
314
"ref": "#range",
282
315
"type": "ref"
283
316
},
317
+
"scale": {
318
+
"description": "How a slider or a MIDI control moves through the range. linear moves by equal differences; log moves by equal ratios, which is how a frequency is heard, so the middle of a 20 to 20000 sweep is about 632 rather than about 10000. log needs a range above zero at both ends. Absent is linear. A parameter with a closed value set has no scale.",
319
+
"knownValues": [
320
+
"linear",
321
+
"log"
322
+
],
323
+
"type": "string"
324
+
},
284
325
"targets": {
285
326
"items": {
286
327
"ref": "#parameterTarget",
287
328
"type": "ref"
288
329
},
289
330
"minLength": 1,
290
331
"type": "array"
291
332
},
292
333
"values": {
293
-
"description": "A closed value set, where the parameter is not numeric.",
334
+
"description": "A closed value set, where the parameter is not numeric. A construction option the parameter targets is given the chosen value itself; an AudioParam it targets is given the chosen value's position in this set, counting from zero, which is how a worklet offers a choice its own code interprets.",
294
335
"items": {
295
336
"maxLength": 200,
296
337
"type": "string"
297
338
},
298
339
"type": "array"
299
340
}
300
341
},
301
342
"required": [
302
343
"id",
303
344
"label",
304
345
"targets"
305
346
],
306
347
"type": "object"
307
348
},
308
349
"parameterTarget": {
309
350
"description": "One of: {node, param}, {node, option}, or {automation, breakpoint, field}.",
310
351
"properties": {
311
352
"automation": {
312
353
"maxLength": 64,
313
354
"type": "string"
314
355
},
315
356
"breakpoint": {
316
357
"minimum": 0,
317
358
"type": "integer"
318
359
},
319
360
"field": {
320
361
"knownValues": [
321
362
"time",
322
363
"value"
323
364
],
324
365
"type": "string"
325
366
},
326
367
"node": {
327
368
"maxLength": 64,
328
369
"type": "string"
329
370
},
330
371
"option": {
331
372
"maxLength": 64,
332
373
"type": "string"
333
374
},
334
375
"param": {
335
376
"maxLength": 64,
336
377
"type": "string"
337
378
}
338
379
},
339
380
"type": "object"
340
381
},
341
382
"port": {
342
383
"description": "One individually identified audio or MIDI boundary of the module.",
343
384
"properties": {
344
385
"id": {
345
386
"maxLength": 64,
346
387
"minLength": 1,
347
388
"type": "string"
348
389
},
349
390
"label": {
350
391
"maxLength": 200,
351
392
"type": "string"
352
393
}
353
394
},
354
395
"required": [
355
396
"id"
356
397
],
357
398
"type": "object"
358
399
},
359
400
"range": {
360
401
"properties": {
361
402
"max": {
362
-
"description": "The high bound. A number that is not a whole number is carried as its decimal string — \"0.5\", not 0.5 — because the ATproto data model has no floating-point type and a PDS refuses one. A whole number is an ordinary integer, and a reader turns such a string back into a number.",
363
-
"type": "unknown"
403
+
"description": "The high bound, as its decimal form — \"20000\", \"0.5\" — because the ATproto data model has no floating-point type and a PDS refuses one. A range is numeric by definition, so a reader turns it back into a number without asking anything else.",
404
+
"maxLength": 200,
405
+
"type": "string"
364
406
},
365
407
"min": {
366
-
"description": "The low bound. A number that is not a whole number is carried as its decimal string — \"0.5\", not 0.5 — because the ATproto data model has no floating-point type and a PDS refuses one. A whole number is an ordinary integer, and a reader turns such a string back into a number.",
367
-
"type": "unknown"
408
+
"description": "The low bound, as its decimal form — \"0.0001\", \"-1\" — because the ATproto data model has no floating-point type and a PDS refuses one. A range is numeric by definition, so a reader turns it back into a number without asking anything else.",
409
+
"maxLength": 200,
410
+
"type": "string"
368
411
}
369
412
},
370
413
"required": [
371
414
"min",
372
415
"max"
373
416
],
374
417
"type": "object"
375
418
},
376
419
"sampleRef": {
377
420
"description": "A sample blob and the account that holds it.",
378
421
"properties": {
379
422
"blob": {
380
423
"accept": [
381
424
"audio/wav"
382
425
],
383
-
"maxSize": 2097152,
426
+
"maxSize": 10485760,
384
427
"type": "blob"
385
428
},
386
429
"ownerDid": {
387
430
"format": "did",
388
431
"type": "string"
389
432
}
390
433
},
391
434
"required": [
392
435
"blob",
393
436
"ownerDid"
394
437
],
395
438
"type": "object"
396
439
},
397
440
"sampleSlot": {
398
441
"description": "A named slot a patch instance may fill with its own sample. `node` names a node in this graph and `property` the thing the sample feeds.",
399
442
"properties": {
400
443
"default": {
401
444
"ref": "#sampleRef",
402
445
"type": "ref"
403
446
},
404
447
"id": {
405
448
"maxLength": 64,
406
449
"minLength": 1,
407
450
"type": "string"
408
451
},
409
452
"label": {
410
453
"maxLength": 200,
411
454
"type": "string"
412
455
},
413
456
"node": {
414
457
"maxLength": 64,
415
458
"minLength": 1,
416
459
"type": "string"
417
460
},
418
461
"property": {
419
462
"knownValues": [
420
463
"buffer"
421
464
],
422
465
"type": "string"
423
466
}
424
467
},
425
468
"required": [
426
469
"id",
427
470
"node",
428
471
"property"
429
472
],
430
473
"type": "object"
431
474
},
432
475
"source": {
433
476
"properties": {
434
477
"node": {
435
478
"maxLength": 64,
436
479
"minLength": 1,
437
480
"type": "string"
438
481
},
439
482
"output": {
440
483
"minimum": 0,
441
484
"type": "integer"
442
485
}
443
486
},
444
487
"required": [
445
488
"node"
446
489
],
447
490
"type": "object"
448
491
},
449
492
"target": {
450
493
"description": "Exactly one of `input` or `param` is present. `param` is modulation: a node output reaching a named AudioParam.",
451
494
"properties": {
452
495
"input": {
453
496
"minimum": 0,
454
497
"type": "integer"
455
498
},
456
499
"node": {
457
500
"maxLength": 64,
458
501
"minLength": 1,
459
502
"type": "string"
460
503
},
461
504
"param": {
462
505
"maxLength": 64,
463
506
"type": "string"
464
507
}
465
508
},
466
509
"required": [
467
510
"node"
468
511
],
469
512
"type": "object"
470
513
}
471
514
},
472
515
"description": "A reusable synth module: Web Audio nodes wired together, with declared audio and MIDI boundaries, exposed parameters, automation and sample slots. Each published version is its own record; records sharing a moduleId form a series.",
473
516
"id": "at.atmosynth.module",
474
517
"lexicon": 1
475
518
}