at.atmosynth.module

atmosynth.at

Schema Diff

+14 -4

From

CID
bafyreibyikm6cn4...
Indexed At
2026-09-24 12:51 UTC
View this version

To

CID
bafyreigkd32vga2...
Indexed At
2026-10-06 13:10 UTC
View this version

Compatibility Analysis

Breaking Changes Detected

2 breaking changes, 2 non-breaking changes.

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

Compare Other Versions

Lexicon Garden

@