Variable AHR Oscillator using Arbitrary Waveform

Status
Not open for further replies.

jason11892

New member
Intro:
I'm relatively new to both programming and teensy, and I've been trying to make an oscillator whose waveform shape is controlled kind of like an envelope: with attack, hold, and release parameters being controlled in real time. So far, I've been using an arbitrary waveform in waveformMod (I want to do FM later) with the waveform shape controlled by an array. The points of the array are calculated with conditions and math in a for loop. At first, I coded the full oscillator as I wanted it. It outputted sound and was able to be controlled by the potentiometers, but the teensy would stop completely (USB audio, DAC audio, and serial communication) if the total of the knobs reached a certain point. After some searching, I found the problem: this part of the code
Code:
if ((i <= aKnob1 + hKnob1 + rKnob1) && i <= 256) {
should have been
Code:
if ((i >= aKnob1 + hKnob1 + rKnob1) && i <= 256) {
(see the full code below, you can change it back to what it was previously to see the earlier issue). Without the issue solved, if the total of the outputs was high enough, it would automatically output silence based on the if statement. With it fixed, though, it now outputs no sound. Then, I made a simple proof-of-concept sketch to see if what I'm trying to do is even possible, and it doesn't output sound either.

Question:
Is it even possible to have a variable array for an arbitrary waveform? My proof-of-concept sketch leads me to think no, but before I fixed the previous version I was getting a variable oscillator. Maybe my OSC_SCALE and OSC_OFFSET constants are inaccurate? I thought about making separate arrays for each knob position and just choosing one based on knob positions, but that seems unnecessarily clunky. What method would you suggest to achieve a variable oscillator/waveform?

Info:
I'm using a Teensy 3.2 and the Teensy Audio Library for this project. The Teensy is set to Audio + Midi + Serial communication, and I have 3 potentiometers going into A0, A1, and A2, respectively. I also have an audio port wired to the DAC, but I've been mainly monitoring audio via USB (I wrote a simple program to take the teensy audio and output it to my headphones. If you're going to monitor via the DAC, I recommend tuning the volume of the oscillator (AhrOsc.begin) way down, like to 0.01).

Code:

AHR Oscillator:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformModulated AhrOsc;         //xy=57,190
AudioOutputUSB           usb1;           //xy=414,236
AudioOutputAnalog        dac1;           //xy=464,159
AudioConnection          patchCord1(AhrOsc, dac1);
AudioConnection          patchCord2(AhrOsc, 0, usb1, 0);
AudioConnection          patchCord3(AhrOsc, 0, usb1, 1);
// GUItool: end automatically generated code

int16_t OscArray[256];

int aKnob1 = 0;
int hKnob1 = 0;
int rKnob1 = 0;

const int OSC_SCALE = 65534;
const int OSC_OFFSET = 32767;


void setup() {
  // put your setup code here, to run once:
  AhrOsc.begin(0.5, 440, WAVEFORM_ARBITRARY);
  AhrOsc.arbitraryWaveform(OscArray, float(20000));
  AudioMemory(64);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  aKnob1 = analogRead(A0) / 3.99;
  hKnob1 = analogRead(A1) / 3.99;
  rKnob1 = analogRead(A2) / 3.99;
  Serial.println(aKnob1 + hKnob1 + rKnob1);
  
  for (int i = 0; i <= 256; i++){ //loop to calculate the array
    if (i < aKnob1) {
      OscArray[i] = ((OSC_SCALE / aKnob1) * i) - OSC_OFFSET; //produces an upwards ramp with it's time/length/slope being controlled by aKnob1
    }
    if ((aKnob1 <= i) && (i < (aKnob1 + hKnob1))) {
      OscArray[i] = int(OSC_SCALE - OSC_OFFSET); //produces a constant flat line in between the attack and release with a time/length of hKnob1.
    }
    if (((aKnob1 + hKnob1) <= i) && (i < aKnob1 + hKnob1 + rKnob1)) {
      OscArray[i] = ((-1 * ((OSC_SCALE / rKnob1) * i)) + OSC_SCALE) - OSC_OFFSET; //produces a downwards ramp with it's time/length/slpe being controlled y rKnob1
    }
    if ((i >= aKnob1 + hKnob1 + rKnob1) && i <= 256) { //line where the previous mistake was
      OscArray[i] = -1 * (OSC_SCALE - OSC_OFFSET); // provides a condition if all the stages are over, but the array has more space, fill it with the lowest value.
    }
  }
}

Proof-of-concept:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformModulated AhrOsc;         //xy=57,190
AudioOutputUSB           usb1;           //xy=414,236
AudioOutputAnalog        dac1;           //xy=464,159
AudioConnection          patchCord1(AhrOsc, dac1);
AudioConnection          patchCord2(AhrOsc, 0, usb1, 0);
AudioConnection          patchCord3(AhrOsc, 0, usb1, 1);
// GUItool: end automatically generated code

int16_t OscArray[256];

int Width = 0;

const int OSC_SCALE = 65534;
const int OSC_OFFSET = 32767;


void setup() {
  // put your setup code here, to run once:
  AhrOsc.begin(0.5, 440, WAVEFORM_ARBITRARY);
  AhrOsc.arbitraryWaveform(OscArray, float(20000));
  AudioMemory(64);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  Width = analogRead(A0) / 3.99;
  Serial.println(Width);
  
  for (int i = 0; i <= 256; i++){ //loop to calculate the array, simple PW square wave
    if (i <= Width){
      OscArray[i] = OSC_SCALE - OSC_OFFSET;
    }
    if (i > Width) {
      OscArray[i] = -1 * (OSC_SCALE - OSC_OFFSET);
    }
  }
}

Thanks so much! I'm open to learning a new method to achieve what I want, too.
 
One quick observation. In both programs you have:
Code:
  for (int i = 0; i <= 256; i++){
This should be
Code:
  for (int i = 0; i < 256; i++){
otherwise when i=256 you'll write off the end of OscArray.

Pete
 
And another thing :)
In the proof of concept, when you fill the array in the loop function, that is happening so fast that, in effect, 'Width' is a constant. This means that all elements of OscArray are set to the same value. This gives a DC output which won't make any sound.

Pete
 
Thanks for the quick reply! I changed the for loop code to be i < 256 in both examples like you said, and it worked perfectly! I got audio out in both examples, and the knobs worked to change the sound. I don't understand what you mean about "Width" being a constant. Don't the 2 if statements make it so even if "Width" was a fixed value, it would set 2 different levels on either side of "Width", making a square wave-like sound? Thanks again for solving it, I'm glad it was so simple!
 
Status
Not open for further replies.
Back
Top