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