at.atmosynth.module
Schema Diff
+55 -8
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#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#breakpoint.value", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.max", 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#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#parameter.default", 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.",
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": {
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.",
234
267
"type": "unknown"
235
268
}
236
269
},
237
270
"required": [
238
271
"id",
239
272
"kind"
240
273
],
241
274
"type": "object"
242
275
},
243
276
"paramTarget": {
244
277
"properties": {
245
278
"node": {
246
279
"maxLength": 64,
247
280
"minLength": 1,
248
281
"type": "string"
249
282
},
250
283
"param": {
251
284
"maxLength": 64,
252
285
"minLength": 1,
253
286
"type": "string"
254
287
}
255
288
},
256
289
"required": [
257
290
"node",
258
291
"param"
259
292
],
260
293
"type": "object"
261
294
},
262
295
"parameter": {
263
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.",
264
297
"properties": {
265
298
"default": {
266
-
"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"
267
302
},
268
303
"id": {
269
304
"maxLength": 64,
270
305
"minLength": 1,
271
306
"type": "string"
272
307
},
273
308
"label": {
274
309
"maxLength": 200,
275
310
"minLength": 1,
276
311
"type": "string"
277
312
},
278
313
"range": {
279
314
"ref": "#range",
280
315
"type": "ref"
281
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
+
},
282
325
"targets": {
283
326
"items": {
284
327
"ref": "#parameterTarget",
285
328
"type": "ref"
286
329
},
287
330
"minLength": 1,
288
331
"type": "array"
289
332
},
290
333
"values": {
291
-
"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.",
292
335
"items": {
293
336
"maxLength": 200,
294
337
"type": "string"
295
338
},
296
339
"type": "array"
297
340
}
298
341
},
299
342
"required": [
300
343
"id",
301
344
"label",
302
345
"targets"
303
346
],
304
347
"type": "object"
305
348
},
306
349
"parameterTarget": {
307
350
"description": "One of: {node, param}, {node, option}, or {automation, breakpoint, field}.",
308
351
"properties": {
309
352
"automation": {
310
353
"maxLength": 64,
311
354
"type": "string"
312
355
},
313
356
"breakpoint": {
314
357
"minimum": 0,
315
358
"type": "integer"
316
359
},
317
360
"field": {
318
361
"knownValues": [
319
362
"time",
320
363
"value"
321
364
],
322
365
"type": "string"
323
366
},
324
367
"node": {
325
368
"maxLength": 64,
326
369
"type": "string"
327
370
},
328
371
"option": {
329
372
"maxLength": 64,
330
373
"type": "string"
331
374
},
332
375
"param": {
333
376
"maxLength": 64,
334
377
"type": "string"
335
378
}
336
379
},
337
380
"type": "object"
338
381
},
339
382
"port": {
340
383
"description": "One individually identified audio or MIDI boundary of the module.",
341
384
"properties": {
342
385
"id": {
343
386
"maxLength": 64,
344
387
"minLength": 1,
345
388
"type": "string"
346
389
},
347
390
"label": {
348
391
"maxLength": 200,
349
392
"type": "string"
350
393
}
351
394
},
352
395
"required": [
353
396
"id"
354
397
],
355
398
"type": "object"
356
399
},
357
400
"range": {
358
401
"properties": {
359
402
"max": {
360
-
"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"
361
406
},
362
407
"min": {
363
-
"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"
364
411
}
365
412
},
366
413
"required": [
367
414
"min",
368
415
"max"
369
416
],
370
417
"type": "object"
371
418
},
372
419
"sampleRef": {
373
420
"description": "A sample blob and the account that holds it.",
374
421
"properties": {
375
422
"blob": {
376
423
"accept": [
377
424
"audio/wav"
378
425
],
379
-
"maxSize": 2097152,
426
+
"maxSize": 10485760,
380
427
"type": "blob"
381
428
},
382
429
"ownerDid": {
383
430
"format": "did",
384
431
"type": "string"
385
432
}
386
433
},
387
434
"required": [
388
435
"blob",
389
436
"ownerDid"
390
437
],
391
438
"type": "object"
392
439
},
393
440
"sampleSlot": {
394
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.",
395
442
"properties": {
396
443
"default": {
397
444
"ref": "#sampleRef",
398
445
"type": "ref"
399
446
},
400
447
"id": {
401
448
"maxLength": 64,
402
449
"minLength": 1,
403
450
"type": "string"
404
451
},
405
452
"label": {
406
453
"maxLength": 200,
407
454
"type": "string"
408
455
},
409
456
"node": {
410
457
"maxLength": 64,
411
458
"minLength": 1,
412
459
"type": "string"
413
460
},
414
461
"property": {
415
462
"knownValues": [
416
463
"buffer"
417
464
],
418
465
"type": "string"
419
466
}
420
467
},
421
468
"required": [
422
469
"id",
423
470
"node",
424
471
"property"
425
472
],
426
473
"type": "object"
427
474
},
428
475
"source": {
429
476
"properties": {
430
477
"node": {
431
478
"maxLength": 64,
432
479
"minLength": 1,
433
480
"type": "string"
434
481
},
435
482
"output": {
436
483
"minimum": 0,
437
484
"type": "integer"
438
485
}
439
486
},
440
487
"required": [
441
488
"node"
442
489
],
443
490
"type": "object"
444
491
},
445
492
"target": {
446
493
"description": "Exactly one of `input` or `param` is present. `param` is modulation: a node output reaching a named AudioParam.",
447
494
"properties": {
448
495
"input": {
449
496
"minimum": 0,
450
497
"type": "integer"
451
498
},
452
499
"node": {
453
500
"maxLength": 64,
454
501
"minLength": 1,
455
502
"type": "string"
456
503
},
457
504
"param": {
458
505
"maxLength": 64,
459
506
"type": "string"
460
507
}
461
508
},
462
509
"required": [
463
510
"node"
464
511
],
465
512
"type": "object"
466
513
}
467
514
},
468
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.",
469
516
"id": "at.atmosynth.module",
470
517
"lexicon": 1
471
518
}