"Complex" Synth question -- Using a global LFO with multiple voices

Status
Not open for further replies.

Tombot7

Active member
Hi!

I'm adapting SimpleSynth and adding LFOs that are global and outside the voices.

Part of this is so I can learn more about object-oriented programming, which I am new to.

Here is the LFO class, which works. I have been able to grab its output from the main program and spit it out the headphones just fine. (this way of grabbing output is also how the main program gets the output of each voice).

Code:
 class LFO_OSC{  
  
private: 
  AudioSynthWaveform   *LFO;
  public:
    LFO_OSC(); // constructor
    float FREQ;
    void SET_FREQ(float Amnt);
    AudioSynthWaveform * getOutput (); 
         //  AudioConnection *patches[1];
    };

inline LFO_OSC::LFO_OSC (){ // constructor
Serial.println ("Started constructing an LFO");
 this->LFO = new AudioSynthWaveform ();
  this->LFO->begin(WAVEFORM_TRIANGLE);
  this->LFO->frequency(0);
  this->LFO->amplitude(1);
  this->FREQ=0;
}

void LFO_OSC::SET_FREQ(float Amnt){
this->LFO->frequency ((Amnt *10) * (Amnt *10)*10);  //100*10=1000 max
};

inline AudioSynthWaveform * LFO_OSC::getOutput(){
  return this->LFO;
};

However, I am not able to take pull the LFO output into the Voices themselves. This has something to do with objects in one class not being able to call objects from another class, but I don't know a good solution.

Here is the relevant portion of the voice code that does not work:

Code:
class Voice{
}

// constructor

Voice::Voice(){

this->patchCords[0] = new AudioConnection (*lfos[0].getOutput(), 0, *this->output, 0);

}

I'm open to any possible solution. My thoughts on possibilities are:

- Making the LFO output somehow more global, so that it can be seen by other objects belonging to other classes (such as Voice)
- Making an overarching class somehow that both voice and LFO are a part of so they can share the LFO audio stream
- Creating a voice INPUTS inside the voice class, and then hooking up the LFO to each voice object inside main

I don't know how to do any of the above and don't know if they are feasible. Any insight would be appreciated.

I'm having a hell of a time understanding pointers, inheritance, etc.

Thank you!
 
Put a simpler way, how can I send audio TO an object?

I can make objects (like voices) that output audio to be mixed elsewhere, but how can those voices receive audio?

Thank you!
 
have you seen my new Design Tool
that takes care of everything for you,

https://manicken.github.io/

but if you don't want to use that you can learn
from the export.

here is a simple approach
generated direct from that tool:
Code:
#include <Arduino.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// TeensyAudioDesign: begin automatically generated code
// the following JSON string contains the whole project, 
// it's included in all generated files.
// JSON string:[{"type":"settings","data":{"arduino":{"Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{}}},{"type":"tab","id":"c5a4e10e.36e74","label":"Voice","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{},"nodes":[{"id":"Voice_In1","type":"TabInput","name":"In","comment":"","x":67,"y":150,"z":"c5a4e10e.36e74","bgColor":"#cce6ff","wires":[["Voice_waveformMod1:0"]]},{"id":"Voice_waveformMod1","type":"AudioSynthWaveformModulated","name":"waveformMod","comment":"","x":200,"y":156,"z":"c5a4e10e.36e74","bgColor":"#E6E0F8","wires":[["Voice_Out1:0"]]},{"id":"Voice_Out1","type":"TabOutput","name":"Out","comment":"","x":340,"y":155,"z":"c5a4e10e.36e74","bgColor":"#cce6ff","wires":[]}]},{"type":"tab","id":"Main","label":"Main","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{},"nodes":[{"id":"Main_sine1","type":"AudioSynthWaveformSine","name":"LFO","comment":"","x":83,"y":118,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_Voice1:0"]]},{"id":"Main_Voice1","type":"Voice","name":"voices[4]","x":189,"y":118,"z":"Main","bgColor":"#CCFFCC","wires":[["Main_mixer4_1:0"]]},{"id":"Main_mixer4_1","type":"AudioMixer4","name":"mixer4","comment":"","inputs":"4","x":367,"y":137,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_i2s1:0","Main_i2s1:1"]]},{"id":"Main_i2s1","type":"AudioOutputI2S","name":"i2s","comment":"","x":491,"y":134,"z":"Main","bgColor":"#E6E0F8","wires":[]}]},{"id":"Voice_In1","type":"TabInput","name":"In","comment":"","x":67,"y":150,"z":"c5a4e10e.36e74","bgColor":"#cce6ff","wires":[["Voice_waveformMod1:0"]]},{"id":"Voice_waveformMod1","type":"AudioSynthWaveformModulated","name":"waveformMod","comment":"","x":200,"y":156,"z":"c5a4e10e.36e74","bgColor":"#E6E0F8","wires":[["Voice_Out1:0"]]},{"id":"Voice_Out1","type":"TabOutput","name":"Out","comment":"","x":340,"y":155,"z":"c5a4e10e.36e74","bgColor":"#cce6ff","wires":[]},{"id":"Main_sine1","type":"AudioSynthWaveformSine","name":"LFO","comment":"","x":83,"y":118,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_Voice1:0"]]},{"id":"Main_Voice1","type":"Voice","name":"voices[4]","x":189,"y":118,"z":"Main","bgColor":"#CCFFCC","wires":[["Main_mixer4_1:0"]]},{"id":"Main_mixer4_1","type":"AudioMixer4","name":"mixer4","comment":"","inputs":"4","x":367,"y":137,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_i2s1:0","Main_i2s1:1"]]},{"id":"Main_i2s1","type":"AudioOutputI2S","name":"i2s","comment":"","x":491,"y":134,"z":"Main","bgColor":"#E6E0F8","wires":[]}]


class Voice 
{
public:
    AudioSynthWaveformModulated      waveformMod;

    Voice() { // constructor (this is called when class-object is created)

        
    }
};

class Main 
{
public:
    AudioSynthWaveformSine           LFO;
    Voice                            voices[4];
    AudioMixer4                      mixer4;
    AudioOutputI2S                   i2s;
    AudioConnection                  *patchCord[10]; // total patchCordCount:10 including array typed ones.

    Main() { // constructor (this is called when class-object is created)
        int pci = 0; // used only for adding new patchcords


        patchCord[pci++] = new AudioConnection(mixer4, 0, i2s, 0);
        patchCord[pci++] = new AudioConnection(mixer4, 0, i2s, 1);
        for (int i = 0; i < 4; i++) {
            patchCord[pci++] = new AudioConnection(LFO, 0, voices[i].waveformMod, 0);
            patchCord[pci++] = new AudioConnection(voices[i].waveformMod, 0, mixer4, i);
        }
        
    }
};
// TeensyAudioDesign: end automatically generated code
 
Last edited:
from a "classic" point of view it will look like this
Code:
class Voice 
{
public:
    AudioSynthWaveformModulated      waveformMod;
    AudioEffectEnvelope              envelope;
    AudioConnection                  *patchCord[1]; // total patchCordCount:1 including array typed ones.

    Voice() { // constructor (this is called when class-object is created)
         // if connections are gonna to be made inside this class
         // for example from the waveformMod to a envelope
         // then it's needed in the pointer format
        
        int pci = 0; // used only for adding new patchcords

        patchCord[pci++] = new AudioConnection(waveformMod, 0, envelope, 0);
    }
};
AudioSynthWaveformSine   LFO;
Voice                                voices[4];
AudioMixer4                      mixer4;
AudioOutputI2S                 i2s;

AudioConnection ac1(LFO, 0, voices[0].waveformMod, 0);
AudioConnection ac2(LFO, 0, voices[1].waveformMod, 0);
AudioConnection ac3(LFO, 0, voices[2].waveformMod, 0);
AudioConnection ac4(LFO, 0, voices[3].waveformMod, 0);
AudioConnection ac5(voices[0].waveformMod, 0, mixer4, 0);
AudioConnection ac6(voices[1].waveformMod, 0, mixer4, 1);
AudioConnection ac7(voices[2].waveformMod, 0, mixer4, 2);
AudioConnection ac8(voices[3].waveformMod, 0, mixer4, 3);
// alternative using envelope
//AudioConnection ac5(voices[0].envelope, 0, mixer4, 0);
//AudioConnection ac6(voices[1].envelope, 0, mixer4, 1);
//AudioConnection ac7(voices[2].envelope, 0, mixer4, 2);
//AudioConnection ac8(voices[3].envelope, 0, mixer4, 3);

AudioConnection ac9(mixer4, 0, i2s, 0);
AudioConnection ac10(mixer4, 0, i2s, 1);
 
I appreciate the response and have used the tool to great effect. I apologize for being vague in my TLDR. When I asked how send audio to an object I didn’t mean an audio object - I get how to do that. I meant an object as in a C++ class member object, such as a single voice. I’m trying to feed each voice the LFO output - which means a patch cable from one class object instance (the two LFOs) to another type of class’s object-instance ( each voice). Sorry if my terminology is bad. I’m new to all this.
 
Another try at TLDR: I’m trying to create only one LFO, not one for each of the 16 voices. But I can’t figure out how to get the audio into the voices - which are each c++ class instances (that is, objects).
 
How do your complete voice code look like?

do you have Audio objects inside the Voice class?
 
Yes, voice has many Audio objects.

Here it is:

Code:
#ifndef Voice_h
#define Voice_h

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include "Synth.h"

class Voice {

private: 



  // Oscillators (4)   
AudioSynthWaveform     *sub;          
AudioSynthWaveform     *sub_fifth;
AudioMixer4              *sub_Mix;
AudioEffectMultiply      *VCA; 
AudioMixer4              *VCA_Mix;
AudioSynthWaveformDc    *VCA_FEED; 

AudioSynthWaveform       *saw;  
AudioSynthWaveformModulated   *saw2;  
AudioMixer4              *SSMixer;
AudioMixer4              *Saw_Phase_Mixer;
AudioSynthWaveformDc     *Saw_Phase_DC; 

AudioSynthWaveformPWM    *pwm1;   
AudioMixer4              *PMix;  
AudioSynthWaveformDc     *PWidth;       


AudioEffectWaveFolder    *Metalizer;
AudioSynthWaveform       *Triangle;
AudioSynthWaveformDc     *Metal_Amnt; 
AudioMixer4              *TriangleMixer;

// output
AudioMixer4              *mixer;      // Osc mixer    

  AudioEffectEnvelope      *envelope;   // VCO envelope
  AudioEffectEnvelope      *ENV1; // Copy of VCO envelope to feed to mods
   AudioSynthWaveformDc     *ENV1FEED;

// LFO (2)
// AudioSynthWaveformModulated   *LFO;   
// LFO now coming from synth.h
// then they are getting sent to seperate mixers for each OSC
// when you throw the switch, it turns on or off that mixer channel
// but the LFO amount is set by the Mod mix for each OSC

AudioMixer4              *LFO_M1;
AudioMixer4              *LFO_M2;
AudioMixer4              *LFO_M3;
AudioMixer4              *LFO_M4;

// NOISE COMING FROM synth.h
// white or pink

AudioEffectEnvelope      *Fenvelope;  // envelope for filter & "ENV 2" for mods 
 AudioSynthWaveformDc     *FEFEED;

AudioMixer4              *ENV_M1;
AudioMixer4              *ENV_M2;
AudioMixer4              *ENV_M3;
AudioMixer4              *ENV_M4 ;
    
// Filter
 AudioSynthWaveformDc     *FFEED;        
AudioSynthWaveformDc     *Keyboard_Amnt;                      
AudioMixer4              *FMod;         // mixer for filter      
AudioFilterStateVariable  *filter;  // filter itself     

  
  bool notePlayed;
  byte note;
  AudioMixer4 *output;
  AudioConnection *patchCords[100];
  AudioMixer4 *input;
  float x;
public:

    Voice(); // constructor 
    
    byte currentNote; // The midi note currently being played.
    unsigned long last_played;

        AudioMixer4 * getOutput();
        AudioMixer4 * getInput();

    void setADR(unsigned int attack, unsigned int decay, unsigned int release);
    void noteOn(byte midiNote = 0);
    void noteOff();
    bool isActive();
    bool isNotePlayed();
    void setNotePlayed(bool notePlayed);
    void setAttack(int att);
    void setDecay(int dec);
    void setRelease(int rel);
    void setFrequency(float frequency);
    void Parameters (byte control, byte value); 
    
    // LFO_OSC lfos[]; //1.getOutput();
    
};


// constructor

Voice::Voice(){
this->notePlayed = false;
Serial.println ("Started the constructor");
// Serial.println (lfo1.FREQ); 
/* 
 //LFO

// LFO now coming from synth.h

this->LFO = new AudioSynthWaveformModulated ();
this->LFO->begin(WAVEFORM_TRIANGLE);
this->LFO->frequency (20);
this->LFO->amplitude (1); 

Serial.println ("Made the LFO");
*/

// SUB
this->sub = new AudioSynthWaveform ();
this->sub->begin(WAVEFORM_SQUARE);
this->sub->amplitude(.5);

this->sub_fifth = new AudioSynthWaveform ();
this->sub_fifth->begin(WAVEFORM_SQUARE);
this->sub_fifth->amplitude(.5);

this->VCA = new AudioEffectMultiply ();
this->VCA_Mix = new AudioMixer4 ();
this->VCA_FEED = new AudioSynthWaveformDc ();
this->VCA_FEED->amplitude(1);
this->VCA_Mix->gain (0, 1); 

this->sub_Mix = new AudioMixer4();
this->sub_Mix->gain (0, 1);
this->sub_Mix->gain (1, 0);      // Fifth off for now 
Serial.println ("Made the SUB");

// SAW
 

    this->saw = new AudioSynthWaveform();
  this->saw->begin(WAVEFORM_SAWTOOTH); 
this->saw->amplitude(.7);


    this->saw2 = new AudioSynthWaveformModulated();
  this->saw2->begin(WAVEFORM_SAWTOOTH);
this->saw2->phaseModulation(180);   //uncomment
this->saw2->amplitude(.7);

this->Saw_Phase_DC = new AudioSynthWaveformDc ();
this->Saw_Phase_DC->amplitude(1);

this->SSMixer = new AudioMixer4 (); 
this->SSMixer->gain(0, 1); 
this->SSMixer->gain(1, 1);   

this->Saw_Phase_Mixer = new AudioMixer4 (); 
this->Saw_Phase_Mixer->gain(0, 1); 
this->Saw_Phase_Mixer->gain(1, 0); 


          
Serial.println ("Made the SAW");

// PWM

this->pwm1 = new AudioSynthWaveformPWM();
this->pwm1->amplitude(0.7);

this->PWidth = new AudioSynthWaveformDc();
this->PWidth->amplitude (.5);
   
  
this->PMix = new AudioMixer4();
this->PMix->gain (0, 1); 
this->PMix->gain (1, 0); // LFO off for now.  

Serial.println ("Made the PW OSC");

// TRIANGLE
this->Metalizer = new AudioEffectWaveFolder ();
this->Triangle = new AudioSynthWaveform();
  this->Triangle->begin(WAVEFORM_TRIANGLE); 
this->Triangle->amplitude(1);

this->TriangleMixer = new AudioMixer4();
this->TriangleMixer->gain(0, 0);  // off for now
this->TriangleMixer->gain(1, 0);  // off for now
this->TriangleMixer->gain(2, 0);  // off for now
this->TriangleMixer->gain(3, 0);  // off for now
this->Metal_Amnt = new AudioSynthWaveformDc (); 
this->Metal_Amnt->amplitude(.7); // Use the mixer

Serial.println ("Made the TRIANGLE");

// VCO ENVELOPE & copy


  this->envelope = new AudioEffectEnvelope();
  this->envelope->sustain(0.5);
  this->envelope->attack(500);
  this->envelope->decay(500);
  this->envelope->release(500);
    this->envelope->delay(0);

  this->ENV1 = new AudioEffectEnvelope();
  this->ENV1->sustain(0.5);
  this->ENV1->attack(500);
  this->ENV1->decay(500);
  this->ENV1->release(500);
    this->ENV1->delay(0);


this->FEFEED = new AudioSynthWaveformDc ();
this->FEFEED->amplitude(1);

  this->Fenvelope = new AudioEffectEnvelope();
  this->Fenvelope->sustain(0.5);
  this->Fenvelope->attack(500);
  this->Fenvelope->decay(500);
  this->Fenvelope->release(500);
    this->Fenvelope->delay(0);


//OUTPUT
  this->mixer = new AudioMixer4();
   this->mixer->gain(0, 0);
      this->mixer->gain(1, 0);
         this->mixer->gain(2, 0);
      this->mixer->gain(3, 1);
        
  this->output = new AudioMixer4();
    this->output->gain(0, 1);
    this->output->gain(1, 0);
        this->output->gain(2, 0);
            this->output->gain(3, 0);
// FILTER
this->FMod = new AudioMixer4();
   this->FMod->gain(0, 0);
      this->FMod->gain(1, 0);
         this->FMod->gain(2, 0);
      this->FMod->gain(3, 0);

this->filter= new AudioFilterStateVariable ();
this->filter->frequency (0);  // we'll see how keyboard control does...  
this->filter->octaveControl (7); // maybe adjust this number with keyboard control on...

this->Keyboard_Amnt = new AudioSynthWaveformDc ();
this->Keyboard_Amnt->amplitude(1); 

//this->noise= new AudioSynthNoisePink ();
// this->noise->amplitude(1);
  
Serial.println ("Created the actual audio componenets");



//this->patchCords[0] = new AudioConnection (*lfos[0].getOutput(), 0, *this->VCA_Mix, 1);
//this->patchCords[1] = new AudioConnection (*lfo1.getOutput(), *this->Saw_Phase_Mixer, 1); 
//this->patchCords[2] = new AudioConnection (*lfo1.getOutput(), *this->PMix, 1);
//this->patchCords[3] = new AudioConnection (*lfo1.getOutput(), 0, *this->TriangleMixer, 1);

Serial.println ("Created the LFO cables");

this->patchCords[4] = new AudioConnection (*this->sub, 0, *this->sub_Mix, 0);
this->patchCords[5] = new AudioConnection (*this->VCA, 0, *this->sub_Mix, 1);
this->patchCords[6] = new AudioConnection (*this->sub_fifth, 0, *this->VCA, 0);
this->patchCords[7] = new AudioConnection (*this->VCA_Mix, 0, *this->VCA, 1);
this->patchCords[8] = new AudioConnection (*this->sub_Mix, 0, *this->mixer, 0);
this->patchCords[9] = new AudioConnection (*this->VCA_FEED, 0, *this->VCA_Mix, 0);

this->patchCords[10] = new AudioConnection (*this->SSMixer, 0, *this->mixer, 1);
this->patchCords[11] = new AudioConnection (*this->saw, 0, *this->SSMixer, 0);
this->patchCords[12] = new AudioConnection (*this->saw2, 0, *this->SSMixer, 1); 
this->patchCords[13] = new AudioConnection (*this->Saw_Phase_Mixer, 0, *this->saw2, 0);
this->patchCords[14] = new AudioConnection (*this->Saw_Phase_DC, 0, *this->Saw_Phase_Mixer, 0);

this->patchCords[15] = new AudioConnection (*this->PWidth, 0, *this->PMix, 0);
this->patchCords[16] = new AudioConnection (*this->PMix, *this->pwm1);
this->patchCords[17] = new AudioConnection (*this->pwm1, 0, *this->mixer, 2);

this->patchCords[18] = new AudioConnection(*this->Metalizer, 0, *this->mixer, 3);
this->patchCords[19] = new AudioConnection(*this->Triangle, 0, *this->Metalizer, 0);
this->patchCords[20] = new AudioConnection(*this->TriangleMixer, 0, *this->Metalizer, 1);
this->patchCords[21] = new AudioConnection(*this->Metal_Amnt, 0, *this->TriangleMixer, 0);

this->patchCords[22] = new AudioConnection(*this->mixer, 0, *this->envelope, 0);
this->patchCords[23] = new AudioConnection(*this->envelope, 0, *this->output, 3);

this->patchCords[24] = new AudioConnection(*this->Fenvelope, 0, *this->VCA_Mix, 3);
this->patchCords[25] = new AudioConnection(*this->Fenvelope, 0, *this->Saw_Phase_Mixer, 3);

this->patchCords[26] = new AudioConnection(*this->Fenvelope, 0, *this->PMix, 3);
this->patchCords[27] = new AudioConnection(*this->Fenvelope, 0, *this->TriangleMixer, 3);
this->patchCords[28] = new AudioConnection(*this->FEFEED, 0, *this->Fenvelope, 0);

this->patchCords[28] = new AudioConnection(*this->envelope, 0, *this->filter, 0);
// this->patchCords[29] = new AudioConnection(*this->filter, 2, *this->output, 0);


this->patchCords[30] = new AudioConnection(*this->FMod, 0, *this->filter, 1);


// this->patchCords[31] = new AudioConnection(*this->LFO, 0, *this->FMod, 0);


this->patchCords[32] = new AudioConnection(*this->Fenvelope, 0, *this->FMod, 1);

//this->patchCords[33] = new AudioConnection(*this->Keyboard_Amnt, 0, *this->FMod, 2);
//this->patchCords[34] = new AudioConnection(*this->noise, 0, *this->FMod, 3);
  
 // this->patchCords [35] = new AudioConnection(SYNTH.input, 0, *this->output, 0);     
  
Serial.println ("Created all patchcords");

}

inline AudioMixer4 * Voice::getOutput(){
  return this->output;
}


AudioMixer4 * Voice::getInput(){
   return 0;
 }

//inline void AudioConnection * Voice::input (x){
// }

inline void Voice::setADR(unsigned int attack, unsigned int decay, unsigned int release){
  
  this->envelope->attack(attack);
  this->envelope->decay(decay);
  this->envelope->release(release);
  
}


inline void Voice::noteOn(byte midiNote) {
float freq = 440.0 * powf(2.0, (float)(midiNote - 69) * 0.08333333);
 // Serial.println (freq);
 
 this->sub->frequency(freq/2);
this->sub_fifth->frequency((freq/4)*3);  
 this->saw->frequency(freq);
  this->saw2->frequency(freq);
 this->pwm1->frequency(freq);
 this->Triangle->frequency(freq/2);
 

 
  this->envelope->noteOn();
    this->Fenvelope->noteOn();
  this->currentNote = midiNote;
  this->last_played = millis();
  this->notePlayed=true;

}

inline void Voice::noteOff() {
 this->envelope->noteOff();
    this->Fenvelope->noteOff();
}

inline bool Voice::isActive(){
return this->envelope->isActive();

}



inline bool Voice::isNotePlayed(){
  return this->notePlayed;
}

inline void Voice::setNotePlayed(bool notePlayed){
  this->notePlayed = notePlayed;
}


inline void Voice::setAttack(int att){
 this->envelope->attack(att);
}
inline void Voice::setDecay(int dec){
  this->envelope->decay(dec);
}
inline void Voice::setRelease(int rel){
  this->envelope->release(rel);
}

inline void Voice::setFrequency(float freq){
 this->saw->frequency(freq);
Serial.print ("Frequency set to: ");
Serial.println (freq);
}




inline void Voice::Parameters (byte control, byte value){
  float x=float(map(value, 0, 127, 0, 100))/100;
float y=float(x/2);

 // float z=float(map(value, 0, 127, 0, 33))/100;
// float zz=float(map(value, 0, 127, 33, 0))/100;
//Serial.println ("Control: ");
// Serial.println (control);     
switch (control){
  
// OSCs (4)
  case 1: // SUB
    this->mixer->gain(0, y); 
  break;
      case 2: // SAW
    this->mixer->gain(1, y); 
  break;
      case 3: // PW
    this->mixer->gain(2, y); 
  break;
  case 4: // TRIANGLE
    this->mixer->gain(3, y); 
  break;

// Osc Mod (DC)
  case 5: // Sub-fifth
    this->sub_Mix->gain(1, x);
  break;
  case 6: // Super Saw!
    this->Saw_Phase_Mixer->gain(0, x); 
  break;
  case 7: // P-width
    this->PMix->gain(0, x); // This works
  break;
  case 8: 
    this->TriangleMixer->gain(0, x); 
  break;


// Osc Mod (LFO)
  case 9: // Sub-fifth
    this->VCA_Mix->gain(1, x);
  break;
  case 10: // Super Saw!
    this->Saw_Phase_Mixer->gain(1, x); 
  //  this->SSMixer->gain(0, y);
  break;
  case 11: // P-width
    this->PMix->gain(1, x);
   // this->PMix->gain(0, y);  
  break;
  case 12: 
    this->TriangleMixer->gain(1, x);
 //   this->DetuneMix->gain(0, zz);  
  break;


// VCO envelope
case 19:
  this->envelope->attack(x*1500);
  break;

case 23:
  this->envelope->decay(x*1500);
  break;
  
case 27:
  this->envelope->sustain(x);
  break;

case 31:
  this->envelope->release(x*1500);
  break;




// F envelope
case 18:
  this->Fenvelope->attack(x*1500);
  break;

case 22:
  this->Fenvelope->decay(x*1500);
  break;
  
case 26:
  this->Fenvelope->sustain(x);
  break;

case 30:
  this->Fenvelope->release(x*1500);
  break;


// F-Envelopes to Modds
  case 13: // Sub-fifth
    this->VCA_Mix->gain(3, x);
  break;
  
  case 14: // Super Saw!
    this->Saw_Phase_Mixer->gain(3, x); 

  break;
  case 15: // P-width
    this->PMix->gain(3, x);
  Serial.println ("Pwidth!");
  break;
  case 16: 
    this->TriangleMixer->gain(3, x);
  break;


  
case 25: // LFO speed
//  this->LFO->frequency(x*5);
break;


// Filter

case 20:
this->filter->frequency(((x*10) * (x*10)* (x*10)) * 5);
Serial.println (((x*10) * (x*10)* (x*10)) * 5);
break;


 

case 24:
this->filter->resonance((x*1.8));
break;



case 28:
this->FMod->gain(0,x);
break;




case 32:
this->FMod->gain(1, x);
break;



case 55:
this->FMod->gain(2, x);
break;

} 
    
}



//inline LFO_OSC** Voice::getLFO(){
 // return this->LFOs;
// }


// }

#endif
 
Yes, voice has many Audio objects.

Here it is:

Code:
#ifndef Voice_h
#define Voice_h

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include "Synth.h"

class Voice {

private: 



  // Oscillators (4)   
AudioSynthWaveform     *sub;          
AudioSynthWaveform     *sub_fifth;
AudioMixer4              *sub_Mix;
AudioEffectMultiply      *VCA; 
AudioMixer4              *VCA_Mix;
AudioSynthWaveformDc    *VCA_FEED; 

AudioSynthWaveform       *saw;  
AudioSynthWaveformModulated   *saw2;  
AudioMixer4              *SSMixer;
AudioMixer4              *Saw_Phase_Mixer;
AudioSynthWaveformDc     *Saw_Phase_DC; 

AudioSynthWaveformPWM    *pwm1;   
AudioMixer4              *PMix;  
AudioSynthWaveformDc     *PWidth;       


AudioEffectWaveFolder    *Metalizer;
AudioSynthWaveform       *Triangle;
AudioSynthWaveformDc     *Metal_Amnt; 
AudioMixer4              *TriangleMixer;

// output
AudioMixer4              *mixer;      // Osc mixer    

  AudioEffectEnvelope      *envelope;   // VCO envelope
  AudioEffectEnvelope      *ENV1; // Copy of VCO envelope to feed to mods
   AudioSynthWaveformDc     *ENV1FEED;

// LFO (2)
// AudioSynthWaveformModulated   *LFO;   
// LFO now coming from synth.h
// then they are getting sent to seperate mixers for each OSC
// when you throw the switch, it turns on or off that mixer channel
// but the LFO amount is set by the Mod mix for each OSC

AudioMixer4              *LFO_M1;
AudioMixer4              *LFO_M2;
AudioMixer4              *LFO_M3;
AudioMixer4              *LFO_M4;

// NOISE COMING FROM synth.h
// white or pink

AudioEffectEnvelope      *Fenvelope;  // envelope for filter & "ENV 2" for mods 
 AudioSynthWaveformDc     *FEFEED;

AudioMixer4              *ENV_M1;
AudioMixer4              *ENV_M2;
AudioMixer4              *ENV_M3;
AudioMixer4              *ENV_M4 ;
    
// Filter
 AudioSynthWaveformDc     *FFEED;        
AudioSynthWaveformDc     *Keyboard_Amnt;                      
AudioMixer4              *FMod;         // mixer for filter      
AudioFilterStateVariable  *filter;  // filter itself     

  
  bool notePlayed;
  byte note;
  AudioMixer4 *output;
  AudioConnection *patchCords[100];
  AudioMixer4 *input;
  float x;
public:

    Voice(); // constructor 
    
    byte currentNote; // The midi note currently being played.
    unsigned long last_played;

        AudioMixer4 * getOutput();
        AudioMixer4 * getInput();

    void setADR(unsigned int attack, unsigned int decay, unsigned int release);
    void noteOn(byte midiNote = 0);
    void noteOff();
    bool isActive();
    bool isNotePlayed();
    void setNotePlayed(bool notePlayed);
    void setAttack(int att);
    void setDecay(int dec);
    void setRelease(int rel);
    void setFrequency(float frequency);
    void Parameters (byte control, byte value); 
    
    // LFO_OSC lfos[]; //1.getOutput();
    
};


// constructor

Voice::Voice(){
this->notePlayed = false;
Serial.println ("Started the constructor");
// Serial.println (lfo1.FREQ); 
/* 
 //LFO

// LFO now coming from synth.h

this->LFO = new AudioSynthWaveformModulated ();
this->LFO->begin(WAVEFORM_TRIANGLE);
this->LFO->frequency (20);
this->LFO->amplitude (1); 

Serial.println ("Made the LFO");
*/

// SUB
this->sub = new AudioSynthWaveform ();
this->sub->begin(WAVEFORM_SQUARE);
this->sub->amplitude(.5);

this->sub_fifth = new AudioSynthWaveform ();
this->sub_fifth->begin(WAVEFORM_SQUARE);
this->sub_fifth->amplitude(.5);

this->VCA = new AudioEffectMultiply ();
this->VCA_Mix = new AudioMixer4 ();
this->VCA_FEED = new AudioSynthWaveformDc ();
this->VCA_FEED->amplitude(1);
this->VCA_Mix->gain (0, 1); 

this->sub_Mix = new AudioMixer4();
this->sub_Mix->gain (0, 1);
this->sub_Mix->gain (1, 0);      // Fifth off for now 
Serial.println ("Made the SUB");

// SAW
 

    this->saw = new AudioSynthWaveform();
  this->saw->begin(WAVEFORM_SAWTOOTH); 
this->saw->amplitude(.7);


    this->saw2 = new AudioSynthWaveformModulated();
  this->saw2->begin(WAVEFORM_SAWTOOTH);
this->saw2->phaseModulation(180);   //uncomment
this->saw2->amplitude(.7);

this->Saw_Phase_DC = new AudioSynthWaveformDc ();
this->Saw_Phase_DC->amplitude(1);

this->SSMixer = new AudioMixer4 (); 
this->SSMixer->gain(0, 1); 
this->SSMixer->gain(1, 1);   

this->Saw_Phase_Mixer = new AudioMixer4 (); 
this->Saw_Phase_Mixer->gain(0, 1); 
this->Saw_Phase_Mixer->gain(1, 0); 


          
Serial.println ("Made the SAW");

// PWM

this->pwm1 = new AudioSynthWaveformPWM();
this->pwm1->amplitude(0.7);

this->PWidth = new AudioSynthWaveformDc();
this->PWidth->amplitude (.5);
   
  
this->PMix = new AudioMixer4();
this->PMix->gain (0, 1); 
this->PMix->gain (1, 0); // LFO off for now.  

Serial.println ("Made the PW OSC");

// TRIANGLE
this->Metalizer = new AudioEffectWaveFolder ();
this->Triangle = new AudioSynthWaveform();
  this->Triangle->begin(WAVEFORM_TRIANGLE); 
this->Triangle->amplitude(1);

this->TriangleMixer = new AudioMixer4();
this->TriangleMixer->gain(0, 0);  // off for now
this->TriangleMixer->gain(1, 0);  // off for now
this->TriangleMixer->gain(2, 0);  // off for now
this->TriangleMixer->gain(3, 0);  // off for now
this->Metal_Amnt = new AudioSynthWaveformDc (); 
this->Metal_Amnt->amplitude(.7); // Use the mixer

Serial.println ("Made the TRIANGLE");

// VCO ENVELOPE & copy


  this->envelope = new AudioEffectEnvelope();
  this->envelope->sustain(0.5);
  this->envelope->attack(500);
  this->envelope->decay(500);
  this->envelope->release(500);
    this->envelope->delay(0);

  this->ENV1 = new AudioEffectEnvelope();
  this->ENV1->sustain(0.5);
  this->ENV1->attack(500);
  this->ENV1->decay(500);
  this->ENV1->release(500);
    this->ENV1->delay(0);


this->FEFEED = new AudioSynthWaveformDc ();
this->FEFEED->amplitude(1);

  this->Fenvelope = new AudioEffectEnvelope();
  this->Fenvelope->sustain(0.5);
  this->Fenvelope->attack(500);
  this->Fenvelope->decay(500);
  this->Fenvelope->release(500);
    this->Fenvelope->delay(0);


//OUTPUT
  this->mixer = new AudioMixer4();
   this->mixer->gain(0, 0);
      this->mixer->gain(1, 0);
         this->mixer->gain(2, 0);
      this->mixer->gain(3, 1);
        
  this->output = new AudioMixer4();
    this->output->gain(0, 1);
    this->output->gain(1, 0);
        this->output->gain(2, 0);
            this->output->gain(3, 0);
// FILTER
this->FMod = new AudioMixer4();
   this->FMod->gain(0, 0);
      this->FMod->gain(1, 0);
         this->FMod->gain(2, 0);
      this->FMod->gain(3, 0);

this->filter= new AudioFilterStateVariable ();
this->filter->frequency (0);  // we'll see how keyboard control does...  
this->filter->octaveControl (7); // maybe adjust this number with keyboard control on...

this->Keyboard_Amnt = new AudioSynthWaveformDc ();
this->Keyboard_Amnt->amplitude(1); 

//this->noise= new AudioSynthNoisePink ();
// this->noise->amplitude(1);
  
Serial.println ("Created the actual audio componenets");



//this->patchCords[0] = new AudioConnection (*lfos[0].getOutput(), 0, *this->VCA_Mix, 1);
//this->patchCords[1] = new AudioConnection (*lfo1.getOutput(), *this->Saw_Phase_Mixer, 1); 
//this->patchCords[2] = new AudioConnection (*lfo1.getOutput(), *this->PMix, 1);
//this->patchCords[3] = new AudioConnection (*lfo1.getOutput(), 0, *this->TriangleMixer, 1);

Serial.println ("Created the LFO cables");

this->patchCords[4] = new AudioConnection (*this->sub, 0, *this->sub_Mix, 0);
this->patchCords[5] = new AudioConnection (*this->VCA, 0, *this->sub_Mix, 1);
this->patchCords[6] = new AudioConnection (*this->sub_fifth, 0, *this->VCA, 0);
this->patchCords[7] = new AudioConnection (*this->VCA_Mix, 0, *this->VCA, 1);
this->patchCords[8] = new AudioConnection (*this->sub_Mix, 0, *this->mixer, 0);
this->patchCords[9] = new AudioConnection (*this->VCA_FEED, 0, *this->VCA_Mix, 0);

this->patchCords[10] = new AudioConnection (*this->SSMixer, 0, *this->mixer, 1);
this->patchCords[11] = new AudioConnection (*this->saw, 0, *this->SSMixer, 0);
this->patchCords[12] = new AudioConnection (*this->saw2, 0, *this->SSMixer, 1); 
this->patchCords[13] = new AudioConnection (*this->Saw_Phase_Mixer, 0, *this->saw2, 0);
this->patchCords[14] = new AudioConnection (*this->Saw_Phase_DC, 0, *this->Saw_Phase_Mixer, 0);

this->patchCords[15] = new AudioConnection (*this->PWidth, 0, *this->PMix, 0);
this->patchCords[16] = new AudioConnection (*this->PMix, *this->pwm1);
this->patchCords[17] = new AudioConnection (*this->pwm1, 0, *this->mixer, 2);

this->patchCords[18] = new AudioConnection(*this->Metalizer, 0, *this->mixer, 3);
this->patchCords[19] = new AudioConnection(*this->Triangle, 0, *this->Metalizer, 0);
this->patchCords[20] = new AudioConnection(*this->TriangleMixer, 0, *this->Metalizer, 1);
this->patchCords[21] = new AudioConnection(*this->Metal_Amnt, 0, *this->TriangleMixer, 0);

this->patchCords[22] = new AudioConnection(*this->mixer, 0, *this->envelope, 0);
this->patchCords[23] = new AudioConnection(*this->envelope, 0, *this->output, 3);

this->patchCords[24] = new AudioConnection(*this->Fenvelope, 0, *this->VCA_Mix, 3);
this->patchCords[25] = new AudioConnection(*this->Fenvelope, 0, *this->Saw_Phase_Mixer, 3);

this->patchCords[26] = new AudioConnection(*this->Fenvelope, 0, *this->PMix, 3);
this->patchCords[27] = new AudioConnection(*this->Fenvelope, 0, *this->TriangleMixer, 3);
this->patchCords[28] = new AudioConnection(*this->FEFEED, 0, *this->Fenvelope, 0);

this->patchCords[28] = new AudioConnection(*this->envelope, 0, *this->filter, 0);
// this->patchCords[29] = new AudioConnection(*this->filter, 2, *this->output, 0);


this->patchCords[30] = new AudioConnection(*this->FMod, 0, *this->filter, 1);


// this->patchCords[31] = new AudioConnection(*this->LFO, 0, *this->FMod, 0);


this->patchCords[32] = new AudioConnection(*this->Fenvelope, 0, *this->FMod, 1);

//this->patchCords[33] = new AudioConnection(*this->Keyboard_Amnt, 0, *this->FMod, 2);
//this->patchCords[34] = new AudioConnection(*this->noise, 0, *this->FMod, 3);
  
 // this->patchCords [35] = new AudioConnection(SYNTH.input, 0, *this->output, 0);     
  
Serial.println ("Created all patchcords");

}

inline AudioMixer4 * Voice::getOutput(){
  return this->output;
}


AudioMixer4 * Voice::getInput(){
   return 0;
 }

//inline void AudioConnection * Voice::input (x){
// }

inline void Voice::setADR(unsigned int attack, unsigned int decay, unsigned int release){
  
  this->envelope->attack(attack);
  this->envelope->decay(decay);
  this->envelope->release(release);
  
}


inline void Voice::noteOn(byte midiNote) {
float freq = 440.0 * powf(2.0, (float)(midiNote - 69) * 0.08333333);
 // Serial.println (freq);
 
 this->sub->frequency(freq/2);
this->sub_fifth->frequency((freq/4)*3);  
 this->saw->frequency(freq);
  this->saw2->frequency(freq);
 this->pwm1->frequency(freq);
 this->Triangle->frequency(freq/2);
 

 
  this->envelope->noteOn();
    this->Fenvelope->noteOn();
  this->currentNote = midiNote;
  this->last_played = millis();
  this->notePlayed=true;

}

inline void Voice::noteOff() {
 this->envelope->noteOff();
    this->Fenvelope->noteOff();
}

inline bool Voice::isActive(){
return this->envelope->isActive();

}



inline bool Voice::isNotePlayed(){
  return this->notePlayed;
}

inline void Voice::setNotePlayed(bool notePlayed){
  this->notePlayed = notePlayed;
}


inline void Voice::setAttack(int att){
 this->envelope->attack(att);
}
inline void Voice::setDecay(int dec){
  this->envelope->decay(dec);
}
inline void Voice::setRelease(int rel){
  this->envelope->release(rel);
}

inline void Voice::setFrequency(float freq){
 this->saw->frequency(freq);
Serial.print ("Frequency set to: ");
Serial.println (freq);
}




inline void Voice::Parameters (byte control, byte value){
  float x=float(map(value, 0, 127, 0, 100))/100;
float y=float(x/2);

 // float z=float(map(value, 0, 127, 0, 33))/100;
// float zz=float(map(value, 0, 127, 33, 0))/100;
//Serial.println ("Control: ");
// Serial.println (control);     
switch (control){
  
// OSCs (4)
  case 1: // SUB
    this->mixer->gain(0, y); 
  break;
      case 2: // SAW
    this->mixer->gain(1, y); 
  break;
      case 3: // PW
    this->mixer->gain(2, y); 
  break;
  case 4: // TRIANGLE
    this->mixer->gain(3, y); 
  break;

// Osc Mod (DC)
  case 5: // Sub-fifth
    this->sub_Mix->gain(1, x);
  break;
  case 6: // Super Saw!
    this->Saw_Phase_Mixer->gain(0, x); 
  break;
  case 7: // P-width
    this->PMix->gain(0, x); // This works
  break;
  case 8: 
    this->TriangleMixer->gain(0, x); 
  break;


// Osc Mod (LFO)
  case 9: // Sub-fifth
    this->VCA_Mix->gain(1, x);
  break;
  case 10: // Super Saw!
    this->Saw_Phase_Mixer->gain(1, x); 
  //  this->SSMixer->gain(0, y);
  break;
  case 11: // P-width
    this->PMix->gain(1, x);
   // this->PMix->gain(0, y);  
  break;
  case 12: 
    this->TriangleMixer->gain(1, x);
 //   this->DetuneMix->gain(0, zz);  
  break;


// VCO envelope
case 19:
  this->envelope->attack(x*1500);
  break;

case 23:
  this->envelope->decay(x*1500);
  break;
  
case 27:
  this->envelope->sustain(x);
  break;

case 31:
  this->envelope->release(x*1500);
  break;




// F envelope
case 18:
  this->Fenvelope->attack(x*1500);
  break;

case 22:
  this->Fenvelope->decay(x*1500);
  break;
  
case 26:
  this->Fenvelope->sustain(x);
  break;

case 30:
  this->Fenvelope->release(x*1500);
  break;


// F-Envelopes to Modds
  case 13: // Sub-fifth
    this->VCA_Mix->gain(3, x);
  break;
  
  case 14: // Super Saw!
    this->Saw_Phase_Mixer->gain(3, x); 

  break;
  case 15: // P-width
    this->PMix->gain(3, x);
  Serial.println ("Pwidth!");
  break;
  case 16: 
    this->TriangleMixer->gain(3, x);
  break;


  
case 25: // LFO speed
//  this->LFO->frequency(x*5);
break;


// Filter

case 20:
this->filter->frequency(((x*10) * (x*10)* (x*10)) * 5);
Serial.println (((x*10) * (x*10)* (x*10)) * 5);
break;


 

case 24:
this->filter->resonance((x*1.8));
break;



case 28:
this->FMod->gain(0,x);
break;




case 32:
this->FMod->gain(1, x);
break;



case 55:
this->FMod->gain(2, x);
break;

} 
    
}



//inline LFO_OSC** Voice::getLFO(){
 // return this->LFOs;
// }


// }

#endif

Here is the main program code:

Code:
 #include "Voice.h"
 #include "Synth.h"
#include <Audio.h>
#include <MIDI.h>


// eventually add USB host stuff too... 

MIDI_CREATE_DEFAULT_INSTANCE(); // MIDI library init

    unsigned int attack;
    unsigned int decay;
    unsigned int release;
   
    const int interval_time = 50;
    elapsedMillis clock_count;
    const byte voiceCount = 8;   // max 16
    Voice *voices[voiceCount];   // so first you create the array
    LFO_OSC *lfos[2];
    
AudioOutputI2S  i2s2;
//AudioOutputUSB           usb1;

// First create an output mixer for the voicemixers to hook up to

AudioMixer4 output; 
//AudioMixer4 *input; 

// then create a mixer for every 4 voices

AudioMixer4 *mixers[voiceCount/4];

// then create stereo outs (actually mono x 2) to i2s2 and usb for output
// this is coming from the output mixer





AudioConnection          patchCord1(output, 0, i2s2, 0);
AudioConnection          patchCord2(output, 0, i2s2, 1);
//AudioConnection          patchCord3(output, 0, usb1, 0);
//AudioConnection          patchCord4(output, 0, usb1, 1);


AudioControlSGTL5000 sgtl5000_1;

//  cables for  connecting the voice mixers to the voices (voicecout)

AudioConnection *VoiceCords[voiceCount]; 

// & more attaching the voice mixers to the output mixers (/4 + x)
AudioConnection *OutputCords[voiceCount/4 + voiceCount]; 
//AudioConnection TEST_CORD; 
AudioConnection *TEST_CORDS[20];// (noise1.getOutput(),0, output, 3);


// These all get connected down in setup.



void setup() {
Serial.begin(9600);

//synth.input.gain(0,1);
//input->gain(0,1);

  
//MOD_BLOCK super_saw;      
//MOD_BLOCK pulse;
//NOISE_OSC noise1;
//FILTER filter1;
//LFO_OSC lfo1;
//LFO_OSC lfo2;
lfos[0] = new LFO_OSC;
lfos[1] = new LFO_OSC;
lfos[0]->SET_FREQ(.5);
Serial.println ("This should be zero: ");
//Serial.println (lfos[0]->tomato);
//lfos[0]->tomato=1;
//lfos[1]->tomato=2;
Serial.println ("Now I've reset them: ");
//Serial.println (lfos[0]->tomato);
//Serial.println (lfos[1]->tomato);
//lfos[0]->input.gain(0,0);
//lfo2.SET_FREQ(0);
//noise1.NOISE_SET_VOL (0); 


Serial.println ("Ok! Messing with the new stuff!");

//Serial.println (noise1.VOL);
//filter1.PRINTALL ();
//Serial.println (filter1.NewLFO(1));
//filter1.PRINTALL ();
//Serial.println (filter1.KEY_FOLLOW);
//filter1.KEY_FOLLOW=true;
//pulse.PRINTALL ();
//Serial.println (filter1.KEY_FOLLOW);
//pulse.PRINTALL ();
//super_saw.VOL = 1000;
//Serial.println (super_saw.DC);
//Serial.println ();

Serial.println ("Hi!");

  MIDI.setHandleNoteOn(onNoteOn);
  MIDI.setHandleNoteOff(onNoteOff);
  MIDI.setHandleControlChange(onCC);
  MIDI.begin(MIDI_CHANNEL_OMNI);
  
  usbMIDI.setHandleNoteOn(onNoteOn);
  usbMIDI.setHandleNoteOff(onNoteOff);
  usbMIDI.setHandleControlChange(onCC);

AudioMemory (250);
  AudioNoInterrupts();
  AudioProcessorUsageMaxReset();
  AudioMemoryUsageMaxReset();

  sgtl5000_1.enable();
  sgtl5000_1.volume(1);

// Serial.println ("made it this far");

//lfos[0] = new LFO_OSC;
  for (int i = 0; i < voiceCount; i++) {
    voices[i] = new Voice();
    voices[i]->setADR (10, 10, 100);
     // TEST_CORDS[i] = new AudioConnection (*lfo1.getOutput(), 0
  }

  
//Serial.println ("Made it past creating voices"); 
// voice mixers need to be created, then hooked up

  for (int i = 0; i < voiceCount/4; i++) {
mixers[i] = new AudioMixer4();
mixers[i]->gain(0, 0.6);
mixers[i]->gain(1, 0.6);
mixers[i]->gain(2, 0.6);
mixers[i]->gain(3, 0.6);
 
  
VoiceCords[i] = new AudioConnection(*voices[i]->getOutput(), 0, *mixers[i], 0);
VoiceCords[i+1] = new AudioConnection(*voices[i+1]->getOutput(), 0, *mixers[i], 1);
VoiceCords[i+2] = new AudioConnection(*voices[i+2]->getOutput(), 0, *mixers[i], 2);
VoiceCords[i+3] = new AudioConnection(*voices[i+3]->getOutput(), 0, *mixers[i], 3);

OutputCords[i] = new AudioConnection (*mixers[i],0, output, i);


 }


// TKW ADDITION FOR TESTING!
//TEST_CORDS[0] = new AudioConnection (synth.input,0, output, 3);

// turn the thing on

output.gain (0, 1);
output.gain (1, 1);
output.gain (2, 1);
output.gain (3, .3);


 AudioInterrupts();

Serial.println ("Finished setup!");


 
}


void loop() {
  // put your main code here, to run repeatedly:
  MIDI.read();
  usbMIDI.read();

  /*if (clock_count >= interval_time) {
    // Do things every 50ms

    // Synth update
    update();

clock_count = 0;
*/

 // }

// Call update based on a timer for every 50 seconds
// read the pins and then call the right function
// it will be based on a copy / paste with changes to to MIDI control change function
// right now though everything is going to come in through MIDI messages only during testing

//  delay(10);

}




void update(){
// This will read the pins and then send out for functions. Model in on a copy past of the void on command
// you can also keep both, that way if you want to plug in a seperate MIDI pedal for additional knobs you could
}



void onCC (byte channel, byte control, byte value){
/*
Serial.println ();
Serial.println (channel);
Serial.println (control);
Serial.println (value);
Serial.println ();
*/

        for (int i = 0; i < voiceCount ; i++) {
          voices[i]->Parameters(control, value);
        }



}



void onNoteOn(byte channel, byte note, byte velocity){
//Serial.println ();
//Serial.print("note on: "); Serial.println (note);

Serial.println ("Audio Memory Usage:");
Serial.println (AudioMemoryUsage());
Serial.println ("Audio Memory MAX Usage:");
Serial.println (AudioMemoryUsageMax());
Serial.println ();
Serial.println ("CPU Usage:");
Serial.println (AudioProcessorUsage());
Serial.println ("CPU MAX Usage:");
Serial.println (AudioProcessorUsageMax());
Serial.println ();
Serial.println ();

 bool foundOne = false;
  int oldestVoice = 0;
  unsigned long oldestVoiceTime = 0;
 // unsigned long currentTime = millis();

    for (int i = 0; i < voiceCount; i++) {
        // Search for the oldest voice
        if(voices[i]->last_played > oldestVoiceTime){
          oldestVoiceTime = voices[i]->last_played;
          oldestVoice = i;

        }

//Serial.print (i);
//Serial.print (" is ");
//Serial.print (voices[i]->isActive ());
//Serial.println (" active. "); 
        
        // Search for an inactive voice
        if(!voices[i]->isActive()){
          // float freq = 440.0 * powf(2.0, (float)(note - 69) * 0.08333333);
          //  voices[i]->setFrequency(freq);
           voices[i]->noteOn(note);
          foundOne = true;
         // Serial.print ("Sent a note on to this voice: ");
          //Serial.println (i);
          break;
        }
       }
    
      // No inactive voice then will take over the oldest note
      if(!foundOne){
        voices[oldestVoice]->noteOn(note);
         //Serial.print ("All voices used. Taking over from: ");
          //Serial.println (oldestVoice);
       }
 
}


    
void onNoteOff(byte channel, byte note, byte velocity){
  // Serial.println ("Note off");

      for (int i = 0; i < voiceCount ; i++) {
        if(voices[i]->currentNote == note){
          voices[i]->noteOff();
          //Serial.print ("Turned a note off: ");
          //Serial.println (i);
        }
      }
}

Here is another header file with the LFOs and "outside" oscillators:

Code:
#ifndef Synth_h
#define Synth_h

#include <Audio.h>

class MOD_BLOCK{
  private:
    float DC;
    float LFO;
    float ENV;
    float NOISE;
    void proportion (float xDC, float xLFO, float xENV, float xNOISE);
   public:
    float VOL;
    float NewDC (float x); 
    float NewLFO (float x);
    float NewENV (float x); 
    float NewNOISE (float x); 
    void PRINTALL();

};

inline float MOD_BLOCK::NewDC (float x){
proportion(x, this->LFO, this->ENV, this->NOISE);
  return this->DC;
}
inline float MOD_BLOCK::NewLFO (float x){
proportion(this->DC, x, this->ENV, this->NOISE);
  return this->LFO;
}
inline float MOD_BLOCK::NewENV (float x){
proportion(this->DC, this->LFO, x, this->NOISE);
  return this->ENV;
}
inline float MOD_BLOCK::NewNOISE (float x){
proportion(this->DC, this->LFO, this->ENV, x);
  return this->NOISE;
}
inline void MOD_BLOCK::proportion (float xDC, float xLFO, float xENV, float xNOISE){

  float total=(xDC+xLFO+xENV+xNOISE);

 if (total > 1){
   this->DC = xDC / total;
   this->LFO = xLFO / total;
   this->ENV = xENV / total;
   this->NOISE = xNOISE / total;
 } else {
  this->DC=xDC;
  this->LFO=xLFO;
  this->ENV=xENV;
  this->NOISE=xNOISE;
 }
  

}

inline void MOD_BLOCK::PRINTALL (){
  Serial.println ("DC: "); Serial.println (this->DC);
  Serial.println ("LFO: "); Serial.println ( this->LFO);
  Serial.println ("ENV: "); Serial.println ( this->ENV);
  Serial.println ("NOISE: "); Serial.println ( this->NOISE);
  Serial.println ();
}

class FILTER: public MOD_BLOCK{
  public:
    bool KEY_FOLLOW;
    bool TYPE_BP;
    
};

 class SYNTH{
 
  public:
 //SYNTH();
// AudioMixer4 *input;
static int tomato;
 
};


class NOISE_OSC{  
    private:
    AudioSynthNoiseWhite *white;
    AudioSynthNoisePink *pink;
    AudioMixer4 *output;
    AudioConnection *patches[2];
 
  public:
    NOISE_OSC(); // constructor
    void NOISE_SET_VOL(float Amnt);
    float VOL;
    bool PINK;
    AudioMixer4 *getOutput();
      
};

inline NOISE_OSC::NOISE_OSC (){ // constructor
  Serial.println ("Started constructing the noise osc");
  this->white= new AudioSynthNoiseWhite ();
  this->pink= new AudioSynthNoisePink ();
  this->white->amplitude(1);
  this->pink->amplitude(1);
  
  this->output=new AudioMixer4;
  this->output->gain(0,1);
   this->output->gain(1,1);
 this->patches[0] = new AudioConnection (*this->white, 0, *this->output, 0);
   this->patches[1] = new AudioConnection (*this->pink, 0, *this->output, 1);
   this->PINK=false;
   this->VOL=0;
};

inline void NOISE_OSC::NOISE_SET_VOL(float Amnt){
  Serial.println ("Setting volume");
  if (PINK==false){
   
    this->output->gain(0, Amnt);
    VOL= Amnt; 
  } else {
    
    this->output->gain(1, Amnt); 
    VOL=Amnt;
  }
  };


inline AudioMixer4 * NOISE_OSC::getOutput(){
  return this->output;
};



class LFO_OSC : public SYNTH{  
  
private: 
  AudioSynthWaveform   *LFO;
  public:
    LFO_OSC(); // constructor
    float FREQ;
    void SET_FREQ(float Amnt);
    AudioSynthWaveform * getOutput (); 
    int getTomato();
    void sendTomato(int x);
       //   AudioConnection *patches[1];
    };

inline LFO_OSC::LFO_OSC (){ // constructor
Serial.println ("Started constructing an LFO");
 //tomato=0;
// input = new AudioMixer4;
 this->LFO = new AudioSynthWaveform ();
  this->LFO->begin(WAVEFORM_TRIANGLE);
  this->LFO->frequency(0);
  this->LFO->amplitude(1);
  this->FREQ=0;
// input->gain(0,1);
// kept this for reference only
//this->patches[0] = new AudioConnection (*this->LFO, 0, input, 0);
};

void LFO_OSC::SET_FREQ(float Amnt){
this->LFO->frequency ((Amnt *10) * (Amnt *10)*10);  //100*10=1000 max
};

inline AudioSynthWaveform * LFO_OSC::getOutput(){
  return this->LFO;
};

LFO_OSC::getTomato(){
return tomato;
}
void LFO_OSC::sendTomato(int x){
  tomato=x;
}


#endif
 
ok that was a lot of code
I will take a look at it tomorrow
it's 00:21 here
and I really need go to sleep

but you want to connect a external LFO to a AudioObject inside the Voice class?
 
but you want to connect a external LFO to a AudioObject inside the Voice class?

Exactly. Well, two LFOs and a Noise osc. I appreciate you looking. Sorry the code is a mess. It’s only 75% done and there’s a lot of weird testing stuff in there.

It boils down to this line not working:

Code:
class Voice{
}

// constructor

Voice::Voice(){

this->patchCords[0] = new AudioConnection (*lfos[0].getOutput(), 0, *this->output, 0);

}

That’s me failing to pull the LFO output into the voice class. That same pointer call to the LFO output works in setup {}. But it’s not allowed inside the voice class.

Have a good night!
 
Argh! I just can't figure this out.

I'm trying to create a global static function for each LFO with something like the below, but I can't figure out how to get audio objects inside a function or to have a function read those objects from outside.


Code:
#ifndef MY_FOO_HEADER_
#define MY_FOO_HEADER_
    inline int foo()
    {
        return 1;
    }
#endif

Maybe I just give up and go back to having a seperate LFO for each voice. It doesn't use up that much processor power or memory. It just seems silly to use 16 of them when 1 would do.
 
I'm sorry for the late reply

You can't access outside declared variables/instances,
because that is outside of the class scope

In pure C you can access everything everywhere just by including the header,
but as said that is not the case here.

That's a just a rule for almost(of what I know) every object oriented programming languages.

You have to do the "linkin" outside of the Voice class

Code:
this->patchCords[0] = new AudioConnection (*lfos[0].getOutput(), 0, *voices[i]->"whatever object you want the lfo to be connected to", 0);


I would recommend using my extended Tool
to do your whole design
https://forum.pjrc.com/threads/65740-Audio-System-Design-Tool-update

One of the reasons I did the updated Tool
is to make the design of complex and big
synths much much easier.

You can actually make the whole project in the new Tool
by using the new code blocks and so on.

And everything (all files) can be exported into a zip file
for easy usage in a Arduino project.

See my embedded demo project "Manicken Poly Synth"
@ ("topmost right menu"-examples)
 
Thank you so much for that line of code as well as for the design tool! I really appreciate it.

This extended tool looks fantastic! I'm starting to play with it now.

Best,
Tom
 
I was curious how your design looked like
and did my best to recreate it in the tool
here it is
Code:
{"version":1,"settings":{"arduino":{"Board":{"Platform":"","Board":"","Options":""}},"BiDirDataWebSocketBridge":{},"workspaces":{},"sidebar":{},"palette":{},"editor":{},"devTest":{},"IndexedDBfiles":{"testFileNames":"testFile.txt"},"NodeDefGenerator":{},"NodeDefManager":{},"NodeHelpManager":{},"OSC":{}},"workspaces":[{"type":"tab","id":"Main","label":"Voice","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{"scaleFactor":0.8},"nodes":[{"id":"Voice_In1","type":"TabInput","name":"In","comment":"","x":115,"y":390,"z":"Main","bgColor":"#cce6ff","wires":[[]]},{"id":"Main_dc6","type":"AudioSynthWaveformDc","name":"FEFEED","comment":"","x":140,"y":575,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_envelope3:0"]]},{"id":"Main_envelope3","type":"AudioEffectEnvelope","name":"Fenvelope","comment":"envelope for filter & \"ENV 2\" for mods","x":145,"y":630,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_2:3","Main_mixer4_5:3","Main_mixer4_6:3","Main_mixer4_7:3","Main_mixer4_17:1"]]},{"id":"Main_dc1","type":"AudioSynthWaveformDc","name":"VCA_FEED","comment":"","x":260,"y":260,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_2:0"]]},{"id":"Main_dc2","type":"AudioSynthWaveformDc","name":"Saw_Phase_DC","comment":"","x":200,"y":515,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_5:0"]]},{"id":"Main_dc4","type":"AudioSynthWaveformDc","name":"Metal_Amnt","comment":"","x":255,"y":755,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_7:0"]]},{"id":"Main_mixer4_18","type":"AudioMixer4","name":"input","comment":"","inputs":"4","x":240,"y":850,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_dc3","type":"AudioSynthWaveformDc","name":"PWidth","comment":"","x":335,"y":610,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_6:0"]]},{"id":"Main_waveform2","type":"AudioSynthWaveform","name":"sub_fifth","comment":"","x":445,"y":235,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_multiply1:0"]]},{"id":"Main_mixer4_2","type":"AudioMixer4","name":"VCA_Mix","comment":"","inputs":"4","x":450,"y":325,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_multiply1:1"]]},{"id":"Main_mixer4_5","type":"AudioMixer4","name":"Saw_Phase_Mixer","comment":"","inputs":"4","x":470,"y":535,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_waveformMod1:0"]]},{"id":"Main_mixer4_6","type":"AudioMixer4","name":"PMix","comment":"","inputs":"4","x":465,"y":630,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_pwm1:0"]]},{"id":"Main_waveform4","type":"AudioSynthWaveform","name":"Triangle","comment":"","x":480,"y":710,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_wavefolder1:0"]]},{"id":"Main_mixer4_7","type":"AudioMixer4","name":"TriangleMixer","comment":"","inputs":"4","x":480,"y":775,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_wavefolder1:1"]]},{"id":"Main_dc7","type":"AudioSynthWaveformDc","name":"Keyboard_Amnt","comment":"","x":490,"y":925,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_waveform3","type":"AudioSynthWaveform","name":"saw","comment":"","x":570,"y":405,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_4:0"]]},{"id":"Main_waveform1","type":"AudioSynthWaveform","name":"sub","comment":"","x":615,"y":210,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_1:0"]]},{"id":"Main_multiply1","type":"AudioEffectMultiply","name":"VCA","comment":"","x":615,"y":295,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_1:1"]]},{"id":"Main_waveformMod1","type":"AudioSynthWaveformModulated","name":"saw2","comment":"","x":635,"y":530,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_4:1"]]},{"id":"Main_mixer4_1","type":"AudioMixer4","name":"sub_Mix","comment":"","inputs":"4","x":755,"y":330,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_3:0"]]},{"id":"Main_mixer4_4","type":"AudioMixer4","name":"SSMixer","comment":"","inputs":"4","x":755,"y":440,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_3:1"]]},{"id":"Main_pwm1","type":"AudioSynthWaveformPWM","name":"pwm1","comment":"","x":745,"y":615,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_3:2"]]},{"id":"Main_wavefolder1","type":"AudioEffectWaveFolder","name":"Metalizer","comment":"","x":750,"y":760,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_3:3"]]},{"id":"Main_mixer4_17","type":"AudioMixer4","name":"FMod","comment":"mixer for filter ","inputs":"4","x":740,"y":890,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_filter1:1"]]},{"id":"Main_envelope2","type":"AudioEffectEnvelope","name":"ENV1","comment":"Copy of VCO envelope to feed to mods","x":925,"y":195,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_3","type":"AudioMixer4","name":"mixer","comment":"Osc mixer","inputs":"4","x":945,"y":545,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_envelope1:0"]]},{"id":"Main_mixer4_13","type":"AudioMixer4","name":"ENV_M1","comment":"","inputs":"4","x":1095,"y":205,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_14","type":"AudioMixer4","name":"ENV_M2","comment":"","inputs":"4","x":1097,"y":272,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_15","type":"AudioMixer4","name":"ENV_M3","comment":"","inputs":"4","x":1097,"y":342,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_16","type":"AudioMixer4","name":"ENV_M4","comment":"","inputs":"4","x":1095,"y":410,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_envelope1","type":"AudioEffectEnvelope","name":"envelope","comment":"VCO envelope","x":1060,"y":545,"z":"Main","bgColor":"#E6E0F8","wires":[["Main_mixer4_8:3","Main_filter1:0"]]},{"id":"Main_mixer4_9","type":"AudioMixer4","name":"LFO_M1","comment":"","inputs":"4","x":1263,"y":198,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_10","type":"AudioMixer4","name":"LFO_M2","comment":"","inputs":"4","x":1265,"y":270,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_11","type":"AudioMixer4","name":"LFO_M3","comment":"","inputs":"4","x":1265,"y":340,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_mixer4_12","type":"AudioMixer4","name":"LFO_M4","comment":"","inputs":"4","x":1275,"y":405,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_dc5","type":"AudioSynthWaveformDc","name":"ENV1FEED","comment":"","x":1265,"y":460,"z":"Main","bgColor":"#E6E0F8","wires":[[]]},{"id":"Main_filter1","type":"AudioFilterStateVariable","name":"filter","comment":"filter itself","x":1200,"y":620,"z":"Main","bgColor":"#E6E0F8","wires":[[],[],[]]},{"id":"Main_mixer4_8","type":"AudioMixer4","name":"output","comment":"","inputs":"4","x":1350,"y":530,"z":"Main","bgColor":"#E6E0F8","wires":[["Voice_Out1:0"]]},{"id":"Voice_Out1","type":"TabOutput","name":"Out","comment":"","x":1546.25,"y":537.5,"z":"Main","bgColor":"#cce6ff","wires":[]}]},{"type":"tab","id":"9a517d51.ac1b3","label":"Synth","inputs":0,"outputs":0,"export":true,"isMain":false,"mainNameType":"tabName","mainNameExt":".ino","generateCppDestructor":false,"extraClassDeclarations":"","settings":{"scaleFactor":0.8},"nodes":[{"id":"Synth_Voice1","type":"Voice","name":"voices[32]","x":295,"y":180,"z":"9a517d51.ac1b3","bgColor":"#CCFFCC","wires":[["Synth_mixer1:0"]]},{"id":"Synth_mixer1","type":"AudioMixer","name":"voicesMixer","inputs":"1","comment":"","x":480,"y":180,"z":"9a517d51.ac1b3","bgColor":"#E6E0F8","wires":[["Synth_i2s1:0","Synth_i2s1:1"]]},{"id":"Synth_i2s1","type":"AudioOutputI2S","name":"i2s","comment":"","x":675,"y":180,"z":"9a517d51.ac1b3","bgColor":"#E6E0F8","wires":[]}]}],"nodeAddons":{}
}
this can be imported into the tool as JSON
 
Yes - that is it! I actually created it using the (non-extended version) of the tool, but then laboriously changed the code so I could put each voice inside its own class in the style of SimpleSynth. The actual voices themselves are modeled after the Microbrute -- basically, it's a sub osc, a saw, a square and a triangle. You then can mod each of those -- sub gets a fifth tone added to it overtop, the saw gets a second saw added a bit out of phase ("super saw"), the square gets PWM, and the triangle gets metalized. For each of the mods you can either use any combination of DC (0-1) either of the two LFOs or either of the two envelopes. The way it is written the mod amount can't go past 1 -- if you change one of the 3 values it recalculates all 3 proportionally so they add up to 1. Also of course it has a filter that can be frequency controlled in all the same ways (DC, LFO, ENV), plus noise.

The actual UI is going to be a sloped metal enclosure with a 6 x 10 front. It will have 8 x 4 pots. The first 4x4 block if for the OSC controls (Osc amount, DC mod, LFO mod, Env mod) x 4. The second 4x4 block is the filter controls, the two envelopes, and then the two LFO speeds, the noise volume, and a main volume pot. There will be two little switches per OSC so you can select LFO 1 or 2 and ENV 1 or 2, and switches to select filter type and filter keyboard control (Filter will be locked to LFO 2 and ENV 2).

I'm using Teensy 4.1 so I will have hostUSB. I'm also going to (of course) be using 3 16 channel multiplexers for the pots, and they will update every 50 msecs. I have the hostUSB code and multiplexer code figured out from a recent project I did which was a foot controlled base midi pedal. I simply could not believe how fast and easy that was with teensy.

In this synth project, I'm also considering using a second teensy for a dedicated effects module... Delay + Reverb mostly but with a dedicated line in from the synth and a second in for external stuff -- I have room on top for that...

Anyway! Thanks for the help and for taking interest in the project to move into the extended design tool.
 
I am running into some weird bugs, especially involving the filter. I am thinking of redoing the whole thing from scratch using your visualizer. I’ll let you know how it goes.
 
Hi Manicksan -

I'm transferring my synth over to your visualizer and trying to get everything functioning. I followed the instructions to here, https://github.com/manicken/arduinoAPIwebserver, under Alternative Install for mac (2020 with M1 chip) and moved API_WebServer into tools. The Teensyduino software now says Websocket Server started. I am now trying to export your polysynth example via the Export Push JSON to the IDE, but I am getting the following error in the IDE ">>>warning: keywords array missing in JSON<<<".

I note there was an additional instruction for "Compile" to compile SK8 Java. I did not do that step because I figured my machine already has java and/or it might not be compatible with an M1 mac.
Do you think that is what is causing this issue?

Thanks again for all the help!

Tom
 
that is actually not a error,
everything should just work fine without it
it's only for the highlighting custom classes in the Arduino IDE

but push JSON only push (saves the current design) to the sketch folder

maybe what you want is export-"class-based"?


have no idea why the keywords are not included,
maybe I planned to use it but forgot
It's now implemented
but only available at the class export
(because it's the only use case)

edit.
you may get a java error (sometimes) but it's nothing to worry about
just a cross thread error
 
Status
Not open for further replies.
Back
Top