Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: Variable AHR Oscillator using Arbitrary Waveform

  1. #1
    Junior Member
    Join Date
    Jun 2021
    Posts
    3

    Variable AHR Oscillator using Arbitrary Waveform

    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.

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,719
    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

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,719
    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

  4. #4
    Junior Member
    Join Date
    Jun 2021
    Posts
    3
    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!

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,719
    even if "Width" was a fixed value, it would set 2 different levels
    Yes, you're right. I was reading into your code something that wasn't there!

    Pete

  6. #6
    Junior Member
    Join Date
    Jun 2021
    Posts
    3
    Okay, thanks!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •