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