dquenne / midi-psg-fm-synth

Chip-based MIDI-controlled synthesizer
2 stars 0 forks source link

Mod matrix #21

Open dquenne opened 10 months ago

dquenne commented 10 months ago

0180f96e5114827bee42ce121f1a71871f8faa3d introduces some flexible modulation options for FM operators, but (1) isn't very scalable, and (2) adds clutter to voices that don't need this level of modulation. The next sensible step is to convert this to a flexible modulation matrix instead.

A lot of this will probably apply to PSG voices, but that can of worms can be left closed for now. (the fact is, PSG voices have far fewer parameters, so this level of flexibility isn't as important or valuable)

Mod matrix parameters

Parameter Values Notes
Destination see Mod Destinations
Source see Mod Sources
Amount 0 - 127
Center 0 - 1023 Source level that results in zero modulation of the destination
Curve linear; logarithmic; exponential non-MVP

Mod destinations

Destination Notes
Pitch in cents
Carrier operator total levels inverted; all operators that are carriers for the patch's algorithm
Feedback non-MVP
Pitch LFO depth
Patch LFO 1 depth
Patch LFO 2 depth
Per-operator destinations Notes
Total level inverted
AR inverted; non-MVP
DR inverted; non-MVP
SR inverted; non-MVP
RR inverted; non-MVP
SL inverted; non-MVP
MUL inverted; non-MVP
Detune signed (+/- 3)

Mod sources

For convenience, all values will probably be normalized to 1024 (in other words, sources with a range of 128 will have their values multiplied by 8)

Controller Mod Sources Range Notes
Velocity 128
After touch (channel) 128
After touch (polyphonic) 128
Pitch Bend 16384
CC 1 (Mod wheel) 128
CC 7 (Volume) 128
CC 10 (Pan) 128
CC 11 (Expression pedal) 128
CC 16 (Ribbon controller) 128
CC 1-127 128 non-MVP
Internal Mod Sources Range Notes
ENV 1 1024
ENV 2 1024
Pitch LFO 1024 this LFO is always wired to pitch, but can be routed to other mod destinations
Patch LFO 1 1024
Patch LFO 2 1024
Global LFO 1 1024 non-MVP
Global LFO 2 1024 non-MVP
dquenne commented 10 months ago

Proof-of-concept implementation here: 55caa373e9c337a460111abbd71b3422879949a5

Still a lot of legwork required to add the other MVP destinations. Biggest headache is threading all the other patch parameters through FmVoice - right now Synth reads them direction from the patch struct.

Another thing blocking removing the limited FmPatchOperatorScalingConfig is introducing a really simple way to have all carrier operators scaled by velocity. This will essentially be a one-byte parameter that is shorthand for a mod matrix entry that scales carrier operator levels by velocity, because this is such a common use case.