synth-datagen
Configuration
synth-datagen reads a YAML configuration file (default: synth-datagen.yml) that defines global parameters and one or more output header files. This page documents the configuration file format, command-line options, and all supported configuration keys.
Command-line usage
synth-datagen [-f config.yml] [-o output_dir] [-c] [-v]
| Flag | Default | Description |
|---|---|---|
-f |
synth-datagen.yml |
Path to the configuration file |
-o |
. |
Output directory for generated files |
-c |
disabled | Generate HTML chart files instead of C headers |
-v |
-- | Print version and exit |
When -c is specified, only outputs with a charts_output field are processed, and the tool generates HTML visualization files (using go-echarts) instead of C headers.
Configuration file structure
The top-level YAML structure has two keys:
global_parameters:
# key-value pairs accessible to all modules
output:
# mapping of output file paths to their content definitions
Global parameters
The global_parameters section is a flat key-value map that provides default values to all module invocations. Each DSP module internally defines a configuration struct with typed fields (e.g., the ADSR module has fields Samples, SampleAmplitude, SampleScalarType). The parameter resolver (data registry) populates these fields by converting each field name to snake_case and searching two maps in order:
- The per-invocation
parametersmap (local override) - The
global_parametersmap (global default)
Within each map, two key forms are checked, in order:
- Module-prefixed key:
{module}_{field}(e.g.,adsr_sample_amplitude) - Unprefixed key:
{field}(e.g.,sample_amplitude)
For example, the ADSR module's SampleAmplitude field (snake_case: sample_amplitude) is resolved for a module named adsr as follows:
- Check local
parametersforadsr_sample_amplitude→ if found, use it - Check local
parametersforsample_amplitude→ if found, use it - Check
global_parametersforadsr_sample_amplitude→ if found, use it - Check
global_parametersforsample_amplitude→ if found, use it - If still not found: pointer and slice fields remain nil (optional); non-pointer, non-slice fields cause an error (required)
This means adsr_samples: 0x0100 in global_parameters matches the ADSR module's Samples field because the module-prefixed lookup adsr_ + samples = adsr_samples succeeds. A shared parameter like sample_rate: 48000 (unprefixed) is found as a fallback for any module that needs a SampleRate field.
To override a global parameter for a specific module invocation, add it to the parameters map of that module:
global_parameters:
sample_rate: &sample_rate 48000
wavetables_sample_amplitude: 0x01ff
output:
firmware/oscillator-data.h:
modules:
oscillator:
name: wavetables
selectors:
- sine
parameters:
# overrides global wavetables_sample_amplitude for this invocation only
wavetables_sample_amplitude: 0x00ff
YAML anchors and aliases can be used to reference values across the configuration:
global_parameters:
sample_rate: &sample_rate 48000
wavetables_sample_amplitude: &wavetables_sample_amplitude 0x01ff
output:
firmware/main-data.h:
macros:
sample_rate: *sample_rate
Output definitions
Each key under output is the relative path for the generated header file. Each output contains:
| Field | Type | Description |
|---|---|---|
charts_output |
string |
Optional path for HTML chart output (used with -c flag) |
includes |
mapping | C #include directives |
macros |
mapping | C #define preprocessor macros |
variables |
mapping | C static const variable declarations |
modules |
mapping | DSP module invocations |
Includes
The includes section maps header file paths to a boolean indicating whether they are system includes:
includes:
stdint.h: true # generates: #include <stdint.h>
avr/pgmspace.h: true # generates: #include <avr/pgmspace.h>
config.h: false # generates: #include "config.h"
Duplicate includes are deduplicated. If the same path appears with both true (system) and false (local), the local form takes precedence.
Macros
Each key under macros becomes the #define identifier. Values can be specified as plain scalars or as objects with additional options:
Simple scalar macro
macros:
sample_rate: 48000
Generates: #define sample_rate 48000
Typed macro
macros:
adsr_sample_amplitude:
value: 0xff
type: uint8_t
hex: true
Generates: #define adsr_sample_amplitude 0xff
| Field | Type | Default | Description |
|---|---|---|---|
value |
any scalar | -- | The macro value |
type |
string |
-- | C type for value conversion (affects hex formatting width) |
hex |
bool |
false |
Format numeric values in hexadecimal |
raw |
bool |
false |
Emit the value as-is without type formatting |
Raw macro
When raw is true, the value is emitted verbatim without any type conversion or formatting. This is useful for referencing platform-specific constants:
macros:
cpu_frqsel:
value: CLKCTRL_FRQSEL_24M_gc
raw: true
Generates: #define cpu_frqsel CLKCTRL_FRQSEL_24M_gc
Expression evaluation
When eval_env is provided (or eval is true), string values are evaluated as expressions using the expr library. The eval_env map provides variables available in the expression:
macros:
timer_tcb_ccmp:
value: clock_frequency / sample_rate
type: uint16_t
eval_env:
clock_frequency: 24000000
sample_rate: 48000
Generates: #define timer_tcb_ccmp 500
This is useful for computing derived constants from base parameters, such as baud rate register values or timer periods.
Variables
The variables section works similarly to macros but generates static const variable declarations instead of #define macros. Each key becomes the variable identifier:
variables:
my_data:
value: [1, 2, 3, 4]
type: uint8_t
Generates:
static const uint8_t my_data[4] = {
0x01, 0x02, 0x03, 0x04,
};
#define my_data_len 4
| Field | Type | Default | Description |
|---|---|---|---|
value |
scalar or array | -- | The variable's value |
type |
string |
-- | C type for the value |
string_width |
int |
-- | Fixed string width (negative for left-aligned) |
attributes |
[]string |
-- | C attributes inserted before the initializer |
eval |
bool |
false |
Evaluate string values as expressions |
eval_env |
mapping | -- | Variables for expression evaluation |
Modules
The modules section invokes DSP modules to generate data arrays. Each key becomes the C identifier prefix:
modules:
oscillator:
name: wavetables
selectors:
- sine
- blsquare
parameters:
data_attributes:
- PROGMEM
| Field | Type | Description |
|---|---|---|
name |
string |
Module name (wavetables, adsr, filters, or notes) |
selectors |
[]string |
Which data arrays to generate |
parameters |
mapping | Per-invocation parameter overrides |
The parameters map is checked before global_parameters during parameter resolution. See DSP modules for detailed documentation of each module's selectors and parameters.
Supported C types
The following C scalar types are supported for type fields and module *_scalar_type parameters:
| C type | Go representation | Notes |
|---|---|---|
bool |
bool |
|
int8_t |
int8 |
|
int16_t |
int16 |
|
int32_t |
int32 |
|
int64_t |
int64 |
|
uint8_t |
uint8 |
|
uint16_t |
uint16 |
|
uint32_t |
uint32 |
|
uint64_t |
uint64 |
|
float |
float32 |
Single-precision FPU targets |
double |
float64 |
Double-precision FPU targets |
char* |
string |
Setting a module's *_scalar_type parameter to float or double produces floating-point arrays that can be used directly on platforms with an FPU, without any fixed-point scaling in firmware. See DSP modules -- Scalar types and fixed-point arithmetic for details on how fractional bit width parameters interact with floating-point types.
Complete example
The following is a minimal but complete configuration generating wavetable and note data:
global_parameters:
sample_rate: &sample_rate 48000
samples_per_cycle: 0x0200
wavetables_sample_amplitude: 0x01ff
wavetables_sample_scalar_type: int16_t
notes_phase_steps_scalar_type: uint32_t
notes_phase_steps_fractional_bit_width: 16
output:
firmware/oscillator-data.h:
includes:
stdint.h: true
modules:
oscillator:
name: wavetables
selectors:
- sine
notes:
name: notes
selectors:
- phase_steps
Running synth-datagen -f synth-datagen.yml -o . generates firmware/oscillator-data.h containing a 512-element int16_t sine wavetable and a 128-element uint32_t phase step table.