Audio Library

Status
Not open for further replies.
Yes. I've programmed every other feature except master mode since I don't have any 32 bit slave source.

I2S protocol should automatically use whatever bits are sent. I'd recommend simply trying the I2S master object that's already in the library, at least for testing. Odds are good the ESS chip will "just work", since the I2S protocol automatically scales as more bits are added.

When/if the code is adapted to send 32 bits, you'll probably want to have the original code tested anyway, so you can hear if there's any improvement.
 
Hello!

I got an error this evening when I downloaded the Audio Library indicating I need Teensyduino version 1.20 but I only see 1.19 on PJRC. .... Do I need to reinstall 1.05 and use the beta 1.20? thanks, tom

C:\Users\thomas\Documents\Arduino\libraries\Audio/Audio.h:31:2: error: #error "Teensyduino version 1.20 or later is required to compile the Audio library"
In file included from C:\Users\thomas\Documents\Arduino\libraries\SD/utility/Sd2Card.h:26:0,
from C:\Users\thomas\Documents\Arduino\libraries\SD/utility/SdFat.h:27,
from C:\Users\thomas\Documents\Arduino\libraries\SD/SD.h:20,
from C:\Users\thomas\Documents\Arduino\libraries\Audio/play_sd_raw.h:31,
from C:\Users\thomas\Documents\Arduino\libraries\Audio/Audio.h:75,
from WavFilePlayer.ino:1:
 
Can you post the code you have so far? I'll look into a fix. It might require tweaking in the ILI9341_t3 library....

Maybe this would make a good example to include with the audio lib?

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

#include "SPI.h"
#include "ILI9341_t3.h"
#define TFT_DC  9
#define TFT_CS 10

//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S       audioInput;         // audio shield: mic or line-in
AudioAnalyzeFFT256  myFFT(20);
AudioOutputI2S      audioOutput;        // audio shield: headphones & line-out

// Create Audio connections between the components
//
AudioConnection c1(audioInput, 0, audioOutput, 0);
AudioConnection c2(audioInput, 0, myFFT, 0);
AudioConnection c3(audioInput, 1, audioOutput, 1);

// Create an object to control the audio shield.
// 
AudioControlSGTL5000 audioShield;


void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);
  
  // Enable the audio shield and set the output volume.
  audioShield.enable();
  audioShield.inputSelect(myInput);
  audioShield.volume(0.6);
  
  //Display setup
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  delay(500);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0,30);
  tft.println("hello world");
}

void loop() {
   
  if (myFFT.available()) {
    // each time new FFT data is available
    // print it all to the Arduino Serial Monitor
    Serial.print("FFT: ");
    for (int i=0; i<128; i++) {
      Serial.print(myFFT.output[i]);
      Serial.print(",");
    }
    Serial.println();
  }
}

This gives me all 00 from the FFT bins, interestingly if I move the "hello world" into loop() I get more interesting ( but wrong ) garbage in the FFT output.
 
.... Do I need to reinstall 1.05 and use the beta 1.20?

No and yes.

You do need to install 1.20-rc2. But you don't need to reinstall Arduino 1.0.5. It's perfectly fine to install 1.20-rc2 "on top" of 1.19.

However, the reverse is not necessarily true. To go back to 1.19, you'd need to start from a fresh copy of Arduino 1.0.5, because 1.19 wasn't built with knowledge of new stuff 1.20 adds. Installing 1.19 "on top" of 1.20 results in leftover files that cause trouble. Recently I added a check for this, so the 1.20-rc3 installer and 1.20 final release will be the first versions that check this error (when 1.21 comes out....)
 
Hi Paul

Is possible make simple example how to use arbitrary waveform ?

Many thanks

Kamil
 

http://www.pjrc.com/teensy/td_libs_AudioPlayMemory.html

I got it to mix wave files quite nicely, I love this audio library. Working on finding blue tooth libraries then I think we will be starting production. We plan to buy pre programmed bootloader chips from your site w/in 3 months in bulk.

It seems that the audio library is using up Serial2 and Serial3. Is there a command to remap any of the pins to free up one of those ports and/or remap a serial port? I see them in grey on the schematic but do not know how to move TX2 from pin 9 to pin 26.
 
Last edited:
Here is a simple sketch that does audio-rate modulation of the corner frequency of a SVF in low-pass mode. The same note is played over and over, but with increasing (doubling) lfo frequency. Lower frequencies give obvious LFO-type warbling. Higher frequencies produce non-harmonic buzzy, chirpy secondary tones. The initial delay feature on the envelope generator is used to hold off the modulation on the mod envelope, until the sustain phase of the note's envelope is mostly done.

Code:
// frequency modulated SVF corner frequency

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

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=134,414
AudioSynthWaveformDc     dc1;            //xy=139,360
AudioSynthWaveform       waveform1;      //xy=162,198
AudioMixer4              mixer1;         //xy=296,384
AudioEffectEnvelope      envelope1;      //xy=366,199
AudioEffectEnvelope      envelope2;      //xy=448,353
AudioFilterStateVariable filter1;        //xy=572,253
AudioOutputI2S           i2s1;           //xy=798,236
AudioConnection          patchCord1(sine1, 0, mixer1, 1);
AudioConnection          patchCord2(dc1, 0, mixer1, 0);
AudioConnection          patchCord3(waveform1, envelope1);
AudioConnection          patchCord4(mixer1, envelope2);
AudioConnection          patchCord5(envelope1, 0, filter1, 0);
AudioConnection          patchCord6(envelope2, 0, filter1, 1);
AudioConnection          patchCord7(filter1, 0, i2s1, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=828,158
// GUItool: end automatically generated code

float LFOfreq = 1.0;

void setup() {
  AudioMemory(12);
  sine1.frequency(LFOfreq); // lfo
  sine1.amplitude(0.4);
  dc1.amplitude(0.3);
  // this is the modulation envelope
  envelope2.delay(30);  
  envelope2.attack(60);
  envelope2.hold(20);
  envelope2.decay(300);
  envelope2.sustain(0.3);
  envelope2.release(100);  
  // now the envelope for the note
  envelope1.attack(15);  
  envelope1.decay(45);  
  envelope1.sustain(0.7);  
  envelope1.release(250);  
  // the actual waveform, saw for lots of harmonics so the effect of the LPF is clear
  // amplitude 0.5 to allow for positive gain of filter near resonance
  waveform1.begin(0.5, 440, TONE_TYPE_SAWTOOTH);
  filter1.resonance(3);
  filter1.frequency(440);
  filter1.octaveControl(1);
  // configure output device
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  // sgtl5000_1.unmuteLineout();
}

void loop() {
  for (int i = 1; i < 20000; i *=2) {
    LFOfreq = i;
    sine1.frequency(LFOfreq);
    envelope1.noteOn();
    envelope2.noteOn();
    delay (1500);
    envelope1.noteOff();
    envelope2.noteOff();
    delay (500);
  }
}

fmod-SVF.png
 
Analog oscillators often have a synchronisation (sync) function. This is particularly handy where several very low-frequency oscillators are being used for modulation and it is desired to reset them all to the start of the waveform (i.e. no modulation), for example when a new note starts. Its also useful to ensure that several oscillators all kick off in phase (for example, when adding multiple waveforms together).

For a digital oscillator, a hard reset is easily done by setting the phase pointer to zero. Would waveform.reset() and sine.reset() be reasonable additions to ask for?

(Soft sync is probably harder, although phase advance sync might be a way to do it.)
 
Can you post the code you have so far? I'll look into a fix. It might require tweaking in the ILI9341_t3 library....
As I don't have either your display nor the audio adapter yet. But decided to order one from your site earlier today, so my guess is I will have it early next week...

Looking at the Audio Adapter board, it looks like for SPI communication you use pin 13 for something else and use pin 14 for SCK. So the problem with the ILI9341_t3 library is probably that you no longer have a second constructor that allows the user to pass in (CS, DIN, DOUT). On my fork I will add this and try it out using my Adafruit 2.8" TFT breakout board...

If it works I will update my fork of the library and either add it to my pull request or put in as a separate pull request.

Kurt
 
No and yes.

You do need to install 1.20-rc2. But you don't need to reinstall Arduino 1.0.5. It's perfectly fine to install 1.20-rc2 "on top" of 1.19.

However, the reverse is not necessarily true. To go back to 1.19, you'd need to start from a fresh copy of Arduino 1.0.5, because 1.19 wasn't built with knowledge of new stuff 1.20 adds. Installing 1.19 "on top" of 1.20 results in leftover files that cause trouble. Recently I added a check for this, so the 1.20-rc3 installer and 1.20 final release will be the first versions that check this error (when 1.21 comes out....)


Ok will do.

Also, I found out if you plug the shield in backwards, it does not fry the codec or the SD card. Thanks Paul!
 
As I mentioned in previous reply, I would look at the ILI9341_t3 library to see if I could make a stab at it. I made a version of it, where I could pass in the MISO, MOSI and SCK pin numbers and set it up to alternate pins. This worked at least when I set up my test case that only moved my DOUT and SCK pins as you mentioned.

But the code I added does it the same way as your code does and the change, so I am now thinking I don't need to upload my changes to github.

Specifically I changed my test case that the setup contains:
Code:
  SPI.setSCK(14);
  SPI.setMOSI(7);
  ili9341.begin();
  ili9341.fillScreen(ILI9341_GREEN);

Note: To use this display with the Audio adapter this does imply you need to use the appropriate IO pins connected up to the display. Something like:
Code:
ILI9341 Pin	Teensy 3.1 Pin	Notes
VCC	VIN	Power: 3.6 to 5.5 volts
GND	GND	
CS	10	Alternate Pins: 9, 15, 20, 21
RESET	+3.3V	
D/C	9	Alternate Pins: 10, 15, 20, 21
[COLOR="#FF0000"]SDI	 7	Normally Was (MOSI) 11 (DOUT)[/COLOR]	
[COLOR="#FF0000"]SCK	14	Normally 13 (SCK)	[/COLOR]
LED	VIN	Use 100 ohm resistor
SDO (MOSI)	12 (DIN)	(Could also be 8 - Alternate pin)

Kurt
 
Code:
#include <Audio.h>
#include <Wire.h>
#include <SD.h>

#include "SPI.h"
#include "ILI9341_t3.h"
#define TFT_DC  9
#define TFT_CS 10

//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S       audioInput;         // audio shield: mic or line-in
AudioAnalyzeFFT256  myFFT(20);
AudioOutputI2S      audioOutput;        // audio shield: headphones & line-out

// Create Audio connections between the components
//
AudioConnection c1(audioInput, 0, audioOutput, 0);
AudioConnection c2(audioInput, 0, myFFT, 0);
AudioConnection c3(audioInput, 1, audioOutput, 1);

// Create an object to control the audio shield.
// 
AudioControlSGTL5000 audioShield;


void setup() {
  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(12);
  
  // Enable the audio shield and set the output volume.
 
  
  //Display setup
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
    tft.begin();
    tft.setRotation(1);
    tft.fillScreen(ILI9341_BLACK);
  delay(500);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(0,30);
  tft.println("hello world");
  audioShield.enable();
  audioShield.inputSelect(myInput);
  audioShield.volume(0.6);
}

void loop() {
  
  if (myFFT.available()) {
    // each time new FFT data is available
    // print it all to the Arduino Serial Monitor
    Serial.print("FFT: ");
    for (int i=0; i<128; i++) {
      Serial.print(myFFT.output[i]);
      Serial.print(",");
    }
    Serial.println();
  }
}

Set up so the display works but garbage on the FFT
 
Analog oscillators often have a synchronisation (sync) function. This is particularly handy where several very low-frequency oscillators are being used for modulation and it is desired to reset them all to the start of the waveform (i.e. no modulation), for example when a new note starts. Its also useful to ensure that several oscillators all kick off in phase (for example, when adding multiple waveforms together).

I had originally planned to implement a phase() function, to allow setting the waveform to any arbitrary point.

One unresolved question is what units such a phase() function ought to take. My gut feeling is degrees is probably simplest for people to understand. I'm sure some people might prefer radians. Any thoughts?
 
I studied electronic music at University and degrees is the units we were using when referring to phase. In some software like Max/MSP phase is scaled in float between 0 and 1 but I don't find it as intuitive...
 
Here is a simple sketch that does audio-rate modulation of the corner frequency of a SVF in low-pass mode. The same note is played over and over, but with increasing (doubling) lfo frequency. Lower frequencies give obvious LFO-type warbling. Higher frequencies produce non-harmonic buzzy, chirpy secondary tones. The initial delay feature on the envelope generator is used to hold off the modulation on the mod envelope, until the sustain phase of the note's envelope is mostly done.

Nice work! I'm listening to it now. Hearing slightly different wobbly sounds on the tones. Good to know the filter is doing something. ;)

I'd love to include a couple examples like this with the library. Is there any chance this could be expanded to sequence multiple sounds with musically pleasing rhythm?
 
I studied electronic music at University and degrees is the units we were using when referring to phase. In some software like Max/MSP phase is scaled in float between 0 and 1 but I don't find it as intuitive...

Degrees also makes it easy to produce quadrature oscillators (for oscillators at the same frequency but progressively 90 degrees out of phase) for example, while radians requires messing around with PI.

I've added a phase(angle) function to the waveform objects.

Yay!
 
Last edited:
Nice work! I'm listening to it now. Hearing slightly different wobbly sounds on the tones. Good to know the filter is doing something. ;)

It shows that audio rate modulation works, at least. The various levels and DAHDSR values are probably not optimal. I did get some (nasty, hard, not musically useful) clippig distortion if the levels were set too high.

I'd love to include a couple examples like this with the library. Is there any chance this could be expanded to sequence multiple sounds with musically pleasing rhythm?
Yes, some sort of evolving looping 8-step sequencer style demo perhaps.
 
Last edited:
How to make an arbitrary wavetable oscillator

Is possible make simple example how to use arbitrary waveform ?

That is probably a good idea. Meanwhile you could try it yourself. First, look at the sine wavetable in data_waveforms.c which you will see is a 257-element table (256, plus the first value repeated in the last place to make interpolation easier). Then, look at the code in synth_sine.h and /synth_sine.cpp.

Once you understand how that code works, copy the .c and .h files to something like synth_table.c and synth_table.h (remember to edit the names in the #includes as well). Now you need some waveform tables that you have the right to use and which are in the correct format. The Adventure Kide waveforms are well known and there are lots of waveforms to choose from. Also the license is good, cc-by (creative commons attribution). It may be helpful to see the shape and spectrum of each wave.

However, these are in D2+2 (600+2) format as used by many samplers. You need them in 256+1 format and as C header files. Luckily that work has been done for you, look at the DataNoiseTV adventure kid waveforms which are in the format we want. For example here are some cello waveforms. Notice that the waveform are declared const, so they will live in the flash memory on Teensy (there is lots of flash memory and not as much RAM).

Copy the ones you want to use and edit your synth_table.c to reference the correct table (or, better, to make it take a parameter which is the table name, making that an index into a table of pointers to waveform tables).
 
Last edited:
float modulus

in synth_sine.h
Code:
void phase(float angle) {
if (angle < 0.0) angle = 0.0;
else if (angle > 360.0) {
angle = angle - 360.0;
if (angle >= 360.0) return;
}
phase_accumulator = angle * (4294967296.0 / 360.0);
}

does the Arduino ARM gcc support fmodf? A modulus operation would avoid having to bail if angle >= 720.
Unless the fmodf code is complex and slow, of course.
 
It is slow unless you are working in powers of 2, when you can use bit wise ANDs instead.

But in this case you are looking at multiple divides :-/
 
Once you understand how that code works, copy the .c and .h files to something like synth_table.c and synth_table.h (remember to edit the names in the #includes as well).

Actually, instead of copypasting, it looks like AudioSynthWaveform.arbitraryWaveform(const int16_t *data, float maxFreq) does that for you. Just add wavetables.
 
I need two hardware serial ports and both are used by the audio board now. I would prefer not to use software serial if possible.

Is there a way to either remap some of the audio library pins to free serial port 2 or 3 or even remap the serial ports?
 
Status
Not open for further replies.
Back
Top