Quad I2S using 1 audio board, switching between synth/mic

Status
Not open for further replies.

propa

Well-known member
I'm trying to put a couple of pieces of code together, one mode outputs a synth sound, one mode outputs the mic in.

I've read you can only use 1 I2S object, and can't use a mixer to send multiple signals to it. The code attached is a work around after finding the quad i2s object.

I'm aware it's been made to use with multiple audio boards; however can it be used to with 1 audio board if you're not simultaneously processing two streams?

There's a great deal of ambiguity in the statement:

"Normally, this object is used with two Audio Shields, which are controlled separately by a pair of "sgtl5000" objects"

Is there any wiggle room with normality? Can the quad I2S object be used like this with only one shield?

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

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=63,154
AudioSynthWaveformSineModulated sine_fm1;       //xy=190,252
AudioInputI2S            i2s2;           //xy=226,65
AudioEffectEnvelope      envelope1;      //xy=340,257
AudioMixer4              mixer2;         //xy=403,79
AudioEffectDelay         delay1;         //xy=501,339
AudioEffectGranular      granular1;      //xy=556,71
AudioMixer4              mixer1;         //xy=681,270
AudioOutputI2SQuad       i2s_quad1;      //xy=784,109
AudioConnection          patchCord1(sine1, sine_fm1);
AudioConnection          patchCord2(sine_fm1, envelope1);
AudioConnection          patchCord3(i2s2, 0, mixer2, 0);
AudioConnection          patchCord4(i2s2, 1, mixer2, 1);
AudioConnection          patchCord5(envelope1, delay1);
AudioConnection          patchCord6(envelope1, 0, i2s_quad1, 2);
AudioConnection          patchCord7(mixer2, granular1);
AudioConnection          patchCord8(delay1, 0, mixer1, 0);
AudioConnection          patchCord9(delay1, 1, mixer1, 1);
AudioConnection          patchCord10(delay1, 2, mixer1, 2);
AudioConnection          patchCord11(delay1, 3, mixer1, 3);
AudioConnection          patchCord12(granular1, 0, i2s_quad1, 0);
AudioConnection          patchCord13(granular1, 0, i2s_quad1, 1);
AudioConnection          patchCord14(mixer1, 0, i2s_quad1, 3);
AudioControlSGTL5000     sgtl5000_1;     //xy=303,373
// GUItool: end automatically generated code
 
Reading the documentation and looking at the schematics of the audio board should tell you that the I2S data stream for the 3rd and 4th channel (I2S0_TXD1) is of no use when using only one audio board. Each SGTL5000 can accept one single stream, either I2S0_TXD0 containing channels 1 and 2 or I2S0_TXD1 containing channels 3 and 4, but never both.
Only when using 2 audio boards, you might connect one data line to the one and the other line to the other, while connecting the master clock, bit clock, and frame sync signals in parallel.
 
Reading the documentation and looking at the schematics of the audio board should tell you that the I2S data stream for the 3rd and 4th channel (I2S0_TXD1) is of no use when using only one audio board. Each SGTL5000 can accept one single stream, either I2S0_TXD0 containing channels 1 and 2 or I2S0_TXD1 containing channels 3 and 4, but never both.
Only when using 2 audio boards, you might connect one data line to the one and the other line to the other, while connecting the master clock, bit clock, and frame sync signals in parallel.

Thank you for making that clear.

Is it still possible to switch between audio input and synthesiser without using two shields then? I've tried using a mixer and switching two of the four channels on and off in code but can't get any synth sound out.

Does the code from the audio tool seem ok? Should it theoretically produce a synth and a mic signal at the same time?

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

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=111,35
AudioSynthWaveformSine   sine2;          //xy=111,70
AudioInputI2S            i2s2;           //xy=210,124
AudioMixer4              mixer3;         //xy=347,137
AudioSynthWaveformModulated waveformMod1;   //xy=439,46
AudioEffectGranular      granular1;      //xy=489,137
AudioMixer4              mixer2;         //xy=646,124
AudioOutputI2S           i2s1;           //xy=797,122
AudioConnection          patchCord1(sine1, 0, waveformMod1, 0);
AudioConnection          patchCord2(sine1, 0, mixer2, 1);
AudioConnection          patchCord3(sine2, 0, waveformMod1, 1);
AudioConnection          patchCord4(i2s2, 0, mixer3, 0);
AudioConnection          patchCord5(i2s2, 1, mixer3, 1);
AudioConnection          patchCord6(mixer3, granular1);
AudioConnection          patchCord7(waveformMod1, 0, mixer2, 0);
AudioConnection          patchCord8(granular1, 0, mixer2, 2);
AudioConnection          patchCord9(granular1, 0, mixer2, 3);
AudioConnection          patchCord10(mixer2, 0, i2s1, 0);
AudioConnection          patchCord11(mixer2, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=122,212
// GUItool: end automatically generated code
 
Take off the second I2S output, you don't have any.

Use a mixer to dispatch your different signals on the left and right channels of the remaining single i2s output. Don't make things more complicated than they are.
 
Take off the second I2S output, you don't have any.

Use a mixer to dispatch your different signals on the left and right channels of the remaining single i2s output. Don't make things more complicated than they are.

I'm not sure I understand, I don't have a second i2s output there. The signals are being mixed by a mixer before going into a single i2s output (same code as 2nd message):

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

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=152,180
AudioSynthWaveformSine   sine2;          //xy=152,215
AudioInputI2S            i2s2;           //xy=251,269
AudioMixer4              mixer3;         //xy=388,282
AudioSynthWaveformModulated waveformMod1;   //xy=480,191
AudioEffectGranular      granular1;      //xy=530,282
AudioMixer4              mixer2;         //xy=687,269
AudioOutputI2S           i2s1;           //xy=834,276
AudioConnection          patchCord1(sine1, 0, waveformMod1, 0);
AudioConnection          patchCord2(sine1, 0, mixer2, 1);
AudioConnection          patchCord3(sine2, 0, waveformMod1, 1);
AudioConnection          patchCord4(i2s2, 0, mixer3, 0);
AudioConnection          patchCord5(i2s2, 1, mixer3, 1);
AudioConnection          patchCord6(mixer3, granular1);
AudioConnection          patchCord7(waveformMod1, 0, mixer2, 0);
AudioConnection          patchCord8(granular1, 0, mixer2, 2);
AudioConnection          patchCord9(granular1, 0, mixer2, 3);
AudioConnection          patchCord10(mixer2, 0, i2s1, 0);
AudioConnection          patchCord11(mixer2, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=163,357
// GUItool: end automatically generated code

I don't understand whether these objects are all being processed at the same time, seems like unnecessary processing if that is the case.
 
Sorry, my fault. I misread i2s2 for an output.

Why not start simpler and let most of the synth stuff away for a moment. Keep just a sine waveform and on mixer and try to alternate between the mic signal and the sine wave. When you got that working, add the second sine wave, and so on. proceed step by step. Much easier to debug.
 
Sorry, my fault. I misread i2s2 for an output.

Why not start simpler and let most of the synth stuff away for a moment. Keep just a sine waveform and on mixer and try to alternate between the mic signal and the sine wave. When you got that working, add the second sine wave, and so on. proceed step by step. Much easier to debug.

Indeed, good idea; that's what I've ended up doing for the last few hours.

Got it working now, mic and synth can be heard at the same time! You can use the mic and create a synth sound at the same time without any problems!

Tried putting together with the granulator and seems to have broken the freeze function sadly:

Code:
// Waveform Modulation Example - Create waveforms with 
// modulated frequency
//
// This example is meant to be used with 3 buttons (pin 0,
// 1, 2) and 2 knobs (pins 16/A2, 17/A3), which are present
// on the audio tutorial kit.
//   https://www.pjrc.com/store/audio_tutorial_kit.html
//
// Use an oscilloscope to view the 2 waveforms.
//
// Button0 changes the waveform shape
//
// Knob A2 changes the amount of frequency modulation
//
// Knob A3 varies the shape (only for Pulse & Variable Triangle)
//
// This example code is in the public domain.

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

#define GRANULAR_MEMORY_SIZE 12800  // enough for 290 ms at 44.1 kHz
int16_t granularMemory[GRANULAR_MEMORY_SIZE];


// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=152,180
AudioSynthWaveformSine   sine2;          //xy=152,215
AudioInputI2S            i2s2;           //xy=251,269
AudioMixer4              mixer3;         //xy=388,282
AudioSynthWaveformModulated waveformMod1;   //xy=480,191
AudioEffectGranular      granular1;      //xy=530,282
AudioMixer4              mixer2;         //xy=687,269
AudioOutputI2S           i2s1;           //xy=834,276
AudioConnection          patchCord1(sine1, 0, waveformMod1, 0);
AudioConnection          patchCord2(sine1, 0, mixer2, 1);
AudioConnection          patchCord3(sine2, 0, waveformMod1, 1);
AudioConnection          patchCord4(i2s2, 0, mixer3, 0);
AudioConnection          patchCord5(i2s2, 1, mixer3, 1);
AudioConnection          patchCord6(mixer3, granular1);
AudioConnection          patchCord7(waveformMod1, 0, mixer2, 0);
AudioConnection          patchCord8(granular1, 0, mixer2, 2);
AudioConnection          patchCord9(granular1, 0, mixer2, 3);
AudioConnection          patchCord10(mixer2, 0, i2s1, 0);
AudioConnection          patchCord11(mixer2, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=163,357
// GUItool: end automatically generated code

Bounce button0 = Bounce(0, 15);
Bounce button1 = Bounce(6, 15);
Bounce button2 = Bounce(7, 15);

int current_waveform=0;
int16_t current_mode = 1;

//extern const int16_t myWaveform[256];  // defined in myWaveform.ino

void setup() {
  Serial.begin(9600);
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);// spdt switch
  pinMode(2, INPUT_PULLUP);// spdt
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  //pinMode(led1, OUTPUT); 
  //pinMode(led2, OUTPUT); 

  delay(300);
  Serial.println("Waveform Modulation Test");
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(100);

  // Comment these out if not using the audio adaptor board.
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.8); // caution: very loud - use oscilloscope only!
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(36);
  
  mixer2.gain(0,0.5);
  mixer2.gain(1,0.5);

  mixer2.gain(2,0.5);
  mixer2.gain(3,0.5);

  mixer3.gain(0,0.5);
  mixer3.gain(1,0.5);
  
  granular1.begin(granularMemory, GRANULAR_MEMORY_SIZE);
  // Confirgure both to use "myWaveform" for WAVEFORM_ARBITRARY
  //waveformMod1.arbitraryWaveform(myWaveform, 172.0);

  // Configure for middle C note without modulation
  waveformMod1.frequency(261.63);
  waveformMod1.amplitude(1.0);
  sine1.frequency(20.3); // Sine waves are low frequency oscillators (LFO)
  sine2.frequency(1.2);

  current_waveform = WAVEFORM_TRIANGLE_VARIABLE;
  waveformMod1.begin(current_waveform);
  // uncomment to try modulating phase instead of frequency
  //waveformMod1.phaseModulation(720.0);
}

void loop() {
  // Read the buttons and knobs, scale knobs to 0-1.0
  button0.update();
  button1.update();
  button2.update();
  float knob_A2 = (float)analogRead(A7) / 1023.0;
  float knob_A3 = (float)analogRead(A6) / 1023.0;
  // use Knobsto adjust the amount of modulation
  sine1.amplitude(knob_A2);
  sine2.amplitude(knob_A3);

  if (button1.fallingEdge()) 
  {
    Serial.println("Current Mode");
    Serial.println(current_mode);
      //switch(current_mode) 
//    {
//      case 1: 
//      synthTime();
//      Serial.println("Current Mode Synth");
//      break;
//      case 2:
//      vocalTime();
//      Serial.println("Current Mode MicIN");
//      break;
//     }
    current_mode += 1;
    if (current_mode > 2) current_mode = 0;
  }
  if (current_mode == 0) 
    {
      synthTime();
      mixer2.gain(0,0.5);
      mixer2.gain(1,0.5);

      mixer2.gain(2,0.0);
      mixer2.gain(3,0.0);
    }

    if (current_mode == 1) 
    {
      mixer2.gain(0,0.0);
      mixer2.gain(1,0.0);
      
      mixer2.gain(2,0.5);
      mixer2.gain(3,0.5);
      vocalTime();
    }

    if (current_mode == 2) 
    {
      vocalTime();
      mixer2.gain(0,0.5); // 
      mixer2.gain(1,0.5); // both together
      
      mixer2.gain(2,0.5);
      mixer2.gain(3,0.5);
    }
    
}

void vocalTime()
{
  float knobA2 = (float)analogRead(A6) / 1023.0;
  float knobA3 = (float)analogRead(A7) / 1023.0;
  
  // Button 0 starts Freeze effect
  if (button0.fallingEdge()) 
  {
    float msec = 100.0 + (knobA3 * 150.0);
    granular1.beginFreeze(msec);
    Serial.print("Begin granular freeze using ");
    Serial.print(msec);
    Serial.println(" grains");
  }
  
  if (button0.risingEdge()) 
  {
    granular1.stop();
  }
  // Button 1 starts Pitch Shift effect
  if (button2.fallingEdge()) {
    float msec = 25.0 + (knobA3 * 75.0);
    granular1.beginPitchShift(msec);
    Serial.print("Begin granular pitch phift using ");
    Serial.print(msec);
    Serial.println(" grains");
  }
  if (button2.risingEdge()) 
  {
    granular1.stop();
  }
  // Continuously adjust the speed, based on the A3 pot
  float ratio;
  ratio = powf(2.0, knobA2 * 2.0 - 1.0); // 0.5 to 2.0
  //ratio = powf(2.0, knobA2 * 6.0 - 3.0); // 0.125 to 8.0 -- uncomment for far too much range!
  granular1.setSpeed(ratio);
}

void synthTime()
{
   // Button 0 changes the waveform type
  if (button0.fallingEdge()) 
  {
    switch (current_waveform) {
      case WAVEFORM_SINE:
        current_waveform = WAVEFORM_SAWTOOTH;
        Serial.println("Sawtooth");
        break;
      case WAVEFORM_SAWTOOTH:
        current_waveform = WAVEFORM_SAWTOOTH_REVERSE;
        Serial.println("Reverse Sawtooth");
        break;
      case WAVEFORM_SAWTOOTH_REVERSE:
        current_waveform = WAVEFORM_SQUARE;
        Serial.println("Square");
        break;
      case WAVEFORM_SQUARE:
        current_waveform = WAVEFORM_TRIANGLE;
        Serial.println("Triangle");
        break;
      case WAVEFORM_TRIANGLE:
        current_waveform = WAVEFORM_TRIANGLE_VARIABLE;
        Serial.println("Variable Triangle");
        break;
      case WAVEFORM_TRIANGLE_VARIABLE:
//        current_waveform = WAVEFORM_ARBITRARY;
//        Serial.println("Arbitary Waveform");
//        break;
//      case WAVEFORM_ARBITRARY:
        current_waveform = WAVEFORM_PULSE;
        Serial.println("Pulse");
        break;
      case WAVEFORM_PULSE:
//        current_waveform = WAVEFORM_SAMPLE_HOLD;
//        Serial.println("Sample & Hold");
//        break;
//      case WAVEFORM_SAMPLE_HOLD:
        current_waveform = WAVEFORM_SINE;
        Serial.println("Sine");
        break;
    }
    waveformMod1.begin(current_waveform);
  }
}

Works but I must be doing something wrong for the freeze function to have stopped working.
 
Status
Not open for further replies.
Back
Top