Browse Source

Reorganize all header files

dds
PaulStoffregen 10 years ago
parent
commit
e4cb836eea
28 changed files with 854 additions and 786 deletions
  1. +28
    -779
      Audio.h
  2. +22
    -0
      AudioControl.h
  3. +50
    -0
      analyze_fft256.h
  4. +0
    -0
      analyze_print.cpp
  5. +16
    -0
      analyze_print.h
  6. +46
    -0
      analyze_tonedetect.h
  7. +70
    -0
      control_sgtl5000.h
  8. +25
    -0
      control_wm8731.h
  9. +34
    -0
      effect_chorus.h
  10. +30
    -0
      effect_fade.h
  11. +39
    -0
      effect_flange.h
  12. +20
    -0
      filter_biquad.h
  13. +41
    -0
      filter_fir.h
  14. +1
    -2
      input_adc.cpp
  15. +20
    -0
      input_adc.h
  16. +31
    -0
      input_i2s.h
  17. +24
    -0
      mixer.h
  18. +1
    -3
      output_dac.cpp
  19. +21
    -0
      output_dac.h
  20. +40
    -0
      output_i2s.h
  21. +22
    -0
      output_pwm.h
  22. +20
    -0
      play_memory.h
  23. +22
    -0
      play_sd_raw.h
  24. +33
    -0
      play_sd_wav.h
  25. +31
    -0
      synth_tonesweep.h
  26. +152
    -0
      synth_waveform.h
  27. +4
    -2
      utility/dspinst.h
  28. +11
    -0
      utility/pdb.h

+ 28
- 779
Audio.h View File

@@ -1,6 +1,5 @@
#include "AudioStream.h"
#include "arm_math.h"

#ifndef Audio_h_
#define Audio_h_

// When changing multiple audio object settings that must update at
// the same time, these functions allow the audio library interrupt
@@ -12,790 +11,40 @@
// library to update with AudioInterrupts(). Both changes will happen
// at the same time, because AudioNoInterrupts() prevents any updates
// while you make changes.
//
#define AudioNoInterrupts() (NVIC_DISABLE_IRQ(IRQ_SOFTWARE))
#define AudioInterrupts() (NVIC_ENABLE_IRQ(IRQ_SOFTWARE))

// waveforms.c
extern "C" {
extern const int16_t AudioWaveformSine[257];
extern const int16_t AudioWaveformTriangle[257];
extern const int16_t AudioWaveformSquare[257];
extern const int16_t AudioWaveformSawtooth[257];
}

// windows.c
extern "C" {
extern const int16_t AudioWindowHanning256[];
extern const int16_t AudioWindowBartlett256[];
extern const int16_t AudioWindowBlackman256[];
extern const int16_t AudioWindowFlattop256[];
extern const int16_t AudioWindowBlackmanHarris256[];
extern const int16_t AudioWindowNuttall256[];
extern const int16_t AudioWindowBlackmanNuttall256[];
extern const int16_t AudioWindowWelch256[];
extern const int16_t AudioWindowHamming256[];
extern const int16_t AudioWindowCosine256[];
extern const int16_t AudioWindowTukey256[];
}

class AudioAnalyzeFFT256 : public AudioStream
{
public:
AudioAnalyzeFFT256(uint8_t navg = 8, const int16_t *win = AudioWindowHanning256)
: AudioStream(1, inputQueueArray), window(win),
prevblock(NULL), count(0), naverage(navg), outputflag(false) { init(); }

bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
virtual void update(void);
//uint32_t cycles;
int32_t output[128] __attribute__ ((aligned (4)));
private:
void init(void);
const int16_t *window;
audio_block_t *prevblock;
int16_t buffer[512] __attribute__ ((aligned (4)));
uint8_t count;
uint8_t naverage;
bool outputflag;
audio_block_t *inputQueueArray[1];
};



#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
class AudioSynthWaveform : public AudioStream
{
public:
AudioSynthWaveform(const int16_t *waveform)
: AudioStream(0, NULL), wavetable(waveform), magnitude(0), phase(0)
, ramp_down(0), ramp_up(0), ramp_mag(0), ramp_length(0)
{ }
void frequency(float freq) {
if (freq > AUDIO_SAMPLE_RATE_EXACT / 2 || freq < 0.0) return;
phase_increment = (freq / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
}
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(magnitude && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_magnitude = magnitude;
}
else if((magnitude == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
}
// set new magnitude
magnitude = n * 32767.0;
}
virtual void update(void);
void set_ramp_length(uint16_t r_length);
private:
const int16_t *wavetable;
uint16_t magnitude;
uint16_t last_magnitude;
uint32_t phase;
uint32_t phase_increment;
uint32_t ramp_down;
uint32_t ramp_up;
uint32_t ramp_mag;
uint16_t ramp_length;
};

#else

#define AUDIO_SAMPLE_RATE_ROUNDED (44118)

#define DELAY_PASSTHRU -1

#define TONE_TYPE_SINE 0
#define TONE_TYPE_SAWTOOTH 1
#define TONE_TYPE_SQUARE 2
#define TONE_TYPE_TRIANGLE 3

class AudioSynthWaveform :
public AudioStream
{
public:
AudioSynthWaveform(void) :
AudioStream(0,NULL),
tone_freq(0), tone_phase(0), tone_incr(0), tone_type(0),
ramp_down(0), ramp_up(0), ramp_length(0)
{
}
// Change the frequency on-the-fly to permit a phase-continuous
// change between two frequencies.
void frequency(int t_hi)
{
tone_incr = (0x100000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
}
// If ramp_length is non-zero this will set up
// either a rmap up or a ramp down when a wave
// first starts or when the amplitude is set
// back to zero.
// Note that if the ramp_length is N, the generated
// wave will be N samples longer than when it is not
// ramp
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(tone_amp && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_tone_amp = tone_amp;
}
else if((tone_amp == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
// reset the phase when the amplitude was zero
// and has now been increased. Note that this
// happens even if the wave is not ramped
// so that the signal starts at zero
tone_phase = 0;
}
// set new magnitude
tone_amp = n * 32767.0;
}
boolean begin(float t_amp,int t_hi,short t_type);
virtual void update(void);
void set_ramp_length(uint16_t r_length);

private:
short tone_amp;
short last_tone_amp;
short tone_freq;
uint32_t tone_phase;
uint32_t tone_incr;
short tone_type;

uint32_t ramp_down;
uint32_t ramp_up;
uint16_t ramp_length;
};

#endif



#if 0
class AudioSineWaveMod : public AudioStream
{
public:
AudioSineWaveMod() : AudioStream(1, inputQueueArray) {}
void frequency(float freq);
//void amplitude(q15 n);
virtual void update(void);
private:
uint32_t phase;
uint32_t phase_increment;
uint32_t modulation_factor;
audio_block_t *inputQueueArray[1];
};
#endif





class AudioOutputPWM : public AudioStream
{
public:
AudioOutputPWM(void) : AudioStream(1, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch3_isr(void);
private:
static audio_block_t *block_1st;
static audio_block_t *block_2nd;
static uint32_t block_offset;
static bool update_responsibility;
static uint8_t interrupt_count;
audio_block_t *inputQueueArray[1];
};





class AudioOutputAnalog : public AudioStream
{
public:
AudioOutputAnalog(void) : AudioStream(1, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
void analogReference(int ref);
friend void dma_ch4_isr(void);
private:
static audio_block_t *block_left_1st;
static audio_block_t *block_left_2nd;
static bool update_responsibility;
audio_block_t *inputQueueArray[1];
};





class AudioPrint : public AudioStream
{
public:
AudioPrint(const char *str) : AudioStream(1, inputQueueArray), name(str) {}
virtual void update(void);
private:
const char *name;
audio_block_t *inputQueueArray[1];
};











// Multiple input & output objects use the Programmable Delay Block
// to set their sample rate. They must all configure the same
// period to avoid chaos.

#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT)
#define PDB_PERIOD 1087 // 48e6 / 44100






class AudioInputI2S : public AudioStream
{
public:
AudioInputI2S(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch1_isr(void);
protected:
AudioInputI2S(int dummy): AudioStream(0, NULL) {} // to be used only inside AudioInputI2Sslave !!
static bool update_responsibility;
private:
static audio_block_t *block_left;
static audio_block_t *block_right;
static uint16_t block_offset;
};


class AudioOutputI2S : public AudioStream
{
public:
AudioOutputI2S(void) : AudioStream(2, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch0_isr(void);
friend class AudioInputI2S;
protected:
AudioOutputI2S(int dummy): AudioStream(2, inputQueueArray) {} // to be used only inside AudioOutputI2Sslave !!
static void config_i2s(void);
static audio_block_t *block_left_1st;
static audio_block_t *block_right_1st;
static bool update_responsibility;
private:
static audio_block_t *block_left_2nd;
static audio_block_t *block_right_2nd;
static uint16_t block_left_offset;
static uint16_t block_right_offset;
audio_block_t *inputQueueArray[2];
};


class AudioInputI2Sslave : public AudioInputI2S
{
public:
AudioInputI2Sslave(void) : AudioInputI2S(0) { begin(); }
void begin(void);
friend void dma_ch1_isr(void);
};


class AudioOutputI2Sslave : public AudioOutputI2S
{
public:
AudioOutputI2Sslave(void) : AudioOutputI2S(0) { begin(); } ;
void begin(void);
friend class AudioInputI2Sslave;
friend void dma_ch0_isr(void);
protected:
static void config_i2s(void);
};





class AudioInputAnalog : public AudioStream
{
public:
AudioInputAnalog(unsigned int pin) : AudioStream(0, NULL) { begin(pin); }
virtual void update(void);
void begin(unsigned int pin);
friend void dma_ch2_isr(void);
private:
static audio_block_t *block_left;
static uint16_t block_offset;
uint16_t dc_average;
static bool update_responsibility;
};




















#include "SD.h"

class AudioPlaySDcardWAV : public AudioStream
{
public:
AudioPlaySDcardWAV(void) : AudioStream(0, NULL) { begin(); }
void begin(void);

bool play(const char *filename);
void stop(void);
bool start(void);
virtual void update(void);
private:
File wavfile;
bool consume(void);
bool parse_format(void);
uint32_t header[5];
uint32_t data_length; // number of bytes remaining in data section
audio_block_t *block_left;
audio_block_t *block_right;
uint16_t block_offset;
uint8_t buffer[512];
uint16_t buffer_remaining;
uint8_t state;
uint8_t state_play;
uint8_t leftover_bytes;
};


class AudioPlaySDcardRAW : public AudioStream
{
public:
AudioPlaySDcardRAW(void) : AudioStream(0, NULL) { begin(); }
void begin(void);
bool play(const char *filename);
void stop(void);
virtual void update(void);
private:
File rawfile;
audio_block_t *block;
bool playing;
bool paused;
};



class AudioPlayMemory : public AudioStream
{
public:
AudioPlayMemory(void) : AudioStream(0, NULL), playing(0) { }
void play(const unsigned int *data);
void stop(void);
virtual void update(void);
private:
const unsigned int *next;
uint32_t length;
int16_t prior;
volatile uint8_t playing;
};










class AudioMixer4 : public AudioStream
{
public:
AudioMixer4(void) : AudioStream(4, inputQueueArray) {
for (int i=0; i<4; i++) multiplier[i] = 65536;
}
virtual void update(void);
void gain(unsigned int channel, float gain) {
if (channel >= 4) return;
if (gain > 32767.0f) gain = 32767.0f;
else if (gain < 0.0f) gain = 0.0f;
multiplier[channel] = gain * 65536.0f; // TODO: proper roundoff?
}
private:
int32_t multiplier[4];
audio_block_t *inputQueueArray[4];
};






class AudioFilterBiquad : public AudioStream
{
public:
AudioFilterBiquad(int *parameters)
: AudioStream(1, inputQueueArray), definition(parameters) { }
virtual void update(void);
void updateCoefs(int *source, bool doReset);
void updateCoefs(int *source);
private:
int *definition;
audio_block_t *inputQueueArray[1];
};



class AudioEffectFade : public AudioStream
{
public:
AudioEffectFade(void)
: AudioStream(1, inputQueueArray), position(0xFFFFFFFF) {}
void fadeIn(uint32_t milliseconds) {
uint32_t samples = (uint32_t)(milliseconds * 441u + 5u) / 10u;
//Serial.printf("fadeIn, %u samples\n", samples);
fadeBegin(0xFFFFFFFFu / samples, 1);
}
void fadeOut(uint32_t milliseconds) {
uint32_t samples = (uint32_t)(milliseconds * 441u + 5u) / 10u;
//Serial.printf("fadeOut, %u samples\n", samples);
fadeBegin(0xFFFFFFFFu / samples, 0);
}
virtual void update(void);
private:
void fadeBegin(uint32_t newrate, uint8_t dir);
uint32_t position; // 0 = off, 0xFFFFFFFF = on
uint32_t rate;
uint8_t direction; // 0 = fading out, 1 = fading in
audio_block_t *inputQueueArray[1];
};



class AudioAnalyzeToneDetect : public AudioStream
{
public:
AudioAnalyzeToneDetect(void)
: AudioStream(1, inputQueueArray), thresh(6554), enabled(false) { }
void frequency(float freq, uint16_t cycles=10) {
set_params((int32_t)(cos((double)freq
* (2.0 * 3.14159265358979323846 / AUDIO_SAMPLE_RATE_EXACT))
* (double)2147483647.999), cycles,
(float)AUDIO_SAMPLE_RATE_EXACT / freq * (float)cycles + 0.5f);
}
void set_params(int32_t coef, uint16_t cycles, uint16_t len);
bool available(void) {
__disable_irq();
bool flag = new_output;
if (flag) new_output = false;
__enable_irq();
return flag;
}
float read(void);
void threshold(float level) {
if (level < 0.01f) thresh = 655;
else if (level > 0.99f) thresh = 64881;
else thresh = level * 65536.0f + 0.5f;
}
operator bool(); // true if at or above threshold, false if below
virtual void update(void);
private:
int32_t coefficient; // Goertzel algorithm coefficient
int32_t s1, s2; // Goertzel algorithm state
int32_t out1, out2; // Goertzel algorithm state output
uint16_t length; // number of samples to analyze
uint16_t count; // how many left to analyze
uint16_t ncycles; // number of waveform cycles to seek
uint16_t thresh; // threshold, 655 to 64881 (1% to 99%)
bool enabled;
volatile bool new_output;
audio_block_t *inputQueueArray[1];
};





// include all the library headers, so a sketch can use a single
// #include <Audio.h> to get the whole library
//
#include "analyze_fft256.h"
#include "analyze_print.h"
#include "analyze_tonedetect.h"
#include "control_sgtl5000.h"
#include "control_wm8731.h"
#include "effect_chorus.h"
#include "effect_fade.h"
#include "effect_flange.h"
#include "filter_biquad.h"
#include "filter_fir.h"
#include "input_adc.h"
#include "input_i2s.h"
#include "mixer.h"
#include "output_dac.h"
#include "output_i2s.h"
#include "output_pwm.h"
#include "play_memory.h"
#include "play_sd_raw.h"
#include "play_sd_wav.h"
#include "synth_tonesweep.h"
#include "synth_waveform.h"


// TODO: more audio processing objects....
// sine wave with frequency modulation (phase)
// waveforms with bandwidth limited tables for synth
// envelope: attack-decay-sustain-release, maybe other more complex?
// MP3 decoding - it is possible with optimized code?
// other decompression, ADPCM, Vorbis, Speex, etc?




// A base class for all Codecs, DACs and ADCs, so at least the
// most basic functionality is consistent.

#define AUDIO_INPUT_LINEIN 0
#define AUDIO_INPUT_MIC 1

class AudioControl
{
public:
virtual bool enable(void) = 0;
virtual bool disable(void) = 0;
virtual bool volume(float volume) = 0; // volume 0.0 to 100.0
virtual bool inputLevel(float volume) = 0; // volume 0.0 to 100.0
virtual bool inputSelect(int n) = 0;
};



class AudioControlWM8731 : public AudioControl
{
public:
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 0.8 + 47.499); }
bool inputLevel(float n) { return false; }
bool inputSelect(int n) { return false; }
protected:
bool write(unsigned int reg, unsigned int val);
bool volumeInteger(unsigned int n); // range: 0x2F to 0x7F
};

class AudioControlWM8731master : public AudioControlWM8731
{
public:
bool enable(void);
};


class AudioControlSGTL5000 : public AudioControl
{
public:
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 1.29 + 0.499); }
bool inputLevel(float n) {return false;}
bool muteHeadphone(void) { return write(0x0024, ana_ctrl | (1<<4)); }
bool unmuteHeadphone(void) { return write(0x0024, ana_ctrl & ~(1<<4)); }
bool muteLineout(void) { return write(0x0024, ana_ctrl | (1<<8)); }
bool unmuteLineout(void) { return write(0x0024, ana_ctrl & ~(1<<8)); }
bool inputSelect(int n) {
if (n == AUDIO_INPUT_LINEIN) {
return write(0x0024, ana_ctrl | (1<<2));
} else if (n == AUDIO_INPUT_MIC) {
//return write(0x002A, 0x0172) && write(0x0024, ana_ctrl & ~(1<<2));
return write(0x002A, 0x0173) && write(0x0024, ana_ctrl & ~(1<<2)); // +40dB
} else {
return false;
}
}
//bool inputLinein(void) { return write(0x0024, ana_ctrl | (1<<2)); }
//bool inputMic(void) { return write(0x002A, 0x0172) && write(0x0024, ana_ctrl & ~(1<<2)); }

bool volume(float left, float right);
unsigned short micGain(unsigned int n) { return modify(0x002A, n&3, 3); }
unsigned short lo_lvl(uint8_t n);
unsigned short lo_lvl(uint8_t left, uint8_t right);
unsigned short dac_vol(float n);
unsigned short dac_vol(float left, float right);
unsigned short dap_mix_enable(uint8_t n);
unsigned short dap_enable(uint8_t n);
unsigned short dap_enable(void);
unsigned short dap_peqs(uint8_t n);
unsigned short dap_audio_eq(uint8_t n);
unsigned short dap_audio_eq_band(uint8_t bandNum, float n);
void dap_audio_eq_geq(float bass, float mid_bass, float midrange, float mid_treble, float treble);
void dap_audio_eq_tone(float bass, float treble);
void load_peq(uint8_t filterNum, int *filterParameters);
protected:
bool muted;
bool volumeInteger(unsigned int n); // range: 0x00 to 0x80
uint16_t ana_ctrl;

unsigned char calcVol(float n, unsigned char range);

unsigned int read(unsigned int reg);
bool write(unsigned int reg, unsigned int val);
unsigned int modify(unsigned int reg, unsigned int val, unsigned int iMask);
};

//For Filter Type: 0 = LPF, 1 = HPF, 2 = BPF, 3 = NOTCH, 4 = PeakingEQ, 5 = LowShelf, 6 = HighShelf
#define FILTER_LOPASS 0
#define FILTER_HIPASS 1
#define FILTER_BANDPASS 2
#define FILTER_NOTCH 3
#define FILTER_PARAEQ 4
#define FILTER_LOSHELF 5
#define FILTER_HISHELF 6

void calcBiquad(uint8_t filtertype, float fC, float dB_Gain, float Q, uint32_t quantization_unit, uint32_t fS, int *coef);



/******************************************************************/

// Maximum number of coefficients in a FIR filter
// The audio breaks up with 128 coefficients so a
// maximum of 150 is more than sufficient
#define MAX_COEFFS 150

// Indicates that the code should just pass through the audio
// without any filtering (as opposed to doing nothing at all)
#define FIR_PASSTHRU ((short *) 1)

class AudioFilterFIR :
public AudioStream
{
public:
AudioFilterFIR(void):
AudioStream(2,inputQueueArray), coeff_p(NULL)
{
}

void begin(short *coeff_p,int f_pin);
virtual void update(void);
void stop(void);
private:
audio_block_t *inputQueueArray[2];
// arm state arrays and FIR instances for left and right channels
// the state arrays are defined to handle a maximum of MAX_COEFFS
// coefficients in a filter
q15_t l_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
q15_t r_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
arm_fir_instance_q15 l_fir_inst;
arm_fir_instance_q15 r_fir_inst;
// pointer to current coefficients or NULL or FIR_PASSTHRU
short *coeff_p;
};



/******************************************************************/
// A u d i o E f f e c t F l a n g e
// Written by Pete (El Supremo) Jan 2014

#define DELAY_PASSTHRU 0

class AudioEffectFlange :
public AudioStream
{
public:
AudioEffectFlange(void):
AudioStream(2,inputQueueArray) {
}

boolean begin(short *delayline,int d_length,int delay_offset,int d_depth,float delay_rate);
boolean modify(int delay_offset,int d_depth,float delay_rate);
virtual void update(void);
void stop(void);
private:
audio_block_t *inputQueueArray[2];
static short *l_delayline;
static short *r_delayline;
static int delay_length;
static short l_circ_idx;
static short r_circ_idx;
static int delay_depth;
static int delay_offset_idx;
static int delay_rate_incr;
static unsigned int l_delay_rate_index;
static unsigned int r_delay_rate_index;
};


/******************************************************************/

// A u d i o E f f e c t C h o r u s
// Written by Pete (El Supremo) Jan 2014


class AudioEffectChorus :
public AudioStream
{
public:
AudioEffectChorus(void):
AudioStream(2,inputQueueArray) {
}

boolean begin(short *delayline,int delay_length,int n_chorus);
virtual void update(void);
void stop(void);
void modify(int n_chorus);
private:
audio_block_t *inputQueueArray[2];
static short *l_delayline;
static short *r_delayline;
static short l_circ_idx;
static short r_circ_idx;
static int num_chorus;
static int delay_length;
};


/******************************************************************/

// A u d i o T o n e S w e e p
// Written by Pete (El Supremo) Feb 2014

class AudioToneSweep : public AudioStream
{
public:
AudioToneSweep(void) :
AudioStream(0,NULL), sweep_busy(0)
{ }

boolean begin(short t_amp,int t_lo,int t_hi,float t_time);
virtual void update(void);
unsigned char busy(void);

private:
short tone_amp;
int tone_lo;
int tone_hi;
uint64_t tone_freq;
uint64_t tone_phase;
uint64_t tone_incr;
int tone_sign;
unsigned char sweep_busy;
};

#endif

+ 22
- 0
AudioControl.h View File

@@ -0,0 +1,22 @@
#ifndef AudioControl_h_
#define AudioControl_h_

#include <stdint.h>

// A base class for all Codecs, DACs and ADCs, so at least the
// most basic functionality is consistent.

#define AUDIO_INPUT_LINEIN 0
#define AUDIO_INPUT_MIC 1

class AudioControl
{
public:
virtual bool enable(void) = 0;
virtual bool disable(void) = 0;
virtual bool volume(float volume) = 0; // volume 0.0 to 100.0
virtual bool inputLevel(float volume) = 0; // volume 0.0 to 100.0
virtual bool inputSelect(int n) = 0;
};

#endif

+ 50
- 0
analyze_fft256.h View File

@@ -0,0 +1,50 @@
#ifndef analyze_fft256_h_
#define analyze_fft256_h_

#include "AudioStream.h"
#include "arm_math.h"

// windows.c
extern "C" {
extern const int16_t AudioWindowHanning256[];
extern const int16_t AudioWindowBartlett256[];
extern const int16_t AudioWindowBlackman256[];
extern const int16_t AudioWindowFlattop256[];
extern const int16_t AudioWindowBlackmanHarris256[];
extern const int16_t AudioWindowNuttall256[];
extern const int16_t AudioWindowBlackmanNuttall256[];
extern const int16_t AudioWindowWelch256[];
extern const int16_t AudioWindowHamming256[];
extern const int16_t AudioWindowCosine256[];
extern const int16_t AudioWindowTukey256[];
}

class AudioAnalyzeFFT256 : public AudioStream
{
public:
AudioAnalyzeFFT256(uint8_t navg = 8, const int16_t *win = AudioWindowHanning256)
: AudioStream(1, inputQueueArray), window(win),
prevblock(NULL), count(0), naverage(navg), outputflag(false) { init(); }

bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
virtual void update(void);
//uint32_t cycles;
int32_t output[128] __attribute__ ((aligned (4)));
private:
void init(void);
const int16_t *window;
audio_block_t *prevblock;
int16_t buffer[512] __attribute__ ((aligned (4)));
uint8_t count;
uint8_t naverage;
bool outputflag;
audio_block_t *inputQueueArray[1];
};

#endif

print.cpp → analyze_print.cpp View File


+ 16
- 0
analyze_print.h View File

@@ -0,0 +1,16 @@
#ifndef analyze_print_h_
#define analyze_print_h_

#include "AudioStream.h"

class AudioPrint : public AudioStream
{
public:
AudioPrint(const char *str) : AudioStream(1, inputQueueArray), name(str) {}
virtual void update(void);
private:
const char *name;
audio_block_t *inputQueueArray[1];
};

#endif

+ 46
- 0
analyze_tonedetect.h View File

@@ -0,0 +1,46 @@
#ifndef analyze_tonedetect_h_
#define analyze_tonedetect_h_

#include "AudioStream.h"

class AudioAnalyzeToneDetect : public AudioStream
{
public:
AudioAnalyzeToneDetect(void)
: AudioStream(1, inputQueueArray), thresh(6554), enabled(false) { }
void frequency(float freq, uint16_t cycles=10) {
set_params((int32_t)(cos((double)freq
* (2.0 * 3.14159265358979323846 / AUDIO_SAMPLE_RATE_EXACT))
* (double)2147483647.999), cycles,
(float)AUDIO_SAMPLE_RATE_EXACT / freq * (float)cycles + 0.5f);
}
void set_params(int32_t coef, uint16_t cycles, uint16_t len);
bool available(void) {
__disable_irq();
bool flag = new_output;
if (flag) new_output = false;
__enable_irq();
return flag;
}
float read(void);
void threshold(float level) {
if (level < 0.01f) thresh = 655;
else if (level > 0.99f) thresh = 64881;
else thresh = level * 65536.0f + 0.5f;
}
operator bool(); // true if at or above threshold, false if below
virtual void update(void);
private:
int32_t coefficient; // Goertzel algorithm coefficient
int32_t s1, s2; // Goertzel algorithm state
int32_t out1, out2; // Goertzel algorithm state output
uint16_t length; // number of samples to analyze
uint16_t count; // how many left to analyze
uint16_t ncycles; // number of waveform cycles to seek
uint16_t thresh; // threshold, 655 to 64881 (1% to 99%)
bool enabled;
volatile bool new_output;
audio_block_t *inputQueueArray[1];
};

#endif

+ 70
- 0
control_sgtl5000.h View File

@@ -0,0 +1,70 @@
#ifndef control_sgtl5000_h_
#define control_sgtl5000_h_

#include "AudioControl.h"

class AudioControlSGTL5000 : public AudioControl
{
public:
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 1.29 + 0.499); }
bool inputLevel(float n) {return false;}
bool muteHeadphone(void) { return write(0x0024, ana_ctrl | (1<<4)); }
bool unmuteHeadphone(void) { return write(0x0024, ana_ctrl & ~(1<<4)); }
bool muteLineout(void) { return write(0x0024, ana_ctrl | (1<<8)); }
bool unmuteLineout(void) { return write(0x0024, ana_ctrl & ~(1<<8)); }
bool inputSelect(int n) {
if (n == AUDIO_INPUT_LINEIN) {
return write(0x0024, ana_ctrl | (1<<2));
} else if (n == AUDIO_INPUT_MIC) {
//return write(0x002A, 0x0172) && write(0x0024, ana_ctrl & ~(1<<2));
return write(0x002A, 0x0173) && write(0x0024, ana_ctrl & ~(1<<2)); // +40dB
} else {
return false;
}
}
//bool inputLinein(void) { return write(0x0024, ana_ctrl | (1<<2)); }
//bool inputMic(void) { return write(0x002A, 0x0172) && write(0x0024, ana_ctrl & ~(1<<2)); }

bool volume(float left, float right);
unsigned short micGain(unsigned int n) { return modify(0x002A, n&3, 3); }
unsigned short lo_lvl(uint8_t n);
unsigned short lo_lvl(uint8_t left, uint8_t right);
unsigned short dac_vol(float n);
unsigned short dac_vol(float left, float right);
unsigned short dap_mix_enable(uint8_t n);
unsigned short dap_enable(uint8_t n);
unsigned short dap_enable(void);
unsigned short dap_peqs(uint8_t n);
unsigned short dap_audio_eq(uint8_t n);
unsigned short dap_audio_eq_band(uint8_t bandNum, float n);
void dap_audio_eq_geq(float bass, float mid_bass, float midrange, float mid_treble, float treble);
void dap_audio_eq_tone(float bass, float treble);
void load_peq(uint8_t filterNum, int *filterParameters);
protected:
bool muted;
bool volumeInteger(unsigned int n); // range: 0x00 to 0x80
uint16_t ana_ctrl;

unsigned char calcVol(float n, unsigned char range);

unsigned int read(unsigned int reg);
bool write(unsigned int reg, unsigned int val);
unsigned int modify(unsigned int reg, unsigned int val, unsigned int iMask);
};

//For Filter Type: 0 = LPF, 1 = HPF, 2 = BPF, 3 = NOTCH, 4 = PeakingEQ, 5 = LowShelf, 6 = HighShelf
#define FILTER_LOPASS 0
#define FILTER_HIPASS 1
#define FILTER_BANDPASS 2
#define FILTER_NOTCH 3
#define FILTER_PARAEQ 4
#define FILTER_LOSHELF 5
#define FILTER_HISHELF 6

void calcBiquad(uint8_t filtertype, float fC, float dB_Gain, float Q, uint32_t quantization_unit, uint32_t fS, int *coef);

#endif

+ 25
- 0
control_wm8731.h View File

@@ -0,0 +1,25 @@
#ifndef control_wm8731_h_
#define control_wm8731_h_

#include "AudioControl.h"

class AudioControlWM8731 : public AudioControl
{
public:
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 0.8 + 47.499); }
bool inputLevel(float n) { return false; }
bool inputSelect(int n) { return false; }
protected:
bool write(unsigned int reg, unsigned int val);
bool volumeInteger(unsigned int n); // range: 0x2F to 0x7F
};

class AudioControlWM8731master : public AudioControlWM8731
{
public:
bool enable(void);
};

#endif

+ 34
- 0
effect_chorus.h View File

@@ -0,0 +1,34 @@
#ifndef effect_chorus_h_
#define effect_chorus_h_

#include "AudioStream.h"

/******************************************************************/

// A u d i o E f f e c t C h o r u s
// Written by Pete (El Supremo) Jan 2014

class AudioEffectChorus :
public AudioStream
{
public:
AudioEffectChorus(void):
AudioStream(2,inputQueueArray) {
}

boolean begin(short *delayline,int delay_length,int n_chorus);
virtual void update(void);
void stop(void);
void modify(int n_chorus);
private:
audio_block_t *inputQueueArray[2];
static short *l_delayline;
static short *r_delayline;
static short l_circ_idx;
static short r_circ_idx;
static int num_chorus;
static int delay_length;
};

#endif

+ 30
- 0
effect_fade.h View File

@@ -0,0 +1,30 @@
#ifndef effect_fade_h_
#define effect_fade_h_

#include "AudioStream.h"

class AudioEffectFade : public AudioStream
{
public:
AudioEffectFade(void)
: AudioStream(1, inputQueueArray), position(0xFFFFFFFF) {}
void fadeIn(uint32_t milliseconds) {
uint32_t samples = (uint32_t)(milliseconds * 441u + 5u) / 10u;
//Serial.printf("fadeIn, %u samples\n", samples);
fadeBegin(0xFFFFFFFFu / samples, 1);
}
void fadeOut(uint32_t milliseconds) {
uint32_t samples = (uint32_t)(milliseconds * 441u + 5u) / 10u;
//Serial.printf("fadeOut, %u samples\n", samples);
fadeBegin(0xFFFFFFFFu / samples, 0);
}
virtual void update(void);
private:
void fadeBegin(uint32_t newrate, uint8_t dir);
uint32_t position; // 0 = off, 0xFFFFFFFF = on
uint32_t rate;
uint8_t direction; // 0 = fading out, 1 = fading in
audio_block_t *inputQueueArray[1];
};

#endif

+ 39
- 0
effect_flange.h View File

@@ -0,0 +1,39 @@
#ifndef effect_flange_h_
#define effect_flange_h_

#include "AudioStream.h"

/******************************************************************/
// A u d i o E f f e c t F l a n g e
// Written by Pete (El Supremo) Jan 2014

#define DELAY_PASSTHRU -1

class AudioEffectFlange :
public AudioStream
{
public:
AudioEffectFlange(void):
AudioStream(2,inputQueueArray) {
}

boolean begin(short *delayline,int d_length,int delay_offset,int d_depth,float delay_rate);
boolean modify(int delay_offset,int d_depth,float delay_rate);
virtual void update(void);
void stop(void);
private:
audio_block_t *inputQueueArray[2];
static short *l_delayline;
static short *r_delayline;
static int delay_length;
static short l_circ_idx;
static short r_circ_idx;
static int delay_depth;
static int delay_offset_idx;
static int delay_rate_incr;
static unsigned int l_delay_rate_index;
static unsigned int r_delay_rate_index;
};

#endif

+ 20
- 0
filter_biquad.h View File

@@ -0,0 +1,20 @@
#ifndef filter_biquad_h_
#define filter_biquad_h_

#include "AudioStream.h"

class AudioFilterBiquad : public AudioStream
{
public:
AudioFilterBiquad(int *parameters)
: AudioStream(1, inputQueueArray), definition(parameters) { }
virtual void update(void);
void updateCoefs(int *source, bool doReset);
void updateCoefs(int *source);
private:
int *definition;
audio_block_t *inputQueueArray[1];
};

#endif

+ 41
- 0
filter_fir.h View File

@@ -0,0 +1,41 @@
#ifndef filter_fir_h_
#define filter_fir_h_

#include "AudioStream.h"

// Maximum number of coefficients in a FIR filter
// The audio breaks up with 128 coefficients so a
// maximum of 150 is more than sufficient
#define MAX_COEFFS 150

// Indicates that the code should just pass through the audio
// without any filtering (as opposed to doing nothing at all)
#define FIR_PASSTHRU ((short *) 1)

class AudioFilterFIR :
public AudioStream
{
public:
AudioFilterFIR(void):
AudioStream(2,inputQueueArray), coeff_p(NULL)
{
}

void begin(short *coeff_p,int f_pin);
virtual void update(void);
void stop(void);
private:
audio_block_t *inputQueueArray[2];
// arm state arrays and FIR instances for left and right channels
// the state arrays are defined to handle a maximum of MAX_COEFFS
// coefficients in a filter
q15_t l_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
q15_t r_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
arm_fir_instance_q15 l_fir_inst;
arm_fir_instance_q15 r_fir_inst;
// pointer to current coefficients or NULL or FIR_PASSTHRU
short *coeff_p;
};

#endif

+ 1
- 2
input_adc.cpp View File

@@ -1,6 +1,5 @@
#include "Audio.h"
#include "arm_math.h"

#include "utility/pdb.h"


DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES];

+ 20
- 0
input_adc.h View File

@@ -0,0 +1,20 @@
#ifndef input_adc_h_
#define input_adc_h_

#include "AudioStream.h"

class AudioInputAnalog : public AudioStream
{
public:
AudioInputAnalog(unsigned int pin) : AudioStream(0, NULL) { begin(pin); }
virtual void update(void);
void begin(unsigned int pin);
friend void dma_ch2_isr(void);
private:
static audio_block_t *block_left;
static uint16_t block_offset;
uint16_t dc_average;
static bool update_responsibility;
};

#endif

+ 31
- 0
input_i2s.h View File

@@ -0,0 +1,31 @@
#ifndef input_i2s_h_
#define _input_i2sh_

#include "AudioStream.h"

class AudioInputI2S : public AudioStream
{
public:
AudioInputI2S(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch1_isr(void);
protected:
AudioInputI2S(int dummy): AudioStream(0, NULL) {} // to be used only inside AudioInputI2Sslave !!
static bool update_responsibility;
private:
static audio_block_t *block_left;
static audio_block_t *block_right;
static uint16_t block_offset;
};


class AudioInputI2Sslave : public AudioInputI2S
{
public:
AudioInputI2Sslave(void) : AudioInputI2S(0) { begin(); }
void begin(void);
friend void dma_ch1_isr(void);
};

#endif

+ 24
- 0
mixer.h View File

@@ -0,0 +1,24 @@
#ifndef mixer_h_
#define mixer_h_

#include "AudioStream.h"

class AudioMixer4 : public AudioStream
{
public:
AudioMixer4(void) : AudioStream(4, inputQueueArray) {
for (int i=0; i<4; i++) multiplier[i] = 65536;
}
virtual void update(void);
void gain(unsigned int channel, float gain) {
if (channel >= 4) return;
if (gain > 32767.0f) gain = 32767.0f;
else if (gain < 0.0f) gain = 0.0f;
multiplier[channel] = gain * 65536.0f; // TODO: proper roundoff?
}
private:
int32_t multiplier[4];
audio_block_t *inputQueueArray[4];
};

#endif

+ 1
- 3
output_dac.cpp View File

@@ -1,7 +1,5 @@
#include "Audio.h"
#include "arm_math.h"


#include "utility/pdb.h"

// #define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT)
// #define PDB_PERIOD 1087 // 48e6 / 44100

+ 21
- 0
output_dac.h View File

@@ -0,0 +1,21 @@
#ifndef output_dac_h_
#define output_dac_h_

#include "AudioStream.h"

class AudioOutputAnalog : public AudioStream
{
public:
AudioOutputAnalog(void) : AudioStream(1, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
void analogReference(int ref);
friend void dma_ch4_isr(void);
private:
static audio_block_t *block_left_1st;
static audio_block_t *block_left_2nd;
static bool update_responsibility;
audio_block_t *inputQueueArray[1];
};

#endif

+ 40
- 0
output_i2s.h View File

@@ -0,0 +1,40 @@
#ifndef output_i2s_h_
#define output_i2s_h_

#include "AudioStream.h"

class AudioOutputI2S : public AudioStream
{
public:
AudioOutputI2S(void) : AudioStream(2, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch0_isr(void);
friend class AudioInputI2S;
protected:
AudioOutputI2S(int dummy): AudioStream(2, inputQueueArray) {} // to be used only inside AudioOutputI2Sslave !!
static void config_i2s(void);
static audio_block_t *block_left_1st;
static audio_block_t *block_right_1st;
static bool update_responsibility;
private:
static audio_block_t *block_left_2nd;
static audio_block_t *block_right_2nd;
static uint16_t block_left_offset;
static uint16_t block_right_offset;
audio_block_t *inputQueueArray[2];
};


class AudioOutputI2Sslave : public AudioOutputI2S
{
public:
AudioOutputI2Sslave(void) : AudioOutputI2S(0) { begin(); } ;
void begin(void);
friend class AudioInputI2Sslave;
friend void dma_ch0_isr(void);
protected:
static void config_i2s(void);
};

#endif

+ 22
- 0
output_pwm.h View File

@@ -0,0 +1,22 @@
#ifndef output_pwm_h_
#define output_pwm_h_

#include "AudioStream.h"

class AudioOutputPWM : public AudioStream
{
public:
AudioOutputPWM(void) : AudioStream(1, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
friend void dma_ch3_isr(void);
private:
static audio_block_t *block_1st;
static audio_block_t *block_2nd;
static uint32_t block_offset;
static bool update_responsibility;
static uint8_t interrupt_count;
audio_block_t *inputQueueArray[1];
};

#endif

+ 20
- 0
play_memory.h View File

@@ -0,0 +1,20 @@
#ifndef play_memory_h_
#define play_memory_h_

#include "AudioStream.h"

class AudioPlayMemory : public AudioStream
{
public:
AudioPlayMemory(void) : AudioStream(0, NULL), playing(0) { }
void play(const unsigned int *data);
void stop(void);
virtual void update(void);
private:
const unsigned int *next;
uint32_t length;
int16_t prior;
volatile uint8_t playing;
};

#endif

+ 22
- 0
play_sd_raw.h View File

@@ -0,0 +1,22 @@
#ifndef play_sd_raw_h_
#define play_sd_raw_h_

#include "AudioStream.h"
#include "SD.h"

class AudioPlaySDcardRAW : public AudioStream
{
public:
AudioPlaySDcardRAW(void) : AudioStream(0, NULL) { begin(); }
void begin(void);
bool play(const char *filename);
void stop(void);
virtual void update(void);
private:
File rawfile;
audio_block_t *block;
bool playing;
bool paused;
};

#endif

+ 33
- 0
play_sd_wav.h View File

@@ -0,0 +1,33 @@
#ifndef play_sd_wav_h_
#define play_sd_wav_h_

#include "AudioStream.h"
#include "SD.h"

class AudioPlaySDcardWAV : public AudioStream
{
public:
AudioPlaySDcardWAV(void) : AudioStream(0, NULL) { begin(); }
void begin(void);

bool play(const char *filename);
void stop(void);
bool start(void);
virtual void update(void);
private:
File wavfile;
bool consume(void);
bool parse_format(void);
uint32_t header[5];
uint32_t data_length; // number of bytes remaining in data section
audio_block_t *block_left;
audio_block_t *block_right;
uint16_t block_offset;
uint8_t buffer[512];
uint16_t buffer_remaining;
uint8_t state;
uint8_t state_play;
uint8_t leftover_bytes;
};

#endif

+ 31
- 0
synth_tonesweep.h View File

@@ -0,0 +1,31 @@
#ifndef synth_tonesweep_h_
#define synth_tonesweep_h_

#include "AudioStream.h"

// A u d i o T o n e S w e e p
// Written by Pete (El Supremo) Feb 2014

class AudioToneSweep : public AudioStream
{
public:
AudioToneSweep(void) :
AudioStream(0,NULL), sweep_busy(0)
{ }

boolean begin(short t_amp,int t_lo,int t_hi,float t_time);
virtual void update(void);
unsigned char busy(void);

private:
short tone_amp;
int tone_lo;
int tone_hi;
uint64_t tone_freq;
uint64_t tone_phase;
uint64_t tone_incr;
int tone_sign;
unsigned char sweep_busy;
};

#endif

+ 152
- 0
synth_waveform.h View File

@@ -0,0 +1,152 @@
#ifndef synth_waveform_h_
#define synth_waveform_h_

#include "AudioStream.h"
#include "arm_math.h"

// waveforms.c
extern "C" {
extern const int16_t AudioWaveformSine[257];
extern const int16_t AudioWaveformTriangle[257];
extern const int16_t AudioWaveformSquare[257];
extern const int16_t AudioWaveformSawtooth[257];
}

#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
class AudioSynthWaveform : public AudioStream
{
public:
AudioSynthWaveform(const int16_t *waveform)
: AudioStream(0, NULL), wavetable(waveform), magnitude(0), phase(0)
, ramp_down(0), ramp_up(0), ramp_mag(0), ramp_length(0)
{ }
void frequency(float freq) {
if (freq > AUDIO_SAMPLE_RATE_EXACT / 2 || freq < 0.0) return;
phase_increment = (freq / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
}
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(magnitude && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_magnitude = magnitude;
}
else if((magnitude == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
}
// set new magnitude
magnitude = n * 32767.0;
}
virtual void update(void);
void set_ramp_length(uint16_t r_length);
private:
const int16_t *wavetable;
uint16_t magnitude;
uint16_t last_magnitude;
uint32_t phase;
uint32_t phase_increment;
uint32_t ramp_down;
uint32_t ramp_up;
uint32_t ramp_mag;
uint16_t ramp_length;
};

#else

#define AUDIO_SAMPLE_RATE_ROUNDED (44118)

#define DELAY_PASSTHRU -1

#define TONE_TYPE_SINE 0
#define TONE_TYPE_SAWTOOTH 1
#define TONE_TYPE_SQUARE 2
#define TONE_TYPE_TRIANGLE 3

class AudioSynthWaveform :
public AudioStream
{
public:
AudioSynthWaveform(void) :
AudioStream(0,NULL),
tone_freq(0), tone_phase(0), tone_incr(0), tone_type(0),
ramp_down(0), ramp_up(0), ramp_length(0)
{
}
// Change the frequency on-the-fly to permit a phase-continuous
// change between two frequencies.
void frequency(int t_hi)
{
tone_incr = (0x100000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
}
// If ramp_length is non-zero this will set up
// either a rmap up or a ramp down when a wave
// first starts or when the amplitude is set
// back to zero.
// Note that if the ramp_length is N, the generated
// wave will be N samples longer than when it is not
// ramp
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(tone_amp && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_tone_amp = tone_amp;
}
else if((tone_amp == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
// reset the phase when the amplitude was zero
// and has now been increased. Note that this
// happens even if the wave is not ramped
// so that the signal starts at zero
tone_phase = 0;
}
// set new magnitude
tone_amp = n * 32767.0;
}
boolean begin(float t_amp,int t_hi,short t_type);
virtual void update(void);
void set_ramp_length(uint16_t r_length);

private:
short tone_amp;
short last_tone_amp;
short tone_freq;
uint32_t tone_phase;
uint32_t tone_incr;
short tone_type;

uint32_t ramp_down;
uint32_t ramp_up;
uint16_t ramp_length;
};

#endif



#if 0
class AudioSineWaveMod : public AudioStream
{
public:
AudioSineWaveMod() : AudioStream(1, inputQueueArray) {}
void frequency(float freq);
//void amplitude(q15 n);
virtual void update(void);
private:
uint32_t phase;
uint32_t phase_increment;
uint32_t modulation_factor;
audio_block_t *inputQueueArray[1];
};
#endif



#endif

+ 4
- 2
utility/dspinst.h View File

@@ -1,3 +1,6 @@
#ifndef dspinst_h_
#define dspinst_h_

#include <stdint.h>

// computes limit((val >> rshift), 2**bits)
@@ -107,5 +110,4 @@ static inline uint32_t logical_and(uint32_t a, uint32_t b)
return a;
}



#endif

+ 11
- 0
utility/pdb.h View File

@@ -0,0 +1,11 @@
#ifndef pdb_h_
#define pdb_h_

// Multiple input & output objects use the Programmable Delay Block
// to set their sample rate. They must all configure the same
// period to avoid chaos.

#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT)
#define PDB_PERIOD 1087 // 48e6 / 44100

#endif

Loading…
Cancel
Save