From fe2706e1e0ecd91d795a80e63315e9a1f06c38a0 Mon Sep 17 00:00:00 2001 From: Patrick Nilan Date: Fri, 13 Mar 2026 08:25:28 -0700 Subject: [PATCH 1/4] Expand Roland S-1 MIDI CC definition to full 54-parameter spec Add 19 missing CC parameters (mod wheel, pan, expression, damper pedal, LFO mode, chord voice controls, OSC draw/chop controls) and document discrete value mappings via notes fields for 17 switched parameters. --- synths/roland_s1.yaml | 129 +++++++++++++++++++++++++++----------- tests/test_synth_yamls.py | 10 ++- 2 files changed, 102 insertions(+), 37 deletions(-) diff --git a/synths/roland_s1.yaml b/synths/roland_s1.yaml index 6b76b90..7d59c85 100644 --- a/synths/roland_s1.yaml +++ b/synths/roland_s1.yaml @@ -2,11 +2,54 @@ name: S-1 manufacturer: Roland midi_channel: 1 cc_map: - # Oscillator + # ── Controls ────────────────────────────────── + mod_wheel: + cc: 1 + portamento_time: + cc: 5 + pan: + cc: 10 + notes: "64=center" + expression: + cc: 11 + damper_pedal: + cc: 64 + notes: "0-63=off, 64-127=on" + portamento_switch: + cc: 65 + notes: "0-63=off, 64-127=on" + + # ── LFO ─────────────────────────────────────── + lfo_rate: + cc: 3 + lfo_waveform: + cc: 12 + notes: "0-25=triangle, 26-51=sawtooth, 52-76=square, 77-102=random, 103-127=noise" + lfo_mod_depth: + cc: 17 + lfo_mode: + cc: 79 + notes: "0-63=normal, 64-127=fast" + lfo_key_trigger: + cc: 105 + notes: "0-63=off, 64-127=on" + lfo_sync: + cc: 106 + notes: "0-63=off, 64-127=on" + + # ── Oscillator ──────────────────────────────── + osc_lfo_pitch: + cc: 13 osc_range: cc: 14 - osc_range_fine_tune: - cc: 76 + notes: "0-21=64ft, 22-42=32ft, 43-63=16ft, 64-84=8ft, 85-106=4ft, 107-127=2ft" + osc_square_pw: + cc: 15 + osc_pwm_source: + cc: 16 + notes: "0-42=manual, 43-85=LFO, 86-127=envelope" + osc_pitch_bend_sens: + cc: 18 osc_square_level: cc: 19 osc_saw_level: @@ -15,18 +58,17 @@ cc_map: cc: 21 osc_sub_octave_type: cc: 22 + notes: "0-42=-2oct-asym, 43-85=-2oct, 86-127=-1oct" osc_noise_level: cc: 23 - osc_square_pw: - cc: 15 - osc_pwm_source: - cc: 16 - osc_pitch_bend_sens: - cc: 18 + osc_range_fine_tune: + cc: 76 + notes: "64=center" noise_mode: cc: 78 + notes: "0-63=pink, 64-127=white" - # Filter + # ── Filter ──────────────────────────────────── filter_cutoff: cc: 74 filter_resonance: @@ -40,7 +82,7 @@ cc_map: filter_bend_sens: cc: 27 - # Envelope + # ── Envelope ────────────────────────────────── env_attack: cc: 73 env_decay: @@ -49,45 +91,60 @@ cc_map: cc: 30 env_release: cc: 72 - env_mode: + amp_env_mode: cc: 28 + notes: "0-63=gate, 64-127=envelope" env_trigger_mode: cc: 29 + notes: "0-42=LFO, 43-85=gate, 86-127=gate+trig" - # LFO - lfo_rate: - cc: 3 - lfo_waveform: - cc: 12 - lfo_pitch_depth: - cc: 13 - lfo_mod_depth: - cc: 17 - lfo_key_trigger: - cc: 105 - lfo_sync_mode: - cc: 106 - - # Performance - portamento_time: - cc: 5 + # ── Performance ─────────────────────────────── portamento_mode: cc: 31 - portamento_switch: - cc: 65 - polyphony_mode: - cc: 80 + notes: "0-42=off, 43-85=on, 86-127=auto" keyboard_transpose: cc: 77 + notes: "64=center" + polyphony_mode: + cc: 80 + notes: "0-31=mono, 32-63=unison, 64-95=poly, 96-127=chord" + + # ── Chord ───────────────────────────────────── + chord_voice_2_sw: + cc: 81 + notes: "0-63=off, 64-127=on" + chord_voice_3_sw: + cc: 82 + notes: "0-63=off, 64-127=on" + chord_voice_4_sw: + cc: 83 + notes: "0-63=off, 64-127=on" + chord_voice_2_key_shift: + cc: 85 + chord_voice_3_key_shift: + cc: 86 + chord_voice_4_key_shift: + cc: 87 - # Effects + # ── Effects ─────────────────────────────────── reverb_time: cc: 89 - reverb_level: - cc: 91 delay_time: cc: 90 + reverb_level: + cc: 91 delay_level: cc: 92 chorus_type: cc: 93 + + # ── OSC Draw / Chop ────────────────────────── + osc_draw_multiply: + cc: 102 + osc_chop_overtone: + cc: 103 + osc_chop_comb: + cc: 104 + osc_draw_sw: + cc: 107 + notes: "0-63=off, 64-127=on" diff --git a/tests/test_synth_yamls.py b/tests/test_synth_yamls.py index d3b5d8c..132491a 100644 --- a/tests/test_synth_yamls.py +++ b/tests/test_synth_yamls.py @@ -33,8 +33,16 @@ def test_s1_yaml_loads(): assert synth.name == "S-1" assert synth.manufacturer == "Roland" assert synth.midi_channel == 1 - assert "filter_cutoff" in synth.cc_map + assert len(synth.cc_map) == 54 + # Verify core parameters assert synth.cc_map["filter_cutoff"].cc == 74 + assert synth.cc_map["polyphony_mode"].cc == 80 + assert synth.cc_map["polyphony_mode"].notes == "0-31=mono, 32-63=unison, 64-95=poly, 96-127=chord" + # Verify draw/chop section present + assert synth.cc_map["osc_draw_multiply"].cc == 102 + assert synth.cc_map["osc_draw_sw"].cc == 107 + # Verify chord section present + assert synth.cc_map["chord_voice_2_sw"].cc == 81 def test_all_synth_yamls_valid(): From 48900f5a9b0a94e9581fe37e58f4f74bd667760c Mon Sep 17 00:00:00 2001 From: Patrick Nilan Date: Fri, 13 Mar 2026 08:27:05 -0700 Subject: [PATCH 2/4] Fix E501 line too long in S-1 test --- tests/test_synth_yamls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_synth_yamls.py b/tests/test_synth_yamls.py index 132491a..44fb22d 100644 --- a/tests/test_synth_yamls.py +++ b/tests/test_synth_yamls.py @@ -37,7 +37,8 @@ def test_s1_yaml_loads(): # Verify core parameters assert synth.cc_map["filter_cutoff"].cc == 74 assert synth.cc_map["polyphony_mode"].cc == 80 - assert synth.cc_map["polyphony_mode"].notes == "0-31=mono, 32-63=unison, 64-95=poly, 96-127=chord" + expected_notes = "0-31=mono, 32-63=unison, 64-95=poly, 96-127=chord" + assert synth.cc_map["polyphony_mode"].notes == expected_notes # Verify draw/chop section present assert synth.cc_map["osc_draw_multiply"].cc == 102 assert synth.cc_map["osc_draw_sw"].cc == 107 From 4d339ff636a1e63665dcde12894d0852dd50cf14 Mon Sep 17 00:00:00 2001 From: Patrick Nilan Date: Fri, 13 Mar 2026 08:33:57 -0700 Subject: [PATCH 3/4] Fix S-1 spec mismatches from PR review - Default MIDI channel 1 -> 3 per Roland documentation - LFO waveform: add missing inv-sawtooth (6 waveforms, not 5) - osc_draw_sw: three states (off/step/slope), not binary on/off --- synths/roland_s1.yaml | 6 +++--- tests/test_synth_yamls.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/synths/roland_s1.yaml b/synths/roland_s1.yaml index 7d59c85..42069e2 100644 --- a/synths/roland_s1.yaml +++ b/synths/roland_s1.yaml @@ -1,6 +1,6 @@ name: S-1 manufacturer: Roland -midi_channel: 1 +midi_channel: 3 cc_map: # ── Controls ────────────────────────────────── mod_wheel: @@ -24,7 +24,7 @@ cc_map: cc: 3 lfo_waveform: cc: 12 - notes: "0-25=triangle, 26-51=sawtooth, 52-76=square, 77-102=random, 103-127=noise" + notes: "0-21=sawtooth, 22-42=inv-sawtooth, 43-63=triangle, 64-84=square, 85-106=random, 107-127=noise" lfo_mod_depth: cc: 17 lfo_mode: @@ -147,4 +147,4 @@ cc_map: cc: 104 osc_draw_sw: cc: 107 - notes: "0-63=off, 64-127=on" + notes: "0-42=off, 43-85=step, 86-127=slope" diff --git a/tests/test_synth_yamls.py b/tests/test_synth_yamls.py index 44fb22d..eed3b6f 100644 --- a/tests/test_synth_yamls.py +++ b/tests/test_synth_yamls.py @@ -32,7 +32,7 @@ def test_s1_yaml_loads(): synth = SynthDefinition(**data) assert synth.name == "S-1" assert synth.manufacturer == "Roland" - assert synth.midi_channel == 1 + assert synth.midi_channel == 3 assert len(synth.cc_map) == 54 # Verify core parameters assert synth.cc_map["filter_cutoff"].cc == 74 From 1c1c202c311351f8f4e02722e7197582b590225b Mon Sep 17 00:00:00 2001 From: Patrick Nilan Date: Fri, 13 Mar 2026 08:44:22 -0700 Subject: [PATCH 4/4] Set S-1 MIDI channel to 13 --- synths/roland_s1.yaml | 2 +- tests/test_synth_yamls.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/synths/roland_s1.yaml b/synths/roland_s1.yaml index 42069e2..497cf65 100644 --- a/synths/roland_s1.yaml +++ b/synths/roland_s1.yaml @@ -1,6 +1,6 @@ name: S-1 manufacturer: Roland -midi_channel: 3 +midi_channel: 13 cc_map: # ── Controls ────────────────────────────────── mod_wheel: diff --git a/tests/test_synth_yamls.py b/tests/test_synth_yamls.py index eed3b6f..990aa55 100644 --- a/tests/test_synth_yamls.py +++ b/tests/test_synth_yamls.py @@ -32,7 +32,7 @@ def test_s1_yaml_loads(): synth = SynthDefinition(**data) assert synth.name == "S-1" assert synth.manufacturer == "Roland" - assert synth.midi_channel == 3 + assert synth.midi_channel == 13 assert len(synth.cc_map) == 54 # Verify core parameters assert synth.cc_map["filter_cutoff"].cc == 74