New Teensy 4.1 DIY Synthesizer

Jeannie with self-made wooden side panels..

20230513-135527.jpg


Case-Metall.jpg


20230516-184103.jpg


20230519-103306-1.jpg


20230516-192917.jpg


20230513-150127.jpg


20230518-200809.jpg


Seite.jpg


20230518-194109.jpg


20230519-081902.jpg


Video: https://youtu.be/0iixKh_5uvA
 
Looks great Rolf! All synt projects need wood side panels. Looks like you color-matched it to your Deepmind as well.

Any recommendations on a (EU) supplier/manufacturer for something similar to that sheet metal enclosure part?
 
@MrCanvas - good experience with Grawart on a short run of 10 custom cases, I used FreeCAD and the SheetMetal workbench to work out a design.
 
[FONT=&quot]There is a virtual midi controller for the Jeannie. I am still working on it...

[/FONT]
The midi controller receives and sends the data via USB. Some functions are too special and can only be programmed or set on the Jeannie.
Now I want to display the prg no. and name when switching. Maybe someone knows how to program the Ctrlr App. For help I would be grateful in any case.


[FONT=&quot]
[/FONT]
Jeannie-Ctrl-1-01.png
 
Hallo Teensy friends..

I would like to implement the Mutable Braids Vowel sound into my Jeannie DIY synthesizer. It sounds very good without pitch modulation. When I turn the pitch wheel up I get distortions in the sound. There seems to be an overflow of increments in the oscillator. I use the Teensy4.1 Audio lib and the AudioSynthWaveformModulated as an oscillator.

Vowel Sound test without pitch modulation. I change parameter_a for vokal and paramter_b for format_shift

Vowel Sound test with pitch modulation..

Vowel Sound with old shruthi core inbuild Jeannie..
Shruthi has only one formant parameter

Thanks for help..


synth_waveform.h
Code:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 
 ElectroTechnique 2020
 Added WAVEFORM_SILENT, sync()                           
 */


#ifndef synth_waveform_h_
#define synth_waveform_h_


#include <Arduino.h>
#include "AudioStream.h"
#include "arm_math.h"




// waveforms.c
extern "C" {
extern const int16_t AudioWaveformSine[257];
}


extern uint8_t LFO1mode;
extern uint8_t LFO2mode;
extern uint8_t LFO3mode;
extern boolean lfo1oneShoot; 
extern boolean lfo2oneShoot;
extern boolean lfo3oneShoot;  
extern uint8_t LFO1phase;
extern uint8_t LFO2phase;
extern uint8_t LFO3phase;
extern uint8_t lfo1ph;
extern uint8_t lfo2ph;
extern uint8_t lfo3ph;
extern int8_t Lfo3Modoutput;
extern boolean LFO1randomFlag;
extern boolean LFO2randomFlag;
extern boolean LFO3randomFlag;
extern uint32_t LFO1delayTime;
extern uint32_t LFO2delayTime;
extern uint32_t LFO3delayTime;
extern uint8_t SupersawSpreadA;
extern uint8_t SupersawSpreadB;
extern float Supersaw_gain1A;
extern float Supersaw_gain2A;
extern float Supersaw_gain1B;
extern float Supersaw_gain2B;
extern uint32_t rng_value32;
extern 


// Oscillator
#define WAVEFORM_SINE                            0
#define WAVEFORM_TRIANGLE                        1
#define WAVEFORM_SAWTOOTH                        3
#define WAVEFORM_SQUARE                            2
#define WAVEFORM_PULSE                            4
#define WAVEFORM_SAWTOOTH_REVERSE                5
#define WAVEFORM_SAMPLE_HOLD                    6
#define WAVEFORM_TRIANGLE_VARIABLE                7
#define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE        8
#define WAVEFORM_BANDLIMIT_SAWTOOTH                9
#define WAVEFORM_BANDLIMIT_SQUARE                10
#define WAVEFORM_BANDLIMIT_PULSE                11
#define WAVEFORM_ARBITRARY                        12
#define WAVEFORM_SAWTOOTH2                        30
#define WAVEFORM_SILENT                            19


// LFO1 (OSC)
#define WAVEFORM_ARBITRARY1                        20
#define WAVEFORM_SAMPLE_HOLD1                    21
#define PWM_WAVEFORM_SINE                        26
#define PWM_WAVEFORM_TRIANGLE                    27
#define PWM_WAVEFORM_SAWTOOTH                    28
#define PWM_WAVEFORM_SQUARE                        29


const uint8_t wav_res_vowel_data[] = {
    27,     40,     89,     15,     13,      1,      0,     18,
    51,     62,     13,     12,      6,      0,     15,     69,
    93,     14,     12,      7,      0,     10,     84,    110,
    13,     10,      8,      0,     23,     44,     87,     15,
    12,      1,      0,     13,     29,     80,     13,      8,
    0,      0,      6,     46,     81,     12,      3,      0,
    0,      9,     51,     95,     15,      3,      0,      3,
    6,     73,     99,      7,      3,     14,      9,
};


const int16_t wav_formant_square[] = {
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,      1,      1,      2,      2,      3,      3,      4,
    4,      5,      6,      8,      9,     11,     13,     16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
    0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
    -4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
};


const int16_t wav_formant_sine[] = {
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      2,      2,      3,      3,      4,      5,      6,
    7,      8,     10,     12,     14,     17,     20,     24,
    0,      3,      4,      5,      6,      7,      9,     10,
    12,     15,     18,     21,     26,     31,     37,     45,
    0,      4,      5,      6,      8,      9,     11,     13,
    16,     19,     23,     28,     34,     40,     49,     58,
    0,      5,      6,      7,      8,     10,     12,     15,
    17,     21,     25,     30,     36,     44,     53,     63,
    0,      4,      5,      6,      8,      9,     11,     13,
    16,     19,     23,     28,     34,     40,     49,     58,
    0,      3,      4,      5,      6,      7,      9,     10,
    12,     15,     18,     21,     26,     31,     37,     45,
    0,      2,      2,      3,      3,      4,      5,      6,
    7,      8,     10,     12,     14,     17,     20,     24,
    0,      0,      0,      0,      0,      0,      0,      0,
    0,      0,      0,      0,      0,      0,      0,      0,
    0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
    -7,     -8,    -10,    -12,    -14,    -17,    -20,    -24,
    0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
    -12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
    0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
    -16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
    0,     -5,     -6,     -7,     -8,    -10,    -12,    -15,
    -17,    -21,    -25,    -30,    -36,    -44,    -53,    -63,
    0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
    -16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
    0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
    -12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
    0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
    -7,     -8,    -10,    -12,    -14,    -17,    -20,    -24,
};


struct PhonemeDefinition {
    uint8_t formant_frequency[3];
    uint8_t formant_amplitude[3];
};


static const PhonemeDefinition vowels_data[9] = {
    { { 27,  40,  89 }, { 15,  13,  1 } },
    { { 18,  51,  62 }, { 13,  12,  6 } },
    { { 15,  69,  93 }, { 14,  12,  7 } },
    { { 10,  84, 110 }, { 13,  10,  8 } },
    { { 23,  44,  87 }, { 15,  12,  1 } },
    { { 13,  29,  80 }, { 13,   8,  0 } },
    { {  6,  46,  81 }, { 12,   3,  0 } },
    { {  9,  51,  95 }, { 15,   3,  0 } },
    { {  6,  73,  99 }, {  7,   3,  14 } }
};


static const PhonemeDefinition consonant_data[8] = {
    { { 6, 54, 121 }, { 9,  9,  0 } },
    { { 18, 50, 51 }, { 12,  10,  5 } },
    { { 11, 24, 70 }, { 13,  8,  0 } },
    { { 15, 69, 74 }, { 14,  12,  7 } },
    { { 16, 37, 111 }, { 14,  8,  1 } },
    { { 18, 51, 62 }, { 14,  12,  6 } },
    { { 6, 26, 81 }, { 5,  5,  5 } },
    { { 6, 73, 99 }, { 7,  10,  14 } },
};


typedef struct step_state
{
  int offset ;
  bool positive ;
} step_state ;




class BandLimitedWaveform
{
public:
  BandLimitedWaveform (void) ;
  int16_t generate_sawtooth (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_square (uint32_t freq_word) ;
  void init_pulse (uint32_t freq_word, uint32_t pulse_width) ;
  


private:
  int32_t lookup (int offset) ;
  void insert_step (int offset, bool rising, int i) ;
  int32_t process_step (int i) ;
  int32_t process_active_steps (uint32_t new_phase) ;
  int32_t process_active_steps_saw (uint32_t new_phase) ;
  int32_t process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width) ;
  void new_step_check_square (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) ;
  
  
  uint32_t phase_word ;
  int32_t dc_offset ;
  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 delptr ;
  int32_t  cyclic[16] ;    // circular buffer of output samples
  bool pulse_state ;
  uint32_t sampled_width ; // pulse width is sampled once per waveform
};




class AudioSynthWaveformTS : public AudioStream
{
public:
  AudioSynthWaveformTS(void) : AudioStream(0,NULL),
    phase_accumulator(0), phase_increment(0), phase_offset(0),
    magnitude(0), pulse_width(0x40000000),
    arbdata(NULL), sample(0), tone_type(WAVEFORM_SINE),
    tone_offset(0),syncFlag(0) {
  }


  void frequency(float freq) {
    if (freq < 0.0) {
      freq = 0.0;
    } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
      freq = AUDIO_SAMPLE_RATE_EXACT / 2;
    }
    phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
    if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
  }
  void phase(float angle) {
    if (angle < 0.0) {
      angle = 0.0;
    } else if (angle > 360.0) {
      angle = angle - 360.0;
      if (angle >= 360.0) return;
    }
    phase_offset = angle * (4294967296.0 / 360.0);
  }
  void sync() {
    syncFlag = 1;
  }       
  void amplitude(float n) { // 0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    magnitude = n * 65536.0;
  }
  void offset(float n) {
    if (n < -1.0) {
      n = -1.0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    tone_offset = n * 32767.0;
  }
  void pulseWidth(float n) {  // 0.0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    pulse_width = n * 4294967296.0;
  }
  void begin(short t_type) {
    phase_offset = 0;
    tone_type = t_type;
    if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
      band_limit_waveform.init_square (phase_increment) ;
    else if (t_type == WAVEFORM_BANDLIMIT_PULSE)
      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) ;
  }
  void begin(float t_amp, float t_freq, short t_type) {
    amplitude(t_amp);
    frequency(t_freq);
    phase_offset = 0;
    begin (t_type);
  }
  void arbitraryWaveform(const int16_t *data, float maxFreq) {
    arbdata = data;
  }
  virtual void update(void);


private:
  uint32_t phase_accumulator;
  uint32_t phase_increment;
  uint32_t phase_offset;
  int32_t  magnitude;
  uint32_t pulse_width;
  const int16_t *arbdata;
  int16_t  sample; // for WAVEFORM_SAMPLE_HOLD
  int16_t  sample2; // for WAVEFORM_SAMPLE_HOLD and oneShot
  short  tone_type;
  int16_t tone_offset;
  int16_t syncFlag;
  BandLimitedWaveform band_limit_waveform;
};




class AudioSynthWaveformModulatedTS : public AudioStream
{
public:
  AudioSynthWaveformModulatedTS(void) : AudioStream(2, inputQueueArray),
    phase_accumulator(0), phase_increment(0), modulation_factor(32768),
    magnitude(0), arbdata(NULL), sample(0), tone_offset(0),
    tone_type(WAVEFORM_SINE), modulation_type(0), syncFlag(0), osc_par_a(0),
    osc_par_b(0)
     {
  }


  void frequency(float freq) {
   freq = freq / 2.0f;    // only for tone_type Vowel
    if (freq < 0.0) {
      freq = 0.0;
    } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
      freq = AUDIO_SAMPLE_RATE_EXACT / 2;
    }
    phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
    //if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
  }
  void amplitude(float n) { // 0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    magnitude = n * 65536.0;
  }
   void sync() {
    syncFlag = 1;
  }              
  void offset(float n) {
    if (n < -1.0) {
      n = -1.0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    tone_offset = n * 32767.0;
  }
  void begin(short t_type) {
    tone_type = t_type;
    if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
      band_limit_waveform.init_square (phase_increment) ;
    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) ;
  }
  void begin(float t_amp, float t_freq, short t_type) {
    amplitude(t_amp);
    frequency(t_freq);
    begin (t_type) ;
  }
  void arbitraryWaveform(const int16_t *data, float maxFreq) {
    arbdata = data;
  }
  void frequencyModulation(float octaves) {
    if (octaves > 12.0) {
      octaves = 12.0;
    } else if (octaves < 0.1) {
      octaves = 0.1;
    }
    modulation_factor = octaves * 4096.0;
    modulation_type = 0;
  }
  void phaseModulation(float degrees) {
    if (degrees > 9000.0) {
      degrees = 9000.0;
    } else if (degrees < 30.0) {
      degrees = 30.0;
    }
    modulation_factor = degrees * (65536.0 / 180.0);
    modulation_type = 1;
  }
  void parameter_a(uint8_t Osc_par_a) {
      osc_par_a = Osc_par_a;
  }
  void parameter_b(uint8_t Osc_par_b) {
      osc_par_b = Osc_par_b;
  }
  virtual void update(void);
  
 
  
private:
  audio_block_t *inputQueueArray[2];
  uint32_t phase_accumulator;
  uint32_t phase_increment;
  uint32_t modulation_factor;
  int32_t  magnitude;
  const int16_t *arbdata;
  uint32_t phasedata[AUDIO_BLOCK_SAMPLES];
  int16_t  sample; // for WAVEFORM_SAMPLE_HOLD
  int16_t  tone_offset;
  uint8_t  tone_type;
  uint8_t  modulation_type;
  int16_t  syncFlag;
  uint32_t data_qs_phase[4];
  uint32_t data_qs_phase_2[4];
  uint8_t Osc_data_cr_decimate;
  uint16_t Osc_data_cr_state;
  uint16_t OscData_sec_phase;
  BandLimitedWaveform band_limit_waveform;
  uint8_t osc_par_a;
  uint8_t osc_par_b;
  uint8_t Osc_vw_update;
  uint32_t state_vow_formant_phase[3];
  uint32_t state_vow_formant_increment[3];
  uint32_t state_vow_formant_amplitude[3];
  boolean strike_;
  uint16_t state_vow_consonant_frames;
  uint32_t state_saw_phase[6];
  uint32_t state_saw_lp;
  uint32_t state_saw_bp;
  uint16_t Osc_vw1_formant_increment[3];
  uint16_t Osc_vw1_formant_amplitude[3];
  uint16_t Osc_vw1_formant_phase[3];
};


synth_waveform.cpp
Code:
/* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
ElectroTechnique 2020
Added WAVEFORM_SILENT, syncFlag
*/


#include <Arduino.h>
#include "synth_waveform.h"
#include "arm_math.h"
#include "utility/dspinst.h"
#include "Entropy.h"




// uncomment for more accurate but more computationally expensive frequency modulation
//#define IMPROVE_EXPONENTIAL_ACCURACY
#define BASE_AMPLITUDE 0x6000  // 0x7fff won't work due to Gibb's phenomenon, so use 3/4 of full range.






void AudioSynthWaveformTS::update(void)
{
    audio_block_t *block;
    int16_t *bp, *end;
    int32_t val1, val2;
    int16_t val3;
    int16_t magnitude15;
    uint32_t i, ph, index, index2, scale;
    const uint32_t inc = phase_increment;
    uint32_t phaseX;
    
    if(syncFlag == 1) {
        phase_accumulator = 0;
        phaseX = 0;
        syncFlag = 0;
        LFO1randomFlag = false;
        LFO2randomFlag = false;
    }
    
    ph = phase_accumulator + phase_offset;
    phaseX = phase_accumulator;
    
    if (magnitude == 0) {
        phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
        return;
    }
    block = allocate();
    if (!block) {
        phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
        return;
    }
    bp = block->data;


    switch(tone_type) {
        
        // PWM SINE
        case PWM_WAVEFORM_SINE:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            index = ph >> 24;
            val1 = AudioWaveformSine[index];
            val2 = AudioWaveformSine[index+1];
            scale = (ph >> 8) & 0xFFFF;
            val2 *= scale;
            val1 *= 0x10000 - scale;
            *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
            ph += inc;
        }
        break;
        
        case PWM_WAVEFORM_TRIANGLE:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            uint32_t phtop = ph >> 30;
            if (phtop == 1 || phtop == 2) {
                *bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16;
                } else {
                *bp++ = (((int32_t)ph >> 15) * magnitude) >> 16;
            }
            ph += inc;
        }
        break;
        
        // PWM SAWTOOTH (LFO offset 0.0f)
        case PWM_WAVEFORM_SAWTOOTH:        // normal sawtooth and inv sawtooth
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            *bp++ = signed_multiply_32x16t(magnitude, ph >> 1);
            ph += inc;
        }
        break;


        
        // PWM SQUARE (LFO offset 1.0)
        case PWM_WAVEFORM_SQUARE:
        magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            //if (ph & 0x80000000) {
            if (ph & 0x80000000) {
                *bp++ = -magnitude15;
                } else {
                *bp++ = magnitude15;
            }
            ph += inc;
        }
        break;
        
        case WAVEFORM_ARBITRARY1:
        if (!arbdata) {
            release(block);
            phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
            return;
        }
        // len = 256
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            index = ph >> 24;
            index2 = index + 1;
            if (LFO1mode == 0) {
                if (index2 >= 256) index2 = 0;  // loop
            }
            else {
                if (index2 >= 256) index2 = 255; // one shot
            }
            val1 = *(arbdata + index);
            val2 = *(arbdata + index2);
            scale = (ph >> 8) & 0xFFFF;
            val2 *= scale;
            val1 *= 0x10000 - scale;
            *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
            uint32_t ph_old = ph;
            uint32_t phaseX_old = phaseX;
            if (LFO1phase == 0) {    // Shape normal
                ph += inc;
                phaseX += inc;
            }
            else {
                ph -= inc;
                phaseX -= inc;        // Shape inverse
            }
            
            if (lfo1oneShoot == true && phaseX < inc) {
                ph = ph_old;
                phaseX = phaseX_old;
            }
        }
        break;


        case WAVEFORM_SAMPLE_HOLD1:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            uint32_t newph = ph + inc;
            if (lfo1oneShoot == true && LFO1randomFlag == false) {    // one shot
                sample = random(magnitude) - (magnitude >> 1);
                sample2 = sample;
                LFO1randomFlag = true;
            }
            else if (newph < ph && lfo1oneShoot == false) {
                sample = random(magnitude) - (magnitude >> 1);
            }
            else if (lfo1oneShoot == true && LFO1randomFlag == true) {
                sample = sample2;
            }
            
            *bp++ = sample;
            ph = newph;
        }
        break;
    
    phase_accumulator = ph - phase_offset;


    if (tone_offset) {
        bp = block->data;
        end = bp + AUDIO_BLOCK_SAMPLES;
        do {
            val1 = *bp;
            *bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0);
        } while (bp < end);
    }
    transmit(block, 0);
    release(block);
}


//--------------------------------------------------------------------------------


void AudioSynthWaveformModulatedTS::update(void)
{
    audio_block_t *block, *moddata, *shapedata;
    int16_t *bp, *end;
    int32_t val1, val2;
    int16_t magnitude15;
    uint32_t i, ph, index, index2, scale, priorphase;
    const uint32_t inc = phase_increment;
    
    moddata = receiveReadOnly(0);
    shapedata = receiveReadOnly(1);


    if(syncFlag==1){
        phase_accumulator = 0;
        syncFlag = 0;
    }
    
    // Pre-compute the phase angle for every output sample of this update
    ph = phase_accumulator;
    priorphase = phasedata[AUDIO_BLOCK_SAMPLES-1];
    if (moddata && modulation_type == 0) {
        // Frequency Modulation
        bp = moddata->data;
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod
            int32_t ipart = n >> 27; // 4 integer bits
            n &= 0x7FFFFFF;          // 27 fractional bits
            #ifdef IMPROVE_EXPONENTIAL_ACCURACY
            // exp2 polynomial suggested by Stefan Stenzel on "music-dsp"
            // mail list, Wed, 3 Sep 2014 10:08:55 +0200
            int32_t x = n << 3;
            n = multiply_accumulate_32x32_rshift32_rounded(5368709  12, x, 1494202713);
            int32_t sq = multiply_32x32_rshift32_rounded(x, x);
            n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615);
            n = n + (multiply_32x32_rshift32_rounded(sq,
            multiply_32x32_rshift32_rounded(x, 1358044250)) << 1);
            n = n << 1;
            #else
            // exp2 algorithm by Laurent de Soras
            // https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html
            n = (n + 134217728) << 3;


            n = multiply_32x32_rshift32_rounded(n, n);
            n = multiply_32x32_rshift32_rounded(n, 715827883) << 3;
            n = n + 715827882;
            #endif
            uint32_t scale = n >> (14 - ipart);
            uint64_t phstep = (uint64_t)inc * scale;
            uint32_t phstep_msw = phstep >> 32;
            if (phstep_msw < 0x7FFE) {
                ph += phstep >> 16;
                } else {
                ph += 0x7FFE0000;
            }
            phasedata[i] = ph;
        }
        release(moddata);
        } else if (moddata) {
        // Phase Modulation
        bp = moddata->data;
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            // more than +/- 180 deg shift by 32 bit overflow of "n"
            uint32_t n = (uint16_t)(*bp++) * modulation_factor;
            phasedata[i] = ph + n;
            ph += inc;
        }
        release(moddata);
        } else {
        // No Modulation Input
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            phasedata[i] = ph;
            ph += inc;
        }
    }
    phase_accumulator = ph;


    //Amplitude is always 1 on TSynth when oscillator is sounding
    //magnitude must be set to zero, otherwise digital noise comes through
    if(tone_type == WAVEFORM_SILENT){
        magnitude  = 0;
        }else{
        magnitude = 65536.0;
    }
    // If the amplitude is zero, no output, but phase still increments properly
    if (magnitude == 0) {
        if (shapedata) release(shapedata);
        return;
    }
    block = allocate();
    if (!block) {
        if (shapedata) release(shapedata);
        return;
    }
    bp = block->data;


    // Now generate the output samples using the pre-computed phase angles
    switch(tone_type) {
        case WAVEFORM_SINE:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            ph = phasedata[i];
            index = ph >> 24;
            val1 = AudioWaveformSine[index];
            val2 = AudioWaveformSine[index+1];
            scale = (ph >> 8) & 0xFFFF;
            val2 *= scale;
            val1 *= 0x10000 - scale;
            *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
        }
        break;


        case WAVEFORM_ARBITRARY:
        if (!arbdata) {
            release(block);
            if (shapedata) release(shapedata);
            return;
        }
        // len = 256
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            ph = phasedata[i];
            index = ph >> 24;
            index2 = index + 1;
            if (index2 >= 256) index2 = 0;
            val1 = *(arbdata + index);
            val2 = *(arbdata + index2);
            scale = (ph >> 8) & 0xFFFF;
            val2 *= scale;
            val1 *= 0x10000 - scale;
            *bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
        }
        break;


        case WAVEFORM_PULSE:
        if (shapedata) {
            magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
            for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
                uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16;
                if (phasedata[i] < width) {
                    *bp++ = magnitude15;
                    } else {
                    *bp++ = -magnitude15;
                }
            }
            break;
        } // else fall through to orginary square without shape modulation


        case WAVEFORM_SQUARE:
        magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            if (phasedata[i] & 0x80000000) {
                *bp++ = -magnitude15;
                } else {
                *bp++ = magnitude15;
            }
        }
        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:
        for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
        {
            int32_t val = band_limit_waveform.generate_square (phasedata[i], i) ;
            *bp++ = (int16_t) ((val * magnitude) >> 16);
        }
        break;
        
        // Vowel ------------------------------------------------
        case WAVEFORM_Vowel
        int16_t parameter_[2];
        uint16_t balance;
        uint8_t vowel_index;
        uint16_t formant_shift;
        parameter_[0] = osc_par_a << 8; // convert parameter into int16 value
        parameter_[1] = osc_par_b << 8; // convert parameter into int16 value
        vowel_index = parameter_[0] >> 12;
        balance = parameter_[0] & 0x0fff;
        formant_shift = (400 + (parameter_[1] >> 5));
        
        if (strike_) {
            strike_ = false;
            state_vow_consonant_frames = 160;
            for (size_t i = 0; i < 3; i++) {
                state_vow_formant_increment[i] = static_cast<uint32_t>(consonant_data[index].formant_frequency[i]) *
                0x1000 * formant_shift;
                state_vow_formant_amplitude[i] = consonant_data[index].formant_amplitude[i];
            }
        }
        if (state_vow_consonant_frames) {
            --state_vow_consonant_frames;
            } else {
            for (size_t i = 0; i < 3; ++i) {
                state_vow_formant_increment[i] = (vowels_data[vowel_index].formant_frequency[i] *
                (0x1000 - balance) + vowels_data[vowel_index + 1].formant_frequency[i] * balance) * formant_shift;
                state_vow_formant_amplitude[i] = (vowels_data[vowel_index].formant_amplitude[i] *
                (0x1000 - balance) + vowels_data[vowel_index + 1].formant_amplitude[i] * balance) >> 12;
            }
        }        
        uint32_t phase_;
                
        for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
            phase_ = phasedata[i];
            size_t phaselet;
            int16_t sample = 0;
            state_vow_formant_phase[0] += state_vow_formant_increment[0];
            phaselet = (state_vow_formant_phase[0] >> 24) & 0xf0;
            sample += wav_formant_sine[phaselet | state_vow_formant_amplitude[0]];
            state_vow_formant_phase[1] += state_vow_formant_increment[1];
            phaselet = (state_vow_formant_phase[1] >> 24) & 0xf0;
            sample += wav_formant_sine[phaselet | state_vow_formant_amplitude[1]];
            state_vow_formant_phase[2] += state_vow_formant_increment[2];
            phaselet = (state_vow_formant_phase[2] >> 24) & 0xf0;
            sample += wav_formant_square[phaselet | state_vow_formant_amplitude[2]];
            sample *= 255 - (phase_ >> 24);
            if (phase_ < phase_increment_) {
                state_vow_formant_phase[0] = 0;
                state_vow_formant_phase[1] = 0;
                state_vow_formant_phase[2] = 0;
                sample = 0;
            }    
            // amplify and soft clip Sound
            int32_t x = (sample * 1.35f);
            int32_t Threshold = 32768;
            float sample_x = (1.0f / Threshold) * x; // convert input into float
            if (sample_x > 1.0f) {
                sample_x = 1.0f;
            }
            if (sample_x < - 1.0f) {
                sample_x = -1.0f;
            }
            sample_x = 1.49f * sample_x - 0.5f * sample_x * sample_x * sample_x;
            x = sample_x * Threshold; // convert float into int
            *bp++ = x;
        }
        break;


        case WAVEFORM_SAWTOOTH_REVERSE:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            *bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, phasedata[i]);
        }
        break;


        case WAVEFORM_BANDLIMIT_SAWTOOTH:
        case WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE:
        for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
        {
            int16_t val = band_limit_waveform.generate_sawtooth (phasedata[i], i) ;
            val = (int16_t) ((val * magnitude) >> 16) ;
            *bp++ = tone_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE ? (int16_t) -val : (int16_t) +val ;
        }
        break;


        case WAVEFORM_TRIANGLE_VARIABLE:
        if (shapedata) {
            for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
                uint32_t width = (shapedata->data[i] + 0x8000) & 0xFFFF;
                uint32_t rise = 0xFFFFFFFF / width;
                uint32_t fall = 0xFFFFFFFF / (0xFFFF - width);
                uint32_t halfwidth = width << 15;
                uint32_t n;
                ph = phasedata[i];
                if (ph < halfwidth) {
                    n = (ph >> 16) * rise;
                    *bp++ = ((n >> 16) * magnitude) >> 16;
                    } else if (ph < 0xFFFFFFFF - halfwidth) {
                    n = 0x7FFFFFFF - (((ph - halfwidth) >> 16) * fall);
                    *bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
                    } else {
                    n = ((ph + halfwidth) >> 16) * rise + 0x80000000;
                    *bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
                }
                ph += inc;
            }
            break;
        } // else fall through to orginary triangle without shape modulation


        case WAVEFORM_TRIANGLE:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            ph = phasedata[i];
            uint32_t phtop = ph >> 30;
            if (phtop == 1 || phtop == 2) {
                *bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16;
                } else {
                *bp++ = (((int32_t)ph >> 15) * magnitude) >> 16;
            }
        }
        break;
        
        case WAVEFORM_SAMPLE_HOLD:
        for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
            ph = phasedata[i];
            if (ph < priorphase) { // does not work for phase modulation
                sample = random(magnitude) - (magnitude >> 1);
            }
            priorphase = ph;
            *bp++ = sample;
        }
        break;
    }


    if (tone_offset) {
        bp = block->data;
        end = bp + AUDIO_BLOCK_SAMPLES;
        do {
            val1 = *bp;
            *bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0);
        } while (bp < end);
    }
    if (shapedata) release(shapedata);
    transmit(block, 0);
    release(block);
}




// BandLimitedWaveform




#define SUPPORT_SHIFT 4
#define SUPPORT (1 << SUPPORT_SHIFT)
#define PTRMASK ((2 << SUPPORT_SHIFT) - 1)


#define SCALE 16
#define SCALE_MASK (SCALE-1)
#define N (SCALE * SUPPORT * 2)


#define GUARD_BITS 8
#define GUARD      (1 << GUARD_BITS)
#define HALF_GUARD (1 << (GUARD_BITS-1))




#define DEG180 0x80000000u


#define PHASE_SCALE (0x100000000L / (2 * BASE_AMPLITUDE))




extern "C"
{
    extern const int16_t bandlimit_step_table [258] ;
}


int32_t BandLimitedWaveform::lookup (int offset)
{
    int off = offset >> GUARD_BITS ;
    int frac = offset & (GUARD-1) ;


    int32_t a, b ;
    if (off < N/2)   // handle odd symmetry by reflecting table
    {
        a = bandlimit_step_table [off+1] ;
        b = bandlimit_step_table [off+2] ;
    }
    else
    {
        a = - bandlimit_step_table [N-off] ;
        b = - bandlimit_step_table [N-off-1] ;
    }
    return  BASE_AMPLITUDE + ((frac * b + (GUARD - frac) * a + HALF_GUARD) >> GUARD_BITS) ; // interpolated
}


// create a new step, apply its past waveform into the cyclic sample buffer
// and add a step_state object into active list so it can be added for the future samples
void BandLimitedWaveform::insert_step (int offset, bool rising, int i)
{
    while (offset <= (N/2-SCALE)<<GUARD_BITS)
    {
        if (offset >= 0)
        cyclic [i & 15] += rising ? lookup (offset) : -lookup (offset) ;
        offset += SCALE<<GUARD_BITS ;
        i ++ ;
    }


    states[newptr].offset = offset ;
    states[newptr].positive = rising ;
    newptr = (newptr+1) & PTRMASK ;
}


// generate value for current sample from one active step, checking for the
// dc_offset adjustment at the end of the table.
int32_t BandLimitedWaveform::process_step (int i)
{
    int off = states[i].offset ;
    bool positive = states[i].positive ;


    int32_t entry = lookup (off) ;
    off += SCALE<<GUARD_BITS ;
    states[i].offset = off ;  // update offset in table for next sample
    if (off >= N<<GUARD_BITS)             // at end of step table we alter dc_offset to extend the step into future
    dc_offset += positive ? 2*BASE_AMPLITUDE : -2*BASE_AMPLITUDE ;


    return positive ? entry : -entry ;
}


// process all active steps for current sample, basically generating the waveform portion
// due only to steps
// square waves use this directly.
int32_t BandLimitedWaveform::process_active_steps (uint32_t new_phase)
{
    int32_t sample = dc_offset ;
    
    int step_count = (newptr - delptr) & PTRMASK ;
    if (step_count > 0)        // for any steps in-flight we sum in table entry and update its state
    {
        int i = newptr ;
        do
        {
            i = (i-1) & PTRMASK ;
            sample += process_step (i) ;
        } while (i != delptr) ;
        if (states[delptr].offset >= N<<GUARD_BITS)  // remove any finished entries from the buffer.
        {
            delptr = (delptr+1) & PTRMASK ;
            // can be upto two steps per sample now for pulses
            if (newptr != delptr && states[delptr].offset >= N<<GUARD_BITS)
            delptr = (delptr+1) & PTRMASK ;
        }
    }
    return sample ;
}


// for sawtooth need to add in the slope and compensate for all the steps being one way
int32_t BandLimitedWaveform::process_active_steps_saw (uint32_t new_phase)
{
    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


    if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, correct dc offset
    dc_offset += 2*BASE_AMPLITUDE ;


    return sample ;
}


// for pulse need to adjust the baseline according to the pulse width to cancel the DC component.
int32_t BandLimitedWaveform::process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width)
{
    int32_t sample = process_active_steps (new_phase) ;


    return sample + BASE_AMPLITUDE/2 - pulse_width / (0x80000000u / BASE_AMPLITUDE) ; // correct DC offset for duty cycle
}


// Check for new steps using the phase update for the current sample for a square wave
void BandLimitedWaveform::new_step_check_square (uint32_t new_phase, int i)
{
    if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step
    {
        int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
        if (offset == SCALE<<GUARD_BITS)
        offset -- ;
        if (pulse_state) // guard against two falling steps in a row (if pulse width changing for instance)
        {
            insert_step (- offset, false, i) ;
            pulse_state = false ;
        }
    }
    else if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, rising step
    {
        int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ;
        if (offset == SCALE<<GUARD_BITS)
        offset -- ;
        if (!pulse_state) // guard against two rising steps in a row (if pulse width changing for instance)
        {
            insert_step (- offset, true, i) ;
            pulse_state = true ;
        }
    }
}


// Checking for new steps for pulse waveform has to deal with changing frequency and pulse width and
// not letting a pulse glitch out of existence as these change across a single period of the waveform
// now we detect the rising edge just like for a square wave and use that to sample the pulse width
// parameter, which then has to be checked against the instantaneous frequency every sample.
void BandLimitedWaveform::new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i)
{
    if (pulse_state && phase_word < sampled_width && (new_phase >= sampled_width || new_phase < phase_word))  // falling edge
    {
        int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
        if (offset == SCALE<<GUARD_BITS)
        offset -- ;
        insert_step (- offset, false, i) ;
        pulse_state = false ;
    }
    if ((!pulse_state) && phase_word >= DEG180 && new_phase < DEG180) // detect wrap around, rising step
    {
        // sample the pulse width value so its not changing under our feet later in cycle due to modulation
        sampled_width = pulse_width ;


        int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ;
        if (offset == SCALE<<GUARD_BITS)
        offset -- ;
        insert_step (- offset, true, i) ;
        pulse_state = true ;
        
        if (pulse_state && new_phase >= sampled_width) // detect falling step directly after a rising edge
        //if (new_phase - sampled_width < DEG180) // detect falling step directly after a rising edge
        {
            int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
            if (offset == SCALE<<GUARD_BITS)
            offset -- ;
            insert_step (- offset, false, i) ;
            pulse_state = false ;
        }
    }
}


// new steps for sawtooth are at 180 degree point, always falling.
void BandLimitedWaveform::new_step_check_saw (uint32_t new_phase, int i)
{
    if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step
    {
        int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (DEG180 - phase_word) / (new_phase - phase_word)) ;
        if (offset == SCALE<<GUARD_BITS)
        offset -- ;
        insert_step (- offset, false, i) ;
    }
}


// the generation function pushd new sample into cyclic buffer, having taken out the oldest entry
// to return.  The output is thus 16 samples behind, which allows the non-casual step function to
// work in real time.
int16_t BandLimitedWaveform::generate_sawtooth (uint32_t new_phase, int i)
{
    new_step_check_saw (new_phase, i) ;
    int32_t val = process_active_steps_saw (new_phase) ;
    int16_t sample = (int16_t) cyclic [i&15] ;
    cyclic [i&15] = val ;
    phase_word = new_phase ;
    return sample ;
}


int16_t BandLimitedWaveform::generate_square (uint32_t new_phase, int i)
{
    new_step_check_square (new_phase, i) ;
    int32_t val = process_active_steps (new_phase) ;
    int16_t sample = (int16_t) cyclic [i&15] ;
    cyclic [i&15] = val ;
    phase_word = new_phase ;
    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_pulse (new_phase, pulse_width) ;
    int32_t sample = cyclic [i&15] ;
    cyclic [i&15] = val ;
    phase_word = new_phase ;
    return (int16_t) ((sample >> 1) - (sample >> 5)) ; // scale down to avoid overflow on narrow pulses, where the DC shift is big
}


void BandLimitedWaveform::init_sawtooth (uint32_t freq_word)
{
    phase_word = 0 ;
    newptr = 0 ;
    delptr = 0 ;
    for (int i = 0 ; i < 2*SUPPORT ; i++)
    phase_word -= freq_word ;
    dc_offset = phase_word < DEG180 ? BASE_AMPLITUDE : -BASE_AMPLITUDE ;
    for (int i = 0 ; i < 2*SUPPORT ; i++)
    {
        uint32_t new_phase = phase_word + freq_word ;
        new_step_check_saw (new_phase, i) ;
        cyclic [i & 15] = (int16_t) process_active_steps_saw (new_phase) ;
        phase_word = new_phase ;
    }
}




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 ;
    sampled_width = pulse_width ;
    newptr = 0 ;
    delptr = 0 ;
    for (int i = 0 ; i < 2*SUPPORT ; i++)
    phase_word -= freq_word ;


    if (phase_word < pulse_width)
    {
        dc_offset = BASE_AMPLITUDE ;
        pulse_state = true ;
    }
    else
    {
        dc_offset = -BASE_AMPLITUDE ;
        pulse_state = false ;
    }
    
    for (int i = 0 ; i < 2*SUPPORT ; i++)
    {
        uint32_t new_phase = phase_word + freq_word ;
        new_step_check_pulse (new_phase, pulse_width, i) ;
        cyclic [i & 15] = (int16_t) process_active_steps_pulse (new_phase, pulse_width) ;
        phase_word = new_phase ;
    }
}


BandLimitedWaveform::BandLimitedWaveform()
{
    newptr = 0 ;
    delptr = 0 ;
    dc_offset = BASE_AMPLITUDE ;
    phase_word = 0 ;
}
 
Last edited:
Result into vowel code..

Code:
if (phase_ < phaseOld_) {
                state_vow_formant_phase[0] = 0;
                state_vow_formant_phase[1] = 0;
                state_vow_formant_phase[2] = 0;
                sample = 0;
            }
            phaseOld_ = phase_;


synth_waveform.h
Code:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 
 ElectroTechnique 2020
 Added WAVEFORM_SILENT, sync()                           
 */


#ifndef synth_waveform_h_
#define synth_waveform_h_


#include <Arduino.h>
#include "AudioStream.h"
#include "arm_math.h"




// waveforms.c
extern "C" {
extern const int16_t AudioWaveformSine[257];
}


//extern int8_t Lfo3Modoutput;




// Oscillator
#define WAVEFORM_SINE							0
#define WAVEFORM_TRIANGLE						1
#define WAVEFORM_SAWTOOTH						3
#define WAVEFORM_SQUARE							2
#define WAVEFORM_PULSE							4
#define WAVEFORM_SAWTOOTH_REVERSE				5
#define WAVEFORM_SAMPLE_HOLD					6
#define WAVEFORM_TRIANGLE_VARIABLE				7
#define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE		8
#define WAVEFORM_BANDLIMIT_SAWTOOTH				9
#define WAVEFORM_BANDLIMIT_SQUARE				10
#define WAVEFORM_BANDLIMIT_PULSE				11
#define WAVEFORM_ARBITRARY						12
#define WAVEFORM_SAWTOOTH2						30
#define WAVEFORM_SILENT							19


// LFO and PWM waveforms
#define LFO_WAVEFORM_ARBITRARY					20
#define LFO_WAVEFORM_SAMPLE_HOLD				21
#define PWM_WAVEFORM_SINE						26
#define PWM_WAVEFORM_TRIANGLE					27
#define PWM_WAVEFORM_SAWTOOTH					28
#define PWM_WAVEFORM_SQUARE						29


/*
const uint8_t wav_res_sine[] {
	 2,      2,      2,      3,      2,      3,      3,      4,
	 5,      4,      7,      5,      9,      7,     10,     11,
	 11,     13,     13,     17,     16,     18,     21,     21,
	 23,     25,     27,     28,     32,     31,     36,     36,
	 39,     41,     43,     46,     48,     51,     53,     55,
	 57,     62,     63,     65,     70,     70,     75,     76,
	 81,     82,     85,     89,     92,     94,     97,    100,
	 104,    107,    109,    112,    116,    119,    122,    124,
	 129,    130,    135,    137,    140,    144,    147,    148,
	 154,    155,    158,    163,    163,    169,    169,    174,
	 177,    178,    182,    185,    187,    191,    192,    195,
	 199,    200,    203,    205,    209,    210,    212,    216,
	 216,    220,    221,    223,    226,    227,    230,    230,
	 233,    235,    235,    239,    238,    241,    242,    243,
	 245,    245,    246,    249,    247,    251,    249,    252,
	 251,    252,    253,    253,    253,    254,    254,    254,
	 253,    255,    254,    253,    253,    254,    252,    253,
	 251,    251,    250,    250,    248,    248,    246,    246,
	 245,    242,    243,    240,    239,    238,    236,    234,
	 233,    231,    230,    226,    226,    224,    221,    219,
	 217,    215,    212,    211,    208,    206,    202,    201,
	 198,    196,    192,    190,    188,    184,    182,    179,
	 177,    173,    170,    168,    164,    162,    158,    156,
	 153,    149,    147,    143,    141,    136,    135,    131,
	 128,    125,    122,    118,    116,    113,    109,    106,
	 104,    101,     96,     95,     92,     88,     85,     83,
	 80,     77,     74,     71,     69,     66,     63,     61,
	 57,     56,     53,     50,     49,     45,     43,     42,
	 38,     37,     35,     32,     31,     29,     26,     26,
	 22,     22,     20,     19,     16,     16,     13,     14,
	 11,     10,     10,      8,      8,      6,      6,      5,
	 4,      5,      2,      4,      2,      2,      2,      3,
	 1
};
*/


const int8_t wav_res_formant_square[256] = {
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16
};


const int8_t wav_res_formant_sine[256] = {
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      2,      2,      3,      3,      4,      5,      6,
	7,      8,     10,     12,     14,     17,     20,     24,
	0,      3,      4,      5,      6,      7,      9,     10,
	12,     15,     18,     21,     26,     31,     37,     45,
	0,      4,      5,      6,      8,      9,     11,     13,
	16,     19,     23,     28,     34,     40,     49,     58,
	0,      5,      6,      7,      8,     10,     12,     15,
	17,     21,     25,     30,     36,     44,     53,     63,
	0,      4,      5,      6,      8,      9,     11,     13,
	16,     19,     23,     28,     34,     40,     49,     58,
	0,      3,      4,      5,      6,      7,      9,     10,
	12,     15,     18,     21,     26,     31,     37,     45,
	0,      2,      2,      3,      3,      4,      5,      6,
	7,      8,     10,     12,     14,     17,     20,     24,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
	-7,     -8,    -10,    -12,    -14,    -17,    -20,    -24,
	0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
	-12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
	0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
	-16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
	0,     -5,     -6,     -7,     -8,    -10,    -12,    -15,
	-17,    -21,    -25,    -30,    -36,    -44,    -53,    -63,
	0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
	-16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
	0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
	-12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
	0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
	-7,     -8,    -10,    -12,    -14,    -17,    -20,    -24
};


const uint16_t wav_res_sine16[] = {
		0,    10,	 39,    88,   157,   245,   352,   479,
	  625,   790,   974,  1178,  1400,  1641,  1901,  2179,
	 2475,  2790,  3122,  3472,  3840,  4225,  4627,  5045,
	 5481,  5932,  6400,  6884,  7382,  7897,  8426,  8969,
     9527, 10098, 10684, 11282, 11893, 12517, 13153, 13800,
    14459, 15129, 15809, 16500, 17200, 17909, 18628, 19355,
    20090, 20832, 21582, 22338, 23100, 23869, 24642, 25421,
    26203, 26990, 27780, 28574, 29369, 30167, 30966, 31767,
    32568, 33369, 34170, 34969, 35768, 36565, 37359, 38151,
    38940, 39724, 40505, 41281, 42052, 42818, 43577, 44330,
    45076, 45815, 46546, 47268, 47982, 48687, 49383, 50068,
    50743, 51408, 52061, 52703, 53332, 53950, 54555, 55147,
    55725, 56290, 56840, 57377, 57898, 58405, 58896, 59372,
    59831, 60275, 60702, 61112, 61506, 61882, 62241, 62582,
    62906, 63211, 63499, 63767, 64018, 64249, 64462, 64656,
    64831, 64987, 65123, 65240, 65338, 65416, 65475, 65514,
    65534, 65534, 65514, 65475, 65416, 65338, 65240, 65123,
    64987, 64831, 64656, 64462, 64249, 64018, 63767, 63499,
    63211, 62906, 62582, 62241, 61882, 61506, 61112, 60702,
    60275, 59831, 59372, 58896, 58405, 57898, 57377, 56840,
    56290, 55725, 55147, 54555, 53950, 53332, 52703, 52061,
    51408, 50743, 50068, 49383, 48687, 47982, 47268, 46546,
    45815, 45076, 44330, 43577, 42818, 42052, 41281, 40505,
    39724, 38940, 38151, 37359, 36565, 35768, 34969, 34170,
    33369, 32568, 31767, 30966, 30167, 29369, 28574, 27780,
    26990, 26203, 25421, 24642, 23869, 23100, 22338, 21582,
    20832, 20090, 19355, 18628, 17909, 17200, 16500, 15809,
    15129, 14459, 13800, 13153, 12517, 11893, 11282, 10684,
    10098,  9527,  8969,  8426,  7897,  7382,  6884,  6400,
     5932,  5481,  5045,  4627,  4225,  3840,  3472,  3122,
     2790,  2475,  2179,  1901,  1641,  1400,  1178,   974,
      790,   625,   479,   352,   245,   157,    88,    39,
	   10
};


const uint8_t wav_res_vowel_data[] = {
	27,     40,     89,     15,     13,      1,      0,     18,
	51,     62,     13,     12,      6,      0,     15,     69,
	93,     14,     12,      7,      0,     10,     84,    110,
	13,     10,      8,      0,     23,     44,     87,     15,
	12,      1,      0,     13,     29,     80,     13,      8,
	0,      0,      6,     46,     81,     12,      3,      0,
	0,      9,     51,     95,     15,      3,      0,      3,
	6,     73,     99,      7,      3,     14,      9,
};


const int16_t wav_formant_square[] = {
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,      1,      1,      2,      2,      3,      3,      4,
	4,      5,      6,      8,      9,     11,     13,     16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
	0,     -1,     -1,     -2,     -2,     -3,     -3,     -4,
	-4,     -5,     -6,     -8,     -9,    -11,    -13,    -16,
};


const int16_t wav_formant_sine[] = {
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      2,      2,      3,      3,      4,      5,      6,
	7,      8,     10,     12,     14,     17,     20,     24,
	0,      3,      4,      5,      6,      7,      9,     10,
	12,     15,     18,     21,     26,     31,     37,     45,
	0,      4,      5,      6,      8,      9,     11,     13,
	16,     19,     23,     28,     34,     40,     49,     58,
	0,      5,      6,      7,      8,     10,     12,     15,
	17,     21,     25,     30,     36,     44,     53,     63,
	0,      4,      5,      6,      8,      9,     11,     13,
	16,     19,     23,     28,     34,     40,     49,     58,
	0,      3,      4,      5,      6,      7,      9,     10,
	12,     15,     18,     21,     26,     31,     37,     45,
	0,      2,      2,      3,      3,      4,      5,      6,
	7,      8,     10,     12,     14,     17,     20,     24,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,      0,      0,      0,      0,      0,      0,      0,
	0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
	-7,     -8,    -10,    -12,    -14,    -17,    -20,    -24,
	0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
	-12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
	0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
	-16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
	0,     -5,     -6,     -7,     -8,    -10,    -12,    -15,
	-17,    -21,    -25,    -30,    -36,    -44,    -53,    -63,
	0,     -4,     -5,     -6,     -8,     -9,    -11,    -13,
	-16,    -19,    -23,    -28,    -34,    -40,    -49,    -58,
	0,     -3,     -4,     -5,     -6,     -7,     -9,    -10,
	-12,    -15,    -18,    -21,    -26,    -31,    -37,    -45,
	0,     -2,     -2,     -3,     -3,     -4,     -5,     -6,
	-7,     -8,    -10,    -12,    -14,    -17,    -20,    -24,
};


struct PhonemeDefinition {
	uint8_t formant_frequency[3];
	uint8_t formant_amplitude[3];
};


static const PhonemeDefinition vowels_data[9] = {
	{ { 27,  40,  89 }, { 15,  13,  1 } },
	{ { 18,  51,  62 }, { 13,  12,  6 } },
	{ { 15,  69,  93 }, { 14,  12,  7 } },
	{ { 10,  84, 110 }, { 13,  10,  8 } },
	{ { 23,  44,  87 }, { 15,  12,  1 } },
	{ { 13,  29,  80 }, { 13,   8,  0 } },
	{ {  6,  46,  81 }, { 12,   3,  0 } },
	{ {  9,  51,  95 }, { 15,   3,  0 } },
	{ {  6,  73,  99 }, {  7,   3,  14 } }
};


static const PhonemeDefinition consonant_data[8] = {
	{ { 6, 54, 121 }, { 9,  9,  0 } },
	{ { 18, 50, 51 }, { 12,  10,  5 } },
	{ { 11, 24, 70 }, { 13,  8,  0 } },
	{ { 15, 69, 74 }, { 14,  12,  7 } },
	{ { 16, 37, 111 }, { 14,  8,  1 } },
	{ { 18, 51, 62 }, { 14,  12,  6 } },
	{ { 6, 26, 81 }, { 5,  5,  5 } },
	{ { 6, 73, 99 }, { 7,  10,  14 } },
};


 static const size_t kNumFormants = 5;
 


typedef struct step_state
{
  int offset ;
  bool positive ;
} step_state ;




class BandLimitedWaveform
{
public:
  BandLimitedWaveform (void) ;
  int16_t generate_sawtooth (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_square (uint32_t freq_word) ;
  void init_pulse (uint32_t freq_word, uint32_t pulse_width) ;
  


private:
  int32_t lookup (int offset) ;
  void insert_step (int offset, bool rising, int i) ;
  int32_t process_step (int i) ;
  int32_t process_active_steps (uint32_t new_phase) ;
  int32_t process_active_steps_saw (uint32_t new_phase) ;
  int32_t process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width) ;
  void new_step_check_square (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) ;
  
  
  uint32_t phase_word ;
  int32_t dc_offset ;
  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 delptr ;
  int32_t  cyclic[16] ;    // circular buffer of output samples
  bool pulse_state ;
  uint32_t sampled_width ; // pulse width is sampled once per waveform
};




class AudioSynthWaveformTS : public AudioStream
{
public:
  AudioSynthWaveformTS(void) : AudioStream(0,NULL),
    phase_accumulator(0), phase_increment(0), phase_offset(0),
    magnitude(0), pulse_width(0x40000000),
    arbdata(NULL), sample(0), tone_type(WAVEFORM_SINE),
    tone_offset(0),syncFlag(0) {
  }


  void frequency(float freq) {
    if (freq < 0.0) {
      freq = 0.0;
    } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
      freq = AUDIO_SAMPLE_RATE_EXACT / 2;
    }
    phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
    if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
  }
  void phase(float angle) {
    if (angle < 0.0) {
      angle = 0.0;
    } else if (angle > 360.0) {
      angle = angle - 360.0;
      if (angle >= 360.0) return;
    }
    phase_offset = angle * (4294967296.0 / 360.0);
  }
  void sync() {
    syncFlag = 1;
  }       
  void amplitude(float n) { // 0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    magnitude = n * 65536.0;
  }
  void offset(float n) {
    if (n < -1.0) {
      n = -1.0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    tone_offset = n * 32767.0;
  }
  void pulseWidth(float n) {  // 0.0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    pulse_width = n * 4294967296.0;
  }
  void begin(short t_type) {
    phase_offset = 0;
    tone_type = t_type;
    if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
      band_limit_waveform.init_square (phase_increment) ;
    else if (t_type == WAVEFORM_BANDLIMIT_PULSE)
      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) ;
  }
  void begin(float t_amp, float t_freq, short t_type) {
    amplitude(t_amp);
    frequency(t_freq);
    phase_offset = 0;
    begin (t_type);
  }
  void arbitraryWaveform(const int16_t *data, float maxFreq) {
    arbdata = data;
  }
  void LFO_mode (uint8_t lfo_Mode) {
	  lfo_mode = lfo_Mode;
  }
  void LFO_phase (uint8_t lfo_Phase) {	// LFO parameter: SYN
	  lfo_phase = lfo_Phase;
  }
  void LFO_oneShoot (boolean lfo_OneShoot) {
	  lfo_oneShoot = lfo_OneShoot;
  }
  
  virtual void update(void);


private:
  uint32_t phase_accumulator;
  uint32_t phase_increment;
  uint32_t phase_offset;
  int32_t  magnitude;
  uint32_t pulse_width;
  const int16_t *arbdata;
  int16_t  sample; // for WAVEFORM_SAMPLE_HOLD
  int16_t  sample2; // for WAVEFORM_SAMPLE_HOLD and oneShot
  short  tone_type;
  int16_t tone_offset;
  int16_t syncFlag;
  BandLimitedWaveform band_limit_waveform;
  uint8_t lfo_mode;
  uint8_t lfo_phase;
  boolean lfo_oneShoot;
  uint8_t lfo1ph;
  boolean lfo_randomFlag;  
};




class AudioSynthWaveformModulatedTS : public AudioStream
{
public:
  AudioSynthWaveformModulatedTS(void) : AudioStream(2, inputQueueArray),
    phase_accumulator(0), phase_increment(0), modulation_factor(32768),
    magnitude(0), arbdata(NULL), sample(0), tone_offset(0),
    tone_type(WAVEFORM_SINE), modulation_type(0), syncFlag(0), osc_par_a(0),
	osc_par_b(0)
	 {
  }


  void frequency(float freq) {
   //freq = freq / 2.0f;	// only for tone_type Vowel
    if (freq < 0.0) {
      freq = 0.0;
    } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
      freq = AUDIO_SAMPLE_RATE_EXACT / 2;
    }
    phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
    if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
  }
  void amplitude(float n) { // 0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    magnitude = n * 65536.0;
  }
   void sync() {
    syncFlag = 1;
  }              
  void offset(float n) {
    if (n < -1.0) {
      n = -1.0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    tone_offset = n * 32767.0;
  }
  void begin(short t_type) {
    tone_type = t_type;
    if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
      band_limit_waveform.init_square (phase_increment) ;
    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) ;
  }
  void begin(float t_amp, float t_freq, short t_type) {
    amplitude(t_amp);
    frequency(t_freq);
    begin (t_type) ;
  }
  void arbitraryWaveform(const int16_t *data, float maxFreq) {
    arbdata = data;
  }
  void frequencyModulation(float octaves) {
    if (octaves > 12.0) {
      octaves = 12.0;
    } else if (octaves < 0.1) {
      octaves = 0.1;
    }
    modulation_factor = octaves * 4096.0;
    modulation_type = 0;
  }
  void phaseModulation(float degrees) {
    if (degrees > 9000.0) {
      degrees = 9000.0;
    } else if (degrees < 30.0) {
      degrees = 30.0;
    }
    modulation_factor = degrees * (65536.0 / 180.0);
    modulation_type = 1;
  }
  void parameter_a(uint8_t Osc_par_a) {
	  osc_par_a = Osc_par_a;
  }
  void parameter_b(uint8_t Osc_par_b) {
	  osc_par_b = Osc_par_b;
  }
  
  virtual void update(void);
  
private:
  audio_block_t *inputQueueArray[2];
  uint32_t phase_accumulator;
  uint32_t phase_increment;
  uint32_t modulation_factor;
  int32_t  magnitude;
  const int16_t *arbdata;
  uint32_t phasedata[AUDIO_BLOCK_SAMPLES];
  int16_t  sample; // for WAVEFORM_SAMPLE_HOLD
  int16_t  tone_offset;
  uint8_t  tone_type;
  uint8_t  modulation_type;
  int16_t  syncFlag;
  uint32_t data_qs_phase[4];
  uint32_t data_qs_phase_2[4];
  uint8_t Osc_data_cr_decimate;
  uint16_t Osc_data_cr_state;
  uint16_t OscData_sec_phase;
  BandLimitedWaveform band_limit_waveform;
  uint8_t osc_par_a;
  uint8_t osc_par_b;
  uint8_t Osc_vw_update;
  uint32_t state_vow_formant_phase[3];
  uint32_t state_vow_formant_increment[3];
  uint32_t state_vow_formant_amplitude[3];
  boolean strike_;
  uint16_t state_vow_consonant_frames;
  uint32_t state_saw_phase[6];
  uint32_t state_saw_lp;
  uint32_t state_saw_bp;
  uint16_t Osc_vw1_formant_increment[3];
  uint16_t Osc_vw1_formant_amplitude[3];
  uint16_t Osc_vw1_formant_phase[3];
  uint32_t phaseOld_= 0;
};


#endif


synth_waveform.cpp
Code:
/* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
ElectroTechnique 2020
Added WAVEFORM_SILENT, syncFlag
R.Degen 2023
Added Supersaw and Mutable instruments Braids digital oscillator
*/


#include <Arduino.h>
#include "synth_waveform.h"
#include "arm_math.h"
#include "utility/dspinst.h"
#include "Entropy.h"




// uncomment for more accurate but more computationally expensive frequency modulation
//#define IMPROVE_EXPONENTIAL_ACCURACY
#define BASE_AMPLITUDE 0x6000  // 0x7fff won't work due to Gibb's phenomenon, so use 3/4 of full range.






void AudioSynthWaveformTS::update(void)
{
	audio_block_t *block;
	int16_t *bp, *end;
	int32_t val1, val2;
	int16_t val3;
	int16_t magnitude15;
	uint32_t i, ph, index, index2, scale;
	const uint32_t inc = phase_increment;
	uint32_t phaseX;
	
	if(syncFlag == 1) {
		phase_accumulator = 0;
		phaseX = 0;
		syncFlag = 0;
		lfo_randomFlag = false;
	}
	
	ph = phase_accumulator + phase_offset;
	phaseX = phase_accumulator;
	
	if (magnitude == 0) {
		phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
		return;
	}
	block = allocate();
	if (!block) {
		phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
		return;
	}
	bp = block->data;


	switch(tone_type) {
		
		// PWM SINE -------------------------------------------------------
		case PWM_WAVEFORM_SINE:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			index = ph >> 24;
			val1 = AudioWaveformSine[index];
			val2 = AudioWaveformSine[index+1];
			scale = (ph >> 8) & 0xFFFF;
			val2 *= scale;
			val1 *= 0x10000 - scale;
			*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
			ph += inc;
		}
		break;
		
		// PWM Triangle ---------------------------------------------------
		case PWM_WAVEFORM_TRIANGLE:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			uint32_t phtop = ph >> 30;
			if (phtop == 1 || phtop == 2) {
				*bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16;
				} else {
				*bp++ = (((int32_t)ph >> 15) * magnitude) >> 16;
			}
			ph += inc;
		}
		break;
		
		// PWM SAWTOOTH ---------------------------------------------------
		case PWM_WAVEFORM_SAWTOOTH:		// normal sawtooth and inv sawtooth
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			*bp++ = signed_multiply_32x16t(magnitude, ph >> 1);
			ph += inc;
		}
		break;


		
		// PWM SQUARE -----------------------------------------------------
		case PWM_WAVEFORM_SQUARE:
		magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			//if (ph & 0x80000000) {
			if (ph & 0x80000000) {
				*bp++ = -magnitude15;
				} else {
				*bp++ = magnitude15;
			}
			ph += inc;
		}
		break;
		
		// LFO Arbitrary waveform -----------------------------------------
		case LFO_WAVEFORM_ARBITRARY:
		uint8_t lfo_mode_;
		uint8_t lfo_phase_;
		boolean lfo_oneShoot_;
		lfo_mode_ = lfo_mode;
		lfo_phase_ = lfo_phase;			// LFO parameter: SYN
		lfo_oneShoot_ = lfo_oneShoot;
		
		if (!arbdata) {
			release(block);
			phase_accumulator += inc * AUDIO_BLOCK_SAMPLES;
			return;
		}
		// len = 256
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			index = ph >> 24;
			index2 = index + 1;
			if (lfo_mode_ == 0) {
				if (index2 >= 256) index2 = 0;		// loop
			}
			else {
				if (index2 >= 256) index2 = 255;	// OneShoot
			}
			val1 = *(arbdata + index);
			val2 = *(arbdata + index2);
			scale = (ph >> 8) & 0xFFFF;
			val2 *= scale;
			val1 *= 0x10000 - scale;
			*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
			uint32_t ph_old = ph;
			uint32_t phaseX_old = phaseX;
			if (lfo_phase_ <= 1) {					// Shape normal
				ph += inc;
				phaseX += inc;
			}
			else {
				ph -= inc;
				phaseX -= inc;						// Shape inverse
			}
			
			if (lfo_oneShoot_ == true && phaseX < inc) {
				ph = ph_old;
				phaseX = phaseX_old;
			}
		}
		break;


		// LFO S&H waveform -----------------------------------------------
		case LFO_WAVEFORM_SAMPLE_HOLD:
		boolean randomFlag_;
		boolean oneShoot_;
		randomFlag_ = lfo_randomFlag;
		oneShoot_ = lfo_oneShoot;
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			uint32_t newph = ph + inc;
			if (oneShoot_ == true && randomFlag_ == false) {	// one shot
				sample = random(magnitude) - (magnitude >> 1);
				sample2 = sample;
				randomFlag_ = true;
			}
			else if (newph < ph && oneShoot_ == false) {
				sample = random(magnitude) - (magnitude >> 1);
			}
			else if (oneShoot_ == true && randomFlag_ == true) {
				sample = sample2;
			}
			
			*bp++ = sample;
			ph = newph;
		}
		lfo_randomFlag = randomFlag_;
		break;
	}
	
	phase_accumulator = ph - phase_offset;


	if (tone_offset) {
		bp = block->data;
		end = bp + AUDIO_BLOCK_SAMPLES;
		do {
			val1 = *bp;
			*bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0);
		} while (bp < end);
	}
	transmit(block, 0);
	release(block);
}


//--------------------------------------------------------------------------------


void AudioSynthWaveformModulatedTS::update(void)
{
	audio_block_t *block, *moddata, *shapedata;
	int16_t *bp, *end;
	int32_t val1, val2;
	int16_t magnitude15;
	uint32_t i, ph, index, index2, scale, priorphase;
	const uint32_t inc = phase_increment;
	uint32_t phase_spread;
	uint32_t saw_phase_increment;
	uint32_t increments[4];
	uint32_t ph_1;
	uint32_t ph_2;
	uint32_t ph_3;
	uint32_t ph_4;
	uint32_t ph_5;
	int32_t Ssaw_value;
	moddata = receiveReadOnly(0);
	shapedata = receiveReadOnly(1);


	if(syncFlag==1){
		phase_accumulator = 0;
		syncFlag = 0;
	}
	
	// Pre-compute the phase angle for every output sample of this update
	ph = phase_accumulator;
	priorphase = phasedata[AUDIO_BLOCK_SAMPLES-1];
	if (moddata && modulation_type == 0) {
		// Frequency Modulation
		bp = moddata->data;
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod
			int32_t ipart = n >> 27; // 4 integer bits
			n &= 0x7FFFFFF;          // 27 fractional bits
			#ifdef IMPROVE_EXPONENTIAL_ACCURACY
			// exp2 polynomial suggested by Stefan Stenzel on "music-dsp"
			// mail list, Wed, 3 Sep 2014 10:08:55 +0200
			int32_t x = n << 3;
			n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713);
			int32_t sq = multiply_32x32_rshift32_rounded(x, x);
			n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615);
			n = n + (multiply_32x32_rshift32_rounded(sq,
			multiply_32x32_rshift32_rounded(x, 1358044250)) << 1);
			n = n << 1;
			#else
			// exp2 algorithm by Laurent de Soras
			// https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html
			n = (n + 134217728) << 3;
			n = multiply_32x32_rshift32_rounded(n, n);
			n = multiply_32x32_rshift32_rounded(n, 715827883) << 3;
			n = n + 715827882;
			#endif
			uint32_t scale = n >> (14 - ipart);
			uint64_t phstep = (uint64_t)inc * scale;
			uint32_t phstep_msw = phstep >> 32;
			if (phstep_msw < 0x7FFE) {
				ph += phstep >> 16;
				} else {
				ph += 0x7FFE0000;
			}
			phasedata[i] = ph;
		}
		
		release(moddata);
		} else if (moddata) {
		// Phase Modulation
		bp = moddata->data;
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			// more than +/- 180 deg shift by 32 bit overflow of "n"
			uint32_t n = (uint16_t)(*bp++) * modulation_factor;
			phasedata[i] = ph + n;
			ph += inc;
		}
		release(moddata);
		} else {
		// No Modulation Input
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			phasedata[i] = ph;
			ph += inc;
		}
	}
	phase_accumulator = ph;


	//Amplitude is always 1 on TSynth when oscillator is sounding
	//magnitude must be set to zero, otherwise digital noise comes through
	if(tone_type == WAVEFORM_SILENT){
		magnitude  = 0;
		}else{
		magnitude = 65536.0;
	}
	// If the amplitude is zero, no output, but phase still increments properly
	if (magnitude == 0) {
		if (shapedata) release(shapedata);
		return;
	}
	block = allocate();
	if (!block) {
		if (shapedata) release(shapedata);
		return;
	}
	bp = block->data;


	// Now generate the output samples using the pre-computed phase angles
	
	switch(tone_type) {
		
		// WaveformModulated Sine -----------------------------------------
		case WAVEFORM_SINE:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			ph = phasedata[i];
			index = ph >> 24;
			val1 = AudioWaveformSine[index];
			val2 = AudioWaveformSine[index+1];
			scale = (ph >> 8) & 0xFFFF;
			val2 *= scale;
			val1 *= 0x10000 - scale;
			*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
		}
		break;


		// WaveformModulated Arbitrary ------------------------------------
		case WAVEFORM_ARBITRARY:
		if (!arbdata) {
			release(block);
			if (shapedata) release(shapedata);
			return;
		}
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			ph = phasedata[i];
			index = ph >> 24;
			index2 = index + 1;
			if (index2 >= 256) index2 = 0;
			val1 = *(arbdata + index);
			val2 = *(arbdata + index2);
			scale = (ph >> 8) & 0xFFFF;
			val2 *= scale;
			val1 *= 0x10000 - scale;
			*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
		}
		break;
		
		// WaveformModulated Pulse ----------------------------------------
		case WAVEFORM_PULSE:
		if (shapedata) {
			magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
			for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
				uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16;
				if (phasedata[i] < width) {
					*bp++ = magnitude15;
					} else {
					*bp++ = -magnitude15;
				}
			}
			break;
		} // else fall through to orginary square without shape modulation


		// WaveformModulated Square ---------------------------------------
		case WAVEFORM_SQUARE:
		magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			if (phasedata[i] & 0x80000000) {
				*bp++ = -magnitude15;
				} else {
				*bp++ = magnitude15;
			}
		}
		break;


		// WaveformModulated Bandlimit Puls -------------------------------
		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


		// WaveformModulated Bandlimit Square -----------------------------
		case WAVEFORM_BANDLIMIT_SQUARE:
		for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
		{
			int32_t val = band_limit_waveform.generate_square (phasedata[i], i) ;
			*bp++ = (int16_t) ((val * magnitude) >> 16);
		}
		break;
		
		// WaveformModulated Supersaw -------------------------------------
		case WAVEFORM_SAWTOOTH:
				
		// Braids vowel ---------------------------------------------------
		int16_t parameter_[2];
		uint16_t balance;
		uint8_t vowel_index;
		uint16_t formant_shift;
		parameter_[0] = osc_par_a << 8; // convert parameter into int16 value
		parameter_[1] = osc_par_b << 8; // convert parameter into int16 value
		vowel_index = parameter_[0] >> 12;
		balance = parameter_[0] & 0x0fff;
		formant_shift = (440 + (parameter_[1] >> 5));
		
		if (strike_) {
			strike_ = false;
			state_vow_consonant_frames = 160;
			for (size_t i = 0; i < 3; i++) {
				state_vow_formant_increment[i] = static_cast<uint32_t>(consonant_data[index].formant_frequency[i]) *
				0x1000 * formant_shift;
				state_vow_formant_amplitude[i] = consonant_data[index].formant_amplitude[i];
			}
		}
		if (state_vow_consonant_frames) {
			--state_vow_consonant_frames;
			} else {
			for (size_t i = 0; i < 3; ++i) {
				state_vow_formant_increment[i] = (vowels_data[vowel_index].formant_frequency[i] *
				(0x1000 - balance) + vowels_data[vowel_index + 1].formant_frequency[i] * balance) * formant_shift;
				state_vow_formant_amplitude[i] = (vowels_data[vowel_index].formant_amplitude[i] *
				(0x1000 - balance) + vowels_data[vowel_index + 1].formant_amplitude[i] * balance) >> 12;
			}
		}
				
		uint32_t phase_;
				
		for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
			phase_ = phasedata[i];
			size_t phaselet;
			int16_t sample = 0;
			state_vow_formant_phase[0] += state_vow_formant_increment[0];
			phaselet = (state_vow_formant_phase[0] >> 24) & 0xf0;
			sample += wav_formant_sine[phaselet | state_vow_formant_amplitude[0]];
			state_vow_formant_phase[1] += state_vow_formant_increment[1];
			phaselet = (state_vow_formant_phase[1] >> 24) & 0xf0;
			sample += wav_formant_sine[phaselet | state_vow_formant_amplitude[1]];
			state_vow_formant_phase[2] += state_vow_formant_increment[2];
			phaselet = (state_vow_formant_phase[2] >> 24) & 0xf0;
			sample += wav_formant_square[phaselet | state_vow_formant_amplitude[2]];
			sample *= 255 - (phase_ >> 24);
			if (phase_ < phaseOld_) {
				state_vow_formant_phase[0] = 0;
				state_vow_formant_phase[1] = 0;
				state_vow_formant_phase[2] = 0;
				sample = 0;
			}
			phaseOld_ = phase_;	
					
			float sample_f;
			sample_f = sample * 1.35f / 32768;
			// a = 1.5*a - 0.5 * a³  //should be converted to fixed point
			sample_f = 1.50f * sample_f - 0.5f * sample_f * sample_f * sample_f; 
			sample = sample_f * 32768;
			*bp++ = (int16_t) ((sample * magnitude) >> 16);			
		}
		break;
	
		
		
		/*
		// Braids VowelFof ------------------------------------------------
		int16_t parameter_[2];
		
		const uint8_t* sync,
		int16_t* buffer,
		size_t size) {


			// The original implementation used FOF but we live in the future and it's
			// less computationally expensive to render a proper bank of 5 SVF.


			int16_t amplitudes[kNumFormants];
			int32_t svf_lp[kNumFormants];
			int32_t svf_bp[kNumFormants];
			int16_t svf_f[kNumFormants];
			
			for (size_t i = 0; i < kNumFormants; ++i) {
				int32_t frequency = InterpolateFormantParameter(
				formant_f_data,
				parameter_[1],
				parameter_[0],
				i) + (12 << 7);
				svf_f[i] = Interpolate824(lut_svf_cutoff, frequency << 17);
				amplitudes[i] = InterpolateFormantParameter(
				formant_a_data,
				parameter_[1],
				parameter_[0],
				i);
				if (init_) {
					svf_lp[i] = 0;
					svf_bp[i] = 0;
					} else {
					svf_lp[i] = state_.fof.svf_lp[i];
					svf_bp[i] = state_.fof.svf_bp[i];
				}
			}
			
			if (init_) {
				init_ = false;
			}
			
			uint32_t phase = phase_;
			int32_t previous_sample = state_.fof.previous_sample;
			int32_t next_saw_sample = state_.fof.next_saw_sample;
			uint32_t increment = phase_increment_ << 1;
			while (size) {
				int32_t this_saw_sample = next_saw_sample;
				next_saw_sample = 0;
				phase += increment;
				if (phase < increment) {
					uint32_t t = phase / (increment >> 16);
					if (t > 65535) {
						t = 65535;
					}
					this_saw_sample -= static_cast<int32_t>(t * t >> 18);
					t = 65535 - t;
					next_saw_sample -= -static_cast<int32_t>(t * t >> 18);
				}
				next_saw_sample += phase >> 17;
				int32_t in = this_saw_sample;
				int32_t out = 0;
				for (int32_t i = 0; i < 5; ++i) {
					int32_t notch = in - (svf_bp[i] >> 6);
					svf_lp[i] += svf_f[i] * svf_bp[i] >> 15;
					CLIP(svf_lp[i])
					int32_t hp = notch - svf_lp[i];
					svf_bp[i] += svf_f[i] * hp >> 15;
					CLIP(svf_bp[i])
					out += svf_bp[i] * amplitudes[0] >> 17;
				}
				CLIP(out);
				*buffer++ = (out + previous_sample) >> 1;
				*buffer++ = out;
				previous_sample = out;
				size -= 2;
			}
			phase_ = phase;
			state_.fof.next_saw_sample = next_saw_sample;
			state_.fof.previous_sample = previous_sample;
			for (size_t i = 0; i < kNumFormants; ++i) {
				state_.fof.svf_lp[i] = svf_lp[i];
				state_.fof.svf_bp[i] = svf_bp[i];
			}
		}
		break;
		*/
		
		
		
		// WaveformModulated Sawtooth reverse -----------------------------
		case WAVEFORM_SAWTOOTH_REVERSE:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			*bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, phasedata[i]);
		}
		break;
		
		// WaveformModulated Bandlimit Sawtooth and Sawtooth reverse ------
		case WAVEFORM_BANDLIMIT_SAWTOOTH:
		case WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE:
		for (i = 0 ; i < AUDIO_BLOCK_SAMPLES ; i++)
		{
			int16_t val = band_limit_waveform.generate_sawtooth (phasedata[i], i) ;
			val = (int16_t) ((val * magnitude) >> 16) ;
			*bp++ = tone_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE ? (int16_t) -val : (int16_t) +val ;
		}
		break;


		// WaveformModulated Variable Triangle (Triangle -> Saw) ----------
		case WAVEFORM_TRIANGLE_VARIABLE:
		if (shapedata) {
			for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
				uint32_t width = (shapedata->data[i] + 0x8000) & 0xFFFF;
				uint32_t rise = 0xFFFFFFFF / width;
				uint32_t fall = 0xFFFFFFFF / (0xFFFF - width);
				uint32_t halfwidth = width << 15;
				uint32_t n;
				ph = phasedata[i];
				if (ph < halfwidth) {
					n = (ph >> 16) * rise;
					*bp++ = ((n >> 16) * magnitude) >> 16;
					} else if (ph < 0xFFFFFFFF - halfwidth) {
					n = 0x7FFFFFFF - (((ph - halfwidth) >> 16) * fall);
					*bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
					} else {
					n = ((ph + halfwidth) >> 16) * rise + 0x80000000;
					*bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
				}
				ph += inc;
			}
			break;
		} // else fall through to orginary triangle without shape modulation


		// WaveformModulated Triangle -------------------------------------
		case WAVEFORM_TRIANGLE:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			ph = phasedata[i];
			uint32_t phtop = ph >> 30;
			if (phtop == 1 || phtop == 2) {
				*bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16;
				} else {
				*bp++ = (((int32_t)ph >> 15) * magnitude) >> 16;
			}
		}
		break;
		
		// WaveformModulated Sample & Hold --------------------------------
		case WAVEFORM_SAMPLE_HOLD:
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			ph = phasedata[i];
			if (ph < priorphase) { // does not work for phase modulation
				sample = random(magnitude) - (magnitude >> 1);
			}
			priorphase = ph;
			*bp++ = sample;
		}
		break;
	}


	if (tone_offset) {
		bp = block->data;
		end = bp + AUDIO_BLOCK_SAMPLES;
		do {
			val1 = *bp;
			*bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0);
		} while (bp < end);
	}
	if (shapedata) release(shapedata);
	transmit(block, 0);
	release(block);
}




// BandLimitedWaveform
#define SUPPORT_SHIFT 4
#define SUPPORT (1 << SUPPORT_SHIFT)
#define PTRMASK ((2 << SUPPORT_SHIFT) - 1)


#define SCALE 16
#define SCALE_MASK (SCALE-1)
#define N (SCALE * SUPPORT * 2)


#define GUARD_BITS 8
#define GUARD      (1 << GUARD_BITS)
#define HALF_GUARD (1 << (GUARD_BITS-1))




#define DEG180 0x80000000u


#define PHASE_SCALE (0x100000000L / (2 * BASE_AMPLITUDE))




extern "C"
{
	extern const int16_t bandlimit_step_table [258] ;
}


int32_t BandLimitedWaveform::lookup (int offset)
{
	int off = offset >> GUARD_BITS ;
	int frac = offset & (GUARD-1) ;


	int32_t a, b ;
	if (off < N/2)   // handle odd symmetry by reflecting table
	{
		a = bandlimit_step_table [off+1] ;
		b = bandlimit_step_table [off+2] ;
	}
	else
	{
		a = - bandlimit_step_table [N-off] ;
		b = - bandlimit_step_table [N-off-1] ;
	}
	return  BASE_AMPLITUDE + ((frac * b + (GUARD - frac) * a + HALF_GUARD) >> GUARD_BITS) ; // interpolated
}


// create a new step, apply its past waveform into the cyclic sample buffer
// and add a step_state object into active list so it can be added for the future samples
void BandLimitedWaveform::insert_step (int offset, bool rising, int i)
{
	while (offset <= (N/2-SCALE)<<GUARD_BITS)
	{
		if (offset >= 0)
		cyclic [i & 15] += rising ? lookup (offset) : -lookup (offset) ;
		offset += SCALE<<GUARD_BITS ;
		i ++ ;
	}


	states[newptr].offset = offset ;
	states[newptr].positive = rising ;
	newptr = (newptr+1) & PTRMASK ;
}


// generate value for current sample from one active step, checking for the
// dc_offset adjustment at the end of the table.
int32_t BandLimitedWaveform::process_step (int i)
{
	int off = states[i].offset ;
	bool positive = states[i].positive ;


	int32_t entry = lookup (off) ;
	off += SCALE<<GUARD_BITS ;
	states[i].offset = off ;  // update offset in table for next sample
	if (off >= N<<GUARD_BITS)             // at end of step table we alter dc_offset to extend the step into future
	dc_offset += positive ? 2*BASE_AMPLITUDE : -2*BASE_AMPLITUDE ;


	return positive ? entry : -entry ;
}


// process all active steps for current sample, basically generating the waveform portion
// due only to steps
// square waves use this directly.
int32_t BandLimitedWaveform::process_active_steps (uint32_t new_phase)
{
	int32_t sample = dc_offset ;
	
	int step_count = (newptr - delptr) & PTRMASK ;
	if (step_count > 0)        // for any steps in-flight we sum in table entry and update its state
	{
		int i = newptr ;
		do
		{
			i = (i-1) & PTRMASK ;
			sample += process_step (i) ;
		} while (i != delptr) ;
		if (states[delptr].offset >= N<<GUARD_BITS)  // remove any finished entries from the buffer.
		{
			delptr = (delptr+1) & PTRMASK ;
			// can be upto two steps per sample now for pulses
			if (newptr != delptr && states[delptr].offset >= N<<GUARD_BITS)
			delptr = (delptr+1) & PTRMASK ;
		}
	}
	return sample ;
}


// for sawtooth need to add in the slope and compensate for all the steps being one way
int32_t BandLimitedWaveform::process_active_steps_saw (uint32_t new_phase)
{
	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


	if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, correct dc offset
	dc_offset += 2*BASE_AMPLITUDE ;


	return sample ;
}


// for pulse need to adjust the baseline according to the pulse width to cancel the DC component.
int32_t BandLimitedWaveform::process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width)
{
	int32_t sample = process_active_steps (new_phase) ;


	return sample + BASE_AMPLITUDE/2 - pulse_width / (0x80000000u / BASE_AMPLITUDE) ; // correct DC offset for duty cycle
}


// Check for new steps using the phase update for the current sample for a square wave
void BandLimitedWaveform::new_step_check_square (uint32_t new_phase, int i)
{
	if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step
	{
		int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
		if (offset == SCALE<<GUARD_BITS)
		offset -- ;
		if (pulse_state) // guard against two falling steps in a row (if pulse width changing for instance)
		{
			insert_step (- offset, false, i) ;
			pulse_state = false ;
		}
	}
	else if (new_phase < DEG180 && phase_word >= DEG180) // detect wrap around, rising step
	{
		int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ;
		if (offset == SCALE<<GUARD_BITS)
		offset -- ;
		if (!pulse_state) // guard against two rising steps in a row (if pulse width changing for instance)
		{
			insert_step (- offset, true, i) ;
			pulse_state = true ;
		}
	}
}


// Checking for new steps for pulse waveform has to deal with changing frequency and pulse width and
// not letting a pulse glitch out of existence as these change across a single period of the waveform
// now we detect the rising edge just like for a square wave and use that to sample the pulse width
// parameter, which then has to be checked against the instantaneous frequency every sample.
void BandLimitedWaveform::new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i)
{
	if (pulse_state && phase_word < sampled_width && (new_phase >= sampled_width || new_phase < phase_word))  // falling edge
	{
		int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
		if (offset == SCALE<<GUARD_BITS)
		offset -- ;
		insert_step (- offset, false, i) ;
		pulse_state = false ;
	}
	if ((!pulse_state) && phase_word >= DEG180 && new_phase < DEG180) // detect wrap around, rising step
	{
		// sample the pulse width value so its not changing under our feet later in cycle due to modulation
		sampled_width = pulse_width ;


		int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (- phase_word) / (new_phase - phase_word)) ;
		if (offset == SCALE<<GUARD_BITS)
		offset -- ;
		insert_step (- offset, true, i) ;
		pulse_state = true ;
		
		if (pulse_state && new_phase >= sampled_width) // detect falling step directly after a rising edge
		//if (new_phase - sampled_width < DEG180) // detect falling step directly after a rising edge
		{
			int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (sampled_width - phase_word) / (new_phase - phase_word)) ;
			if (offset == SCALE<<GUARD_BITS)
			offset -- ;
			insert_step (- offset, false, i) ;
			pulse_state = false ;
		}
	}
}


// new steps for sawtooth are at 180 degree point, always falling.
void BandLimitedWaveform::new_step_check_saw (uint32_t new_phase, int i)
{
	if (new_phase >= DEG180 && phase_word < DEG180) // detect falling step
	{
		int32_t offset = (int32_t) ((uint64_t) (SCALE<<GUARD_BITS) * (DEG180 - phase_word) / (new_phase - phase_word)) ;
		if (offset == SCALE<<GUARD_BITS)
		offset -- ;
		insert_step (- offset, false, i) ;
	}
}


// the generation function pushd new sample into cyclic buffer, having taken out the oldest entry
// to return.  The output is thus 16 samples behind, which allows the non-casual step function to
// work in real time.
int16_t BandLimitedWaveform::generate_sawtooth (uint32_t new_phase, int i)
{
	new_step_check_saw (new_phase, i) ;
	int32_t val = process_active_steps_saw (new_phase) ;
	int16_t sample = (int16_t) cyclic [i&15] ;
	cyclic [i&15] = val ;
	phase_word = new_phase ;
	return sample ;
}


int16_t BandLimitedWaveform::generate_square (uint32_t new_phase, int i)
{
	new_step_check_square (new_phase, i) ;
	int32_t val = process_active_steps (new_phase) ;
	int16_t sample = (int16_t) cyclic [i&15] ;
	cyclic [i&15] = val ;
	phase_word = new_phase ;
	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_pulse (new_phase, pulse_width) ;
	int32_t sample = cyclic [i&15] ;
	cyclic [i&15] = val ;
	phase_word = new_phase ;
	return (int16_t) ((sample >> 1) - (sample >> 5)) ; // scale down to avoid overflow on narrow pulses, where the DC shift is big
}


void BandLimitedWaveform::init_sawtooth (uint32_t freq_word)
{
	phase_word = 0 ;
	newptr = 0 ;
	delptr = 0 ;
	for (int i = 0 ; i < 2*SUPPORT ; i++)
	phase_word -= freq_word ;
	dc_offset = phase_word < DEG180 ? BASE_AMPLITUDE : -BASE_AMPLITUDE ;
	for (int i = 0 ; i < 2*SUPPORT ; i++)
	{
		uint32_t new_phase = phase_word + freq_word ;
		new_step_check_saw (new_phase, i) ;
		cyclic [i & 15] = (int16_t) process_active_steps_saw (new_phase) ;
		phase_word = new_phase ;
	}
}




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 ;
	sampled_width = pulse_width ;
	newptr = 0 ;
	delptr = 0 ;
	for (int i = 0 ; i < 2*SUPPORT ; i++)
	phase_word -= freq_word ;


	if (phase_word < pulse_width)
	{
		dc_offset = BASE_AMPLITUDE ;
		pulse_state = true ;
	}
	else
	{
		dc_offset = -BASE_AMPLITUDE ;
		pulse_state = false ;
	}
	
	for (int i = 0 ; i < 2*SUPPORT ; i++)
	{
		uint32_t new_phase = phase_word + freq_word ;
		new_step_check_pulse (new_phase, pulse_width, i) ;
		cyclic [i & 15] = (int16_t) process_active_steps_pulse (new_phase, pulse_width) ;
		phase_word = new_phase ;
	}
}


BandLimitedWaveform::BandLimitedWaveform()
{
	newptr = 0 ;
	delptr = 0 ;
	dc_offset = BASE_AMPLITUDE ;
	phase_word = 0 ;
}


// Braids Vowel waveform
int16_t InterpolateFormantParameter(
const int16_t table[][kNumFormants][kNumFormants],
int16_t x,
int16_t y,
uint8_t formant) {
	uint16_t x_index = x >> 13;
	uint16_t x_mix = x << 3;
	uint16_t y_index = y >> 13;
	uint16_t y_mix = y << 3;
	int16_t a = table[x_index][y_index][formant];
	int16_t b = table[x_index + 1][y_index][formant];
	int16_t c = table[x_index][y_index + 1][formant];
	int16_t d = table[x_index + 1][y_index + 1][formant];
	a = a + ((b - a) * x_mix >> 16);
	c = c + ((d - c) * x_mix >> 16);
	return a + ((c - a) * y_mix >> 16);
}
 
The next step. I want to modulate the Parameter_A and Parameter_B in the vowel oscillator with a source (LFO or envelope).
 
I programmed AudioSynthWaveformModulated with two additional modulation inputs..
The modulation inputs can be connected to any modulation source (envelope, LFO and more..) in the AudioPatch.h

waveformMod into synth_waveform.cpp
Code:
void AudioSynthWaveformModulatedTS::update(void)
{
	audio_block_t *block, *moddata, *shapedata, *par_A, *par_B;
	//audio_block_t *block, *moddata, *shapedata;
	int16_t *bp, *end, *par_A_mod, *par_B_mod;
	int32_t val1, val2;
	int16_t magnitude15;
	uint32_t i, ph, index, index2, scale, priorphase;
	const uint32_t inc = phase_increment;
	uint32_t phase_spread;
	uint32_t saw_phase_increment;
	uint32_t increments[4];
	uint32_t ph_1;
	uint32_t ph_2;
	uint32_t ph_3;
	uint32_t ph_4;
	uint32_t ph_5;
	int32_t Ssaw_value;
	
	moddata = receiveReadOnly(0);
	shapedata = receiveReadOnly(1);
	par_A = receiveReadOnly(2);			// new parameter_A input
	par_B = receiveReadOnly(3);			// new parameter_B input


	if(syncFlag==1){
		phase_accumulator = 0;
		syncFlag = 0;
	}
	
	// Pre-compute the phase angle for every output sample of this update
	ph = phase_accumulator;
	priorphase = phasedata[AUDIO_BLOCK_SAMPLES-1];
	if (moddata && modulation_type == 0) {
		
		// Frequency Modulation
		bp = moddata->data;
		
		// read two new Modulation parameter from AudioConnection into AudioPatching.h
		par_A_mod = par_A->data;
		par_B_mod = par_B->data;
		
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod
			int32_t ipart = n >> 27; // 4 integer bits
			n &= 0x7FFFFFF;          // 27 fractional bits
			#ifdef IMPROVE_EXPONENTIAL_ACCURACY
			// exp2 polynomial suggested by Stefan Stenzel on "music-dsp"
			// mail list, Wed, 3 Sep 2014 10:08:55 +0200
			int32_t x = n << 3;
			n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713);
			int32_t sq = multiply_32x32_rshift32_rounded(x, x);
			n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615);
			n = n + (multiply_32x32_rshift32_rounded(sq,
			multiply_32x32_rshift32_rounded(x, 1358044250)) << 1);
			n = n << 1;
			#else
			// exp2 algorithm by Laurent de Soras
			// https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html
			n = (n + 134217728) << 3;
			n = multiply_32x32_rshift32_rounded(n, n);
			n = multiply_32x32_rshift32_rounded(n, 715827883) << 3;
			n = n + 715827882;
			#endif
			uint32_t scale = n >> (14 - ipart);
			uint64_t phstep = (uint64_t)inc * scale;
			uint32_t phstep_msw = phstep >> 32;
			if (phstep_msw < 0x7FFE) {
				ph += phstep >> 16;
				} else {
				ph += 0x7FFE0000;
			}
			phasedata[i] = ph;
		}
		release(moddata);
		release(par_A);
		release(par_B);
		par_a_mod_ = *par_A_mod; // save modulation data
		par_b_mod_ = *par_B_mod; // save modulation data
		
		} else if (moddata) {
		// Phase Modulation
		bp = moddata->data;
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			// more than +/- 180 deg shift by 32 bit overflow of "n"
			uint32_t n = (uint16_t)(*bp++) * modulation_factor;
			phasedata[i] = ph + n;
			ph += inc;
		}
		release(moddata);
		} else {
		// No Modulation Input
		for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
			phasedata[i] = ph;
			ph += inc;
		}
	}
	phase_accumulator = ph;
	
	//Amplitude is always 1 on TSynth when oscillator is sounding
	//magnitude must be set to zero, otherwise digital noise comes through
	if(tone_type == WAVEFORM_SILENT){
		magnitude  = 0;
		}else{
		magnitude = 65536.0;
	}
	// If the amplitude is zero, no output, but phase still increments properly
	if (magnitude == 0) {
		if (shapedata) release(shapedata);
		return;
	}
	block = allocate();
	if (!block) {
		if (shapedata) release(shapedata);
		return;
	}
	bp = block->data;


	// Now generate the output samples using the pre-computed phase angles

Synth_waveform.h
Code:
class AudioSynthWaveformModulatedTS : public AudioStream
{
public:
  AudioSynthWaveformModulatedTS(void) : AudioStream(4, inputQueueArray),
    phase_accumulator(0), phase_increment(0), modulation_factor(32768),
    magnitude(0), arbdata(NULL), sample(0), tone_offset(0),
    tone_type(WAVEFORM_SINE), modulation_type(0), syncFlag(0), osc_par_a(0),
    osc_par_b(0), par_a_mod_(0), par_b_mod_(0)
     {
  }
  void frequency(float freq) {
   //freq = freq / 2.0f;    // only for tone_type Vowel
    if (freq < 0.0) {
      freq = 0.0;
    } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
      freq = AUDIO_SAMPLE_RATE_EXACT / 2;
    }
    phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
    if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
  }
  void amplitude(float n) { // 0 to 1.0
    if (n < 0) {
      n = 0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    magnitude = n * 65536.0;
  }
   void sync() {
    syncFlag = 1;
  }              
  void offset(float n) {
    if (n < -1.0) {
      n = -1.0;
    } else if (n > 1.0) {
      n = 1.0;
    }
    tone_offset = n * 32767.0;
  }
  void begin(short t_type) {
    tone_type = t_type;
    if (t_type == WAVEFORM_BANDLIMIT_SQUARE)
      band_limit_waveform.init_square (phase_increment) ;
    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) ;
  }
  void begin(float t_amp, float t_freq, short t_type) {
    amplitude(t_amp);
    frequency(t_freq);
    begin (t_type) ;
  }
  void arbitraryWaveform(const int16_t *data, float maxFreq) {
    arbdata = data;
  }
  void frequencyModulation(float octaves) {
    if (octaves > 12.0) {
      octaves = 12.0;
    } else if (octaves < 0.1) {
      octaves = 0.1;
    }
    modulation_factor = octaves * 4096.0;
    modulation_type = 0;
  }
  void phaseModulation(float degrees) {
    if (degrees > 9000.0) {
      degrees = 9000.0;
    } else if (degrees < 30.0) {
      degrees = 30.0;
    }
    modulation_factor = degrees * (65536.0 / 180.0);
    modulation_type = 1;
  }
  void parameter_a(uint8_t Osc_par_a) {        // parameter_a im Osc Menu
      osc_par_a = Osc_par_a;
  }
  void parameter_b(uint8_t Osc_par_b) {        // parameter_b im Osc Menu
      osc_par_b = Osc_par_b;
  }
  
  virtual void update(void);
  
private:
  audio_block_t *inputQueueArray[4];
  uint32_t phase_accumulator;
  uint32_t phase_increment;
  uint32_t modulation_factor;
  int32_t  magnitude;
  const int16_t *arbdata;
  uint32_t phasedata[AUDIO_BLOCK_SAMPLES];
  int16_t  sample; // for WAVEFORM_SAMPLE_HOLD
  int16_t  tone_offset;
  uint8_t  tone_type;
  uint8_t  modulation_type;
  int16_t  syncFlag;
  uint32_t data_qs_phase[4];
  uint32_t data_qs_phase_2[4];
  uint8_t Osc_data_cr_decimate;
  uint16_t Osc_data_cr_state;
  uint16_t OscData_sec_phase;
  BandLimitedWaveform band_limit_waveform;
  uint8_t osc_par_a;
  uint8_t osc_par_b;
  uint8_t Osc_vw_update;
  uint32_t state_vow_formant_phase[3];
  uint32_t state_vow_formant_increment[3];
  uint32_t state_vow_formant_amplitude[3];
  boolean strike_;
  uint16_t state_vow_consonant_frames;
  uint32_t state_saw_phase[6];
  uint32_t state_saw_lp;
  uint32_t state_saw_bp;
  uint16_t Osc_vw1_formant_increment[3];
  uint16_t Osc_vw1_formant_amplitude[3];
  uint16_t Osc_vw1_formant_phase[3];
  uint32_t phaseOld_= 0;
  uint16_t par_a_mod_;    // vowel parameter_A
  uint16_t par_b_mod_;    // vowel parameter_B
};
 
Last edited:
Next Update coming soon.. and more Braids synthesis

22.10.23​V2.79​Added Braids and Shruthi Synthesis
Braids VOWL : low-fi Vowel synthesis. PRM_A : formant, PRM_B : formant_shift​
Shruthi ZSAW : Phase-distortion sawtooth with filter sweep​
Shruthi ZSYNC :​
Shruthi ZTRI :​
Shruthi ZRESO :​
Shruthi ZPULS :​
Shruthi Chrushed_Sine :​
Braids VOSM : Sawtooth with 2 formants. PRM_A : formant1 frequency, PRM_B : formant2 frequency​
Braids TOY : Low-fi Circuit-bent sounds. PRM_A : sample reduction, PRM_B : bit toggling​
Braids SuperSaw : Swarm of 7 sawtooths, PRM_A: Detune, PRM_B High-pass filter​
Braids ZLPF : Direct synthesis of LP/Peaking/BP/HP filtered waveform​
Braids ZPKF : PRM_A: Cutoff frequency, PRM_B: Waveshape​
Braids ZBPF :​
Braids ZHPF :

Video
Screenshot-2023-10-23-160635.png

https://youtu.be/rIK02G-8oj4

Code on github..
Code.png


Link: https://github.com/rolfdegen/Jeannie-Open-source-Synthesizer

Greetings. Rolf
 
Back
Top