Skip to content

Instantly share code, notes, and snippets.

@jpcima
Created June 5, 2018 00:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpcima/bc1abe06d249fe44eb8042a65b849b28 to your computer and use it in GitHub Desktop.
Save jpcima/bc1abe06d249fe44eb8042a65b849b28 to your computer and use it in GitHub Desktop.
#include "osc.h"
#include "utility/arithmetic.h"
#include <math.h>
#pragma message("TODO implement OSC")
namespace cws80 {
// resolution per interval of a semitone
static constexpr uint osc_phi_oversample = 8;
static constexpr uint osc_phi_tablen = 128 * osc_phi_oversample;
Osc::Osc()
: param_(&initial_program().oscs[0]) {
}
void Osc::initialize(f64 fs, uint bs, Osc *other) {
if (other) {
osc_phi_ = other->osc_phi_;
} else {
osc_phi_.reset(new u32[128 * osc_phi_oversample]);
initialize_tables(fs);
}
}
void Osc::setparam(const Param *p) {
param_ = p;
}
void Osc::reset() {
phase_ = 0;
}
void Osc::generate(
i16 *outp, const i8 *syncinp, i8 *syncoutp,
const i8 *modps[2], const i8 modamts[2],
uint key, uint n) {
const Param &P = *param_;
uint waveform = P.WAVEFORM;
const i8 *mod1 = modps[0];
const i8 *mod2 = modps[1];
i8 modamt1 = clamp<i8>(modamts[0], -63, +63);
i8 modamt2 = clamp<i8>(modamts[1], -63, +63);
Waveset waveset = waveset_by_id(waveform);
u8 wavenum = waveset.wavenum[16 * key / 128];
Wave wave = wave_by_id(wavenum);
Sample sample = wave_sample(wave);
// bool oneshot = wave_oneshot(wavenum);
u32 phase = phase_;
const u32 *osc_phi = osc_phi_.get();
for (uint i = 0; i < n; ++i) {
int mod = mod1[i] * modamt1 + mod2[i] * modamt2; // -7938..+7938
mod = mod * 127 / 7938; // -127..127
uint pitch = key * osc_phi_oversample;
#pragma message("TODO OSC semi/fine (wave)")
#pragma message("TODO OSC semi/fine (program)")
#pragma message("TODO OSC pitch mods")
u32 phaseinc = osc_phi[clamp<uint>(pitch, 0, osc_phi_tablen - 1)];
bool syncd = syncinp[i] > 0;
u32 oldphase = phase;
phase = syncd ? 0 : (phase + phaseinc); // aliased sync
bool wrapd = syncd | (phase < oldphase);
syncoutp[i] = wrapd;
int out;
if (false) { // no interpolation
uint index = phase >> (32 - sample.log2length);
out = (int)sample.data[index] * 65534 / 255 - 32767;
} else { // linear interpolation
uint length = 1 << sample.log2length;
uint shift = 32 - sample.log2length;
u32 i0 = phase >> shift;
u32 i1 = (i0 < length - 1) ? (i0 + 1) : 0;
int s0 = (int)sample.data[i0] * 65534 / 255 - 32767;
int s1 = (int)sample.data[i1] * 65534 / 255 - 32767;
uint frac = (phase >> (shift - 16)) & 65535;
out = ix16(s1 * (i32)frac + s0 * (i32)(65536 - frac));
}
syncoutp[i] = wrapd;
outp[i] = out;
}
phase_ = phase;
}
void Osc::initialize_tables(f64 fs) {
u32 *osc_phi = osc_phi_.get();
for (uint i = 0; i < 128; ++i) {
for (uint j = 0, o = osc_phi_oversample; j < o; ++j) {
uint idx = j + i * o;
f64 key = i + (f64)j / o;
f64 freq = 440 * exp2((key - 69) / 12);
f64 rate = freq / fs;
osc_phi[idx] = (u32)(rate * UINT32_MAX);
}
}
}
} // namespace cws80
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment