Documentation » Cyaml Schemas

Copyright (C) 2019 Alexandros Theodotou <alex at="" zrythm="" dot="" org>="">

This file is part of Zrythm

Zrythm is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Zrythm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with Zrythm. If not, see https://www.gnu.org/licenses/.

Introduction

Zrythm uses libcyaml to save projects into YAML. Cyaml can serialize C structs, given that you provide it with the schemas of each struct. This page has some tips on writing schemas.

Fields

For all fields, use the CYAML_FLAG_OPTIONAL flag to indicate that a variable can be NULL.

Ints

Use CYAML_FIELD_INT with the CYAML_FLAG_DEFAULT flag.

Example, having an 'enabled' flag inside a Plugin:

CYAML_FIELD_INT (
  "enabled", CYAML_FLAG_DEFAULT,
  Plugin, enabled),

Enums

Use CYAML_FIELD_ENUM with the CYAML_FLAG_DEFAULT flag.

Example, RegionType inside a Region:

CYAML_FIELD_ENUM (
  "type", CYAML_FLAG_DEFAULT,
  Region, type, region_type_strings,
  CYAML_ARRAY_LEN (region_type_strings)),

Enums also need a cyaml_strval_t argument:

static const cyaml_strval_t
region_type_strings[] =
{
  { "Midi",          REGION_TYPE_MIDI    },
  { "Audio",         REGION_TYPE_AUDIO   },
};

String Pointers (char *)

Use CYAML_FIELD_STRING_PTR with the CYAML_FLAG_POINTER flag.

Example, Region name:

CYAML_FIELD_STRING_PTR (
  "name", CYAML_FLAG_POINTER,
  Region, name,
  0, CYAML_UNLIMITED),

Direct struct (not pointer) inside another struct

Use CYAML_FIELD_MAPPING with the CYAML_FLAG_DEFAULT flag.

Example, having a plain Position inside a MidiNote:

CYAML_FIELD_MAPPING (
  "start_pos",
  CYAML_FLAG_DEFAULT,
  MidiNote, start_pos, position_fields_schema)

Pointer to Struct

Use CYAML_FIELD_MAPPING_PTR with the CYAML_FLAG_POINTER flag.

Example, having a pointer to an Lv2Plugin inside a Plugin:

CYAML_FIELD_MAPPING_PTR (
  "lv2", CYAML_FLAG_POINTER,
  Plugin, lv2,
  lv2_plugin_fields_schema),

Arrays of Pointers (variable count)

There are two cases. Fixed-width arrays, like below. In this case, use the CYAML_FLAG_DEFAULT flag.

MyStruct * my_structs[MAX_STRUCTS];
int        num_my_structs;

The other case is dynamic arrays, like below. In this case use @CYAML_FLAG_POINTER.

AutomationTrack ** ats;
int               num_ats;
int               ats_size;

Use CYAML_FIELD_SEQUENCE_COUNT with the CYAML_FLAG_DEFAULT or CYAML_FLAG_POINTER flag as described above.

Use CYAML_FLAG_POINTER when declaring the schema of the child struct.

Example, fixed-size array of MidiNote pointers inside a Region:

CYAML_FIELD_SEQUENCE_COUNT (
  "midi_notes", CYAML_FLAG_DEFAULT,
  Region, midi_notes, num_midi_notes,
  &midi_note_schema, 0, CYAML_UNLIMITED),

Example, dynamic array of AutomationTrack pointers in AutomationTracklist:

CYAML_FIELD_SEQUENCE_COUNT (
  "ats", CYAML_FLAG_POINTER,
  AutomationTracklist, ats, num_ats,
  &automation_track_schema, 0, CYAML_UNLIMITED),

Arrays of Pointers (fixed count)

MyStruct * my_structs[9];

Use CYAML_FIELD_SEQUENCE_FIXED with the CYAML_FLAG_DEFAULT flag.

Example:

CYAML_FIELD_SEQUENCE_FIXED (
  "plugins", CYAML_FLAG_DEFAULT,
  Channel, plugins,
  &plugin_schema, STRIP_SIZE),

Arrays of Structs (variable count)

MyStruct my_structs[MAX_MY_STRUCTS];
int      num_my_structs;

Use CYAML_FIELD_SEQUENCE_COUNT with the CYAML_FLAG_DEFAULT flag.

Use CYAML_FLAG_DEFAULT when declaring the schema of the child struct.

Example, destination PortIdentifier's of a Port:

static const cyaml_schema_value_t
port_identifier_schema_default = {
  CYAML_VALUE_MAPPING (
    CYAML_FLAG_DEFAULT, // note the flag
    PortIdentifier,
    port_identifier_fields_schema),
};

CYAML_FIELD_SEQUENCE_COUNT (
  "dest_ids", CYAML_FLAG_DEFAULT,
  Port, dest_ids, num_dests,
  &port_identifier_schema_default,
  0, CYAML_UNLIMITED),

Bitfields

typedef enum PortFlags
{
  PORT_FLAG_STEREO_L = 0x01,
  PORT_FLAG_STEREO_R = 0x02,
  PORT_FLAG_PIANO_ROLL = 0x04,
  PORT_FLAG_SIDECHAIN = 0x08,
  PORT_FLAG_MAIN_PORT = 0x10,
  OPT_F = 0x20,
} PortFlags;

First, declare the bitfield definitions.

static const cyaml_bitdef_t
flags_bitvals[] =
{
  { .name = "stereo_l", .offset =  0, .bits =  1 },
  { .name = "stereo_r", .offset =  1, .bits =  1 },
  { .name = "piano_roll", .offset = 2, .bits = 1 },
  { .name = "sidechain", .offset = 3, .bits =  1 },
  { .name = "main_port", .offset = 4, .bits = 1 },
  { .name = "opt_f", .offset = 5, .bits = 1 },
};

Use CYAML_FIELD_BITFIELD with the CYAML_FLAG_DEFAULT flag.

Example, PortFlags:

CYAML_FIELD_BITFIELD (
  "flags", CYAML_FLAG_DEFAULT,
  PortIdentifier, flags, flags_bitvals,
  CYAML_ARRAY_LEN (flags_bitvals)),

Schema Values

Schemas will normally be CYAML_VALUE_MAPPING with a CYAML_FLAG_POINTER flag. Use the CYAML_FLAG_DEFAULT if the struct will be used directly in another struct (not as a pointer).