at.atmosynth.module
Schema Diff
+33 -11
Compatibility Analysis
Breaking Changes Detected
8 breaking changes, 7 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#breakpoint.value", 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" }
Non-Breaking Changes (7)
- 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" }
- 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.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:body.noteOutputs" }AddedVertex { vertex_id: "at.atmosynth.module:body.noteOutputs:items" }AddedVertex { vertex_id: "at.atmosynth.module:body.noteSource" }
Constraint Changes
- 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#parameter.default", sort: "maxLength", value: "200" }
- ConstraintAdded ConstraintAdded { vertex_id: "at.atmosynth.module#range.max", 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: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.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
"id": "at.atmosynth.module",
3
3
"defs": {
4
4
"main": {
5
5
"key": "tid",
6
6
"type": "record",
7
7
"record": {
8
8
"type": "object",
9
9
"required": [
10
10
"descriptionVersion",
11
11
"moduleId",
12
12
"name",
13
13
"description",
14
14
"audioInputs",
15
15
"audioOutputs",
16
16
"midiInputs",
17
17
"nodes",
18
18
"connections",
19
19
"createdAt"
20
20
],
21
21
"properties": {
22
22
"name": {
23
23
"type": "string",
24
24
"maxLength": 200,
25
25
"minLength": 1
26
26
},
27
27
"nodes": {
28
28
"type": "array",
29
29
"items": {
30
30
"ref": "#node",
31
31
"type": "ref"
32
32
}
33
33
},
34
34
"moduleId": {
35
35
"type": "string",
36
36
"maxLength": 128,
37
37
"description": "Stable identity shared by every published version of this module."
38
38
},
39
39
"createdAt": {
40
40
"type": "string",
41
41
"format": "datetime"
42
42
},
43
43
"automation": {
44
44
"type": "array",
45
45
"items": {
46
46
"ref": "#automation",
47
47
"type": "ref"
48
48
},
49
49
"description": "Scheduled AudioParam envelopes. Web Audio has no envelope node, so these are their own structure."
50
50
},
51
51
"forkedFrom": {
52
52
"ref": "#lineage",
53
53
"type": "ref"
54
54
},
55
55
"midiInputs": {
56
56
"type": "array",
57
57
"items": {
58
58
"ref": "#port",
59
59
"type": "ref"
60
-
}
60
+
},
61
+
"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."
62
+
},
63
+
"noteSource": {
64
+
"type": "string",
65
+
"maxLength": 64,
66
+
"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. A reader that does not know the named behaviour cannot run the module, and says so rather than guessing.",
67
+
"knownValues": [
68
+
"keyboard",
69
+
"sequencer"
70
+
]
61
71
},
62
72
"parameters": {
63
73
"type": "array",
64
74
"items": {
65
75
"ref": "#parameter",
66
76
"type": "ref"
67
77
}
68
78
},
69
79
"versionKey": {
70
80
"type": "string",
71
81
"maxLength": 128,
72
-
"description": "This record's own key within the series. Informational; the record key is authoritative."
82
+
"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."
73
83
},
74
84
"audioInputs": {
75
85
"type": "array",
76
86
"items": {
77
87
"ref": "#port",
78
88
"type": "ref"
79
89
},
80
90
"description": "Zero or more individually identified audio inputs."
81
91
},
82
92
"connections": {
83
93
"type": "array",
84
94
"items": {
85
95
"ref": "#connection",
86
96
"type": "ref"
87
97
}
88
98
},
89
99
"description": {
90
100
"type": "string",
91
101
"maxLength": 3000
92
102
},
103
+
"noteOutputs": {
104
+
"type": "array",
105
+
"items": {
106
+
"ref": "#port",
107
+
"type": "ref"
108
+
},
109
+
"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."
110
+
},
93
111
"sampleSlots": {
94
112
"type": "array",
95
113
"items": {
96
114
"ref": "#sampleSlot",
97
115
"type": "ref"
98
116
}
99
117
},
100
118
"audioOutputs": {
101
119
"type": "array",
102
120
"items": {
103
121
"ref": "#port",
104
122
"type": "ref"
105
123
}
106
124
},
107
125
"descriptionVersion": {
108
126
"type": "integer",
109
127
"minimum": 1,
110
128
"description": "Version of the module description this record follows. A reader accepts any version at or below its own."
111
129
}
112
130
}
113
131
},
114
132
"description": "A module, held in its author's own repository."
115
133
},
116
134
"node": {
117
135
"type": "object",
118
136
"required": [
119
137
"id",
120
138
"kind"
121
139
],
122
140
"properties": {
123
141
"id": {
124
142
"type": "string",
125
143
"maxLength": 64,
126
144
"minLength": 1
127
145
},
128
146
"kind": {
129
147
"type": "string",
130
148
"maxLength": 64,
131
149
"minLength": 1
132
150
},
133
151
"options": {
134
152
"type": "unknown",
135
-
"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."
153
+
"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."
136
154
}
137
155
},
138
156
"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."
139
157
},
140
158
"port": {
141
159
"type": "object",
142
160
"required": [
143
161
"id"
144
162
],
145
163
"properties": {
146
164
"id": {
147
165
"type": "string",
148
166
"maxLength": 64,
149
167
"minLength": 1
150
168
},
151
169
"label": {
152
170
"type": "string",
153
171
"maxLength": 200
154
172
}
155
173
},
156
174
"description": "One individually identified audio or MIDI boundary of the module."
157
175
},
158
176
"range": {
159
177
"type": "object",
160
178
"required": [
161
179
"min",
162
180
"max"
163
181
],
164
182
"properties": {
165
183
"max": {
166
-
"type": "unknown",
167
-
"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."
184
+
"type": "string",
185
+
"maxLength": 200,
186
+
"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."
168
187
},
169
188
"min": {
170
-
"type": "unknown",
171
-
"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."
189
+
"type": "string",
190
+
"maxLength": 200,
191
+
"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."
172
192
}
173
193
}
174
194
},
175
195
"source": {
176
196
"type": "object",
177
197
"required": [
178
198
"node"
179
199
],
180
200
"properties": {
181
201
"node": {
182
202
"type": "string",
183
203
"maxLength": 64,
184
204
"minLength": 1
185
205
},
186
206
"output": {
187
207
"type": "integer",
188
208
"minimum": 0
189
209
}
190
210
}
191
211
},
192
212
"target": {
193
213
"type": "object",
194
214
"required": [
195
215
"node"
196
216
],
197
217
"properties": {
198
218
"node": {
199
219
"type": "string",
200
220
"maxLength": 64,
201
221
"minLength": 1
202
222
},
203
223
"input": {
204
224
"type": "integer",
205
225
"minimum": 0
206
226
},
207
227
"param": {
208
228
"type": "string",
209
229
"maxLength": 64
210
230
}
211
231
},
212
232
"description": "Exactly one of `input` or `param` is present. `param` is modulation: a node output reaching a named AudioParam."
213
233
},
214
234
"lineage": {
215
235
"type": "object",
216
236
"required": [
217
237
"uri",
218
238
"authorDid"
219
239
],
220
240
"properties": {
221
241
"uri": {
222
242
"type": "string",
223
243
"format": "at-uri"
224
244
},
225
245
"moduleId": {
226
246
"type": "string",
227
247
"maxLength": 128
228
248
},
229
249
"authorDid": {
230
250
"type": "string",
231
251
"format": "did"
232
252
}
233
253
},
234
254
"description": "The module this one was forked from, and its author."
235
255
},
236
256
"parameter": {
237
257
"type": "object",
238
258
"required": [
239
259
"id",
240
260
"label",
241
261
"targets"
242
262
],
243
263
"properties": {
244
264
"id": {
245
265
"type": "string",
246
266
"maxLength": 64,
247
267
"minLength": 1
248
268
},
249
269
"label": {
250
270
"type": "string",
251
271
"maxLength": 200,
252
272
"minLength": 1
253
273
},
254
274
"range": {
255
275
"ref": "#range",
256
276
"type": "ref"
257
277
},
258
278
"values": {
259
279
"type": "array",
260
280
"items": {
261
281
"type": "string",
262
282
"maxLength": 200
263
283
},
264
284
"description": "A closed value set, where the parameter is not numeric."
265
285
},
266
286
"default": {
267
-
"type": "unknown",
268
-
"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."
287
+
"type": "string",
288
+
"maxLength": 200,
289
+
"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."
269
290
},
270
291
"targets": {
271
292
"type": "array",
272
293
"items": {
273
294
"ref": "#parameterTarget",
274
295
"type": "ref"
275
296
},
276
297
"minLength": 1
277
298
}
278
299
},
279
300
"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."
280
301
},
281
302
"sampleRef": {
282
303
"type": "object",
283
304
"required": [
284
305
"blob",
285
306
"ownerDid"
286
307
],
287
308
"properties": {
288
309
"blob": {
289
310
"type": "blob",
290
311
"accept": [
291
312
"audio/wav"
292
313
],
293
314
"maxSize": 2097152
294
315
},
295
316
"ownerDid": {
296
317
"type": "string",
297
318
"format": "did"
298
319
}
299
320
},
300
321
"description": "A sample blob and the account that holds it."
301
322
},
302
323
"automation": {
303
324
"type": "object",
304
325
"required": [
305
326
"id",
306
327
"target",
307
328
"breakpoints"
308
329
],
309
330
"properties": {
310
331
"id": {
311
332
"type": "string",
312
333
"maxLength": 64,
313
334
"minLength": 1
314
335
},
315
336
"label": {
316
337
"type": "string",
317
338
"maxLength": 200
318
339
},
319
340
"target": {
320
341
"ref": "#paramTarget",
321
342
"type": "ref"
322
343
},
323
344
"sustainAt": {
324
345
"type": "integer",
325
346
"minimum": 0,
326
347
"description": "Index into breakpoints where the value holds while a note is held. Absent means a one-shot."
327
348
},
328
349
"breakpoints": {
329
350
"type": "array",
330
351
"items": {
331
352
"ref": "#breakpoint",
332
353
"type": "ref"
333
354
},
334
355
"minLength": 1
335
356
}
336
357
},
337
358
"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."
338
359
},
339
360
"breakpoint": {
340
361
"type": "object",
341
362
"required": [
342
363
"time",
343
364
"value"
344
365
],
345
366
"properties": {
346
367
"time": {
347
368
"type": "integer",
348
369
"minimum": 0,
349
370
"description": "Milliseconds from the trigger."
350
371
},
351
372
"curve": {
352
373
"type": "string",
353
374
"description": "How the value travels from the previous breakpoint.",
354
375
"knownValues": [
355
376
"step",
356
377
"linear",
357
378
"exponential"
358
379
]
359
380
},
360
381
"value": {
361
-
"type": "unknown",
362
-
"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."
382
+
"type": "string",
383
+
"maxLength": 200,
384
+
"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."
363
385
}
364
386
}
365
387
},
366
388
"connection": {
367
389
"type": "object",
368
390
"required": [
369
391
"from",
370
392
"to"
371
393
],
372
394
"properties": {
373
395
"to": {
374
396
"ref": "#target",
375
397
"type": "ref"
376
398
},
377
399
"from": {
378
400
"ref": "#source",
379
401
"type": "ref"
380
402
}
381
403
},
382
404
"description": "An audio connection from a node output to either an audio input or a named AudioParam."
383
405
},
384
406
"sampleSlot": {
385
407
"type": "object",
386
408
"required": [
387
409
"id",
388
410
"node",
389
411
"property"
390
412
],
391
413
"properties": {
392
414
"id": {
393
415
"type": "string",
394
416
"maxLength": 64,
395
417
"minLength": 1
396
418
},
397
419
"node": {
398
420
"type": "string",
399
421
"maxLength": 64,
400
422
"minLength": 1
401
423
},
402
424
"label": {
403
425
"type": "string",
404
426
"maxLength": 200
405
427
},
406
428
"default": {
407
429
"ref": "#sampleRef",
408
430
"type": "ref"
409
431
},
410
432
"property": {
411
433
"type": "string",
412
434
"knownValues": [
413
435
"buffer"
414
436
]
415
437
}
416
438
},
417
439
"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."
418
440
},
419
441
"paramTarget": {
420
442
"type": "object",
421
443
"required": [
422
444
"node",
423
445
"param"
424
446
],
425
447
"properties": {
426
448
"node": {
427
449
"type": "string",
428
450
"maxLength": 64,
429
451
"minLength": 1
430
452
},
431
453
"param": {
432
454
"type": "string",
433
455
"maxLength": 64,
434
456
"minLength": 1
435
457
}
436
458
}
437
459
},
438
460
"parameterTarget": {
439
461
"type": "object",
440
462
"properties": {
441
463
"node": {
442
464
"type": "string",
443
465
"maxLength": 64
444
466
},
445
467
"field": {
446
468
"type": "string",
447
469
"knownValues": [
448
470
"time",
449
471
"value"
450
472
]
451
473
},
452
474
"param": {
453
475
"type": "string",
454
476
"maxLength": 64
455
477
},
456
478
"option": {
457
479
"type": "string",
458
480
"maxLength": 64
459
481
},
460
482
"automation": {
461
483
"type": "string",
462
484
"maxLength": 64
463
485
},
464
486
"breakpoint": {
465
487
"type": "integer",
466
488
"minimum": 0
467
489
}
468
490
},
469
491
"description": "One of: {node, param}, {node, option}, or {automation, breakpoint, field}."
470
492
}
471
493
},
472
494
"$type": "com.atproto.lexicon.schema",
473
495
"lexicon": 1,
474
496
"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."
475
497
}