#ifndef CONTROL_H
#define CONTROL_H
/**
Control Component
The midi implementation polls the midi device every whenever and gets to
react to midi events. Any and all changes should not happen directly to the
active `value`, but rather to the `mod`. This way the sound engine can
smoothly interpolate the changed value while generating samples.
The sound engine fills a buffer with samples. The buffer has BUFFER_SIZE.
Each call of the sound callback will insert BUFFER_SIZE samples in the
buffer. Before we get the samples, we poll the synth's ccs for any changes.
This will set the target value to the `value + mod`, and the sound engine
will interpolate the `value` from value to target . It should also reset the
mod since other midi events might trigger until the next buffer generation.
*/
typedef struct cc_t {
char name[64];
int midi_cc;
float min, max;
float step;
float def;
float value; /* active value (start for interpolation) */
float mod; /* stores the modified value before it is set as target */
float target; /* target value (end for interpolation) */
} cc_t;
#ifndef CC
#define CC2(NAME, MIN, MAX, STEP, DEF) \
(cc_t) { \
.name = NAME, \
.midi_cc = -1, \
.min = MIN, \
.max = MAX, \
.step = STEP, \
.def = DEF, \
.value = DEF, \
.mod = 0, \
.target = DEF \
};
#define CC(SYNTH, NAME, MIN, MAX, STEP, DEF) \
strcpy(SYNTH.name, NAME); \
SYNTH.midi_cc = -1; \
SYNTH.min = MIN; \
SYNTH.max = MAX; \
SYNTH.step = STEP; \
SYNTH.def = DEF; \
SYNTH.value = DEF; \
SYNTH.mod = 0; \
SYNTH.target = DEF; \
synth->ccs[synth->cci++] = &SYNTH;
#endif
/**
Step the value of the target cc for `steps`.
`steps` can be positive or negative.
The change will occur in the mod value of the cc.
returns 1 if the value changed, 0 otherwise
*/
int cc_step(cc_t *cc, int steps);
/**
Reset the cc to defaults
*/
void cc_reset(cc_t *cc);
/**
Get the interpolated value from 0 to `max` in position `i`
*/
float cc_iget(cc_t *cc, unsigned int i, unsigned int max);
void cc_prep(cc_t *cc);
void cc_fix(cc_t *cc);
const char * cc_to_str(cc_t *cc);
#endif /* CONTROL_H */