analogRead() Interrupts with audio library

Status
Not open for further replies.

Janson

Member
Hello,

I'm working on a realtime effects processor (delay and reverb) using the teensy audio board.

I have two pots to change delay and reverb parameters using analogRead() on two pins. So far so good.

Currently I use a function to read the values which is called periodically in the loop() function. Is there a way to convert it to some kind of interrupt to save processing time? Is this necessary? I only want to change the actual variables if the input value change by 10, because i don't need the full precision of analogRead(). Here is how I did it now:

float dly = 0;
float rev = 0;

void readValues(void) {
short dly_tmp = analogRead(3);
if (dly > dly_tmp) {
if ((dly - dly_tmp) > 10)
dly = dly_tmp;
} else {
if ((dly_tmp - dly) > 10)
dly = dly_tmp;
}
short rev_tmp = analogRead(2);
if (rev > rev_tmp) {
if ((rev - rev_tmp) > 10)
rev = rev_tmp;
} else {
if ((rev_tmp - rev) > 10)
rev = rev_tmp;
}
}


I also found this library:

https://github.com/merose/AnalogScanner

Maybe this is suitable for me?

Thanks :)
 
I'd rather use the add library which comes with the Teensyduino installation. It allows to do continuous "scanning" of analogue inputs in the background and writing the the results in a ring buffer via DMA. The latter allows to attach a callback function which could only be executed when the variation is important enough.

More info here: https://github.com/pedvide/ADC
 
Okay, thank you for the suggestion. I looked over the code and examples but I don't have a clue where and how to attach a callback function. Sorry If this is a stupid question, but I used callbacks only once when I worked with MIDI :rolleyes:
 
Another way that I am doing analogReads without hanging around for the results is by using ADC library.

In my case I am using an IntervalTimer, in my case I am reading 4 analog values in, there are two on each of the analog channels.
So what I do in my Intervaltimer is something like:
Code:
  if (_interval_counter & 1) {
    g_Sensors[0]->completeAnalogRead();
    g_Sensors[1]->completeAnalogRead();
    g_Sensors[2]->startAnalogRead();
    g_Sensors[3]->startAnalogRead();
  } else {
    g_Sensors[2]->completeAnalogRead();
    g_Sensors[3]->completeAnalogRead();
    g_Sensors[0]->startAnalogRead();
    g_Sensors[1]->startAnalogRead();
  }
  _interval_counter++;
Where the startAnalogRead and completeAnalogRead do:
Code:
void CurrentSensor::startAnalogRead(void)                    // Update - do analogRead - return 1 if cycle time completed
{

 if (!adc->startSingleRead(_pin, _adc_num)) { // also: startSingleDifferential, analogSynchronizedRead, analogSynchronizedReadDifferential
    Serial.println("Start single failed");
    _analog_read_started = 0;
  }  else {
    _analog_read_started = 1;
  } 
}

//==========================================================================
// completeAnalogRead - complete the analog read
//==========================================================================
void CurrentSensor::completeAnalogRead(void)                    // Update - do analogRead - return 1 if cycle time completed
{
  if (!_analog_read_started) {
    return;
  }
  if (!adc->isComplete(_adc_num)) {
    Serial.printf("%d(%d)!isComplete\n", _pin, _adc_num);
  }
  uint16_t cur_value =  adc->readSingle(_adc_num);
  // Do something with the data I just read in...
  _analog_read_started = 0;
}
Hopefully I removed most of the extra stuff here...

But hopefully shows the idea...
 
Is there a way to convert it to some kind of interrupt to save processing time? Is this necessary?

Yes, it's possible, and no, it's not necessary.

In fact, when using the audio lib, your best option is to just keep all analogRead for pots in your program and avoid interrupts. As soon as you start doing things in interrupts, you run the risk of glitching the audio. The system is designed to be fairly robust, but if you have a choice, best to just keep the analogRead stuff without interrupts.
 
I agree that it is not needed to use interrupts on potmeters. But when you want to have an accurate tap tempo it comes in handy. I have up till now made it without interrups, but the accuracy is not good enough then. How would you recommend implementing interrupts without disturbing the audio?
 
Again what I did above was to use the ADC library, and then split up the analogRead into parts, which don't spend time waiting around for an analog conversion to complete.

That is you can issue a request to start an analog conversion: adc->startSingleRead(_pin, _adc_num)

Then in your code you can checkup to see if the conversion is done: adc->isComplete(_adc_num)

if it is then you can grab the results: adc->readSingle(_adc_num):

Again in my case I had 4 analog sensors I want to read, 2 on each of the ADC units, so I alternate, I do this on IntervalTimer interrupt as I wanted the results at a constant checking as I am doing some RMS like sampling... But if you simply want to check pots during your code, you could easily do all of this with simple functions that poll at convenient locations in your code.
 
How would you recommend implementing interrupts without disturbing the audio?

Just use interrupts the normal way, where you minimize the time your interrupt code runs. And use the default priority level, or raise the priority (lower numbers = higher priority) of your interrupt.

Each audio input/output object has a slightly different implementation, but they all work with the 128 sample block size. Some can tolerate a full 2.9 ms of latency. Others can only withstand latency half or a quarter of the 2.9 ms update time before you will glitch the audio.

Odds are your ADC interrupt will manage to get its work done in a matter of microseconds. Just be quick and don't get anywhere close to the scale of 2.9 ms. Lots of other libs using interrupts work great with the audio library, because almost all of them have well designed interrupt routines that complete in the scale of 5 to 50 microseconds.
 
Thanks Paul, will do that..
One more thing; could it be an idea to have a block in the audio lib that can be set up to be a i.e tap tempo block. You assign a pin as input and then it handles the interrupts and gives out a signal like the function generator module.
I know it is more flexible to have it outside, but I think it would be good to add some more UI modules to the library to get people fast up and running. Also a read potmeter giving ie. dc out. Simple but useful.
Any thought if this is a good or bad idea?
 
I'll split it in two and try to sort my thoughts..

-The first one: Basically the waveform object in the library with an option to assign an Inputpin that can be used to adjust the tempo by tapping the tempo. Typically a momentary switch connected to the inputpin.

-The other object I am thinking about is to make the DC object directly coupled to a ADC input pin. So you can get the value from the potmeter directly into the audiostream as a control.

This is absolutely not important to make as it easily can be made in code. But for the absolute beginners it might comes in handy. Or of you have a lot of pots/controls.
 
-The first one: Basically the waveform object in the library with an option to assign an Inputpin that can be used to adjust the tempo by tapping the tempo. Typically a momentary switch connected to the inputpin.

I *still* have no idea what you mean.

If you really want to make a serious proposal, perhaps a good way to start would be with a fake entry in the design tool.

First, run the design tool locally (not via the internet), as described on page 9 of the audio tutorial.

Then open index.html in a text editor. Find a similar object in the library and make a copy. There's a table near the beginning which defines the essential properties needed to make it appear in the list. Do this first. Then later in the file is a block of documentation text. Try copying the docs for a similar object, and then fill in the details for your proposal... what each input and output stream does, what hardware is uses, what functions it provides and what they do, and so on.

Maybe this documentation process can express your thoughts in a form I can understand? (and others using the object could understand... it's useless if you can't explain to users what it actually does for them)


-The other object I am thinking about is to make the DC object directly coupled to a ADC input pin. So you can get the value from the potmeter directly into the audiostream as a control.

Would this be a new object, or merely an option to turn off the DC blocking feature of the ADC object? Or perhaps set a fixed offset?
 
Ok, I drop the first suggestion. My main programming language is LabView, so I have a tendency to think in wires all over. Maybe too much..
So the tap tempo thing should be done in the code outside the audio core.

But the second suggestion you are spot on:
Would this be a new object, or merely an option to turn off the DC blocking feature of the ADC object? Or perhaps set a fixed offset?

I think it would be less confusing to make it as a separate object.
And as you said a fixed offset or min/max limits can be configured.
I think configurable min/max between -1 and 1 would be good.

I made a suggestion like you described in the attached index.html file
ContAdc.JPG

It does not need an update rate in the same way as the adcin object.
Once every cycle is enough from a user interaction standpoint I think.


While I was a the task, I also added another suggestion.
It is a variable delayline with a control/modulation input.
This is made by @B.Jaquot and the tread can be found here: https://forum.pjrc.com/threads/34194-Changing-Delay-time-without-distortion?highlight=modulated+delay
The source files can be found here:
https://github.com/Jacquot-SFE/Synth-drum/tree/master/teensy-based/fx/cosmic-delay-sketch
mod-delay.h/cpp
I have tested the files and they work. But maybe they need some polishing..
At least I made a cool pitch/up down effect using this algorithm. The only thing to be aware of is to avoid getting close to 0 delay. That gives artifacts in the sound.

Here is a suggestion for the audio lib:
Mod-delay.JPG

I have attached the files in the zip file.
 

Attachments

  • files.zip
    115.3 KB · Views: 114
I think it would be less confusing to make it as a separate object.
And as you said a fixed offset or min/max limits can be configured.
I think configurable min/max between -1 and 1 would be good.

What you've described sounds exactly like the ADC object we already have, but with the high pass filter disabled and the reference changed to 3.3V.

Please understand I have a strong sense of restraint about adding redundant objects to the library. Many, many more objects are planned, so the already long list will grow much, much longer over the next year or so.

There's a phrase from the github folks that goes something like "anything added dilutes everything else". I strongly believe in this philosophy when it comes to GUI design.

It does not need an update rate in the same way as the adcin object.
Once every cycle is enough from a user interaction standpoint I think.

All objects in the audio library (with data streams) always communicate 16 bit data at 44.1 kHz rate. No other speeds or options are supported. That's simply how the audio library is designed.

I also added another suggestion.
It is a variable delayline with a control/modulation input.

Yes, a signal controlled delay line has been on my todo list for quite some time.

I have tested the files and they work. But maybe they need some polishing..

Yes, I have that one and many others on a long list to merge into the library later this year. That "some polishing" part usually turns out to be quite a bit of work. So far, in late 2016 and so far in 2017, Teensy 3.5+3.6 and USB host for 3.6 have taken priority over audio library development. I will get back to the audio lib "soon"...
 
Last edited:
I absolutely understand your arguments.
I also like it as clean as possible when it comes to GUI, but it's hard when it comes to stuff like this. Audio Weaver got over 400 blocks, so as long as it is structured well it can work.
Really looking forward to the new stuff coming in the audio lib!
 
Status
Not open for further replies.
Back
Top