reaper-jsfx-synth
SKILL.md
REAPER JSFX Synthesis
Patterns for building synthesizers and virtual instruments in JSFX. Covers oscillators, envelopes, polyphony, and MIDI instrument handling.
Requires: reaper-jsfx-core for language fundamentals.
Rules
| Rule | Description |
|---|---|
| oscillators | Anti-aliased oscillators (PolyBLEP), wavetable, FM synthesis |
| envelopes | ADSR, multi-stage envelopes, modulation routing |
| voices | Polyphonic voice management, allocation, stealing |
| midi-instrument | Note handling, pitch bend, mod wheel, aftertouch |
Official Documentation
External References
- Tale's JSFX Libraries - poly_blep, adsr, midi_queue
- PolyBLEP Oscillators
Key Principles
1. Mark as Instrument
desc:My Synthesizer
tags:instrument synthesizer
// For instruments: no audio input, MIDI input expected
in_pin:none
out_pin:left output
out_pin:right output
2. Anti-Alias Oscillators
Naive oscillators create aliasing. Use PolyBLEP or wavetable:
// BAD: Naive saw (aliases)
phase += freq / srate;
phase >= 1 ? phase -= 1;
output = phase * 2 - 1;
// GOOD: PolyBLEP saw (anti-aliased)
phase += freq / srate;
phase >= 1 ? phase -= 1;
output = phase * 2 - 1;
// Apply PolyBLEP correction at discontinuities
t = phase / dt; // Normalized position
t < 1 ? output -= polyblep(t);
3. Sample-Accurate MIDI
For tight timing, process MIDI at sample level:
@block
while(midirecv(offset, msg1, msg2, msg3)) (
// Store event with sample offset
midi_queue_add(offset, msg1, msg2, msg3);
);
@sample
// Check for events at this sample
while(midi_queue_peek(current_sample) >= 0) (
midi_queue_get(msg1, msg2, msg3);
process_midi(msg1, msg2, msg3);
);
current_sample += 1;
4. Efficient Polyphony
Allocate voice arrays once, manage with indexes:
@init
MAX_VOICES = 8;
voice_note = 0;
voice_gate = MAX_VOICES;
voice_env = MAX_VOICES * 2;
// ... allocate all voice state arrays
freembuf(MAX_VOICES * 10); // Total state size
Quick Reference
| Use Case | Rule |
|---|---|
| Saw/Square/Sine oscillators | oscillators |
| ADSR envelope | envelopes |
| Polyphonic synth | voices |
| MIDI note handling | midi-instrument |
Minimal Synth Template
desc:Simple Mono Synth
tags:instrument synthesizer
in_pin:none
out_pin:left output
out_pin:right output
slider1:attack_ms=10<1,1000,1:log>Attack (ms)
slider2:decay_ms=100<1,1000,1:log>Decay (ms)
slider3:sustain=0.7<0,1,0.01>Sustain
slider4:release_ms=200<1,2000,1:log>Release (ms)
@init
note = -1;
gate = 0;
env = 0;
phase = 0;
@slider
attack_coeff = exp(-1 / (attack_ms * srate / 1000));
decay_coeff = exp(-1 / (decay_ms * srate / 1000));
release_coeff = exp(-1 / (release_ms * srate / 1000));
@block
while(midirecv(offset, msg1, msg2, msg3)) (
status = msg1 & $xF0;
status == $x90 && msg3 > 0 ? ( // Note On
note = msg2;
velocity = msg3 / 127;
gate = 1;
freq = 440 * pow(2, (note - 69) / 12);
dt = freq / srate;
) : (status == $x80 || (status == $x90 && msg3 == 0)) && msg2 == note ? (
gate = 0;
);
);
@sample
// Simple saw oscillator
phase += dt;
phase >= 1 ? phase -= 1;
osc = phase * 2 - 1;
// ADSR envelope
gate ? (
env < 1 ? (
env = attack_coeff * env + (1 - attack_coeff);
) : (
env = decay_coeff * env + (1 - decay_coeff) * sustain;
);
) : (
env = release_coeff * env;
);
// Output
output = osc * env * velocity * 0.3;
spl0 = spl1 = output;
Weekly Installs
2
Repository
mthines/jsfx-ag…t-skillsFirst Seen
12 days ago
Security Audits
Installed on
amp2
cline2
opencode2
cursor2
kimi-cli2
codex2