Audio Library

Status
Not open for further replies.
Not sure what #1071 refers to? I was responding to Roels entry, he said he uses 1024 word tables. Can't use quote feature on my phone for some reason :/
 
Oh, sorry, I see now.. the forum reply numbers dont show up on the mobile site which I am typically using.. also I completely missed that 1071 is referring to his own class, which I am about to check out.
 
In flash_spi.cpp are only functions to read block-wise. It is not necessary to read blockwise.
Here's a little extension, I use it in my codec-lib:
Code:
void readserflash(uint8_t* buffer, const size_t position, const size_t bytes)
{//flash_spi.h has no such function.
	digitalWriteFast(SERFLASH_CS, LOW);
	SPI.transfer(0x0b);//CMD_READ_HIGH_SPEED
	SPI.transfer((position >> 16) & 0xff);
	SPI.transfer((position >> 8) & 0xff);
	SPI.transfer(position & 0xff);
	SPI.transfer(0);
	for(unsigned i = 0;i < bytes;i++) {
		*buffer++ = SPI.transfer(0);
	}
	digitalWriteFast(SERFLASH_CS, HIGH);
}

have Fun :)

Regards,
Frank

Do you need to add anything to the .h file to use this?
 
@nantonos

About the point of band limiting:



My teensy project happens to be a virtual analog synthesizer.
about wavetables: I use 14 band limited wavetables, with 1024 samples each (it fills the teensy quite fast!)
Each wavetables I covers half an octave, which gives around 7 octaves. This is almost, but not yet enough.
Still, the lowerest octaves can be relatively harmonically rich with 500 harmonics.
The higher notes use less aliases.
I can't hear the switching of wavetables, so that doesn't give any problems.

a possible optimization might be to use smaller wavetables for higher octaves with less harmonics.
I might implement it if I run out of memory.

Another optimization is that the pulse oscillator is made by subtracting 2 phase shifted saws.
shifting one of those saws changes the duty cycle of the pulse.

Perhaps my code can help, it can be found at my github


I also added hard sync, but haven't anti-aliased that part yet.
Is there an audible difference between hard and soft sync?
I couldn't find a good comparison.



I am checking out your code, does it work in tandem with the teensy audio library?
Also very curious about your DigitalPotFilter Class.. is this for removing zipper noise on a digital pot or is it an actual analog filter circuit being controlled with a digital pot?
I'd be curious if you are willing to share the schematic if it is the latter.

Cheers, good work!
 
Sorry for the late answer, I didn't get a notification of the message :p

I am checking out your code, does it work in tandem with the teensy audio library?

I'm not quite sure If I have a right understanding of the question,
but the code needs and uses the Audio library.
I haven't changed the audio library at all, so it should work for you too.
Probably the easiest is to just copy the oscillator class.

Also very curious about your DigitalPotFilter Class.. is this for removing zipper noise on a digital pot or is it an actual analog filter circuit being controlled with a digital pot?
I'd be curious if you are willing to share the schematic if it is the latter.

Well, about the DigitalPotFilter class... it was used to control the filter cutoff and resonance of an analog filter.
I used a schematic from wikipedia.
However, it didn't work too well with digipots.
The digipot has divided in 256 steps, which were divided linearly.
The 256 steps weren't divided linearly for frequency, with small steps in frequency for a low cutoff.
When the cutoff increased, one digipot-step could mean a difference of 1000 hertz or more.
This... was audible and ugly.

Now I use a vcf that is also used in the Meeblip anode.
It isn't perfect either, but it is possible to control it with a pwm voltage.

How were you able to use 1024 samples in the wave table? It says they are limited to 256? Or did I misunderstand the notes in the function on the audio config tool?

I use a linear interpolation function that I modified from Paul's version.
The original version is indeed limited to 256 samples, but can be extended (or you can write your own).
Here is my version:

Code:
int16_t LinearSample(const int16_t *pWaveTable, uint32_t ph, int TableSizeBits, int32_t magnitude)
{
    uint32_t index,scale;
    int32_t val1, val2;
    
    index = ph >> 22;
    val1 = pWaveTable[index];
    val2 = pWaveTable[index+1];
    scale = (ph >> 6) & 0xFFFF;
    val2 *= scale;
    val1 *= 0xFFFF - scale;
    return multiply_32x32_rshift32(val1 + val2, magnitude);
}

I modified these lines:
Code:
index = ph >> 22;
//original value was >>24
this way only the top 10 bits are kept,
which corresponds to a lookup table of 1024 values.

Code:
scale = (ph >> 6) & 0xFFFF;
//original value was >>8

I honestly can't remember this one.
Somewhere in this thread I asked the same question,
I had some weird high frequency noise with the original value.
 
Well, about the DigitalPotFilter class... it was used to control the filter cutoff and resonance of an analog filter.
I used a schematic from wikipedia.
However, it didn't work too well with digipots.
The digipot has divided in 256 steps, which were divided linearly.
The 256 steps weren't divided linearly for frequency, with small steps in frequency for a low cutoff.
When the cutoff increased, one digipot-step could mean a difference of 1000 hertz or more.
This... was audible and ugly.

That is the usual behaviour for a linear (V/Hz) system, which is why they are rarely used compared to logarithmic (V/octave) systems. Half of the voltage range is used for the top octave, while the lowest octaves need tiny changes of the order of microvolts. (Korg use V/Hz for some odd reason).

The drawback of V/oct circuitry is the need for an exponential converter; in the analog domain this tends to have limited accuracy and needs careful compensation for temperature dependency as well (this is typically added for the expo converter in a VCO and sometimes added for the expo converter in a VCF, especially if self-oscillation is an important feature (i.i its actually being used as a sinewave oscillator)).
 
I just started with the Teensy 3.1 and the Audio library and am interested in writing simple effects for guitar. I started with an input jack to ADC circuit as described on github and a simple DAC to 10u cap to output jack on a breadboard. A simple sketch with adc, mixer, and dac passes through audio fine. When I try a sketch with delay
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=55,98
AudioEffectDelay         delay1;         //xy=223,207
AudioMixer4              mixer1;         //xy=380,146
AudioOutputAnalog        dac1;           //xy=564,155
AudioConnection          patchCord1(adc1, 0, mixer1, 0);
AudioConnection          patchCord2(adc1, delay1);
AudioConnection          patchCord3(delay1, 0, mixer1, 1);
AudioConnection          patchCord4(mixer1, dac1);
// GUItool: end automatically generated code

void setup()
{
    // allocate storage
    AudioMemory(120);

    // 300 ms of delay
    delay1.delay(0, 300.0);

    // wet/dry mix at 0.8
    mixer1.gain(0, 0.2);
    mixer1.gain(1, 0.8);
}

void loop()
{
    // empty
}
or the Delay example (with sgtl5000 removed and i2s1 replaced by dac) I don't hear any of the delayed audio, just the input or the chirps, respectively. Is there hardware to support AudioMemory on the Teensy 3.1 or is that just on the audio adapter? I'm also not sure where the source to AudioMemory is.

Thanks in advance.
 
Audio memory simply assigns RAM to the audio engine, I don't think that is your problem. But then I can't see an issue anywhere else in your code. I've not used analog in or DAC output before so maybe someone else can comment.
 
Audio memory simply assigns RAM to the audio engine, I don't think that is your problem. But then I can't see an issue anywhere else in your code. I've not used analog in or DAC output before so maybe someone else can comment.

Thanks, I've been trying a few other things today, and same thing, I don't seem to get the wet/effected/delayed signal, only the dry/undelayed signal. E.g.

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

// GUItool: begin automatically generated code
AudioInputAnalog         adc1;           //xy=113,154
AudioMixer4              mixer1;         //xy=335,362
AudioEffectDelay         delay1;         //xy=352,183
AudioOutputAnalog        dac1;           //xy=592,204
AudioConnection          patchCord1(adc1, 0, mixer1, 0);
AudioConnection          patchCord2(mixer1, delay1);
AudioConnection          patchCord3(delay1, 0, dac1, 0);
AudioConnection          patchCord4(delay1, 0, mixer1, 1);
// GUItool: end automatically generated code

void setup()
{
  // allocate storage
  AudioMemory(120);

  // 300 ms of delay
  delay1.delay(0, 300.0);

  // feedback at 0.8
  mixer1.gain(0, 1.0);
  mixer1.gain(1, 0.8);
}

void loop()
{
  // empty
}

Here's a photo of my breadboard if that helps

http://postimg.org/image/wt59kdsap/
 
If using the ADC, make sure you have 96 MHz selected. It doesn't work at 72 MHz. Yes, that's a known bug.

Hello Paul, thank you for the reply.

I was using 96 MHz actually, and just tested with 48 MHz and 72 MHz, and I still get audio going from adc to dac in all cases (although it switches to mono of course). What I don't get is any audio coming from Delay (through Mixer in various arrangements). Maybe the way I'm using Mixer is the problem? I have USB type set to "MIDI" if that matters.
 
Hi guys, I'm new here. First off, I want to thank the Devs for the great effort they've put in the audio shield and library!

I've bought a pair of teensy+audio boards for the following project idea: I have an 19" analog audio peak compressor with side-chain functionallity, and I was thinking I could abuse that side-chain functionallity to make the peak compressor into an RMS compressor (or AGC/AVC). Therefore, the RMS of the side-chain signal should be analysed, and converted to a 1 or 2kHz sine wave whose amplitude is modulated by the result of the RMS analysis.
Due to the digital conversion, you'll always have a small delay in the feedback to the compressor. I am looking into shortening that delay a bit, so I took a look at the DAC's volume control and volume ramping functionallity to see if that'd speed up the response. Ramping seems to affect 768 samples (linear) or 256 (exponential). Without ramping, the volume seems to be changed at a zero crossing. I have yet to determine the delay between sending the dacVolume() command and the volume change.

This quest resulted in some new code which might be useful to others, thus I've submitted a pull request of some things:
- an AnalyzeRMS object that calculates the RMS of an audio block
- 2 additional SGTL5000 functions to control the DAC ramping.
- a fix of AnalyzePeak, which returned the maximum distance between the positive and negative peak of the audio, while (in my opinion) normally it should return the maximum absolute distance to DC.

Let me know what you guys think :)
 
This quest resulted in some new code which might be useful to others, thus I've submitted a pull request of some things:
- an AnalyzeRMS object that calculates the RMS of an audio block
- 2 additional SGTL5000 functions to control the DAC ramping.
- a fix of AnalyzePeak, which returned the maximum distance between the positive and negative peak of the audio, while (in my opinion) normally it should return the maximum absolute distance to DC.

Those look like useful additions. I would agree that a peak detector should return max(abs(signal)).
 
Created pull request Change max Q of SVF to 25 #105 because I found that the maximum Q of 5 on the state variable filter was much too low for the sort of resonant filter effects common in subtractive analog synthesis.

Also added an example which is a toy monophonic synthesizer. It has a single sawtooth oscillator which goes through a 12dB/oct low pass SVF and then an envelope. The filter is resonant, with a Q of 18. There are two LFOs which are multiplied together and used (via another envelope) to modulate the cutoff frequency of the filter. The synth responds to USB MIDI (just note on and note off; to keep the example straightforward velocity is just ignored).
It would be fairly straightforward for a user to extend the example in whatever direction was of interest (add switchable waveforms, add multiple oscillators for a detuned supersaw, add CC control of LFOs frequency, make duophonic, respond to velocity by changing dynamics envelope, respond to channel aftertouch to bring in the LFO modulation...)

This is the example:
Code:
// Demonstrate a resonant state-variable filter whose filter frequency
// is controlled by an LFO and envelope. A second encelope is used
// to control the dynamics of each note. This example is a simple,
// monophonic synth.
//
// Accepts MIDI in over USB. Set USB type to MIDI in the Tools menu.
//
// This example code is in the public domain.
 


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

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=86,359
AudioSynthWaveform       waveform2;      //xy=89,302
AudioSynthWaveformSine   sine2;          //xy=90,419
AudioEffectMultiply      multiply1;      //xy=229,389
AudioEffectEnvelope      envelope1;      //xy=379,388
AudioFilterStateVariable filter1;        //xy=383,309
AudioEffectEnvelope      envelope2;      //xy=547,295
AudioOutputI2S           i2s1;           //xy=727,300
AudioConnection          patchCord1(sine1, 0, multiply1, 0);
AudioConnection          patchCord2(waveform2, 0, filter1, 0);
AudioConnection          patchCord3(sine2, 0, multiply1, 1);
AudioConnection          patchCord4(multiply1, envelope1);
AudioConnection          patchCord5(envelope1, 0, filter1, 1);
AudioConnection          patchCord6(filter1, 0, envelope2, 0);
AudioConnection          patchCord7(envelope2, 0, i2s1, 0);
AudioConnection          patchCord8(envelope2, 0, i2s1, 1);
AudioControlSGTL5000     audioShield;     //xy=720,223
// GUItool: end automatically generated code

byte currentNote = 255;  // MIDI note number of currently playing note, 0 - 127 or 255 for no note

void setup(void)
{
  //set up a basic subtractive synth patch
  AudioMemory(8);
  audioShield.enable();
  audioShield.volume(0.45);  // headphone volume (line-out muted)
  // modulation
  sine1.frequency(5);        // 5Hz LFO
  sine1.amplitude(0.7);     // controls modulation depth
  sine2.frequency(23);        // 23Hz second LFO
  sine1.amplitude(0.9);     // controls modulation depth
  envelope1.attack(140);  // fairly slow attack and decay
  envelope1.hold(180);
  envelope1.sustain(0.3);
  envelope1.decay(140);
  envelope1.release(40);
  // saw oscillator
  waveform2.begin(0.2, 220, WAVEFORM_SAWTOOTH);  // 220Hz saw wave oscillator
                                                                                  // quiet level of 0.4 as resonant filter adds gain
  // resonant filter, low-pass mode (output 0 of filter is LP)
  filter1.resonance(18);
  filter1.octaveControl(1.5);  // modulation signal shifts resonant frequency by +/- 1.5 octaves
  filter1.frequency(200);    // start below the resonant peak
  //envelope for note -on and -off dynamics
  envelope2.attack(10);
  envelope2.decay(20);
  envelope2.release(80);
  
  // now respond to MIDI over USB. In this example, only note-on and note-off used and velocity ignored
  usbMIDI.setHandleNoteOff(OnNoteOff);
  usbMIDI.setHandleNoteOn(OnNoteOn);
}
  
 void loop() {
  usbMIDI.read(); // USB MIDI receive
}

void OnNoteOn(byte channel, byte note, byte velocity) {
  // accept input on any channel, and ignore velocity
  
  // check for a currently held note and brutally kill it
  // this sounds bad so only play one note at once, retro style
  if (currentNote <= 127) {
    envelope2.release(2);
    envelope2.noteOff();
    delay(3);  // briefest period for killed note to stop sounding
    envelope2.release(80);
  }
  currentNote = note;
   // MIDI note 69 == A4 == 440Hz
  float freq = ((float)note - 69) / 12.0;  // semitones above or below A4
  freq = 440.0 * powf(2.0, freq);
  sine1.phase(0);          // reset LFOs phases
  sine2.phase(0);    
  envelope1.noteOn();  // start modulation
  waveform2.frequency(freq);
  waveform2.phase(0);
  filter1.frequency(1.2 * freq);  // resonance above played note
  envelope2.noteOn();
}
  
void OnNoteOff(byte channel, byte note, byte velocity) {
  // accept any channel, ignore off-velocity as most things do
  // we only care about the currently playing note
  if (note == currentNote) {
    envelope2.noteOff();
    envelope1.noteOff();
    currentNote = 255;
  }
}
 
I'm attempting to build a lip sync corrector with a Teensy 3.1 and audio shield to compensate for the visual processing lag on my Samsung TV when I play the audio through my HiFi...

I've realised a sonically acceptable 264ms stereo delay by maxing out the AudioMemory(220) - but I haven't tested if it's sufficient yet because I wanted to integrate a 128x64 OLED to display the delay time first.

I've since managed to get a squirrel-labs 128x64 oled display - https://www.squirrel-labs.net/oled-...ay-module-for-arduino-i2c-iic-spi-serial.html - to work with nox771's v7 'New I2C library for Teensy3' - https://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3 - and his modified version of the Adafruit SD1306 library as detailed in this thread - https://forum.pjrc.com/threads/23798-Sabernetics-I2C-OLED-display-Adafruit-SSD1306-library-problem...

But now I've combined my two test files I'm getting an error...

In file included from Teensy_Lip_Sync_Corrector_2.ino:35:0:
/Applications/Coding/Arduino 1.0.6 Teensyduino 1.20.app/Contents/Resources/Java/libraries/Wire/Wire.h:94:16: error: conflicting declaration 'TwoWire Wire'
In file included from Teensy_Lip_Sync_Corrector_2.ino:14:0:
/Users/Shared/AllUsers/Arduino/Sketchbook/libraries/i2c_t3/i2c_t3.h:716:15: error: 'Wire' has a previous declaration as 'i2c_t3 Wire'

There's obviously a conflict between the I2C library the OLED uses and the Wire library the audio library uses...

Any thoughts on whether it's possible to resolve this - and how I might do it? Advice appreciated.

Best

Prodical
 
Overclocking issue:
If I run at 120 or 144Mhz everything plays faster (i.e higher pitch). I'm sure it's quite possible to hack it to work, (i recall there is a constant somewhere which details the frequency of updates) but there will be other implications to any mods I make.

If Paul could have easily written it to handle overclocking better, I'm sure he would have - so there are reasons it does not. Possibly time? Possibly more sinister ones! :)

Has anyone got it running at faster speed but playing back at 44Khz properly?
 
Has anyone got it running at faster speed but playing back at 44Khz properly?

works for me, i use 120MHz with both play_sd_wav and Frank's SPI raw/flash library, mostly because of the 30MHz SPI clock thing. i use a different codec but that shouldn't make a difference.
 
I didn't notice the increase in pitch at first. going to 144Mhz its rather more noticeable. It works fine for me, of course. Have you compared playback of the original sample by ear?
 
Also added an example which is a toy monophonic synthesizer.

Having a crack at it :) need to get fiddling with my dusty knobs.


Concept: In mp3 encoding, there is a joint stereo feature. Massive space saver. Mono base plus stereo modifier channels.

We have custom RAW format (which we should really call PRW) with a small header. Would it not be possible to conceive a format for stereo PRW files utilising joint stereo principles, which routed a monophonic base signal through to a left and right channel, and added a small additive per channel as a joint stereo modifier? In this way one could store Stereo files at high quality , and play them back with a bare minimum of SPI bandwidth baggage.

I think i just answered my own question. This would involve FFTs wouldn't it? So it wouldn't save any CPU time at a pinch. Well that's what you get for thinking aloud.
 
As it happens I've just finished a Mid-Side encode and decode effect, which could be used to modify your stereo image :) I only need to test it running (individual math works).

To that end, I have 2 questions:
1) Earlier I've submitted a pull request with other functionality. Would you (Paul) prefer if I push these 2 extra effects once tested to my master and thus add upon that pull request, or branch and make a new pull request (i'm no git pro yet, so I'd prefer the first)?

2) I had to add a few DSP functions, being "signed_subtract_16_and_16()", "signed_halving_add_16_and_16()" and "signed_halving_subtract_16_and_16()". Can these just be added to "utility/dspinst.h"?
 
CPU load is 3%!!!

This is so much fun....my twiddlepots are twiddling, now i just need to know more about synths.
 
Last edited:
To that end, I have 2 questions:
1) Earlier I've submitted a pull request with other functionality. Would you (Paul) prefer if I push these 2 extra effects once tested to my master and thus add upon that pull request, or branch and make a new pull request (i'm no git pro yet, so I'd prefer the first)?

Please don't use branches. I'm not a github pro either!

Even if I did know the finer points of git & github, I'm absolutely terrible at maintaining more than 1 copy of anything. Just submit a normal pull request, and please understand I'm crazy busy with Teensy-LC at the moment. It'll likely be about 1 month until I can really look at anything other than the simplest bug fixes.

2) I had to add a few DSP functions, being "signed_subtract_16_and_16()", "signed_halving_add_16_and_16()" and "signed_halving_subtract_16_and_16()". Can these just be added to "utility/dspinst.h"?

Sounds fine.
 
Status
Not open for further replies.
Back
Top