Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Patch Format

Overview

Patch files are JSON documents that capture the complete state of a synthesizer patch, including oscillator settings, filter parameters, envelope configurations, LFO modulation, mixer levels, keyboard response, and effects processing. They allow you to save, share, and recall synthesizer configurations.

It does not store the settings from the settings panel like midi channel or device as these are something that is likely to change from session to session.

Patches are stored in your user level library directory here: ~/Library/Application\ Support/AccidentalSynthesizer/patches/

User patches are stored in JSON format text files so that they are human readable. You can manually create, edit, or delete files. Changes will be loaded when you restart the application.

While manually creating and editing patches is in no way required to use the Accidental Synthesizer, it does give you a little more control and provides some creative opportunities that are not available in the UI. For example, while the UI Portamento controls control all the oscillators at once, the patch files provide portamento controls per oscillator allowing you the freedom to set them all to unique values.

Get creative with it but be careful about the levels when combining effects as things could get very loud. Also some combinations will create very quiet or even no output. If that happens you might have to play with the settings in the UI until you get it where you needed it and then save that state as a new patch.

Root Structure

A patch file has the following top-level keys:

{
  "clock": {...},
  "effects": [...],
  "envelopes": [...],
  "filter": {...},
  "keyboard": {...},
  "lfos": [...],
  "mixer": {...},
  "oscillators": [...]
}

All keys are required. The following sections define the structure and valid ranges for each.

Clock

Single clock object that stores the last known MIDI clock tempo. Used by the engine when no external MIDI clock is present. Changing this wont have any real impact on the synth though as it needs midi clock signal to work and that will just over write it.

FieldTypeRangeDescription
bpmnumber> 0Tempo in beats per minute

Example Clock

{
  "bpm": 120
}

Oscillators

Array of 4 oscillator objects, in order: Sub, Osc 1, Osc 2, Osc 3.

FieldTypeRangeDescription
wave_shape_indexinteger0-11Waveform shape (see Waveforms table)
course_tuneinteger-12 to +12Coarse pitch in semitones
fine_tuneinteger-63 to +63Fine pitch in cents
clipper_boostinteger0-30Clipper output boost in dB
shape_parameter1number0.0-1.0Waveform-dependent (e.g., pulse width, AM/FM depth)
shape_parameter2number0.0-1.0Waveform-dependent
pitch_bendintegersee belowPitch bend offset in cents (see Pitch Bend)
portamento_enabledbooleanEnable pitch glide between notes
portamento_timeinteger0-65535Glide duration in audio buffers
hard_sync_enabledbooleanEnable hard sync to master oscillator
key_sync_enabledbooleanReset phase on each note
gate_flagbooleanPerformance state — leave as false
pitch_envelope_amountnumber-1.0 to 1.0How much the Pitch Envelope modulates this oscillator's pitch

Example Oscillator

{
  "wave_shape_index": 3,
  "course_tune": 0,
  "fine_tune": 0,
  "clipper_boost": 0,
  "shape_parameter1": 0,
  "shape_parameter2": 0,
  "pitch_bend": 0,
  "portamento_enabled": false,
  "portamento_time": 7,
  "hard_sync_enabled": false,
  "key_sync_enabled": false,
  "gate_flag": false,
  "pitch_envelope_amount": 0
}

Filter

Single filter object controlling the resonant lowpass filter.

FieldTypeRangeDescription
cutoff_frequencynumber0.0-20000.0Filter cutoff in Hz (clamped to 35% of Nyquist at runtime)
filter_polesinteger1-4Number of filter poles (1 = 6 dB/oct, 2 = 12, 3 = 18, 4 = 24)
resonancenumber0.0-0.90Filter resonance (peak at cutoff)
key_tracking_amountnumber0.0-1.0Bipolar key tracking (see Key Tracking)
current_note_numberintegerPerformance state — leave at 0

Example Filter

{
  "cutoff_frequency": 16800,
  "filter_poles": 4,
  "resonance": 0,
  "key_tracking_amount": 0.5,
  "current_note_number": 0
}

Envelopes

Array of 3 envelope objects: [Amplitude Envelope, Filter Envelope, Pitch Envelope].

Each envelope is an ADSR (Attack, Decay, Sustain, Release) generator.

The Pitch Envelope (index 2) modulates oscillator pitch. Each oscillator's pitch_envelope_amount controls how much it is affected. The amount, is_inverted, sustain_pedal, and gate_flag fields on the Pitch Envelope are not used; set them to their defaults.

FieldTypeRangeDescription
amountnumber0.0-1.0Modulation depth (envelope intensity)
attack_msinteger1-5000Attack time in milliseconds
decay_msinteger10-5000Decay time in milliseconds
sustain_levelnumber0.0-1.0Sustain level after decay
release_msinteger10-10000Release time in milliseconds
is_invertedbooleanInvert the envelope output
sustain_pedalbooleanPerformance state — leave as false
gate_flagintegerPerformance state — leave at 0

Example Envelope

{
  "amount": 1,
  "attack_ms": 200,
  "decay_ms": 200,
  "sustain_level": 0.8,
  "release_ms": 200,
  "is_inverted": false,
  "sustain_pedal": false,
  "gate_flag": 0
}

LFOs

Array of 2 LFO objects: [LFO 1, LFO 2].

Low-frequency oscillators provide modulation sources for other parameters.

FieldTypeRangeDescription
wave_shapeinteger0-11Waveform shape (see Waveforms table)
frequencynumber0.01-20000.0Oscillation frequency in Hz (used when clock_synced is false)
center_valuenumber-1.0 to 1.0Center point of modulation range
rangenumber0.01-2.0Modulation depth (values near 0.01 are effectively no modulation)
phasenumber0.0-1.0Starting phase (0.0 to 1.0 wraps one cycle)
resetbooleanReset phase to 0 on note-on
clock_syncedbooleanWhen true, rate is determined by thirty_second_notes instead of frequency
thirty_second_notesinteger1–128Rate in 32nd note subdivisions when clock_synced is true (e.g. 32 = one note per bar in 4/4)
key_syncedbooleanWhen true, LFO phase resets on MIDI note-on. If clock_synced is also true, the reset waits for the next 32nd-note trigger after the key press so the LFO stays on beat
synced_frequencynumberPerformance state — computed at runtime from clock and thirty_second_notes; leave as 0.5
sync_triggeredbooleanPerformance state — set by the engine at each 32nd-note clock boundary; leave as false
gate_flagbooleanPerformance state — leave as false

Example LFO

{
  "wave_shape": 0,
  "frequency": 10,
  "synced_frequency": 0.5,
  "sync_triggered": false,
  "thirty_second_notes": 32,
  "clock_synced": false,
  "key_synced": false,
  "center_value": 1,
  "range": 0,
  "phase": 0,
  "reset": false,
  "gate_flag": false
}

Mixer

Single mixer object controlling oscillator levels and master output.

FieldTypeRangeDescription
levelnumber0.0-1.0Master output level
balancenumber-1.0 to 1.0Master stereo pan (0 = center)
is_mutedbooleanMute master output
quad_mixer_inputsarray4 objects (one per oscillator)

Each quad_mixer_inputs object has:

FieldTypeRangeDescription
levelnumber0.0-1.0Oscillator output level
balancenumber-1.0 to 1.0Oscillator stereo pan (0 = center)
mutebooleanMute this oscillator

Example Mixer

{
  "level": 0.8,
  "balance": 0,
  "is_muted": false,
  "quad_mixer_inputs": [
    { "level": 0, "balance": 0, "mute": false },
    { "level": 1, "balance": 0, "mute": false },
    { "level": 1, "balance": 0, "mute": false },
    { "level": 1, "balance": 0, "mute": false }
  ]
}

Keyboard

Single keyboard object controlling MIDI response and velocity sensitivity.

FieldTypeRangeDescription
pitch_bend_rangeinteger2-12Maximum pitch bend in semitones
velocity_curvenumber0.0-1.0Velocity response curve (see Velocity Curve)
aftertouch_amountnumber0.0-1.0Aftertouch modulation depth
mod_wheel_amountnumber0.0-1.0Modulation wheel depth
polarity_flippedbooleanInvert polarity of all pitch-related inputs

Example Keyboard

{
  "pitch_bend_range": 12,
  "velocity_curve": 0.5,
  "aftertouch_amount": 0,
  "mod_wheel_amount": 0,
  "polarity_flipped": false
}

Effects

Array of 12 effect objects in fixed order. Each effect has:

FieldTypeRangeDescription
namestringDisplay name of the effect (informational; does not affect processing)
is_enabledbooleanEnable/disable the effect
parametersarray of 40.0-1.0Effect-specific parameters

Effects are processed in this order:

IndexNameParam 0Param 1Param 2Param 3
0Saturationtypedrive amountpost-saturation gain cutunused
1Colour Compressorthresholdratiomakeup gainblend
2Wave Folderfold amount (positive samples)asymmetric mode togglefold amount (negative samples, asymmetric mode only)unused
3Bit Shifterbit reduction (normalized 1–16)blendunusedunused
4Clipperthresholdpre-clip boostpost-clip makeup gainnotch toggle
5Gate Clippingthresholdpre-gate level cutpost-gate makeup gainnotch toggle
6Wave Rectifierfull wave mode toggle (0 = half wave)blendunusedunused
7ChorusDepthRateFeedbackBlend
8FlangerDepthRateFeedbackBlend
9Auto-Panratewidthwave shapeunused
10Tremoloratedepthwave shapeunused
11Delayamounttimefeedbackunused

All parameters use the range 0.0 to 1.0, including "unused" fields which should be set to 0. Toggle parameters are 0.0 for Off and > 0.0 values for on but 1.0 is the preferred On value.

Example Effect

{
  "name": "Saturation",
  "is_enabled": false,
  "parameters": [0.5, 0.5, 0.5, 0]
}

Waveforms

Both oscillators and LFOs use the same waveform index table:

IndexNameDescription
0SinePure sinusoidal
1TriangleTriangular wave
2Square50% duty cycle square
3SawRising sawtooth
4PulsePulse with duty cycle control (use shape_parameter1/wave_shape)
5RampFalling sawtooth ramp
6SupersawDetuned sawtooth stack
7AMAmplitude modulation (shape_parameter1 controls depth)
8FMFrequency modulation (shape_parameter1/2 control depth)
9PMPhase modulation (shape_parameter1/2 control depth)
10BrokenDeliberately glitchy/unstable oscillator (shape_parameter1 controls jank amount)
11NoiseWhite noise

Notes for Manual Patch Editing

Performance State Fields

Some fields reflect live performance state — they are updated in real time by MIDI input or the synth engine during playback. While you can set these in a patch file, they will be overwritten as soon as the corresponding MIDI event occurs. In most cases they should be left at their default values.

  • oscillators[*].pitch_bend — Leave at 0 (overwritten by MIDI pitch bend wheel)
  • oscillators[*].gate_flag — Leave as false (overwritten by note on/off)
  • filter.current_note_number — Leave at 0 (overwritten by note on)
  • envelopes[*].sustain_pedal — Leave as false (overwritten by MIDI sustain pedal)
  • envelopes[*].gate_flag — Leave at 0 (overwritten by note on/off)
  • lfos[*].synced_frequency — Leave at 0.5 (computed at runtime from MIDI clock and thirty_second_notes)
  • lfos[*].sync_triggered — Leave as false (set by the engine at each 32nd-note clock boundary)
  • lfos[*].gate_flag — Leave as false (overwritten by note on/off)

Key Tracking

key_tracking_amount is stored as a normalized 0.0–1.0 value but represents a bipolar range internally:

ValueEffective trackingMeaning
0.0-1.0 (full negative)Higher notes lower the cutoff
0.50.0 (no tracking)Cutoff is independent of pitch — this is the default
1.0+1.0 (full positive)Higher notes raise the cutoff

The conversion is: bipolar = (key_tracking_amount - 0.5) * 2.0. The reference note is MIDI note 64 (E4) — notes above shift the cutoff up or down relative to that center depending on the tracking direction.

Pitch Bend

pitch_bend is stored in cents (100 cents = 1 semitone), not raw MIDI values. Its effective range is determined by the keyboard.pitch_bend_range setting:

  • Maximum positive bend = pitch_bend_range × 100 cents
  • Maximum negative bend = -(pitch_bend_range × 100) cents

For example, with pitch_bend_range: 12 (12 semitones = 1 octave), the range is -1200 to +1200 cents. With pitch_bend_range: 2, the range is -200 to +200 cents.

A value of 0 means no pitch bend (center position). This is a performance state field — it will be overwritten by MIDI pitch bend input during playback.

Velocity Curve

velocity_curve controls how MIDI velocity maps to amplitude. The value 0.5 is the midpoint:

ValueResponseBehavior
0.0FixedAll velocities produce maximum volume
0.0–0.5CompressedSofter touch still produces relatively loud output
0.5LinearVelocity maps 1:1 to amplitude
0.5–1.0ExpandedRequires harder touch for loud output
1.0Maximum expansionVery sensitive to velocity differences

Parameter Validation

JSON files are validated at runtime. Invalid values will be clamped to their ranges. However, it is best practice to respect the documented ranges when editing patches manually.

File Format

  • Use standard JSON formatting (valid JSON is required)
  • All numeric values must be valid JSON numbers (not strings)
  • Boolean values use JSON true and false (not strings)
  • Trailing commas are not valid JSON

Creating New Patches

Start from init.json as a template and modify parameters as desired. The initial patch is a good reference for structure and default values.

Example: Creating a Saw Lead

Here is a simplified example of a sawtooth lead patch with portamento:

{
  "oscillators": [
    {
      "wave_shape_index": 3,
      "course_tune": -12,
      "fine_tune": 0,
      "clipper_boost": 0,
      "shape_parameter1": 0,
      "shape_parameter2": 0,
      "pitch_bend": 0,
      "portamento_enabled": true,
      "portamento_time": 27,
      "hard_sync_enabled": false,
      "key_sync_enabled": false,
      "gate_flag": false,
      "pitch_envelope_amount": 0
    },
    {
      "wave_shape_index": 3,
      "course_tune": 0,
      "fine_tune": 0,
      "clipper_boost": 0,
      "shape_parameter1": 0,
      "shape_parameter2": 0,
      "pitch_bend": 0,
      "portamento_enabled": true,
      "portamento_time": 27,
      "hard_sync_enabled": false,
      "key_sync_enabled": false,
      "gate_flag": false,
      "pitch_envelope_amount": 0
    },
    {
      "wave_shape_index": 3,
      "course_tune": 12,
      "fine_tune": 0,
      "clipper_boost": 0,
      "shape_parameter1": 0,
      "shape_parameter2": 0,
      "pitch_bend": 0,
      "portamento_enabled": true,
      "portamento_time": 27,
      "hard_sync_enabled": false,
      "key_sync_enabled": false,
      "gate_flag": false,
      "pitch_envelope_amount": 0
    },
    {
      "wave_shape_index": 0,
      "course_tune": 0,
      "fine_tune": 0,
      "clipper_boost": 0,
      "shape_parameter1": 0,
      "shape_parameter2": 0,
      "pitch_bend": 0,
      "portamento_enabled": false,
      "portamento_time": 7,
      "hard_sync_enabled": false,
      "key_sync_enabled": false,
      "gate_flag": false,
      "pitch_envelope_amount": 0
    }
  ],
  "filter": {
    "cutoff_frequency": 8000,
    "filter_poles": 4,
    "resonance": 0.5,
    "key_tracking_amount": 0.8,
    "current_note_number": 0
  },
  "envelopes": [
    {
      "amount": 1,
      "attack_ms": 50,
      "decay_ms": 300,
      "sustain_level": 0.7,
      "release_ms": 500,
      "is_inverted": false,
      "sustain_pedal": false,
      "gate_flag": 0
    },
    {
      "amount": 1,
      "attack_ms": 10,
      "decay_ms": 200,
      "sustain_level": 0.5,
      "release_ms": 300,
      "is_inverted": false,
      "sustain_pedal": false,
      "gate_flag": 0
    },
    {
      "amount": 0,
      "attack_ms": 1,
      "decay_ms": 200,
      "sustain_level": 0,
      "release_ms": 10,
      "is_inverted": false,
      "sustain_pedal": false,
      "gate_flag": 0
    }
  ],
  "lfos": [
    {
      "wave_shape": 0,
      "frequency": 5,
      "synced_frequency": 0.5,
      "sync_triggered": false,
      "thirty_second_notes": 32,
      "clock_synced": false,
      "key_synced": false,
      "center_value": 1,
      "range": 0,
      "phase": 0,
      "reset": false,
      "gate_flag": false
    },
    {
      "wave_shape": 0,
      "frequency": 0.1,
      "synced_frequency": 0.5,
      "sync_triggered": false,
      "thirty_second_notes": 32,
      "clock_synced": false,
      "key_synced": false,
      "center_value": 0,
      "range": 0,
      "phase": 0,
      "reset": false,
      "gate_flag": false
    }
  ],
  "mixer": {
    "level": 0.8,
    "balance": 0,
    "is_muted": false,
    "quad_mixer_inputs": [
      { "level": 0.3, "balance": -0.3, "mute": false },
      { "level": 1, "balance": 0, "mute": false },
      { "level": 1, "balance": 0.3, "mute": false },
      { "level": 0, "balance": 0, "mute": true }
    ]
  },
  "keyboard": {
    "pitch_bend_range": 12,
    "velocity_curve": 0.5,
    "aftertouch_amount": 0,
    "mod_wheel_amount": 0,
    "polarity_flipped": false
  },
  "effects": [
    { "name": "Saturation", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Colour Compressor", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Wave Folder", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Bit Crusher", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Clipper", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Gate Clipping", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Wave Rectifier", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Chorus", "is_enabled": true, "parameters": [1.0, 0.2, 0.0, 0.3] },
    { "name": "Flanger", "is_enabled": false, "parameters": [0.5,0.0633,0.5,0.5] },
    { "name": "Auto-Pan", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Tremolo", "is_enabled": false, "parameters": [0, 0, 0, 0] },
    { "name": "Delay", "is_enabled": false, "parameters": [0, 0, 0, 0] }
  ],
  "clock": {
    "bpm": 1
  }
}