@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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,6 +1,5 @@ | |||
#include "Audio.h" | |||
#include "arm_math.h" | |||
#include "utility/pdb.h" | |||
DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; |
@@ -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 |
@@ -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 |
@@ -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,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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |