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

Thread: making Mozzi work with Teensy Audio Adaptor (SGTL5000)

  1. #1
    Junior Member
    Join Date
    Dec 2017
    Posts
    6

    making Mozzi work with Teensy Audio Adaptor (SGTL5000)

    Hi guys
    Recently got a teensy 3.2 and a audio adaptor along with it, thinking that i could program Mozzi and have a basic inputs and outputs bundled on the adaptor for easy access.

    well, turns out I didn't do my research and the ports are NOT simply redirecting signals to A14 and whatnot, but they're digial inputs that works with SGTL5000. you know what, i'm still not sure. correct me if I'm talking unicorns.

    I could just get a headphone jack connected to A14 but i want to actually use the adaptor.
    so i did muh research and managed to have Mozzi's output streamed into I2S's AudioPlayQueue

    References from
    https://forum.pjrc.com/threads/28254...1-audio-Shield
    https://forum.pjrc.com/threads/27736...g%29-frequency

    So what I'm doing is :
    - have a typical Mozzi project. Code below is a modification of a Mozzi example Control Echo Theremin. I modded it so a sine wave's pitch alters according to input pin 2.
    - in each updateAudio(), I collected the samples before its returned, into a buffer(just a simple list of 128 int16_t)
    - when the buffer hits the end, I'd put them in a memory from where the queue resides,
    - playQueue() and restart the buffer
    - also got the hint from the above thread to change the STGL5000's sample rate to 16384.
    - tada

    Took me long to fiddle with buffer size and where to put any functions.. but this is the best I could do.

    Now where I need you guys help is the consistent clicks in the output. First guess is that this is caused by sample rate not 100% in sync with Mozzi by decimals. Meh... I think this is the limit of mixing two independant audio system... But i'd really like to use mozzi and the teensy audio shield, though.

    I'd really appreciate it if anyone could help with this!

    Thanks in advance guys


    Code:
    #include <MozziGuts.h>
    #include <Oscil.h> // oscillator template
    #include <tables/sin2048_int8.h> // sine table for oscillator
    #include <RollingAverage.h>
    #include <ControlDelay.h>
    
    
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    AudioPlayQueue           queue1;         //xy=92,334
    AudioOutputI2S           i2s1;           //xy=342,313
    AudioConnection          patchCord1(queue1, 0, i2s1, 0);
    AudioConnection          patchCord2(queue1, 0, i2s1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=298,544
    
    #define FSAMPLE 16384
    
    int16_t buffer[128];
    int bufferIndex = 0;
    
    // function prototype
    bool setI2SmasterClock(uint32_t freq, uint32_t mult = 256);
    float getI2SmasterClock(uint32_t mult = 256);
    #define INPUT_PIN 2 // analog control input
    
    unsigned int echo_cells_1 = 32;
    unsigned int echo_cells_2 = 60;
    unsigned int echo_cells_3 = 127;
    
    #define CONTROL_RATE 64
    ControlDelay <128, int> kDelay; // 2seconds
    
    // oscils to compare bumpy to averaged control input
    Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin0(SIN2048_DATA);
    Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin1(SIN2048_DATA);
    Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin2(SIN2048_DATA);
    Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin3(SIN2048_DATA);
    
    // use: RollingAverage <number_type, how_many_to_average> myThing
    RollingAverage <int, 32> kAverage; // how_many_to_average has to be power of 2
    int averaged;
    
    void setup(){
      kDelay.set(echo_cells_1);
      startMozzi();
        AudioMemory(60);
      setI2SmasterClock(FSAMPLE);
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.6);
      Serial.begin(9600);
    }
    
    
    void updateControl(){
      int bumpy_input = mozziAnalogRead(INPUT_PIN);
      
      averaged = kAverage.next(bumpy_input);
      aSin0.setFreq(averaged);
      aSin1.setFreq(kDelay.next(averaged));
      aSin2.setFreq(kDelay.read(echo_cells_2));
      aSin3.setFreq(kDelay.read(echo_cells_3));
    }
    
    
    int updateAudio(){
      int16_t currentSample =  3*((int)aSin0.next()+aSin1.next()+(aSin2.next()>>1)+(aSin3.next()>>2)) << 3;
    
      if(bufferIndex < 128){
        buffer[bufferIndex] = currentSample;
        bufferIndex++;
      }else{
        int16_t *bufferPointer = queue1.getBuffer();
        memcpy(bufferPointer, buffer, 256);
        queue1.playBuffer();
        bufferIndex = 0;
      }
      return currentSample;
    }
    
    
    void loop(){
      
    
      audioHook();
    }
    
    
    
    /* Generate I2S master clock
    
       The MCLK output frequencies should be in the range from F_pll/4096 to 12.5 MHz.
       For convenience the frequency has been split into a sample frequency and 
       a sample clock multiplication factor.
       For direct control of the master clock frequency, set the multiplier to 1.
       For almost all combinations of sample clocks (8, 11.025, 12, 16, 22.05, 24,
       32, 44.1 and 48 kHz) and cpu clock frequencies it will find a ratio, that
       generates the exact frequency. For the other few, the output frequency
       lies within 0.5 Hz distance from the desired frequency.
    
       freq: sample frequency in Hz
       mult: sample clock multiplication factor, (default 256)
       return value: true if the frequency is within the valid range
    */
    
    bool setI2SmasterClock(uint32_t freq, uint32_t mult)
    {
            // determine fractional ratio for: p / q = freq * mult / f_pll
            // f_pll = 16 MHz * ((MCG_C6 & 0x1f) + 24) / ((MCG_C5 & 0x1f) + 1)
      uint32_t p = freq * mult * ((MCG_C5 & 0x1f) + 1);
            uint32_t q = 16000000ul * ((MCG_C6 & 0x1f) + 24);
      uint32_t fract = 0, divide = 1; // I2Sx_MDR register values
      uint32_t fract1, fract2 = 1;  // values of iterations n-1 and n-2.
      uint32_t divide1, divide2 = 0;  // idem.
            uint8_t src = 3;    // clock source selection: 3 = pll
    
            // Master clock should be slower than reference clock
            if (p > q)
                    return false;
            else if (p == q)
                    fract = divide = 1;
            else {
              // Approximate p/q by a continued fraction expansion.
                // (typically takes only 4 to 8 iterations)
                while (p) {
                // find next element of continued fraction
            uint32_t a = q / p;
            uint32_t oldp = p;
            p = q - a * p;
            q = oldp;
    
                // update fract/divide by Wallis method
            fract1 = fract;
            divide1 = divide;
            fract = fract1 * a + fract2;
            divide = divide1 * a + divide2;
            fract2 = fract1;
            divide2 = divide1;
    
            // Exit loop if fraction gets too big for the registers
            if (fract > 256 || divide > 4096) {
              // Revert back to last approximation that still fitted
              fract = fract2;
              divide = divide2;
              break;
            }
          }
                // Check if frequency too low or too high
                if (!fract)
                        return false;
            }
    
      // Actually set registers and enable MCLK.
            SIM_SCGC6 |= SIM_SCGC6_I2S;
      I2S0_MDR = I2S_MDR_FRACT((fract - 1)) | I2S_MDR_DIVIDE((divide - 1));
            I2S0_MCR = I2S_MCR_MICS(src) | I2S_MCR_MOE;
    
      // 'Connect' MCLK output to an actual output pin
            CORE_PIN11_CONFIG = PORT_PCR_MUX(6);
            //CORE_PIN28_CONFIG = PORT_PCR_MUX(4); // Pin on bottom
    
            return true;
    }
    
    float getI2SmasterClock(uint32_t mult)
    {
            float fpll = 16.0e6f * ((MCG_C6 & 0x1f) + 24) / ((MCG_C5 & 0x1f) + 1);
            uint32_t fract = ((I2S0_MDR >> 12) & 0xff) + 1;
            uint32_t divide = (I2S0_MDR & 0xfff) + 1;
            return fpll * fract / (divide * mult);
    }

  2. #2
    Junior Member
    Join Date
    Dec 2017
    Posts
    6
    lolololololololololololololololol

    imma correct my own stupidity.

    the incremental bufferIndex should go from 0 to 127, not 0 to 128 hahahahahahahahahaha

    Code:
      buffer[bufferIndex] = currentSample;
      if(bufferIndex < 127){
        bufferIndex++;
      }else{
        int16_t *bufferPointer = queue1.getBuffer();
        memcpy(bufferPointer, buffer, 256);
        queue1.playBuffer();
        bufferIndex = 0;
      }

    I guess this thread became a tip thread rather than a question thread. oh well I'm happy, hope this could help anyone in need!

    happy coding guys

  3. #3
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    1,153
    Not writing or reading beyond array boundaries is self-understanding and common sense, especially in C/C++ where the read or write address pointer just advances without asking for your initial array dimensions. Higher (but slower) programming languages check such potential issues at runtime and throw qualified errors at the expense of additional memory and cpu cycle consumption.

    But it's perhaps important, though, to mentions such problems from time to time, since there are also a few beginners walking in here occasionally.

  4. #4
    Junior Member
    Join Date
    Dec 2017
    Posts
    6
    Yeah, understanding memory allocations or managing pointers is really awkward for me, having been comfortable all my developing life with javascript. Infact, memcpy itself was pretty baffling to me, but I guess I got past it.

    Correct me if I'm wrong - I suspected that the pops and clicks happened because I was collecting 129 samples (0 to 128) but audioPlayQueue only plays 128 samples, thus losing a sample and making a consistent clicks.

  5. #5
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    1,153
    Quote Originally Posted by jidagraphy View Post
    Yeah, understanding memory allocations or managing pointers is really awkward for me, having been comfortable all my developing life with javascript. Infact, memcpy itself was pretty baffling to me, but I guess I got past it.

    Correct me if I'm wrong - I suspected that the pops and clicks happened because I was collecting 129 samples (0 to 128) but audioPlayQueue only plays 128 samples, thus losing a sample and making a consistent clicks.
    Sounds like a logical explanation...

    What I don't understand is why you try to use the Mozzi stuff instead of using explicitly the Teensy audio library which has higher quality and performance. Compared to the Teensy audio objects, Mozzi looks like the poor cousin next village...

Posting Permissions

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