Skip to content

Instantly share code, notes, and snippets.

@boochow
Last active August 13, 2020 12:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boochow/6f0767cc18888152612bbff4085ec6fb to your computer and use it in GitHub Desktop.
Save boochow/6f0767cc18888152612bbff4085ec6fb to your computer and use it in GitHub Desktop.
/*
* File: smplefm.cpp
*
* Simple FM Synthesis
*
*/
#include "userosc.h"
typedef struct State {
float w0;
float phase;
float lfoz;
float mod_int;
float mod_val;
uint8_t flags;
} State;
enum {
k_flags_none = 0,
k_flag_reset = 1<<0,
};
const float modfreq[16] = {1./4, 1./2, 2./3, 1, 4./3, 3./2, 5./3, 2., \
3, 4, 5, 6, 8, 9, 12, 16};
static State s_state;
void OSC_INIT(uint32_t platform, uint32_t api)
{
s_state.w0 = 0.f;
s_state.phase = 0.f;
s_state.lfoz = 0.f;
s_state.mod_int = 0.f;
s_state.mod_val = 1.;
s_state.flags = k_flags_none;
}
__fast_inline float fill_buf(q31_t * __restrict y, const q31_t * y_e, \
float phase, const float w0, float lfo, const float lfo_inc) {
const float mod_val = s_state.mod_val;
const float mod_int = s_state.mod_int;
for (; y != y_e; ) {
float coeff = mod_int + (1 - mod_int) * lfo;
float mod = 1.f - coeff * osc_sinf(phase * mod_val);
float sig = osc_sinf(phase + mod);
*(y++) = f32_to_q31(sig);
phase += w0;
if (phase > 12.0) {phase -= 12;}
lfo += lfo_inc;
}
return phase;
}
void OSC_CYCLE(const user_osc_param_t * const params,
int32_t *yn,
const uint32_t frames)
{
const uint8_t flags = s_state.flags;
s_state.flags = k_flags_none;
float phase = (flags & k_flag_reset) ? 0.f : s_state.phase;
const float w0 = s_state.w0 = osc_w0f_for_note((params->pitch)>>8,
params->pitch & 0xFF);
const float lfo = q31_to_f32(params->shape_lfo);
const float lfo_inc = (lfo - s_state.lfoz) / frames;
s_state.phase = fill_buf((q31_t *) yn, (q31_t *) yn + frames,
phase, w0, s_state.lfoz, lfo_inc);
s_state.lfoz = lfo;
}
void OSC_NOTEON(const user_osc_param_t * const params)
{
s_state.flags |= k_flag_reset;
}
void OSC_NOTEOFF(const user_osc_param_t * const params)
{
(void)params;
}
void OSC_PARAM(uint16_t index, uint16_t value)
{
const float valf = param_val_to_f32(value);
switch (index) {
case k_user_osc_param_id1:
case k_user_osc_param_id2:
case k_user_osc_param_id3:
case k_user_osc_param_id4:
case k_user_osc_param_id5:
case k_user_osc_param_id6:
break;
case k_user_osc_param_shape:
s_state.mod_int = valf;
break;
case k_user_osc_param_shiftshape:
s_state.mod_val = modfreq[value >> 6];
break;
default:
break;
}
}
@boochow
Copy link
Author

boochow commented Aug 10, 2020

SImple FM oscillator for Korg logue SDK.
blog (in Japanese) => https://blog.boochow.com/article/nts1-making-osc-2.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment