AtlatestRepositorysigil-dsp

sigil-dsp / tree / src / cfm4.h

1/*
2 * fm4.h - Four-operator phase-modulation FM voice
3 *
4 * DX/OPL-style: four sine operators, an algorithm table that says which
5 * operator modulates which and which operators are carriers, a per-
6 * operator frequency ratio, level and linear ADSR, feedback on operator 4,
7 * and a global modulation index that scales every modulator's depth.
8 *
9 * Everything here is deterministic given the parameters and the sample
10 * rate: the sine comes from a 4096-entry table with linear interpolation
11 * (no libm at run time), so the same inputs produce the same samples on
12 * every target that runs the same float arithmetic.
13 *
14 * Signal-rate inputs (set every sample by the host, motif's render loop):
15 * freq base frequency (Hz)
16 * gate > 0.5 is on; a rising edge resets phases and retriggers
17 * every operator envelope
18 * index global modulation index (0 = every carrier is a pure sine)
19 * velocity 0..1, scales the index through the velocity curve
20 *
21 * Per-operator parameters (set at init or with sp_fm4_set_op):
22 * ratio frequency multiple of `freq` (coarse + fine folded in)
23 * level 0..1 output level (carriers: amplitude; modulators: depth)
24 * a d s r attack / decay / release in seconds, sustain 0..1
25 */
27#ifndef SIGIL_DSP_FM4_H
28#define SIGIL_DSP_FM4_H
30#include "soundpipe.h"
32#define SP_FM4_OPS 4
33#define SP_FM4_ALGORITHMS 8
35typedef struct {
36 SPFLOAT ratio;
37 SPFLOAT level;
38 SPFLOAT attack, decay, sustain, release;
39 /* state */
40 SPFLOAT phase; /* 0..1 */
41 SPFLOAT env; /* current envelope value */
42 int stage; /* 0 idle, 1 attack, 2 decay, 3 sustain, 4 release */
43 SPFLOAT out; /* this sample's output */
44 SPFLOAT out_prev; /* previous sample's output (feedback) */
45 SPFLOAT out_prev2; /* two samples back (feedback averaging) */
46 SPFLOAT rel_rate; /* envelope decrement per sample during release */
47} sp_fm4_op;
49typedef struct sp_fm4 {
50 int algorithm; /* 0..SP_FM4_ALGORITHMS-1 */
51 SPFLOAT feedback; /* 0..1; 1 = pi radians of self-modulation on op 4 */
52 SPFLOAT vel_depth; /* 0..1: how much velocity scales the index */
53 SPFLOAT vel_curve; /* exponent applied to velocity (1 = linear) */
54 sp_fm4_op op[SP_FM4_OPS];
55 int gate_prev;
56 SPFLOAT sr;
57} sp_fm4;
59int sp_fm4_create(sp_fm4 **p);
60int sp_fm4_destroy(sp_fm4 **p);
61/* Defaults: algorithm 0, feedback 0, vel_depth 0, vel_curve 1, every
62 * operator ratio 1 level 1 ADSR 0.005/0.1/1.0/0.1. */
63int sp_fm4_init(sp_data *sp, sp_fm4 *p);
64int sp_fm4_set_algorithm(sp_fm4 *p, int algorithm);
65int sp_fm4_set_op(sp_fm4 *p, int op, SPFLOAT ratio, SPFLOAT level,
66 SPFLOAT attack, SPFLOAT decay, SPFLOAT sustain,
67 SPFLOAT release);
68/* One sample. */
69int sp_fm4_compute(sp_data *sp, sp_fm4 *p, SPFLOAT freq, SPFLOAT gate,
70 SPFLOAT index, SPFLOAT velocity, SPFLOAT *out);
72/* Algorithm table entries: mod_mask[i] is the bitmask of operators that
73 * modulate operator i; carrier_mask is the bitmask of operators summed
74 * into the output. Exposed so hosts can print or validate a table. */
75typedef struct {
76 const char *name;
77 unsigned char mod_mask[SP_FM4_OPS];
78 unsigned char carrier_mask;
79} sp_fm4_algorithm;
81const sp_fm4_algorithm *sp_fm4_algorithm_table(void);
83#endif