generates a bandlimited sawtooth, nothing else
This commit is contained in:
parent
e14f0ded1a
commit
f0bc568030
|
@ -7,7 +7,7 @@
|
|||
# --------------------------------------------------------------
|
||||
# Project name, used for binaries
|
||||
|
||||
NAME = Nekobi
|
||||
NAME = Nekobi-v8
|
||||
|
||||
# --------------------------------------------------------------
|
||||
# Files to build
|
||||
|
|
|
@ -83,8 +83,7 @@ nekobee_voice_note_on(nekobee_synth_t *synth, nekobee_voice_t *voice,
|
|||
voice->delay4 = 0.0f;
|
||||
voice->c5 = 0.0f;
|
||||
voice->osc_index = 0;
|
||||
voice->osc1.last_waveform = -1;
|
||||
voice->osc1.pos = 0.0f;
|
||||
voice->osc.phase = 0.0f;
|
||||
|
||||
}
|
||||
voice->vca_eg_phase = 0;
|
||||
|
|
|
@ -34,23 +34,6 @@
|
|||
/* maximum size of a rendering burst */
|
||||
#define XSYNTH_NUGGET_SIZE 64
|
||||
|
||||
/* minBLEP constants */
|
||||
/* minBLEP table oversampling factor (must be a power of two): */
|
||||
#define MINBLEP_PHASES 64
|
||||
/* MINBLEP_PHASES minus one: */
|
||||
#define MINBLEP_PHASE_MASK 63
|
||||
/* length in samples of (truncated) step discontinuity delta: */
|
||||
#define STEP_DD_PULSE_LENGTH 72
|
||||
/* length in samples of (truncated) slope discontinuity delta: */
|
||||
#define SLOPE_DD_PULSE_LENGTH 71
|
||||
/* the longer of the two above: */
|
||||
#define LONGEST_DD_PULSE_LENGTH STEP_DD_PULSE_LENGTH
|
||||
/* MINBLEP_BUFFER_LENGTH must be at least XSYNTH_NUGGET_SIZE plus
|
||||
* LONGEST_DD_PULSE_LENGTH, and not less than twice LONGEST_DD_PULSE_LENGTH: */
|
||||
#define MINBLEP_BUFFER_LENGTH 512
|
||||
/* delay between start of DD pulse and the discontinuity, in samples: */
|
||||
#define DD_SAMPLE_DELAY 4
|
||||
|
||||
struct _nekobee_patch_t {
|
||||
float tuning;
|
||||
unsigned char waveform;
|
||||
|
@ -71,12 +54,9 @@ enum nekobee_voice_status {
|
|||
of envelopes */
|
||||
};
|
||||
|
||||
struct blosc {
|
||||
int last_waveform, /* persistent */
|
||||
waveform, /* comes from LADSPA port each cycle */
|
||||
bp_high; /* persistent */
|
||||
float pos, /* persistent */
|
||||
pw; /* comes from LADSPA port each cycle */
|
||||
struct blosc_t {
|
||||
float phase; // 0 - 1, with 1 being 2pi radians of phase rotation
|
||||
float delay; // one sample delay for blep
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -95,11 +75,11 @@ struct _nekobee_voice_t {
|
|||
|
||||
/* persistent voice state */
|
||||
float prev_pitch, target_pitch, lfo_pos;
|
||||
struct blosc osc1;
|
||||
struct blosc_t osc;
|
||||
float vca_eg, vcf_eg, accent_slug, delay1, delay2, delay3, delay4, c5;
|
||||
unsigned char vca_eg_phase, vcf_eg_phase;
|
||||
int osc_index; /* shared index into osc_audio */
|
||||
float osc_audio[MINBLEP_BUFFER_LENGTH];
|
||||
float osc_audio[XSYNTH_NUGGET_SIZE];
|
||||
float freqcut_buf[XSYNTH_NUGGET_SIZE];
|
||||
float vca_buf[XSYNTH_NUGGET_SIZE];
|
||||
};
|
||||
|
@ -112,13 +92,6 @@ struct _nekobee_voice_t {
|
|||
|
||||
extern float nekobee_pitch[128];
|
||||
|
||||
typedef struct {
|
||||
float value, delta;
|
||||
} float_value_delta;
|
||||
extern float_value_delta step_dd_table[];
|
||||
|
||||
extern float slope_dd_table[];
|
||||
|
||||
/* nekobee_voice.c */
|
||||
nekobee_voice_t *nekobee_voice_new();
|
||||
void nekobee_voice_note_on(nekobee_synth_t *synth, nekobee_voice_t *voice,
|
||||
|
@ -147,7 +120,7 @@ void nekobee_voice_render(nekobee_synth_t *synth, float *out,
|
|||
static inline void nekobee_voice_off(nekobee_voice_t *voice) {
|
||||
voice->status = XSYNTH_VOICE_OFF;
|
||||
/* silence the oscillator buffer for the next use */
|
||||
memset(voice->osc_audio, 0, MINBLEP_BUFFER_LENGTH * sizeof(float));
|
||||
memset(voice->osc_audio, 0, XSYNTH_NUGGET_SIZE * sizeof(float));
|
||||
/* -FIX- decrement active voice count? */
|
||||
}
|
||||
|
||||
|
|
|
@ -20,25 +20,93 @@
|
|||
|
||||
// complete rewrite of the voice engine
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nekobee_synth.h"
|
||||
|
||||
// centre oscillator around Middle C
|
||||
// conveniently the middle of the 303's range
|
||||
#define REF_NOTE 60
|
||||
|
||||
float nekobee_pitch[128];
|
||||
float logpot[128];
|
||||
|
||||
void nekobee_init_tables(void) {
|
||||
// create tables used by Nekobee to save on expensive calculations
|
||||
// mostly involving exponentiation!
|
||||
// tables are scaled to 128 values for ease of calculation with MIDI
|
||||
|
||||
// it's worth noting that a real 303 only responds over four octaves
|
||||
// although in theory its DAC could do five
|
||||
|
||||
// it's a bit of a waste defining 128 MIDI notes in the expo scale
|
||||
|
||||
uint8_t i;
|
||||
float x;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
// expo pitch scale (MIDI note number to VCO control current)
|
||||
nekobee_pitch[i] = powf(2, (i - REF_NOTE) / 12.0f);
|
||||
// log pot scale used for volume, decay, cutoff, and env mod
|
||||
// for a range of "0 to 1" scaled to 0-127, gives a log response
|
||||
// with 50% of "pot rotation" giving 15% output
|
||||
x = i / 128.0f; // pot input from 0 to 1
|
||||
logpot[i] = 0.0323 * powf(32, x) - 0.0323;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void vco(nekobee_synth_t *synth, uint32_t count) {
|
||||
// generate a bandlimited oscillator
|
||||
// uses polyblep for bandlimiting
|
||||
// massive and endless thanks to Mystran
|
||||
// https://www.kvraudio.com/forum/viewtopic.php?t=398553
|
||||
|
||||
nekobee_voice_t *voice = synth->voice;
|
||||
blosc_t *osc = &voice->osc;
|
||||
|
||||
uint32_t i;
|
||||
|
||||
float phase = osc->phase; // current running phase 0..1
|
||||
float delay = osc->delay; // delay sample for polyblep
|
||||
float out, t; // output sample, temporary value for blep
|
||||
|
||||
// calculate omega for phase shift
|
||||
float w = nekobee_pitch[voice->key] * 261.63 * synth->deltat;
|
||||
|
||||
// FIXME this only does saws
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
phase += w;
|
||||
out = delay;
|
||||
delay = 0;
|
||||
|
||||
if (phase > 1.0f) {
|
||||
t = (phase - 1) / w;
|
||||
out -= 0.5 * t * t; // other polynomials are available
|
||||
t = 1 - t;
|
||||
delay += 0.5 * t * t;
|
||||
phase -= 1.0f;
|
||||
}
|
||||
delay += phase; // save value for next time
|
||||
voice->osc_audio[i] = 0.5 - out; // save output in buffer, remove DC offset
|
||||
}
|
||||
osc->phase = phase;
|
||||
osc->delay = delay;
|
||||
}
|
||||
|
||||
void nekobee_voice_render(nekobee_synth_t *synth, float *out, uint32_t count) {
|
||||
// generate "count" samples into the buffer at out
|
||||
|
||||
vco(synth, count);
|
||||
|
||||
for(uint32_t i=0; i<count; i++) {
|
||||
out[i] = synth->voice->osc_audio[i];
|
||||
}
|
||||
|
||||
return;
|
||||
(void)synth;
|
||||
(void)out;
|
||||
(void)count;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue