Xybrid's various save formats are CBOR objects; CBOR was chosen over msgpack due to Qt5.12 having built-in support probably have a field of raw data for (some) node saves, and keep it resident in case of plugin crashes extensions { .xyp - project .xyn - node } project: [ "xybrid:project" (int version) { "meta": { "artist": ... "title": ... "comment": ... etc. } "patterns": [ array of pattern structs ] "sequence": [ array of pattern numbers, int, separator is anything negative ] "graph": { root graph (contents) } } ] pattern: { "name": "asdf" "channels": [ { "name": "asdf" "rows": [ // probably better name... [ int port, int note, n*(int c, int amt) ] // for each row // any number of empty rows is expressed as an integer number of rows skipped // this number is only written if there are any non-empty rows after ] } ] // if no channels have their last row filled, an integer representing the // total number of rows is written as the last entry of the channel array } sample: { "name": "asdf" "type": "raw" "rate": 48000 "channels": 2 "data" : [ len*channels float32s as raw bytefield ] } also sample variant using flac?