Browse Source

Add bandlimited pulse support

dds
mark 4 years ago
parent
commit
1c191983d7
3 changed files with 74 additions and 28 deletions
  1. +1
    -0
      keywords.txt
  2. +49
    -24
      synth_waveform.cpp
  3. +24
    -4
      synth_waveform.h

+ 1
- 0
keywords.txt View File

WAVEFORM_BANDLIMIT_SAWTOOTH LITERAL1 WAVEFORM_BANDLIMIT_SAWTOOTH LITERAL1
WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE LITERAL1 WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE LITERAL1
WAVEFORM_BANDLIMIT_SQUARE LITERAL1 WAVEFORM_BANDLIMIT_SQUARE LITERAL1
WAVEFORM_BANDLIMIT_PULSE LITERAL1


AUDIO_MEMORY_23LC1024 LITERAL1 AUDIO_MEMORY_23LC1024 LITERAL1
AUDIO_MEMORY_MEMORYBOARD LITERAL1 AUDIO_MEMORY_MEMORYBOARD LITERAL1

+ 49
- 24
synth_waveform.cpp View File

} }
break; break;


case WAVEFORM_BANDLIMIT_PULSE:
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++)
{
int32_t new_ph = ph + inc ;
int32_t val = band_limit_waveform.generate_pulse (new_ph, pulse_width, i) ;
*bp++ = (int16_t) ((val * magnitude) >> 16) ;
ph = new_ph ;
}
break;

case WAVEFORM_SAMPLE_HOLD: case WAVEFORM_SAMPLE_HOLD:
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
*bp++ = sample; *bp++ = sample;
} }
break; break;


case WAVEFORM_BANDLIMIT_PULSE:
if (shapedata)
{
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++)
{
uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16;
int32_t val = band_limit_waveform.generate_pulse (phasedata[i], width, i) ;
*bp++ = (int16_t) ((val * magnitude) >> 16) ;
}
break;
} // else fall through to orginary square without shape modulation

case WAVEFORM_BANDLIMIT_SQUARE: case WAVEFORM_BANDLIMIT_SQUARE:
for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++) for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
{ {


int32_t BandLimitedWaveform::process_active_steps_saw (uint32_t new_phase) int32_t BandLimitedWaveform::process_active_steps_saw (uint32_t new_phase)
{ {
int32_t sample = dc_offset ;
int step_count = (newptr - delptr) & PTRMASK ;
if (step_count > 0)
{
int i = newptr ;
do
{
i = (i-1) & PTRMASK ;
sample += process_step (i) ;
} while (i != delptr) ;
if (states[delptr].offset >= N<<GUARD_BITS)
delptr = (delptr+1) & PTRMASK ;
}
int32_t sample = process_active_steps (new_phase) ;


sample += (int16_t) ((((uint64_t)phase_word * (2*BASE_AMPLITUDE)) >> 32) - BASE_AMPLITUDE) ; // generate the sloped part of the wave sample += (int16_t) ((((uint64_t)phase_word * (2*BASE_AMPLITUDE)) >> 32) - BASE_AMPLITUDE) ; // generate the sloped part of the wave


return sample ; return sample ;
} }


void BandLimitedWaveform::new_step_check (uint32_t new_phase, int i)
void BandLimitedWaveform::new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i)
{ {
if (new_phase >= DEG180 && phase_word < DEG180) // detect rising step
if (new_phase >= pulse_width && phase_word < pulse_width) // detect rising step
{ {
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (DEG180 - phase_word) / (new_phase - phase_word)) ;
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (pulse_width - phase_word) / (new_phase - phase_word)) ;
if (offset == SCALE<<GUARD_BITS) if (offset == SCALE<<GUARD_BITS)
offset -- ; offset -- ;
insert_step (- offset, true, i) ; insert_step (- offset, true, i) ;
} }
if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, falling step
if (new_phase < pulse_width && phase_word >= pulse_width) // detect wrap around, falling step
{ {
int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ; int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ;
if (offset == SCALE<<GUARD_BITS) if (offset == SCALE<<GUARD_BITS)
int16_t BandLimitedWaveform::generate_sawtooth (uint32_t new_phase, int i) int16_t BandLimitedWaveform::generate_sawtooth (uint32_t new_phase, int i)
{ {
new_step_check_saw (new_phase, i) ; new_step_check_saw (new_phase, i) ;
uint16_t val = (int16_t) process_active_steps_saw (new_phase) ;
int16_t sample = cyclic [i&15] ;
int32_t val = process_active_steps_saw (new_phase) ;
int16_t sample = (int16_t) cyclic [i&15] ;
cyclic [i&15] = val ; cyclic [i&15] = val ;
phase_word = new_phase ; phase_word = new_phase ;
return sample ; return sample ;


int16_t BandLimitedWaveform::generate_square (uint32_t new_phase, int i) int16_t BandLimitedWaveform::generate_square (uint32_t new_phase, int i)
{ {
new_step_check (new_phase, i) ;
uint16_t val = (int16_t) process_active_steps (new_phase) ;
int16_t sample = cyclic [i&15] ;
new_step_check_pulse (new_phase, DEG180, i) ;
int32_t val = process_active_steps (new_phase) ;
int16_t sample = (int16_t) cyclic [i&15] ;
cyclic [i&15] = val ; cyclic [i&15] = val ;
phase_word = new_phase ; phase_word = new_phase ;
return sample ; return sample ;
} }


int16_t BandLimitedWaveform::generate_pulse (uint32_t new_phase, uint32_t pulse_width, int i)
{
new_step_check_pulse (new_phase, pulse_width, i) ;
int32_t val = process_active_steps (new_phase) ;
int32_t sample = cyclic [i&15] ;
cyclic [i&15] = val ;
phase_word = new_phase ;
return (int16_t) (sample - (sample >> 2)) ; // scale down a bit to avoid overflow on narrow pulses
}

void BandLimitedWaveform::init_sawtooth (uint32_t freq_word) void BandLimitedWaveform::init_sawtooth (uint32_t freq_word)
{ {
phase_word = 0 ; phase_word = 0 ;




void BandLimitedWaveform::init_square (uint32_t freq_word) void BandLimitedWaveform::init_square (uint32_t freq_word)
{
init_pulse (freq_word, DEG180) ;
}

void BandLimitedWaveform::init_pulse (uint32_t freq_word, uint32_t pulse_width)
{ {
phase_word = 0 ; phase_word = 0 ;
newptr = 0 ; newptr = 0 ;
delptr = 0 ; delptr = 0 ;
for (int i = 0 ; i < 2*SUPPORT ; i++) for (int i = 0 ; i < 2*SUPPORT ; i++)
phase_word -= freq_word ; phase_word -= freq_word ;

dc_offset = phase_word < DEG180 ? -BASE_AMPLITUDE : BASE_AMPLITUDE ; dc_offset = phase_word < DEG180 ? -BASE_AMPLITUDE : BASE_AMPLITUDE ;
for (int i = 0 ; i < 2*SUPPORT ; i++) for (int i = 0 ; i < 2*SUPPORT ; i++)
{ {
uint32_t new_phase = phase_word + freq_word ; uint32_t new_phase = phase_word + freq_word ;
new_step_check (new_phase, i) ;
new_step_check_pulse (new_phase, pulse_width, i) ;
cyclic [i & 15] = (int16_t) process_active_steps (new_phase) ; cyclic [i & 15] = (int16_t) process_active_steps (new_phase) ;
phase_word = new_phase ; phase_word = new_phase ;
} }

+ 24
- 4
synth_waveform.h View File

#define WAVEFORM_BANDLIMIT_SAWTOOTH 9 #define WAVEFORM_BANDLIMIT_SAWTOOTH 9
#define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE 10 #define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE 10
#define WAVEFORM_BANDLIMIT_SQUARE 11 #define WAVEFORM_BANDLIMIT_SQUARE 11
#define WAVEFORM_BANDLIMIT_PULSE 12




typedef struct step_state typedef struct step_state
BandLimitedWaveform (void) ; BandLimitedWaveform (void) ;
int16_t generate_sawtooth (uint32_t new_phase, int i) ; int16_t generate_sawtooth (uint32_t new_phase, int i) ;
int16_t generate_square (uint32_t new_phase, int i) ; int16_t generate_square (uint32_t new_phase, int i) ;
int16_t generate_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ;
void init_sawtooth (uint32_t freq_word) ; void init_sawtooth (uint32_t freq_word) ;
void init_square (uint32_t freq_word) ; void init_square (uint32_t freq_word) ;
void init_pulse (uint32_t freq_word, uint32_t pulse_width) ;


private: private:
int32_t process_step (int i) ; int32_t process_step (int i) ;
int32_t process_active_steps (uint32_t new_phase) ; int32_t process_active_steps (uint32_t new_phase) ;
int32_t process_active_steps_saw (uint32_t new_phase) ; int32_t process_active_steps_saw (uint32_t new_phase) ;
void new_step_check (uint32_t new_phase, int i) ;
void new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ;
void new_step_check_saw (uint32_t new_phase, int i) ; void new_step_check_saw (uint32_t new_phase, int i) ;


step_state states [32] ; // circular buffer of active steps step_state states [32] ; // circular buffer of active steps
int newptr ; // buffer pointers into states, AND'd with PTRMASK to keep in buffer range. int newptr ; // buffer pointers into states, AND'd with PTRMASK to keep in buffer range.
int delptr ; int delptr ;
int16_t cyclic[16] ; // circular buffer of output samples
int32_t cyclic[16] ; // circular buffer of output samples
}; };




n = 1.0; n = 1.0;
} }
pulse_width = n * 4294967296.0; pulse_width = n * 4294967296.0;
if (tone_type == WAVEFORM_BANDLIMIT_PULSE)
{
if (pulse_width < phase_increment) // ensure pulse never narrow enough to glitch out of existence.
pulse_width = phase_increment ;
else if (pulse_width > -phase_increment)
pulse_width = -phase_increment;
}
} }
void begin(short t_type) { void begin(short t_type) {
phase_offset = 0; phase_offset = 0;
tone_type = t_type; tone_type = t_type;
if (t_type == WAVEFORM_BANDLIMIT_SQUARE) if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
band_limit_waveform.init_square (phase_increment) ; band_limit_waveform.init_square (phase_increment) ;
if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE)
else if (t_type == WAVEFORM_BANDLIMIT_PULSE)
{
if (pulse_width < phase_increment) // ensure pulse never narrow enough to glitch out of existence.
pulse_width = phase_increment ;
else if (pulse_width > -phase_increment)
pulse_width = -phase_increment;
band_limit_waveform.init_pulse (phase_increment, pulse_width) ;
}
else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE)
band_limit_waveform.init_sawtooth (phase_increment) ; band_limit_waveform.init_sawtooth (phase_increment) ;
} }
void begin(float t_amp, float t_freq, short t_type) { void begin(float t_amp, float t_freq, short t_type) {
tone_type = t_type; tone_type = t_type;
if (t_type == WAVEFORM_BANDLIMIT_SQUARE) if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
band_limit_waveform.init_square (phase_increment) ; band_limit_waveform.init_square (phase_increment) ;
if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE)
else if (t_type == WAVEFORM_BANDLIMIT_PULSE)
band_limit_waveform.init_pulse (phase_increment, 0x80000000u) ;
else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE)
band_limit_waveform.init_sawtooth (phase_increment) ; band_limit_waveform.init_sawtooth (phase_increment) ;
} }
void begin(float t_amp, float t_freq, short t_type) { void begin(float t_amp, float t_freq, short t_type) {

Loading…
Cancel
Save