Audio Library

Status
Not open for further replies.
I have enjoyed using the audio library on my Teensy to build a software defined radio (SDR). I have added to the audio library code to include a TI3204 codec which has features which are benificial to SDR projects. And, I have successfully added a 512 bin FFT module.

I have been able to modify the library I2S input and output modules to operate at 48000 sample rate.

I would like to modify the sample rate to 8000 samples per second.

I the I2S input and output modules are happy with this sample rate. I am able to feed in audio signals and get them out undamaged my doing a simple connection between input and output modules.

However, when I attempt to run the audio streams thru an FIR filter I get some huge noise bands over the entire 4 kHz audio spectrum.

I suspect the problem revolves around the requirement discussed in your 01-07-2014 post which states that the update function must complete within 2.9 ms or 278528 cpu cycles.

Given a sample rate of 8000 hz and 128 block size, the update time would be 0.016 msec or 153600 cpu cycles.

I had mad a thorough review of the audio library code and I can not find where the update time rules are enforced so that I can modify the update time for the 8000 hz.

The most germane code that I have found is the function "void software_isr(void) // AudioStream::update_all()" which is in the AudioStream.cpp file.


Will you please help me by pointing me where or how I can get the audio streams to play nicely at 8000 hz?

Thanks for your patience.

Regards,

Charley
 
I actually just last night started looking into a cache management bug in that code. Yesterday I found a test case that reliably reproduces the bug, so I'll probably have a fix soonish...

Very difficult to say if that bug is responsible for the problems you're seeing.

Just wondering if you had a chance to look into this? We have this bug happen at least once a day on our product.
 
I fixed that bug (and greatly improved the cache management) on August 7th.

https://github.com/PaulStoffregen/SD/commits/master

Edit: or August 8th, depending on which time zone github uses when showing that page...

fwiw, it doesn't seem to fix this issue or work as a drop-in replacement. still sounds as if something gets chopped up; does "seek" behave differently than with regular SD?


as an aside, the filename that's returned seems to crash strlen (unlike regular SD)

e.g.

Code:
char* _name = thisfile.name();  
len = strlen(_name);


i had to replace it with a loop checking for '.' (ie when checking for valid filenames in setup)
 
i had to replace it with a loop checking for '.'

So you find the dot then expect 3 char extension? If you provided the (7?) char values you find after the dot to USB and clipped here - and repeat for a few files with various length first parts - it might give a clue. Missing NULL - but why? - seeing what's in that buffer space may give a clue. Though looking at the code alone could probably solve it.
 
So you find the dot then expect 3 char extension? If you provided the (7?) char values you find after the dot to USB and clipped here - and repeat for a few files with various length first parts - it might give a clue. Missing NULL - but why? - seeing what's in that buffer space may give a clue. Though looking at the code alone could probably solve it.

didn't get a chance to look into it. i just quickly tried this morning with the latest SD + USE_TEENSY3_OPTIMIZED_CODE and that's where things got stuck, ie. with strlen. not a big deal, just thought i'd mention it because it seemed a bit odd. ie as the exact same code doesn't trip up with regular SD.

(and yep, sort of. i find the dot, and check for the extension and other stuff; mostly because i use a display but don't want to display the extension; and copy stuff that end in .RAW into SPI flash, but not things that end in WAV; also with osx lots of junk ends up on the card, .Trashes, .Spotlight-V100, and duplicates ("_*~1.WAV") which need to be filtered out.)
 
I'm trying to get some new I2S library objects working for my 24 bit audio board, but I'm having a lot of trouble. I'm trying to set up the new I2S objects such that the I2S and DMA transfers are all 32 bits (with the upper 24 bits containing signal), and copying only the 16 most significant bits of each sample to/from the audio blocks.

The new objects also need to be slave mode to match with the audio board setup (I2S clocks generated by the codec).

I've got everything setup in a way that seems like it should work, but I'm getting really weird behavior. If I just have the 32-bit I2S slave output object present, the sketches work and I can read back the codec configuration and print to the serial monitor, but there's only output for a really short period of time at startup (around 150ms or so). If I have both the input and output 32-bit I2S objects present, the sketch seems to restart every 20ms or so (I can see the startup waveforms repeating on my DSlogic logic analyzer).

Right now I'm thinking that something is going wrong in the routines that copy the data to/from the audio blocks, but I can't see anything wrong with the code. I'm sure that there is something blatantly wrong, but I've been staring at the code too long to see it :)

If someone would be willing to take a peek at it and see if they can spot anything obvious, it would be much appreciated.

The new library objects are in my github fork of the audio library here: https://github.com/whollender/Audio/tree/SuperAudioBoard

The input object is here: https://github.com/whollender/Audio/blob/SuperAudioBoard/input_i2s.cpp
The output is here: https://github.com/whollender/Audio/blob/SuperAudioBoard/output_i2s.cpp
The new CS4272 control object is under: https://github.com/whollender/Audio/blob/SuperAudioBoard/control_cs4272.cpp (I can read back the configuration over I2C, and it's the same as the code that I have working without the audio library, so I think that it's working).

Here are the sketches that I'm using to try to test:
Output only:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=185.09091186523438,194.09091186523438
//AudioSynthWaveformSine   sine2;          //xy=189.09091186523438,245.09091186523438
AudioOutputI2S32bitslave           i2s1;           //xy=376.0909118652344,219.09091186523438
AudioConnection          patchCord1(sine1, 0, i2s1, 0);
//AudioConnection          patchCord2(sine2, 0, i2s1, 1);
AudioControlCS4272       AudioBoard;
// GUItool: end automatically generated code


#define CS4272_ADDR 0x10


void setup() {
  // put your setup code here, to run once:
  AudioMemory(20);
  AudioBoard.enable();

  sine1.amplitude(0.5);
  sine1.frequency(1000);

  //sine2.amplitude(0.5);
  //sine2.frequency(1000);

}

void loop() {
  // put your main code here, to run repeatedly:
// Read back audioboard settings
  for(unsigned int i = 1; i < 9; i++)
  {
    Wire.beginTransmission(CS4272_ADDR);
    Wire.write(i);
    int ii = Wire.endTransmission();
    if(ii != 0)
    {
      Serial.println("Error in end transmission:");
      Serial.println(ii);
      break;
    }
    if(Wire.requestFrom(CS4272_ADDR,1) < 1)
    {
      Serial.println("Error in request from");
      break;
    }
    Serial.println(Wire.read());
  }
  
  delay(10000);
}

Output and input:
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

// GUItool: begin automatically generated code
AudioInputI2S32bitslave  i2s1;           //xy=163,159
AudioAnalyzeFFT256       fft;      //xy=318,157
AudioSynthWaveformSine   sine1;          //xy=384,224
AudioOutputI2S32bitslave i2s2;           //xy=530,231
AudioConnection          patchCord1(i2s1, 1, fft, 0);
AudioConnection          patchCord2(sine1, 0, i2s2, 1);
AudioControlCS4272       AudioBoard;     //xy=365,320
// GUItool: end automatically generated code

#define CS4272_ADDR 0x10

void setup()
{
  AudioMemory(10);
  AudioBoard.enable();
  //AudioBoard.volume(0.5);
  //AudioBoard.muteHeadphone();
  //AudioBoard.unmuteLineout();
  //AudioBoard.inputSelect(AUDIO_INPUT_LINEIN);
  sine1.amplitude(0.5);
  sine1.frequency(1000);

}

void loop()
{
  if(fft.available())
  {
    Serial.println("1kHz Amplitude (bin 6):");
    Serial.println(fft.read(0));
    
  }
  else
  {
    Serial.println("FFT result not available");
  }


  // Read back audioboard settings
  for(unsigned int i = 1; i < 9; i++)
  {
    Wire.beginTransmission(CS4272_ADDR);
    Wire.write(i);
    int ii = Wire.endTransmission();
    if(ii != 0)
    {
      Serial.println("Error in end transmission:");
      Serial.println(ii);
      break;
    }
    if(Wire.requestFrom(CS4272_ADDR,1) < 1)
    {
      Serial.println("Error in request from");
      break;
    }
    Serial.println(Wire.read());
  }
  
  delay(10000);
}
 
Dear whollender,

I took a quick look at your code but I do not see anything obvious. You will understand that there is lot there to digest and dissemble.

I do have a couple of suggestions from my experience in getting a TI3204 codec working with the teensy audio library.

1) Make sure that the codec I2S data format matches the teensy I2S data format. By format I mean left justified data, right justified data, I2S data format, etc.

2) As a first step see if you can get your codec to play with the audio library I2S using native 16 bit I2S objects.

3) Use a very simple sketch which has an I2S audio input directly connected to an I2S audio output.

4) Once you have 16 bit stuff working then start modifying codec configuration and I2S modules for the 24 bit operation.

Since you report that the new I2S objects seem to work for a very brief period I suspect you have a data format mismatch problem.

I hope this helps a little.

Regards,

Charley
 
Hey Charley,

Thanks for taking a look and the suggestions. I have a working setup outside of the audio library and have been using that as a reference. The codec setup I can verify as exactly the same as in the working setup (left justified, etc), and I'm using nearly identical I2S setup (only difference is the fifo watermark generates a DMA request instead of an interrupt).

The reason that I'm setting up a 32 bit object instead of testing with the 16 bit objects is because the codec is setup for master mode (isolators between the teensy and codec mean that slave mode is out of the question), and can only do 32 bit frames in master mode.

I think that the issue is related to the copy routines is that the code is causing erratic behavior, and buffer overflows can often generate that kind of behavior.

I'll try walking through the code again tonight and see if I can spot anything.

Thanks again for looking at the code. Every pair of eyes helps.
 
It's working!

Turns out I hadn't correctly adjusted the DMA major loop iteration count for the 32 bit transfers, so the DMA would overwrite its buffers.

I haven't tested all the other functionality (volume, dither, etc), but that should be pretty easy to test.
 
Just a friendly suggestion, can we split this thread into several threads dealing with specific audio related issues?
I find this monster thread hard to follow.
 
Should I merge this code into the audio library?

We've got only a few days left to change any changes in the final Teensyduino 1.25 release.
 
@mlu, Sorry, I thought of making a new thread, but this one seems to be the most official one for Audio lib stuff. I agree that it is easier to have multiple threads, so I'll make a new one next time.

@Paul, I'm not quite sure that it's ready for primetime just yet. Here are a couple of things that may need to be addressed:
  • the code only supports 48kHz (the HW also supports 96/192kHz, but not 44.1kHz). How should the "SAMPLE_RATE" defines get updated to reflect the new sample rates?
  • I made new I2S objects to do 32 bit frames, but it might be possible to incorporate that into the existing I2S objects. Should they stay separate for now?
At a minimum some of the code may need to be cleaned up to match the rest of the Audio library style.

That said, I don't think it would be a big risk to include it because only a small number of people will probably be playing with the new objects.
 
The crystal on the board is a 24.576MHz crystal, and the i2s isolators are unidirectional, so I had to either go with master or slave mode and chose master mode for best performance.

If the crystal was 22.5792MHz instead, then it would do 44.1kHz.

Edit: it looks like Digikey has one crystal that would meet the requirements (22.5792MHz, ~20pF load cap, same footprint: http://www.digikey.com/product-detail/en/9C-22.5792MAAJ-T/887-2438-1-ND/4475492), so it would be possible to load a different crystal and get 44.1/88.2/176.4kHz sample rates. They don't have a large number in stock, so I'm a little wary of how available these parts will be in the future.

It would still be nice to be able to use 48kHz without modifying AudioStream.h
 
Last edited:
Hi everyone, my first post here.

I have noticed a problem with envelope generator - when release cycle starts before sustain level is reached (before attack is finished), sustain level is forced at the beginning of release cycle, and there is annoying click there.

I have addressed this problem by removing line 58 from effect_envelope.cpp, method "void AudioEffectEnvelope::noteOff(void)":
mult = sustain_mult; // removed this

So release cycle now starts from the level it encounters, and there is no click.

Great work on audio library, spared me so much time on my synth hobby project, and more importantly, code really helps me understand sw synthesis better.
Huge thanks!
 
It would still be nice to be able to use 48kHz without modifying AudioStream.h

If the sample rate becomes a variable instead of a preprocessor define, then lots of complex code that currently is all evaluated by the compiler and compiles down to constants or very simple code all becomes complex, slow calculations done on the Teensy at runtime.
 
If the sample rate becomes a variable instead of a preprocessor define, then lots of complex code that currently is all evaluated by the compiler and compiles down to constants or very simple code all becomes complex, slow calculations done on the Teensy at runtime.

Yeah, I've been trying to think of a good way to go about redefining the sample rate so that it can be selected by the user but still maintain the benefits of a defined constant.

Maybe something similar to how the cpu frequency is selected?

Or, maybe enclose the definition in AudioStream in and #ifndef so that the user can define it before including Audio.h?
 
Are there any known issues with using the Capacitive Sensor / CapSense library while using the Audio Library? Any gotchas with the timing, etc.?

Thanks so much. I look forward to trying the improved SD card performance.
 
You should use touchRead(pin) using the pins with hardware touch sensing.

The accuracy of the CapacitiveSensor library will be impacted by CPU time consumed by the Audio library. It will still work, but accuracy will suffer, especially if the CPU usage of the audio lib changes.

The hardware touch sensing with touchRead() works *much* better than CapacitiveSensor, so you should use it, even if the Audio library isn't a factor.
 
Hi, I am new here...
Audiolibrary is great! I've done few small projects with it but now I have unexpected problem...
I want to make 12 sine oscillators each with fade object. But if I add fade object it stops working. Actually with only one fade object on the first oscillator it was working--- I don't understand why...
Without any fade object is ev ok but I need smooth beginning and ending of the sounds...

I am using Teensy 3.1, teensy loader1.20, and 1.02 Audiolibrary version.
Here is code with just four sine osc, three fade objects and one osc without fade. It doesnot work, even serial communication is not working.
Please do you have any idea what is wrong?

Thanks a lot!

code: ( sorry there are some notes in my native czech language...)
Code:
// MONOLIT start //
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=158,137
AudioSynthWaveformSine   sine2;          //xy=160,186
AudioSynthWaveformSine   sine4;          //xy=164,304
AudioSynthWaveformSine   sine3;          //xy=165,234
AudioEffectFade          fade1;          //xy=324,147
AudioEffectFade          fade3;          //xy=344,237
AudioEffectFade          fade2;          //xy=347,195
AudioMixer4              mixer1;         //xy=506,209
AudioOutputAnalog        dac1;           //xy=629,212
AudioConnection          patchCord1(sine1, fade1);
AudioConnection          patchCord2(sine2, fade2);
AudioConnection          patchCord3(sine4, 0, mixer1, 3);
AudioConnection          patchCord4(sine3, fade3);
AudioConnection          patchCord5(fade1, 0, mixer1, 0);
AudioConnection          patchCord6(fade3, 0, mixer1, 2);
AudioConnection          patchCord7(fade2, 0, mixer1, 1);
AudioConnection          patchCord8(mixer1, dac1);
// GUItool: end automatically generated code


float globalVol = 0.3;
int maxmem = 0;
int maxcpu = 0;

// stupnice array ---- all musical stuff...

float harmofreq[14] = {130.81, 146.83, 155.56, 174.61, 195.99, 207.65, 246.94, 261.63, 293.66, 311.13, 349.23, 391.99, 415.31, 439.88   } ;  // na Hz osc -float bude fungovat???
 
uint16_t pitch = 440; // přičítání - transpozice 
float midi[127];
int a = 440; // a is 440 hz...
int x = 0; // na for vypocet MIDI not
int y = 0;  // na for prirazeni frekvecni


// input def
int tlac1_pin = 2;
int tlac2_pin = 3;
int tlac3_pin = 4;
int tlac4_pin = 5;
int tlac5_pin = 6;
int tlac6_pin = 7;
int tlac7_pin = 8;
int tlac8_pin = 9;
int tlac9_pin = 10;
int tlac10_pin = 11;
int tlac11_pin = 12;
int tlac12_pin = 22;
int tlac13_pin = 23;


// array var

unsigned long tlac[12]; 

void sendMessage (char letter, int number)
     {
     Serial1.print(letter);
     Serial1.println (number, DEC);     
     } 


//-----------------S E T U P -----------
void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);

  AudioMemory(16); 

 
  pinMode(tlac1_pin, INPUT);
  pinMode(tlac2_pin, INPUT);
  pinMode(tlac3_pin, INPUT);
  pinMode(tlac4_pin, INPUT);
  pinMode(tlac5_pin, INPUT);
  pinMode(tlac6_pin, INPUT);
  pinMode(tlac7_pin, INPUT);
  pinMode(tlac8_pin, INPUT);
  pinMode(tlac9_pin, INPUT);
  pinMode(tlac10_pin, INPUT);
  pinMode(tlac11_pin, INPUT);
  pinMode(tlac12_pin, INPUT);
  pinMode(tlac13_pin, INPUT);
 
}
// ---------------- M A I N     l O O P -------------
void loop() { 

//tlac[0] =  digitalRead(tlac0_pin);
tlac[1] =  digitalRead(tlac1_pin);
tlac[2] =  digitalRead(tlac2_pin);
tlac[3] =  digitalRead(tlac3_pin);
tlac[4] =  digitalRead(tlac4_pin);
tlac[5] =  digitalRead(tlac5_pin);
tlac[6] =  digitalRead(tlac6_pin);
tlac[7] =  digitalRead(tlac7_pin);
tlac[8] =  digitalRead(tlac8_pin);
tlac[9] =  digitalRead(tlac9_pin);
tlac[10] =  digitalRead(tlac10_pin);
tlac[11] =  digitalRead(tlac11_pin);
tlac[12] =  digitalRead(tlac12_pin);
tlac[13] =  digitalRead(tlac13_pin);

// serial communication to another teensy 
int hodsum = 0;
{
  int i;
  for (i=1;i<=13;i++) {
     if (tlac[i] == HIGH) hodsum+=(1 << (i-1));
  }
}
sendMessage ('X',  hodsum);
if (hodsum==0) delay(10);     //  when nothing pressed it makes 10ms "hole" in the stream to protect buffer issues...



//--------------------------------- A U D I O ---------------------------------------------------------- 

 mixer1.gain (0, globalVol);
 mixer1.gain (1, globalVol);
 mixer1.gain (2, globalVol);
 mixer1.gain (3, globalVol);
       
       
   if ( tlac[1] == HIGH){   
                            AudioNoInterrupts(); 
                            fade1.fadeIn(2);  
                            sine1.amplitude(1);
                            sine1.frequency(harmofreq[8]);                          
                            AudioInterrupts();
                           
                            
                        
                        }
   else {  AudioNoInterrupts();
            fade1.fadeOut(20);
           AudioInterrupts(); 
          
         }
         
   if ( tlac[2] == HIGH){   AudioNoInterrupts(); 
                             fade2.fadeIn(2);  
                             sine2.amplitude(1);
                           sine2.frequency(harmofreq[9]);
                            AudioInterrupts();
                        
                        }
   else {  AudioNoInterrupts();
            fade2.fadeOut(20);
           AudioInterrupts(); 
         }
 
if ( tlac[3] == HIGH){   AudioNoInterrupts(); 
                            fade3.fadeIn(2); 
                            sine3.amplitude(1);                        
                             sine3.frequency(harmofreq[10]);
                             AudioInterrupts();
                        
                        }
   else {  AudioNoInterrupts();
           fade3.fadeOut(20);
           AudioInterrupts(); 
         }
       
 if ( tlac[4] == HIGH){   AudioNoInterrupts(); 
                            sine4.amplitude(1);                         
                             sine4.frequency(harmofreq[11]);
                             AudioInterrupts();
                        
                        }
   else {  AudioNoInterrupts();
          sine4.amplitude(0); 
           AudioInterrupts(); 
         }            
}
 
Last edited:
Status
Not open for further replies.
Back
Top