Audio Library

Status
Not open for further replies.
Only 16 bit PCM encoded files at 44100 Hz sample rate are supported. Mono and stereo work.

The WAV file parser, like the rest of the library, is in beta testing and may still have bugs. I fixed 2 bugs this morning, so please make sure you're using the latest code.

If your file still won't play, and you're sure it's 16 bit and 44.1 kHz, I'll need a copy of the file to test and figure out (and hopefully fix) what's wrong. But before you send me a file and ask me to dig into the code, please make sure you're running the very latest version, because I did just fix 2 bugs earlier today.
 
Thanks for reply nlecaude,
I downloaded again the library, but i can not still hear my sound by the headphones. I dont know what happen, i think than i stored the file in wrong way on the SD.

Firstly, I used the SdCardTest example to be sure of the file name.
SDCardTest.png

With any file of the SD i am using the follow code (the same code of PlayWavFormSdCard example):

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

// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioPlaySdWav wav;
AudioOutputI2S dac;

// Create Audio connections between the components
//
AudioConnection c1(wav, 0, dac, 0);
AudioConnection c2(wav, 1, dac, 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(5);

audioShield.enable();
audioShield.volume(20);

SPI.setMOSI(7);
SPI.setSCK(14);
if (SD.begin(10)) {
wav.play("BARK.WAV");
}
}

void loop() {
float vol = analogRead(15);
vol = vol / 10.24;
audioShield.volume(vol);
delay(20);
}

I dont know why i cannot hear any file.

Thanks,
 
Are you able to hear sounds from the PlayFromSketch example?

Maybe the library should come with a sample, known-to-work WAV file? Any have any suggestions?
 
Paul that would really help, when I got my audio board and wasn't able to have a sound playing I spent 2 hours troubleshooting the SD card and reader thinking they were the culprit.
You could sing a song and use that as a sound file :p
 
+1 for Paul singing to us!!!

@JBeale:
1Hz response I get does seem incongruous but the same delay, waiting for the output to flush the previous frequency samples before measuring the peak-in again, is in play for each frequency transition in my code and I didn't manage to find a mistake where perhaps I skip the delay on transition from highest to lowest frequency or anything like that so I posted the data I was getting. I'm going to put the source code that produced the table in this post so you can try to find my error which made that 1Hz glitch if you want :)

I've committed an update with a method to control the ADC high pass filter and made a pull request.

@jp3141:
I'll be interested to see your results but not interested enough to bother modding my current batch of code enough to do it myself (lots of other stuff I have/want to get done instead, soz) but, just in case it helps much as a starting point, here is the whole (god awful mess) of the sketch I used to output the table above.
Code:
/* Audio Sweeper

Objective: Output a sinusoidal waveform from 10Hz to ~22500Hz read back energy value to determine external attenuation using as few extra parts, aside from Teensy, to do so.

*/

typedef struct
{
  char data[256];
  uint8_t ptr=0;
} byte_buffer;

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

const char cmds[]="gain:\0filters:\0filter:\0sweepid\0\0"; // channel, filter_number (0-3), cF, Gain, Q

/*
gain:#channel,#input,#value ; channel 0=left, 1=right, 2=dac ; input 0=filtered, 1=synthSine, 2 table ; value (float) gain setting.
gain:#channel,2,#element,#value ; element 0 to 275 ; value (float) gain setting.
filters:#channel,#number_of_filters
filter:#channel,#filter_num,#filter_type,#frequency,#gain,#Q
*/


byte_buffer cons;

#define START_FREQ 1.0111248868808
// #define START_FREQ 10
#define LIMIT_FREQ AUDIO_SAMPLE_RATE_EXACT/2
#define MULTI_FREQ 1.02608176245271

#define SETTLE_TIME 10
#define SETTLE_TIMEOUT 25

// roughly 900mV PP.
#define BASE_AMPLITUDE (0.9/3.3)

int L_filters[32]; // not immediately using them all but can see scope for 4 sets.
int R_filters[32]; // for use in preamps with three inputs, filters might be used
int A_filters[32]; // to pre-attenuate to match known responses from pickups.

uint16_t Gain_L[276]; // these are inappropriate unless START_FREQ equ 10
uint16_t Gain_R[276]; // when executing this sketch as is I never sent it
uint16_t Gain_A[276]; // any gain changing commands although some are safe.
// Anything to do with 'gain tables' will cause trouble till these are resized.

int tFilter[5]; // temporary coefficient holder

uint8_t Gain_F=0; // all three outputs can use gain tables instead of flat or filtered, defaulting to flat here.

AudioInputI2S stereoIn;
AudioMixer4 mixer_P; // to temper Stereo_R
AudioPeak peakIn[2];

AudioSynthWaveform synthSine;
AudioFilterBiquad filters_L(L_filters);
AudioFilterBiquad filters_R(R_filters);
AudioFilterBiquad filters_A(A_filters);

AudioMixer4 mixer_L;
AudioMixer4 mixer_R;
AudioMixer4 mixer_A;

AudioOutputI2S stereoOut;
AudioOutputAnalog monoOut;
AudioPeak peakOut[4];

AudioConnection cIn_L(stereoIn,0,peakIn[0],0);
AudioConnection cIn_P(stereoIn,1,mixer_P,0);
AudioConnection cIn_R(mixer_P,0,peakIn[1],0);

AudioConnection cFlt_L(synthSine,0,filters_L,0);
AudioConnection cFlt_R(synthSine,0,filters_R,0);
AudioConnection cFlt_A(synthSine,0,filters_A,0);
AudioConnection cPkRaw(synthSine,0,peakOut[3],0);

AudioConnection cMix_L(filters_L,0,mixer_L,0);
AudioConnection cMix_Ls(synthSine,0,mixer_L,1);
AudioConnection cMix_R(filters_R,0,mixer_R,0);
AudioConnection cMix_Rs(synthSine,0,mixer_R,1);
AudioConnection cMix_A(filters_A,0,mixer_A,0);
AudioConnection cMix_As(synthSine,0,mixer_A,1);

AudioConnection cOut_L(mixer_L,0,stereoOut,0);
AudioConnection cPeak_L(mixer_L,0,peakOut[0],0);
AudioConnection cOut_R(mixer_R,0,stereoOut,1);
AudioConnection cPeak_R(mixer_R,0,peakOut[1],0);
AudioConnection cOut_A(mixer_A,0,monoOut,0);
AudioConnection cPeak_A(mixer_A,0,peakOut[2],0);

float freq=START_FREQ;
boolean op_running=false;
 
AudioControlSGTL5000 audioShield;

uint16_t steps=0;


float strHex(char* buf, unsigned char* ptr)
{
	unsigned char go=1;
	unsigned char breaker=0;
	float tmp=0;

	while((*buf<48)&&(*buf!=0))
	{
		buf++;
		*ptr+=1;
	}
	if((*buf=='0')&&(*(buf+1)=='x'))
	{
		buf+=2;
		*ptr+=2;
	}
	if(*buf==0) return 0;
	while(go!=0&&(++breaker)) {
		if((*buf>64)&&(*buf<71)) *buf-=7;
		if((*buf>96)&&(*buf<103)) *buf-=39;
		if((*buf>47)&&(*buf<64)) {
			tmp=(tmp*16)+((*buf)-48);
			buf++;
			*ptr+=1;
		} else {
			go=0;
		}
	}
	return tmp;
}

float strfig(char* buf, unsigned char* ptr)
{
	unsigned char go=1;
	unsigned char breaker=0;
	float tmp=0;
	float frac=0;
	float sign1=1;

	while(go!=0&&(++breaker)) {
		if(*buf!=0) {
			if((*buf<33)||(*buf=='=')||(*buf==',')||(*buf==';')) {
				buf++;
				*ptr+=1;
			} else {
				go=0;
			}
		} else {
			go=0;
		}
	}

	if(((*buf==0)||(*buf<48)||(*buf>57))&&(*buf!='-')) {
		return 0;
	}
	if(*buf=='-')
	{
		sign1=-1;
		buf++;
		*ptr+=1;
	}
	if((*buf=='0')&&(*(buf+1)=='x')) {
		return sign1*strHex(buf,ptr);
	}
	go=1;
	while(go!=0&&(++breaker)) {
		if((*buf>47)&&(*buf<58)) {
			if(frac)
			{
				tmp=tmp+(((*buf)-48)/frac);
				frac*=10;
			} else {
				tmp=(tmp*10)+((*buf)-48);
			}
			buf++;
			*ptr+=1;
		} else if(*buf=='.') {
			if(frac) return sign1*tmp; // second decimal point in a number is bullshit.
			frac=10;
			buf++;
			*ptr+=1;
		} else {
			go=0;
		}
	}
	return sign1*tmp;
}

unsigned char strfig(char* buf1, unsigned char* ptr, const char* cPtr)
{
	const char * sPtr;
	char * tPtr;
	unsigned char count=0,cnt2,go=1;
	while(go)
	{
		count++;
		sPtr=cPtr;
		while(*cPtr!=0) {
			cPtr++;
		}
		cPtr++;
		tPtr=buf1;
		cnt2=0;
		while((*sPtr==*tPtr)&&(*tPtr!=0))
		{
			cnt2++;
			sPtr++;
			tPtr++;
		}
		if(*sPtr==0)
		{
			*ptr+=cnt2;
			return count;
		}
		go=*cPtr;
	}
	return 0;
}




void setup ()
{
  AudioMemory(10);
  op_running=synthSine.begin(BASE_AMPLITUDE,(unsigned short)freq,TONE_TYPE_SINE);
  calcBiquad(FILTER_PARAEQ,1000,0,0.707,2147483648,AUDIO_SAMPLE_RATE_EXACT,tFilter);
  filters_L.updateCoefs(tFilter);
  filters_R.updateCoefs(tFilter); 
  filters_A.updateCoefs(tFilter); 
  
  audioShield.enable();
  audioShield.inputSelect(AUDIO_INPUT_LINEIN);
  audioShield.adc_hpf(1); // not done for the table I posted previously...
  audioShield.volume(0);
  audioShield.dac_vol(97);
  audioShield.unmuteLineout();
  
  Serial.begin(Serial.baud());
//  delay(5000);
//  Serial.println("Ready or not!");
  
  for(uint16_t index=0;index<276;index++) Gain_L[index]=Gain_R[index]=Gain_A[index]=32767; // 1.
  mixer_P.gain(0,1);
  mixer_L.gain(0,0);
  mixer_R.gain(0,0);
  mixer_A.gain(0,0); // synthSine filtered
  mixer_L.gain(1,1);
  mixer_R.gain(1,1);
  mixer_A.gain(1,1); // synthSine flat
}

elapsedMillis capture_time;
#if PIN_VOL!=0
  elapsedMillis volUpd;
#endif
float lastVol=BASE_AMPLITUDE;

float bp[]={10,10};

int timed1=0;
// uint16_t steps=0;


uint8_t chan1;
uint8_t inpt1;
float gain1;


void loop()
{
  if(Serial.available())
 {
   char chr=Serial.read();
   if(chr<32)
   {
     cons.data[cons.ptr]=0;
     cons.ptr=0;
     while(cons.data[cons.ptr]!=0)
     {
       switch(strfig(&cons.data[cons.ptr],&cons.ptr,cmds))
       {
        case 1: // gain=#channel,#input,#float_gain
          chan1=strfig(&cons.data[cons.ptr],&cons.ptr);
          inpt1=strfig(&cons.data[cons.ptr],&cons.ptr);
          switch(chan1)
          {
            case 0: // mixer_L
              if(inpt1<2)
              {
                mixer_L.gain(inpt1,strfig(&cons.data[cons.ptr],&cons.ptr));
                Gain_F&=254;
              } else {
                Gain_L[(uint16_t)strfig(&cons.data[cons.ptr],&cons.ptr)]=strfig(&cons.data[cons.ptr],&cons.ptr)*32767;
                Gain_F|=1;
              }
            break;
            case 1: // mixer_R
              if(inpt1<2)
              {
                mixer_R.gain(inpt1,strfig(&cons.data[cons.ptr],&cons.ptr));
                Gain_F&=253;
              } else {
                Gain_R[(uint16_t)strfig(&cons.data[cons.ptr],&cons.ptr)]=strfig(&cons.data[cons.ptr],&cons.ptr)*32767;
                Gain_F|=2;
              }
            break;
            case 2: // mixer_A
              if(inpt1<2)
              {
                mixer_A.gain(inpt1,strfig(&cons.data[cons.ptr],&cons.ptr));
                Gain_F&=251;
              } else {
                Gain_A[(uint16_t)strfig(&cons.data[cons.ptr],&cons.ptr)]=strfig(&cons.data[cons.ptr],&cons.ptr)*32767;
                Gain_F|=4;
              }
            break;
            case 3: // synthSine
              lastVol=strfig(&cons.data[cons.ptr],&cons.ptr);
              synthSine.amplitude(lastVol);
            break;
            case 4: // mixer_P
              mixer_P.gain(0,strfig(&cons.data[cons.ptr],&cons.ptr));
          }
        break;
        case 2: // filters=#channel,#number_of_filters
          chan1=strfig(&cons.data[cons.ptr],&cons.ptr);
          inpt1=strfig(&cons.data[cons.ptr],&cons.ptr);
          if(!inpt1) calcBiquad(FILTER_PARAEQ,1000,0,0.707,2147483648,AUDIO_SAMPLE_RATE_EXACT,tFilter); // a flat, no effect, filter
          
          switch(chan1)
          {
            case 0: // filter_L; L_filters[]....
              if(inpt1>3) L_filters[23]|=0x80000000; else L_filters[23]&=0x3FFF;
              if(inpt1>2) L_filters[15]|=0x80000000; else L_filters[15]&=0x3FFF;
              if(inpt1>1) L_filters[7]|=0x80000000; else L_filters[7]&=0x3FFF;
              if(!inpt1) filters_L.updateCoefs(tFilter);
            break;
            case 1: // filter_R
              if(inpt1>3) R_filters[23]|=0x80000000; else R_filters[23]&=0x3FFF;
              if(inpt1>2) R_filters[15]|=0x80000000; else R_filters[15]&=0x3FFF;
              if(inpt1>1) R_filters[7]|=0x80000000; else R_filters[7]&=0x3FFF;
              if(!inpt1) filters_R.updateCoefs(tFilter);
            break;
            case 2: // filter_A
              if(inpt1>3) A_filters[23]|=0x80000000; else A_filters[23]&=0x3FFF;
              if(inpt1>2) A_filters[15]|=0x80000000; else A_filters[15]&=0x3FFF;
              if(inpt1>1) A_filters[7]|=0x80000000; else A_filters[7]&=0x3FFF;
              if(!inpt1) filters_A.updateCoefs(tFilter);
          }
        break;
        case 3: // filter=#channel,#filter_num,#filter_type,#frequency,#gain,#Q
          chan1=strfig(&cons.data[cons.ptr],&cons.ptr);
          inpt1=strfig(&cons.data[cons.ptr],&cons.ptr);
          calcBiquad(strfig(&cons.data[cons.ptr],&cons.ptr),strfig(&cons.data[cons.ptr],&cons.ptr),strfig(&cons.data[cons.ptr],&cons.ptr),strfig(&cons.data[cons.ptr],&cons.ptr),2147483648,AUDIO_SAMPLE_RATE_EXACT,tFilter);
          switch(chan1)
          {
            case 0: // filter_L; L_filters[]....
              filters_L.updateCoefs(inpt1,tFilter);
            break;
            case 1: // filter_R
              filters_R.updateCoefs(inpt1,tFilter);
            break;
            case 2: // filter_A
              filters_A.updateCoefs(inpt1,tFilter);
          }
        break;
        case 4:
          Serial.println("sweeper");
        break;
        
        default:
          if(cons.data[cons.ptr]!=0) cons.ptr++;
        }
      }
      cons.ptr=0; 
   } else {
     cons.data[cons.ptr++]=chr;
   }
 }
  
  
  if(capture_time>timed1)
  { // the objects have had time to have their effects.
    peakIn[0].stop();
    peakIn[1].stop();
    peakOut[0].stop();
    peakOut[1].stop();
    peakOut[2].stop();
    peakOut[3].stop();


    Serial.printf("%u,%u,%u,%u,%u,%u,%u,%u\n",steps,(unsigned short)freq,peakIn[0].Dpp(),peakIn[1].Dpp(),peakOut[0].Dpp(),peakOut[1].Dpp(),peakOut[2].Dpp(),peakOut[3].Dpp());
//    Serial.printf("%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",steps,(unsigned short)freq,peakIn[0].Dpp(),peakIn[1].Dpp(),peakOut[0].Dpp(),peakOut[1].Dpp(),peakOut[2].Dpp(),peakOut[3].Dpp(), Gain_L[steps],Gain_R[steps],Gain_A[steps]);

    int temp1=(int)freq;
    while((int)freq==temp1) freq*=MULTI_FREQ;
    
    if(freq>LIMIT_FREQ)
    {
      freq=START_FREQ;
     // Serial.printf("0Hz,0,%u\n",steps);
      bp[0]=bp[1]=10;
      steps=0;
    } else {
      steps++;
      if((int)freq==22050) freq=22049;
    }
    
    if(Gain_F&1) mixer_L.gain(1,(float)Gain_L[steps]/32767);
    if(Gain_F&2) mixer_R.gain(1,(float)Gain_R[steps]/32767);
    if(Gain_F&4) mixer_A.gain(1,(float)Gain_A[steps]/32767);
  
    if(op_running==false) // AudioSynthWaveform doesn't start output when .begin in setup() apparently.
    {
      op_running=synthSine.begin(lastVol,(unsigned short)freq,TONE_TYPE_SINE);
      // Serial.printf("synthSine.begin(%f,%f,TONE_TYPE_SINE)\n",lastVol,freq);
    } else {
      synthSine.frequency((unsigned short)freq);
    }
    if(freq>bp[0])
    {
//      Serial.print(bp[0],DEC);
      if(bp[0]==bp[1]*10)
      {
//        Serial.println("Hz,0,#");
        bp[1]*=10;
        bp[0]=bp[1]*2;
      } else {
//        Serial.println("Hz,0,|");
        bp[0]+=bp[1];
      }
    }
    float freq1=(int)freq;
    if(freq1>0) timed1=(1/freq1)*1000; else timed1=1000;
    if(freq>99&&freq1<125) timed1=9;
    if(timed1<4) timed1=4;
    timed1=(timed1*2)+1;
    capture_time=0;
  } else if(capture_time==3) {
    peakIn[0].begin();
    peakIn[1].begin();
    peakOut[0].begin();
    peakOut[1].begin();
    peakOut[2].begin();
    peakOut[3].begin();
  }
}
the 'gain tables' need to be dropped or fixed up for the number of steps it becomes by starting at 1 instead of 10 and if you want to make it start at .1 then it will be necessary to change from using el_supremo's AudioSynthWaveform to using Paul's original version which does fractions of frequencies but doesn't seem to obey its 'gain' control properly; so to temper it (unless you change methodology elsewhere) it will be necessary to add another AudioMixer4 object (or other gain controller) in between the AudioSynthWaveform and the objects which take its output as their inputs at the moment. Of course all the integer casting of freq will have to be dropped as well.

If you do use this and modify it to your purposes I recommend starting with the current value of START_FREQ and dividing it by MULTI_FREQ until it is small enough to suit you - if you drop the bit which keeps multiplying freq by MULTI_FREQ till it is a different integer value you will get many more output steps and that will be better for values < 1. If you want to use the gain tables you can just run it with your START_FREQ and watch the output, the three arrays currently dimensioned as 276 elements need to be changed to the maximum value returned for steps.

There is more I could write about this but if I write much more of that I could just as well spend the time modifying the code to your purpose myself instead - next time I touch the version of the code I am keeping I want to rewrite it to drop use of milliseconds to figure out if the previous frequency's samples have flushed through to the current frequency and to decide the objects have had time to collect the peaks yet to instead use peaking itself to determine timing; should be faster and more accurate across the range.
 
@robsoles -- my plan was to initially use the Teensy to do the setup on the SGTL5000, and to use a signal generator and an oscilloscope to do the measurements. That's somewhat manual, but I'll use it to confirm some sample points from your more automated code before fuly trusting that !

I'll short the input and output decoupling caps before doing this. It'll be at least this weekend before I can start.
 
Last edited:
I'd like to talk about the upcoming 1.0 release. My goals are...

  1. Fix bugs: This might involve a brief feature freeze. At the moment, known bugs on my radar are the issues with simultaneous ADC and DAC usage, and the line level input levels of the SGTL5000. I probably need to spend some time reviewing the last 50-100 messages. If anyone knows of other bugs that need to be fixed before 1.0, please post them as bugs on the github issue tracker.
  2. Naming convention: I really need to define a convention and I could really use your input. In a day or two I hope to have a first draft....
  3. Documentation!!!

My hope is to *finally* wrap up the beta test period and publish a stable 1.0 library, where stable means it's pretty well tested and the API (object names, function names, parameters, etc) will remain compatible in future versions of the library.
 
Audio routing on the SGTL5000

I am trying to figure out signal flow on the audio board. I think something like line-in -> ADC -> AudioInputI2S. After reading the doc I would think something like line-in -> ADC -> DAP -> AudioInputI2S would be possible.

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

// Create the Audio components.  These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S            audioIn;
AudioAnalyzeToneDetect   row1;     // 7 tone detectors are needed
AudioAnalyzeToneDetect   row2;     // to receive DTMF dial tones
AudioAnalyzeToneDetect   row3;
AudioAnalyzeToneDetect   row4;
AudioAnalyzeToneDetect   column1;
AudioAnalyzeToneDetect   column2;
AudioAnalyzeToneDetect   column3;
//AudioSynthWaveform       sine1(AudioWaveformSine);  // 2 sine wave
//AudioSynthWaveform       sine2(AudioWaveformSine);  // to create DTMF
AudioMixer4              mixer;
AudioOutputI2S           audioOut;

// Create Audio connections between the components
//
AudioConnection c01(audioIn, 0, row1, 0);
AudioConnection c02(audioIn, 0, row2, 0);
AudioConnection c03(audioIn, 0, row3, 0);
AudioConnection c04(audioIn, 0, row4, 0);
AudioConnection c05(audioIn, 0, column1, 0);
AudioConnection c06(audioIn, 0, column2, 0);
AudioConnection c07(audioIn, 0, column3, 0);
//AudioConnection c10(sine1, 0, mixer, 0);
//AudioConnection c11(sine2, 0, mixer, 1);
AudioConnection c12(mixer, 0, audioOut, 0);
AudioConnection c13(mixer, 0, audioOut, 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.volume(82);
  audioShield.dap_enable();
  // here are some settings for AVC that have a fairly obvious effect
  audioShield.dap_avc(2,1,1,-30,0.5,0.5); // see comments starting line #699 of control_sgtl5000.cpp in ./libraries/audio/
  // AVC has its own enable/disable bit
  audioShield.dap_avc_enable(); // you can use audioShield.dap_avc_enable(0); to turn off AVC
  while (!Serial) ;
  delay(100);
  
  // Configure the tone detectors with the frequency and number
  // of cycles to match.  These numbers were picked for match
  // times of approx 30 ms.  Longer times are more precise.
  row1.frequency(349, 21);
  row2.frequency(368, 23);
  row3.frequency(389, 25);
  row4.frequency(410, 28);
  column1.frequency(444, 28);
  column2.frequency(458, 28);
  column3.frequency(484, 28);
}

const float row_threshold = 0.2;
const float column_threshold = 0.2;

void loop() {
  float r1, r2, r3, r4, c1, c2, c3;
  char digit=0;

  // read all seven tone detectors
  r1 = row1.read();
  r2 = row2.read();
  r3 = row3.read();
  r4 = row4.read();
  c1 = column1.read();
  c2 = column2.read();
  c3 = column3.read();

  // print the raw data, for troubleshooting
  Serial.println();
  Serial.print("tones: ");
  Serial.print(r1);
  Serial.print(", ");
  Serial.print(r2);
  Serial.print(", ");
  Serial.print(r3);
  Serial.print(", ");
  Serial.print(r4);
  Serial.print(",   ");
  Serial.print(c1);
  Serial.print(", ");
  Serial.print(c2);
  Serial.print(", ");
  Serial.print(c3);

  
  delay(25);
}


In control_sgtl5000:
write(CHIP_SSS_CTRL, 0x0010); // ADC->I2S, I2S->DAC;

I changed to:
write(CHIP_SSS_CTRL, 0x0013);

I see some change but I don't see the hard compression that I was looking for. First question is what I am trying to do possible? Second if possible what am I doing wrong?
 
I've looked through the last several pages and opened issues on github for (hopefully) everything mentioned.

https://github.com/PaulStoffregen/Audio/issues?state=open

If I've missed anything, please let me know, or better yet, create a new issue on github. From this point forward, I'd like to use the github issue tracker to maintain the list of known bugs. This forum is still the best place for general questions and discussion ideas and development of the library.
 
I am trying to figure out signal flow on the audio board. I think something like line-in -> ADC -> AudioInputI2S. After reading the doc I would think something like line-in -> ADC -> DAP -> AudioInputI2S would be possible.

Code:
<snip />


In control_sgtl5000:
write(CHIP_SSS_CTRL, 0x0010); // ADC->I2S, I2S->DAC;

I changed to:
write(CHIP_SSS_CTRL, 0x0013);

I see some change but I don't see the hard compression that I was looking for. First question is what I am trying to do possible? Second if possible what am I doing wrong?

.dap_enable() routes via the DAP block and enables it, if you keep your change in control_sgtl5000.cpp and remove the '.dap_enable();' line from the sketch I expect you will get silence because the DAP block defaults to disabled and you are routing the (*disabled*) DAP output to the Teensy AudioInputI2S - correct me if you try removing that line from the sketch and actually get any kind of desirable output using that change alone in the library.

Original .enable(); routes (Selected Input)->ADC->I2S_OUT->(Teensy 3.x)->I2S_IN->DAC->(Outputs)
.dap_enable(); re-routes (Selected Input)->ADC->I2S_OUT->(Teensy 3.x)->I2S_IN->DAP->DAC->(Outputs)

I think I need to study the AVC more than I have time for right now to be actually helpful toward your goal there.

It looks like you are trying to make it cut anything bigger than -30dB signal back/down to -30dB, is that right?
 
Last edited:
@Paul: I've submitted pull requests for the speed up in the FFT code and fixed issue #20 with receiveReadOnly in the FIR code.

Pete
 
@Paul:
I'm fixing up the DTMF player/decoder example to work with the new AudioSynthWaveform. How do you want to handle new versions of the examples? With the example that plays music I changed its name because the use of "MIDI" in the name was misleading. With the other examples should I use the existing name DialTone_DTMF which will replace the original, or would you prefer a different name to indicate that it has been updated?

Pete
 
@robsoles

Thanks for the reply, I will work up a better sketch to test this, was in the middle of testing the feasibility of using the tone detect for a two-tone decoder. I was hoping I could compress and limit the line-in audio with the AVC. Otherwise I will monitor the input level and change the tone trigger level based off that, which might be simpler.
 
.dap_enable() routes via the DAP block and enables it, if you keep your change in control_sgtl5000.cpp and remove the '.dap_enable();' line from the sketch I expect you will get silence because the DAP block defaults to disabled and you are routing the (*disabled*) DAP output to the Teensy AudioInputI2S - correct me if you try removing that line from the sketch and actually get any kind of desirable output using that change alone in the library.

Original .enable(); routes (Selected Input)->ADC->I2S_OUT->(Teensy 3.x)->I2S_IN->DAC->(Outputs)
.dap_enable(); re-routes (Selected Input)->ADC->I2S_OUT->(Teensy 3.x)->I2S_IN->DAP->DAC->(Outputs)

I think I need to study the AVC more than I have time for right now to be actually helpful toward your goal there.

It looks like you are trying to make it cut anything bigger than -30dB signal back/down to -30dB, is that right?


I did a quick test with the existing sketch. Had output with both the dap enabled and disabled, AVC did not seem to function either way.
 
That's odd cartere; when I made the dap_avc_agc example I experimented and found settings for it which made it seem obvious to me - removing/commenting-out the .dap_avc_enable(); line, recompiling and downloading the sketch, definite difference to output where having that line compile as well seemed to make the difference I expected for the settings.

Has anyone else had a play with it? How many people think it is broken? Does anybody think, like me, that it works?
 
I've uploaded a first draft of the naming conventions document.

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

Please don't freak out. This is still very tentative. I'd really like to hear your input.

Many parts of the library currently do not meet these naming conventions, and/or don't follow the Arduino Library Style Guidelines. I'm open to suggestions that will improve the library long-term. At this very early stage, with the 1.0 release looming, we're at the last & best opportunity to define the API and change functions to make the whole library consistent and easy to use. After a 1.0 release, I really want to stick to whatever naming convention is chosen and avoid any incompatible changes.


Also new on the website is this page about creating new objects, which shouldn't be a big surprise. It's mostly just a cleanup of the new_objects.md files that's been on github.

http://www.pjrc.com/teensy/td_libs_AudioNewObjects.html
 
Last edited:
That's odd cartere; when I made the dap_avc_agc example I experimented and found settings for it which made it seem obvious to me - removing/commenting-out the .dap_avc_enable(); line, recompiling and downloading the sketch, definite difference to output where having that line compile as well seemed to make the difference I expected for the settings.

Has anyone else had a play with it? How many people think it is broken? Does anybody think, like me, that it works?


Don't misunderstand, I am sure it works. I was trying to do DAP -> Teensy -> tone detect which does not work. The DAP is on the wrong end of the processing path.
 
Maybe the library should come with a sample, known-to-work WAV file? Any have any suggestions?

There are the two files referenced in the sd_speed_test.ino example that I can't seem to find...but maybe I'm not looking hard enough?:

File f1 = SD.open("01_16S.WAV");
File f2 = SD.open("01_16M.WAV");
 
Don't misunderstand, I am sure it works. I was trying to do DAP -> Teensy -> tone detect which does not work. The DAP is on the wrong end of the processing path.
oh, I should have realised that was your intent.

I will review the methods I got into the library before and probably just add an optional flag to control ordering so you can easily switch to (Selected Input)->ADC->DAP->I2S_OUT->(Teensy 3.x)->I2S_IN->DAC->(outputs)

I think you can expect a result from me well within 48 hours - I should easily find an opportunity to make the necessary change(s).
 
@Paul (or C++ gurus):
I've run into an oddity where the compiler optimizes away calls to 'frequency' in AudioSynthwaveForm if it is defined, as it is right now, in the .h file. If I move the frequency function into the .cpp file then the compiler leaves it alone.
This example demonstrates - it requires that my current pull request be installed for it to work properly.
Code:
/*
  Demo - generate RTTY tones 2125/2295 at 45.45 baud which
  is 22 milliseconds per bit.

140313
  a
  - initial version.


 FMI:
 The audio board uses the following pins.
 6 - MEMCS
 7 - MOSI
 9 - BCLK
 10 - SDCS
 11 - MCLK
 12 - MISO
 13 - RX
 14 - SCLK
 15 - VOL
 18 - SDA
 19 - SCL
 22 - TX
 23 - LRCLK

 */

#include <arm_math.h>
#include <Audio.h>
#include <Wire.h>
//#include <WM8731.h>
#include <SD.h>
#include <SPI.h>

AudioSynthWaveform       myEffect;
AudioOutputI2S      audioOutput;        // audio shield: headphones & line-out

// Send the tone to both left and right channels
AudioConnection c1(myEffect, 0, audioOutput, 0);
AudioConnection c2(myEffect, 0, audioOutput, 1);

AudioControlSGTL5000 audioShield;


// Type of tone. SINE, SAWTOOTH, SQUARE or TRIANGLE
short type = TONE_TYPE_SINE;

// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
void setup()
{

  Serial.begin(9600);
  while (!Serial) ;
  delay(2000);

  AudioMemory(2);

  audioShield.enable();
  audioShield.volume(50);
  // I want output on the line out too
  audioShield.unmuteLineout();
  //  audioShield.muteHeadphone();


// THIS WORKS
// Phase-discontinuous RTTY using delayMicroseconds
  myEffect.begin(0.8,2125,type);
  for(int i=0;i< 100;i++) {
//    myEffect.amplitude(0.8);
    myEffect.begin(0.8,2125,type);
    delayMicroseconds(22000);
//    myEffect.amplitude(0.8);
    myEffect.begin(0.8,2295,type);
    delayMicroseconds(22000);
  }
  myEffect.begin(0,0,type);

  delay(2000);
  
// THIS WORKS
// Phase-continuous RTTY using delay
  myEffect.set_ramp_length(144);
  myEffect.begin(0.8,2125,type);
  for(int i=0;i< 100;i++) {
//    myEffect.amplitude(0.8);
    myEffect.frequency(2125);
    delay(22);
//    myEffect.amplitude(0.8);
    myEffect.frequency(2295);
    delay(22);
  }
  myEffect.amplitude(0);

  delay(2000);
  
// THIS will WORK only if I move frequency from the .h to the .cpp
// Phase-continuous RTTY using delayMicroseconds
  myEffect.begin(0.8,2125,type);
  for(int i=0;i< 100;i++) {
//    myEffect.amplitude(0.8);
    myEffect.frequency(2125);
    delayMicroseconds(22000);
//    myEffect.amplitude(0.8);
    myEffect.frequency(2295);
    delayMicroseconds(22000);
  }
  myEffect.amplitude(0);

}

void loop()
{
}
I've had a look at the assembler code and in the third example both calls to frequency are optimized out of existence. I suspect that what is happening is that the compiler doesn't recognize that myEffect.frequency has a side effect which only occurs at interrupt time.
I don't know C++ well enough to do anything other than move frequency to the .cpp file but is there a C++ incantation which can be added to the .h file to prevent the compiler optimizing .frequency out of existence?

Pete
 
I have a fix. The frequency function modifies the variable tone_incr and if I declare it to be volatile the compiler doesn't optimize frequency out of existence.

Pete
 
Status
Not open for further replies.
Back
Top