|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- #include "AudioStream.h"
- #include "arm_math.h"
-
-
- // When changing multiple audio object settings that must update at
- // the same time, these functions allow the audio library interrupt
- // to be disabled. For example, you may wish to begin playing a note
- // in response to reading an analog sensor. If you have "velocity"
- // information, you might start the sample playing and also adjust
- // the gain of a mixer channel. Use AudioNoInterrupts() first, then
- // make both changes to the 2 separate objects. Then allow the audio
- // 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), outputflag(false),
- prevblock(NULL), count(0), naverage(navg), window(win) { 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];
- };
-
-
-
- class AudioSynthWaveform : public AudioStream
- {
- public:
- AudioSynthWaveform(const int16_t *waveform)
- : AudioStream(0, NULL), wavetable(waveform), magnitude(0), phase(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;
- magnitude = n * 32767.0;
- }
- virtual void update(void);
- private:
- const int16_t *wavetable;
- uint16_t magnitude;
- uint32_t phase;
- uint32_t phase_increment;
- };
-
-
-
-
- #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];
- };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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);
- 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];
- };
-
-
-
-
-
-
-
- // 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)); }
- protected:
- bool muted;
- bool volumeInteger(unsigned int n); // range: 0x00 to 0x80
- uint16_t ana_ctrl;
-
-
-
- unsigned int read(unsigned int reg);
- bool write(unsigned int reg, unsigned int val);
- };
-
-
-
-
- /******************************************************************/
-
- // 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) {
- }
-
- void begin(short *coeff_p,int f_pin);
- virtual void update(void);
- void stop(void);
-
- private:
- audio_block_t *inputQueueArray[2];
- static q15_t l_StateQ15[];
- static q15_t r_StateQ15[];
- static arm_fir_instance_q15 l_fir_inst;
- static arm_fir_instance_q15 r_fir_inst;
- static short *coeff_p;
- };
-
-
-
-
-
-
-
-
|