Arbitrary waveform object issue

Status
Not open for further replies.

Ross Fish

Member
Hey Everyone,

We released this synthesizer last week and got an overwhelmingly positive response. It shipped with some minor bugs that didn't come to my attention until after the units were out in the wild. As you turn the "wave" knob for the 2nd LFO, the pot adds 0-8hz to the main oscillator. I've confirmed that this is not hardware related as I've monitored the ADCs and they show know change. Furthermore, the order of operations makes this bug jump from pot to pot; rather than being the wave pot, it will arbitrarily switch to a different pot if you start moving pieces of code around. If you'll notice in my attached video, the LFO i'm messing with is completely disengaged from the program as the depth control is completely down. This effect will occur regardless of the function the pot is mapped to and as I previously stated, has the tendency to jump to other pots depending on order of operations. If I comment out the line of code responsible for reading this pots ADC, the bug moves to a different pot.


Code:
/*
             Stargazer
           CC-BY-NC-SA
    Created by Ross Fish 2018
        Moffenzeef Modular
  http://moffenzeefmodular.com/stargazer

        Waveforms by Adventure Kid
    AKWF waveforms are Public Domain
  https://www.adventurekid.se/akrt/waveforms/adventure-kid-waveforms/

    Waveforms formatted for Teensy by Datanoise
  https://github.com/DatanoiseTV/AKWF_WaveForms
*/

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

// GUItool: begin automatically generated code
AudioSynthWaveform       waveform2;      //xy=1628,1374
AudioSynthWaveform       waveform1;      //xy=1631,1335
AudioSynthWaveform       waveform3;      //xy=1746,1425
AudioMixer4              mixer1;         //xy=1777,1355
AudioEffectWaveshaper    waveshape1;     //xy=1874,1470
AudioFilterStateVariable filter1;        //xy=1902,1362
AudioSynthWaveformDc     dc1;            //xy=2009,1298
AudioSynthWaveform       waveform5;      //xy=2013,1244
AudioAnalyzeRMS          rms2;           //xy=2020,1476
AudioSynthWaveform       waveform4;      //xy=2024,1412
AudioEffectBitcrusher    bitcrusher1;    //xy=2035,1356
AudioEffectWaveshaper    waveshape2;     //xy=2162,1188
AudioMixer4              mixer3;         //xy=2169,1262
AudioEffectWaveshaper    waveshape3;     //xy=2172,1446
AudioFilterStateVariable filter2;        //xy=2174,1361
AudioAnalyzeRMS          rms4;           //xy=2306,1191
AudioAnalyzeRMS          rms3;           //xy=2313,1447
AudioEffectMultiply      multiply1;      //xy=2332,1313
AudioMixer4              mixer2;         //xy=2467,1328
AudioOutputAnalog        dac1;           //xy=2617,1315
AudioConnection          patchCord1(waveform2, 0, mixer1, 1);
AudioConnection          patchCord2(waveform1, 0, mixer1, 0);
AudioConnection          patchCord3(waveform3, 0, filter1, 1);
AudioConnection          patchCord4(waveform3, waveshape1);
AudioConnection          patchCord5(mixer1, 0, filter1, 0);
AudioConnection          patchCord6(waveshape1, rms2);
AudioConnection          patchCord7(filter1, 0, bitcrusher1, 0);
AudioConnection          patchCord8(dc1, 0, mixer3, 1);
AudioConnection          patchCord9(waveform5, 0, mixer3, 0);
AudioConnection          patchCord10(waveform5, waveshape2);
AudioConnection          patchCord11(waveform4, 0, filter2, 1);
AudioConnection          patchCord12(waveform4, waveshape3);
AudioConnection          patchCord13(bitcrusher1, 0, filter2, 0);
AudioConnection          patchCord14(waveshape2, rms4);
AudioConnection          patchCord15(mixer3, 0, multiply1, 0);
AudioConnection          patchCord16(waveshape3, rms3);
AudioConnection          patchCord17(filter2, 0, multiply1, 1);
AudioConnection          patchCord18(multiply1, 0, mixer2, 0);
AudioConnection          patchCord19(mixer2, dac1);
// GUItool: end automatically generated code

float osc1 = 0;
float osc2 = 0;
float oscMix = 0;

float cutoff1 = 0;
float res1 = 0;
float cutoff2 = 0;
float res2 = 0;


float LFO1AMP = 0;
float LFO1FREQ = 0;
float LFO1MATH = 0;

float LFO2AMP = 0;
float LFO2FREQ = 0;
float LFO2MATH = 0;

float LFO3AMP = 0;
float LFO3FREQ = 0;
float LFO3MATH = 0;

int waveSelect1 = 0;
int waveSelect2 = 0;
int waveSelect3 = 0;
int waveSelect4 = 0;

int bitRate = 0;
int sampleRedux = 0;

int expPedal = 0;

int LFO1led = 0;
int LFO2led = 0;
int LFO3led = 0;

float rectify[2] = {0.0, 1.0};

float sub = 0;

float diffWAVE = 0;
int currentWAVE = 0;
float smoothWAVE = 0;

float diffOSC = 0;
int currentADCOSC = 0;
float smoothADCOSC = 0;

float diffPEDAL = 0;
float smoothPEDAL = 0;
int currentPEDAL = 0;

int waveSelect = 0;

#include "AKWF_R.H"
#include "AKWF_aguitar.H"
#include "AKWF_altosax.H"
#include "AKWF_birds.H"
#include "AKWF_bitreduced.H"
#include "AKWF_blended.H"
#include "AKWF_bsaw.H"
#include "AKWF_c604.H"
#include "AKWF_clavinet.H"
#include "AKWF_distorted.H"
#include "AKWF_eguitar.H"
#include "AKWF_eorgan.H"
#include "AKWF_epiano.H"
#include "AKWF_fmsynth.H"
#include "AKWF_granular.H"
#include "AKWF_hvoice.H"
#include "AKWF_overtone.H"

struct WaveTable {
  int16_t const* table;
};

#define TABLE_NUM 89 // 

WaveTable waveTables[TABLE_NUM] {
  AKWF_R_sym_saw_15,
  AKWF_R_sym_saw_25,
  AKWF_aguitar_0008,
  AKWF_altosax_0005,
  AKWF_birds_0002,
  AKWF_birds_0004,
  AKWF_birds_0005,
  AKWF_bitreduced_0002,
  AKWF_bitreduced_0006,
  AKWF_bitreduced_0007,
  AKWF_bitreduced_0011,
  AKWF_bitreduced_0013,
  AKWF_bitreduced_0016,
  AKWF_bitreduced_0019,
  AKWF_bitreduced_0022,
  AKWF_bitreduced_0026,
  AKWF_bitreduced_0028,
  AKWF_bitreduced_0031,
  AKWF_bitreduced_0032,
  AKWF_bitreduced_0038,
  AKWF_blended_0002,
  AKWF_blended_0003,
  AKWF_blended_0007,
  AKWF_blended_0012,
  AKWF_blended_0013,
  AKWF_blended_0030,
  AKWF_bsaw_0001,
  AKWF_c604_0004,
  AKWF_clavinet_0001,
  AKWF_distorted_0004,
  AKWF_distorted_0005,
  AKWF_distorted_0009,
  AKWF_distorted_0010,
  AKWF_distorted_0014,
  AKWF_distorted_0015,
  AKWF_distorted_0017,
  AKWF_distorted_0018,
  AKWF_distorted_0022,
  AKWF_distorted_0023,
  AKWF_distorted_0026,
  AKWF_distorted_0027,
  AKWF_eguitar_0003,
  AKWF_eorgan_0042,
  AKWF_eorgan_0043,
  AKWF_eorgan_0046,
  AKWF_eorgan_0055,
  AKWF_eorgan_0058,
  AKWF_eorgan_0059,
  AKWF_eorgan_0060,
  AKWF_eorgan_0061,
  AKWF_eorgan_0062,
  AKWF_epiano_0005,
  AKWF_epiano_0008,
  AKWF_fmsynth_0002,
  AKWF_fmsynth_0004,
  AKWF_fmsynth_0005,
  AKWF_fmsynth_0006,
  AKWF_fmsynth_0007,
  AKWF_fmsynth_0024,
  AKWF_fmsynth_0034,
  AKWF_fmsynth_0035,
  AKWF_fmsynth_0036,
  AKWF_fmsynth_0040,
  AKWF_fmsynth_0051,
  AKWF_fmsynth_0055,
  AKWF_fmsynth_0056,
  AKWF_fmsynth_0057,
  AKWF_fmsynth_0058,
  AKWF_fmsynth_0059,
  AKWF_fmsynth_0060,
  AKWF_granular_0009,
  AKWF_granular_0020,
  AKWF_granular_0033,
  AKWF_hvoice_0030,
  AKWF_hvoice_0033,
  AKWF_hvoice_0035,
  AKWF_hvoice_0036,
  AKWF_hvoice_0039,
  AKWF_hvoice_0048,
  AKWF_hvoice_0052,
  AKWF_hvoice_0054,
  AKWF_hvoice_0056,
  AKWF_hvoice_0071,
  AKWF_overtone_0001,
  AKWF_overtone_0005,
  AKWF_overtone_0017,
  AKWF_overtone_0026,
  AKWF_overtone_0028,
};

short waveShapesLFO1[6] = {
  WAVEFORM_SINE,
  WAVEFORM_TRIANGLE,
  WAVEFORM_SAWTOOTH,
  WAVEFORM_SAWTOOTH_REVERSE,
  WAVEFORM_SQUARE,
  WAVEFORM_SAMPLE_HOLD,
};

short waveShapesLFO2[6] = {
  WAVEFORM_SINE,
  WAVEFORM_TRIANGLE,
  WAVEFORM_SAWTOOTH,
  WAVEFORM_SAWTOOTH_REVERSE,
  WAVEFORM_SQUARE,
  WAVEFORM_SAMPLE_HOLD,
};

short waveShapesLFO3[6] = {
  WAVEFORM_SINE,
  WAVEFORM_TRIANGLE,
  WAVEFORM_SAWTOOTH,
  WAVEFORM_SAWTOOTH_REVERSE,
  WAVEFORM_SQUARE,
  WAVEFORM_SAMPLE_HOLD,
};

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void setup() {
  waveform1.begin(WAVEFORM_ARBITRARY);
  waveform2.begin(WAVEFORM_ARBITRARY);
  AudioMemory(100);  // put your setup code here, to run once:
  dac1.analogReference(EXTERNAL);
  analogReference(EXTERNAL);
  pinMode(2, INPUT); // Sub OCT switch
  pinMode(13, OUTPUT); // Teensy LED
  pinMode(3, OUTPUT); // Main LED
  digitalWrite(13, HIGH);
  digitalWrite(3, HIGH);
}

void loop() {

  // EXPRESSION PEDAL
  currentPEDAL = analogRead(A0);
  diffPEDAL = currentPEDAL - smoothPEDAL;
  smoothPEDAL = smoothPEDAL + (diffPEDAL * 0.005f); // Lower decimal value = more smoothing
  expPedal = map(smoothPEDAL, 1, 1023, -512, 512);

  // MAIN OSCILLATOR FREQUENCY & AMPLITUDE
  waveform1.amplitude(0.8f);
  currentADCOSC = analogRead(A1);
  diffOSC = currentADCOSC - smoothADCOSC;
  smoothADCOSC = smoothADCOSC + (diffOSC * 0.01f); // Decimal value is digital lowpass, lower value = more slew
  osc1 = mapfloat(smoothADCOSC, 0, 1023, 1.0f, 500.0f);
  waveform1.frequency(osc1);

  // MAIN OSCILLATOR WAVETABLE SELECTION
  currentWAVE = analogRead(A3);
  diffWAVE = currentWAVE - smoothWAVE;
  smoothWAVE = smoothWAVE + (diffWAVE * 0.006f); // Decimal value is digital lowpass, lower value = more slew
  waveSelect = map(smoothWAVE, 0, 1023, 0, 88);

  struct WaveTable* waveTable  = &waveTables[waveSelect];
  int16_t* wave = const_cast<short int*>(waveTable->table);

  waveform1.arbitraryWaveform(wave, 500.0f);
  waveform2.arbitraryWaveform(wave, 500.0f);

  // DETUNED OSCILLATOR SECTION
  if (digitalRead(2) == HIGH) {
    sub = 1;
  }
  else {
    sub = 2;
  }

  osc2 = osc1 + mapfloat(analogRead(A2), 0, 1023, -5.0f, 5.0f);
  waveform2.amplitude(0.8f);
  waveform2.frequency(osc2 / sub);

  oscMix = mapfloat(analogRead(A4), 0, 1023, 0.0f, 0.5f);
  mixer1.gain(0, 0.5f);
  mixer1.gain(1, oscMix);
  mixer1.gain(2, 0.0);
  mixer1.gain(3, 0.0);

  // FILTER 1
  cutoff1 = mapfloat(analogRead(A5), 0, 1023, 80.0f, 5000.0f);
  res1 = mapfloat(analogRead(A6), 0, 1023, 1.5f, 5.0f);
  filter1.frequency(cutoff1);
  filter1.resonance(res1);

  // LFO 1
  waveSelect2 = map(analogRead(A9), 0, 1023, 0, 5);
  waveform3.begin(waveShapesLFO1[waveSelect2]);
  waveform3.arbitraryWaveform(waveShapesLFO1, 100.0f);

  LFO1MATH = expPedal + analogRead(A10);
  LFO1MATH = max(LFO1MATH, 0);
  LFO1MATH = min(LFO1MATH, 1023);
  LFO1FREQ = mapfloat(LFO1MATH, 0, 1023, 0.05f, 100.0f);
  waveform3.frequency(LFO1FREQ);

  LFO1AMP = mapfloat(analogRead(A11), 0, 1023, 0.0f, 1.0f);
  waveform3.amplitude(LFO1AMP);

  // SAMPLE RATE AND BIT DEPTH
  sampleRedux = map(analogRead(A19), 0, 1023, 18000, 1);
  bitRate = map(analogRead(A20), 0, 1023, 11, 1);
  bitcrusher1.sampleRate(sampleRedux);
  bitcrusher1.bits(bitRate);

  // FILTER 2
  cutoff2 = mapfloat(analogRead(A7), 0, 1023, 80.0f, 15000.0f);
  res2 = mapfloat(analogRead(A8), 0, 1023, 1.5f, 5.0f);
  filter2.frequency(cutoff2);
  filter2.resonance(res2);

  // LFO 2
  waveSelect3 = map(analogRead(A12), 0, 1023, 0, 5);
  waveform4.begin(waveShapesLFO2[waveSelect3]);
  waveform4.arbitraryWaveform(waveShapesLFO3, 100.0f);
  
  LFO2MATH = expPedal + analogRead(A13);
  LFO2MATH = max(LFO2MATH, 0);
  LFO2MATH = min(LFO2MATH, 1023);
  LFO2FREQ = mapfloat(LFO2MATH, 0, 1023, 0.05f, 100.0f);
  waveform4.frequency(LFO2FREQ);

  LFO2AMP = mapfloat(analogRead(A15), 0, 1023, 0.0f, 1.0f);
  waveform4.amplitude(LFO2AMP);

  // VCA
  dc1.amplitude(1.0f);
  mixer3.gain(0, 1.0f);
  mixer3.gain(1, 1.0f);
  mixer3.gain(2, 0.0f);
  mixer3.gain(3, 0.0f);

  // LFO 3 
  waveSelect4 = map(analogRead(A16), 0, 1023, 0, 5);
  waveform5.begin(waveShapesLFO3[waveSelect4]);
  waveform5.arbitraryWaveform(waveShapesLFO3, 100.0f);

  LFO3MATH = expPedal + analogRead(A17);
  LFO3MATH = max(LFO3MATH, 0);
  LFO3MATH = min(LFO3MATH, 1023);
  LFO3FREQ = mapfloat(LFO3MATH, 0, 1023, 0.05f, 100.0f);
  waveform5.frequency(LFO3FREQ);
  
  LFO3AMP = mapfloat(analogRead(A18), 0, 1023, 0.0f, 1.0f);
  waveform5.amplitude(LFO3AMP); 

  // Final Output Attenuator
  mixer2.gain(0, 0.2f);
  mixer2.gain(1, 0.0f);
  mixer2.gain(2, 0.0f);
  mixer2.gain(3, 0.0f);

  // Rectifiers for LEDS
  waveshape1.shape(rectify, 2);
  waveshape2.shape(rectify, 2);
  waveshape3.shape(rectify, 2);

  // Write LEDs
  LFO1led = mapfloat(rms2.read(), 0.5f, 1.0f, 0, 255);
  analogWrite(4, LFO1led);

  LFO2led = mapfloat(rms3.read(), 0.5f, 1.0f, 0, 255);
  analogWrite(5, LFO2led);

  LFO3led = mapfloat(rms4.read(), 0.5f, 1.0f, 0, 255);
  analogWrite(6, LFO3led);
}
 

Attachments

  • AKWF_aguitar.h
    1.9 KB · Views: 102
  • AKWF_altosax.h
    1.9 KB · Views: 86
  • AKWF_birds.h
    5.8 KB · Views: 125
  • AKWF_bitreduced.h
    25.2 KB · Views: 119
  • AKWF_blended.h
    11.6 KB · Views: 114
  • AKWF_bsaw.h
    1.9 KB · Views: 106
  • AKWF_c604.h
    1.9 KB · Views: 100
  • AKWF_cello.h
    36.7 KB · Views: 143
  • AKWF_clavinet.h
    1.9 KB · Views: 99
  • AKWF_dbass.h
    133.4 KB · Views: 107
Looks like an interesting project. I don't see where you connect the pots to the Teensy in your code.
 
I need you to trim this to a smaller program, just enough to demonstrate the problem.

If there is a bug in the audio library causing this, I will fix it. But I can't dedicate the engineering time to reducing your program. I really need you to do that part.
 
Sorry, ... beginner's oversight. I didn't scroll down far enough, where the pots are read and thus connected.
 
Just a quick reminder, I'd like to investigate this problem, but I really need a more reproducible (and ideally smaller) test program. Use of analogRead() is ok, but using 20 analog values to vary the oscillators isn't something I can reliably reproduce. The code really needs to use fixed values that consistently reproduce the problem.

I have only 1 more bug on my list before 1.42-beta6. 1.42 is being held up by a multiple instances bug in teensy_ports on Windows. Once that's fixed (beta6 may do the trick) I'm going to want to release the long-overdue 1.42 version.

In other words, time is (probably) running out to get a fix for this into 1.42. Of course there's always 1.43, either in ~3 months or when a new Arduino release forces us to release too.
 
how come this guy has 2 posts 18 minutes apart and i just checked New posts 5 minutes ago both wernt posted yet...
 
Hello All,

Our problem was hardware related in the end. Turns out the ADC's didn't like the high impedance of the pots we selected. All issues stemmed from that...

Thanks for your help and sorry for the confusion!

Cheers,
Ross
 
As stated in the Kinetis ADC application note, the source impedance should be less than 10k. Thus, 10k potentiometers are ok. Kinetis recommends also to add a small (10nF) capacitor between the wiper (or the ADC input) and ground to give more stable readings since the ADC input impedance varies during a measurement cycle due to the SAR conversion.
 
Status
Not open for further replies.
Back
Top