From
bafyreigksk5z2wbuuta2mt7lmzkh3rgftqnlp43b7uny2ehahtctiokh5q
indexed 2026-11-04 10:46 UTC
View this version
To
bafyreierchpdr6pqzg5akbfgoblmddig3zhzywm7hphdjol365p6p4wply
indexed 2026-11-09 08:20 UTC
View this version
Compatibility
backward compatible No changes detected.
Changes
11
{22
"$type": "com.atproto.lexicon.schema",33
"defs": {44
"automation": {55
"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.",66
"properties": {77
"breakpoints": {88
"items": {99
"ref": "#breakpoint",1010
"type": "ref"1111
},1212
"minLength": 1,1313
"type": "array"1414
},1515
"id": {1616
"maxLength": 64,1717
"minLength": 1,1818
"type": "string"1919
},2020
"label": {2121
"maxLength": 200,2222
"type": "string"2323
},2424
"sustainAt": {2525
"description": "Index into breakpoints where the value holds while a note is held. Absent means a one-shot.",2626
"minimum": 0,2727
"type": "integer"2828
},2929
"target": {3030
"ref": "#paramTarget",3131
"type": "ref"3232
}3333
},3434
"required": [3535
"id",3636
"target",3737
"breakpoints"3838
],3939
"type": "object"4040
},4141
"breakpoint": {4242
"properties": {4343
"curve": {4444
"description": "How the value travels from the previous breakpoint.",4545
"knownValues": [4646
"step",4747
"linear",4848
"exponential"4949
],5050
"type": "string"5151
},5252
"time": {5353
"description": "Milliseconds from the trigger.",5454
"minimum": 0,5555
"type": "integer"5656
},5757
"value": {5858
"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.",5959
"maxLength": 200,6060
"type": "string"6161
}6262
},6363
"required": [6464
"time",6565
"value"6666
],6767
"type": "object"6868
},6969
"connection": {7070
"description": "An audio connection from a node output to either an audio input or a named AudioParam.",7171
"properties": {7272
"from": {7373
"ref": "#source",7474
"type": "ref"7575
},7676
"to": {7777
"ref": "#target",7878
"type": "ref"7979
}8080
},8181
"required": [8282
"from",8383
"to"8484
],8585
"type": "object"8686
},8787
"lineage": {8888
"description": "The module this one was forked from, and its author.",8989
"properties": {9090
"authorDid": {9191
"format": "did",9292
"type": "string"9393
},9494
"moduleId": {9595
"maxLength": 128,9696
"type": "string"9797
},9898
"uri": {9999
"format": "at-uri",100100
"type": "string"101101
}102102
},103103
"required": [104104
"uri",105105
"authorDid"106106
],107107
"type": "object"108108
},109109
"main": {110110
"description": "A module, held in its author's own repository.",111111
"key": "tid",112112
"record": {113113
"properties": {114114
"audioInputs": {115115
"description": "Zero or more individually identified audio inputs.",116116
"items": {117117
"ref": "#port",118118
"type": "ref"119119
},120120
"type": "array"121121
},122122
"audioOutputs": {123123
"items": {124124
"ref": "#port",125125
"type": "ref"126126
},127127
"type": "array"128128
},129129
"automation": {130130
"description": "Scheduled AudioParam envelopes. Web Audio has no envelope node, so these are their own structure.",131131
"items": {132132
"ref": "#automation",133133
"type": "ref"134134
},135135
"type": "array"136136
},137137
"connections": {138138
"items": {139139
"ref": "#connection",140140
"type": "ref"141141
},142142
"type": "array"143143
},144144
"createdAt": {145145
"format": "datetime",146146
"type": "string"147147
},148148
"description": {149149
"maxLength": 3000,150150
"type": "string"151151
},152152
"descriptionVersion": {153153
"description": "Version of the module description this record follows. A reader accepts any version at or below its own.",154154
"minimum": 1,155155
"type": "integer"156156
},157157
"forkedFrom": {158158
"ref": "#lineage",159159
"type": "ref"160160
},161161
"midiInputs": {162162
"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.",163163
"items": {164164
"ref": "#port",165165
"type": "ref"166166
},167167
"type": "array"168168
},169169
"moduleId": {170170
"description": "Stable identity shared by every published version of this module.",171171
"maxLength": 128,172172
"type": "string"173173
},174174
"name": {175175
"maxLength": 200,176176
"minLength": 1,177177
"type": "string"178178
},179179
"nodes": {180180
"items": {181181
"ref": "#node",182182
"type": "ref"183183
},184184
"type": "array"185185
},186186
"noteOutputs": {187187
"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.",188188
"items": {189189
"ref": "#port",190190
"type": "ref"191191
},192192
"type": "array"193193
},194194
"noteSource": {195195
"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.",196196
"knownValues": [197197
"keyboard",198198
"sequencer",199199
"range",200200
"transpose",201201
"assign",202202
"oneshot"203203
],204204
"maxLength": 64,205205
"type": "string"206206
},207207
"parameters": {208208
"items": {209209
"ref": "#parameter",210210
"type": "ref"211211
},212212
"type": "array"213213
},214214
"patternSource": {215215
"description": "What this module chooses a sequencer's patterns 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 patterns 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.",216216
"knownValues": [217217
"arranger",218218
"scenes"219219
],220220
"maxLength": 64,221221
"type": "string"222222
},223223
"sampleSlots": {224224
"items": {225225
"ref": "#sampleSlot",226226
"type": "ref"227227
},228228
"type": "array"229229
},230230
"versionKey": {231231
"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.",232232
"maxLength": 128,233233
"type": "string"234234
}235235
},236236
"required": [237237
"descriptionVersion",238238
"moduleId",239239
"name",240240
"description",241241
"audioInputs",242242
"audioOutputs",243243
"midiInputs",244244
"nodes",245245
"connections",246246
"createdAt"247247
],248248
"type": "object"249249
},250250
"type": "record"251251
},252252
"node": {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.",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. A `dsp` node is the one kind made of code its author wrote in DSP JS, a subset of JavaScript that plays the same in a browser and in a DAW: its options are `code`, the source as its author wrote it, and `tail`, a switch saying that what it is handed is still heard after the note that made it has ended. Its inputs, its outputs, its parameters and the samples it reads are what the source declares (`static inputs`, `static outputs`, `static params`, `sample(\"…\")`), and nothing in the record repeats them: a connection into one of its parameters, or a `param` target, names a key of its `static params`, and a connection's `input` or `output` counts its buses. Each sample its source reads is filled through exactly one of the module's `sampleSlots`, which names the node and has the name the source reads as its `property`. A module holds at most four `dsp` nodes, each of at most 65536 bytes of source; one whose source is not DSP JS cannot be played. `audioWorklet`, the kind code was carried in before DSP JS, is no longer in the vocabulary and is refused as any unknown kind is.",254254
"properties": {255255
"id": {256256
"maxLength": 64,257257
"minLength": 1,258258
"type": "string"259259
},260260
"kind": {261261
"maxLength": 64,262262
"minLength": 1,263263
"type": "string"264264
},265265
"options": {266266
"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.",267267
"type": "unknown"268268
}269269
},270270
"required": [271271
"id",272272
"kind"273273
],274274
"type": "object"275275
},276276
"paramTarget": {277277
"properties": {278278
"node": {279279
"maxLength": 64,280280
"minLength": 1,281281
"type": "string"282282
},283283
"param": {284284
"maxLength": 64,285285
"minLength": 1,286286
"type": "string"287287
}288288
},289289
"required": [290290
"node",291291
"param"292292
],293293
"type": "object"294294
},295295
"parameter": {296296
"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.",297297
"properties": {298298
"default": {299299
"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.",300300
"maxLength": 200,301301
"type": "string"302302
},303303
"id": {304304
"maxLength": 64,305305
"minLength": 1,306306
"type": "string"307307
},308308
"label": {309309
"maxLength": 200,310310
"minLength": 1,311311
"type": "string"312312
},313313
"range": {314314
"ref": "#range",315315
"type": "ref"316316
},317317
"scale": {318318
"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.",319319
"knownValues": [320320
"linear",321321
"log"322322
],323323
"type": "string"324324
},325325
"targets": {326326
"items": {327327
"ref": "#parameterTarget",328328
"type": "ref"329329
},330330
"minLength": 1,331331
"type": "array"332332
},333333
"values": {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.",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 `dsp` node offers a choice its own code interprets.",335335
"items": {336336
"maxLength": 200,337337
"type": "string"338338
},339339
"type": "array"340340
}341341
},342342
"required": [343343
"id",344344
"label",345345
"targets"346346
],347347
"type": "object"348348
},349349
"parameterTarget": {350350
"description": "One of: {node, param}, {node, option}, or {automation, breakpoint, field}.",351351
"properties": {352352
"automation": {353353
"maxLength": 64,354354
"type": "string"355355
},356356
"breakpoint": {357357
"minimum": 0,358358
"type": "integer"359359
},360360
"field": {361361
"description": "Which field of the breakpoint the parameter sets. `time` is milliseconds from the trigger; `duration` is milliseconds from the breakpoint before this one, so a later stage keeps its length when an earlier one is made longer, and is never set on breakpoint 0. `value` is the level travelled to. `curve` is how it travels there, and the parameter then declares a closed value set drawn from the breakpoint's own curves.",362362
"knownValues": [363363
"time",364364
"duration",365365
"value",366366
"curve"367367
],368368
"type": "string"369369
},370370
"node": {371371
"maxLength": 64,372372
"type": "string"373373
},374374
"option": {375375
"maxLength": 64,376376
"type": "string"377377
},378378
"param": {379379
"maxLength": 64,380380
"type": "string"381381
}382382
},383383
"type": "object"384384
},385385
"port": {386386
"description": "One individually identified audio or MIDI boundary of the module.",387387
"properties": {388388
"id": {389389
"maxLength": 64,390390
"minLength": 1,391391
"type": "string"392392
},393393
"label": {394394
"maxLength": 200,395395
"type": "string"396396
}397397
},398398
"required": [399399
"id"400400
],401401
"type": "object"402402
},403403
"range": {404404
"properties": {405405
"max": {406406
"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.",407407
"maxLength": 200,408408
"type": "string"409409
},410410
"min": {411411
"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.",412412
"maxLength": 200,413413
"type": "string"414414
}415415
},416416
"required": [417417
"min",418418
"max"419419
],420420
"type": "object"421421
},422422
"sampleRef": {423423
"description": "A sample blob and the account that holds it.",424424
"properties": {425425
"blob": {426426
"accept": [427427
"audio/wav",428428
"audio/flac"429429
],430430
"maxSize": 10485760,431431
"type": "blob"432432
},433433
"ownerDid": {434434
"format": "did",435435
"type": "string"436436
}437437
},438438
"required": [439439
"blob",440440
"ownerDid"441441
],442442
"type": "object"443443
},444444
"sampleSlot": {445
"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.",445
"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. On a `dsp` node, `property` is a name its source passes to `sample()`: each such name has exactly one slot, so two DSP JS nodes reading the same name are two slots, each filled and defaulted on its own, and a slot naming something the source never reads cannot be played.",446446
"properties": {447447
"default": {448448
"ref": "#sampleRef",449449
"type": "ref"450450
},451451
"id": {452452
"maxLength": 64,453453
"minLength": 1,454454
"type": "string"455455
},456456
"label": {457457
"maxLength": 200,458458
"type": "string"459459
},460460
"node": {461461
"maxLength": 64,462462
"minLength": 1,463463
"type": "string"464464
},465465
"property": {466
"description": "What the sample feeds: `buffer` on a node that plays one sample, or, on a `dsp` node, the name its source reads the sample by.",466467
"knownValues": [467468
"buffer"468469
],469470
"type": "string"470471
}471472
},472473
"required": [473474
"id",474475
"node",475476
"property"476477
],477478
"type": "object"478479
},479480
"source": {480481
"properties": {481482
"node": {482483
"maxLength": 64,483484
"minLength": 1,484485
"type": "string"485486
},486487
"output": {487488
"minimum": 0,488489
"type": "integer"489490
}490491
},491492
"required": [492493
"node"493494
],494495
"type": "object"495496
},496497
"target": {497498
"description": "Exactly one of `input` or `param` is present. `param` is modulation: a node output reaching a named AudioParam.",498499
"properties": {499500
"input": {500501
"minimum": 0,501502
"type": "integer"502503
},503504
"node": {504505
"maxLength": 64,505506
"minLength": 1,506507
"type": "string"507508
},508509
"param": {509510
"maxLength": 64,510511
"type": "string"511512
}512513
},513514
"required": [514515
"node"515516
],516517
"type": "object"517518
}518519
},519520
"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.",520521
"id": "at.atmosynth.module",521522
"lexicon": 1522523
}