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