audio & sd lib upgrade (SdFatSdioEX)

migration from 'smp_v1p0' dev.
for 'sampler' -> skip irrelavant note msg. and keep playing
This commit is contained in:
Dooho Yi 2019-12-11 23:37:44 +09:00
parent f360082c75
commit 91f92c0e6c
389 changed files with 180898 additions and 66 deletions

1
sampler/lib/Audio_SdFat/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.swp

View file

@ -0,0 +1,46 @@
{
"name": "Audio",
"frameworks": [
"arduino"
],
"platforms": [
"teensy"
],
"keywords": [
"sound",
"audio",
"fft",
"filter",
"effect"
],
"description": "Teensy Audio Library",
"version": "1.3",
"export": {
"exclude": [
"gui",
"extras"
]
},
"authors": [
{
"email": null,
"url": null,
"maintainer": true,
"name": "Paul Stoffregen"
}
],
"repository": {
"type": "git",
"url": "https://github.com/PaulStoffregen/Audio"
},
"dependencies": {
"name": "SerialFlash",
"frameworks": "arduino"
},
"examples": [
"examples/*/*.ino",
"examples/*/*/*.ino"
],
"homepage": "http://www.pjrc.com/teensy/td_libs_Audio.html",
"id": 70
}

View file

@ -0,0 +1,124 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef Audio_h_
#define Audio_h_
#if TEENSYDUINO < 120
#error "Teensyduino version 1.20 or later is required to compile the Audio library."
#endif
#ifdef __AVR__
#error "The Audio Library only works with Teensy 3.X. Teensy 2.0 is unsupported."
#endif
#include "DMAChannel.h"
#if !defined(DMACHANNEL_HAS_BEGIN) || !defined(DMACHANNEL_HAS_BOOLEAN_CTOR)
#error "You need to update DMAChannel.h & DMAChannel.cpp"
#error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.h"
#error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.cpp"
#endif
// 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))
// 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_fft1024.h"
#include "analyze_print.h"
#include "analyze_tonedetect.h"
#include "analyze_notefreq.h"
#include "analyze_peak.h"
#include "analyze_rms.h"
#include "control_sgtl5000.h"
#include "control_wm8731.h"
#include "control_ak4558.h"
#include "control_cs4272.h"
#include "control_cs42448.h"
#include "control_tlv320aic3206.h"
#include "effect_bitcrusher.h"
#include "effect_chorus.h"
#include "effect_fade.h"
#include "effect_flange.h"
#include "effect_envelope.h"
#include "effect_multiply.h"
#include "effect_delay.h"
#include "effect_delay_ext.h"
#include "effect_midside.h"
#include "effect_reverb.h"
#include "effect_freeverb.h"
#include "effect_waveshaper.h"
#include "effect_granular.h"
#include "effect_combine.h"
#include "filter_biquad.h"
#include "filter_fir.h"
#include "filter_variable.h"
#include "input_adc.h"
#include "input_adcs.h"
#include "input_i2s.h"
#include "input_i2s_quad.h"
#include "input_tdm.h"
#include "input_pdm.h"
#include "mixer.h"
#include "output_dac.h"
#include "output_dacs.h"
#include "output_i2s.h"
#include "output_i2s_quad.h"
#include "output_pwm.h"
#include "output_spdif.h"
#include "output_pt8211.h"
#include "output_tdm.h"
#include "output_adat.h"
#include "play_memory.h"
#include "play_queue.h"
#include "play_sd_raw.h"
#include "play_sd_wav.h"
#include "play_serialflash_raw.h"
#include "record_queue.h"
#include "synth_tonesweep.h"
#include "synth_sine.h"
#include "synth_waveform.h"
#include "synth_dc.h"
#include "synth_whitenoise.h"
#include "synth_pinknoise.h"
#include "synth_karplusstrong.h"
#include "synth_simple_drum.h"
#include "synth_pwm.h"
#include "synth_wavetable.h"
#endif

View file

@ -0,0 +1,48 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#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 1.0
virtual bool inputLevel(float volume) = 0; // volume 0.0 to 1.0
virtual bool inputSelect(int n) = 0;
};
#endif

View file

@ -0,0 +1,70 @@
Teensy Audio Library
====================
16 bit, 44.1 kHz streaming audio library for Teensy 3.x, featuring:
* Polyphonic Playback
* Recording
* Synthesis
* Analysis
* Effects
* Filtering
* Mixing
* Multiple Simultaneous Inputs & Outputs
* Flexible signal routing between library objects
* Automatic Streaming while your Arduino sketch runs
Main Audio Library Page
-----------------------
http://www.pjrc.com/teensy/td_libs_Audio.html
Audio System Design Tool
------------------------
Use this graphical tool to design your audio project. Easily browse the library's many features, connect objects, export to Arduino code, and quickly access details for the functions each object provides for you to control it from your Arduino sketch!
http://www.pjrc.com/teensy/gui/index.html
Supported Hardware
------------------
[Audio Adaptor Board](http://www.pjrc.com/store/teensy3_audio.html) for 16 bit stereo input and output.
![Inputs](/gui/img/audioshield_inputs.jpg) ![Outputs](/gui/img/audioshield_outputs.jpg)
Dual [Audio Adaptor Boards](http://www.pjrc.com/store/teensy3_audio.html) for quad channel 16 bit input and output.
![](/gui/img/audioshield_quad_out.jpg)
[Teensy 3.6](http://www.pjrc.com/store/teensy36.html), [Teensy 3.5](http://www.pjrc.com/store/teensy35.html), [Teensy 3.2](http://www.pjrc.com/store/teensy32.html), or [Teensy 3.1](http://www.pjrc.com/store/teensy31.html) 12 bit DAC Output (Mono)
![DAC Output](/gui/img/dacpin.jpg)
[Teensy 3.6](http://www.pjrc.com/store/teensy36.html), [Teensy 3.5](http://www.pjrc.com/store/teensy35.html), [Teensy 3.2](http://www.pjrc.com/store/teensy32.html), [Teensy 3.1](http://www.pjrc.com/store/teensy31.html) or [Teensy 3.0](http://www.pjrc.com/store/teensy3.html) ADC Input (Mono)
![ADC Input](/gui/img/adccircuit.png)
[Teensy 3.6](http://www.pjrc.com/store/teensy36.html), [Teensy 3.5](http://www.pjrc.com/store/teensy35.html), or [Teensy 3.2](http://www.pjrc.com/store/teensy32.html) ADC Input (Stereo)
![ADC Input](/gui/img/adccircuit2.png)
[Teensy 3.6](http://www.pjrc.com/store/teensy36.html) or [Teensy 3.5](http://www.pjrc.com/store/teensy35.html) 12 bit DAC Output (Stereo)
![DAC Output](/gui/img/dacpins.png)
[Teensy 3.6](http://www.pjrc.com/store/teensy36.html), [Teensy 3.5](http://www.pjrc.com/store/teensy35.html), [Teensy 3.2](http://www.pjrc.com/store/teensy32.html), [Teensy 3.1](http://www.pjrc.com/store/teensy31.html) or [Teensy 3.0](http://www.pjrc.com/store/teensy3.html) PWM Output (Mono)
![PWM Output](/gui/img/pwmdualcircuit.jpg)
USB Audio: Bi-Directional Stereo Streaming to a PC
![Inputs](/gui/img/usbtype_audio_in.png) ![Outputs](/gui/img/usbtype_audio_out.png)

View file

@ -0,0 +1,132 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_fft1024.h"
#include "sqrt_integer.h"
#include "utility/dspinst.h"
// 140312 - PAH - slightly faster copy
static void copy_to_fft_buffer(void *destination, const void *source)
{
const uint16_t *src = (const uint16_t *)source;
uint32_t *dst = (uint32_t *)destination;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
*dst++ = *src++; // real sample plus a zero for imaginary
}
}
static void apply_window_to_fft_buffer(void *buffer, const void *window)
{
int16_t *buf = (int16_t *)buffer;
const int16_t *win = (int16_t *)window;;
for (int i=0; i < 1024; i++) {
int32_t val = *buf * *win++;
//*buf = signed_saturate_rshift(val, 16, 15);
*buf = val >> 15;
buf += 2;
}
}
void AudioAnalyzeFFT1024::update(void)
{
audio_block_t *block;
block = receiveReadOnly();
if (!block) return;
#if defined(KINETISK)
switch (state) {
case 0:
blocklist[0] = block;
state = 1;
break;
case 1:
blocklist[1] = block;
state = 2;
break;
case 2:
blocklist[2] = block;
state = 3;
break;
case 3:
blocklist[3] = block;
state = 4;
break;
case 4:
blocklist[4] = block;
state = 5;
break;
case 5:
blocklist[5] = block;
state = 6;
break;
case 6:
blocklist[6] = block;
state = 7;
break;
case 7:
blocklist[7] = block;
// TODO: perhaps distribute the work over multiple update() ??
// github pull requsts welcome......
copy_to_fft_buffer(buffer+0x000, blocklist[0]->data);
copy_to_fft_buffer(buffer+0x100, blocklist[1]->data);
copy_to_fft_buffer(buffer+0x200, blocklist[2]->data);
copy_to_fft_buffer(buffer+0x300, blocklist[3]->data);
copy_to_fft_buffer(buffer+0x400, blocklist[4]->data);
copy_to_fft_buffer(buffer+0x500, blocklist[5]->data);
copy_to_fft_buffer(buffer+0x600, blocklist[6]->data);
copy_to_fft_buffer(buffer+0x700, blocklist[7]->data);
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_q15(&fft_inst, buffer);
// TODO: support averaging multiple copies
for (int i=0; i < 512; i++) {
uint32_t tmp = *((uint32_t *)buffer + i); // real & imag
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp);
output[i] = sqrt_uint32_approx(magsq);
}
outputflag = true;
release(blocklist[0]);
release(blocklist[1]);
release(blocklist[2]);
release(blocklist[3]);
blocklist[0] = blocklist[4];
blocklist[1] = blocklist[5];
blocklist[2] = blocklist[6];
blocklist[3] = blocklist[7];
state = 4;
break;
}
#else
release(block);
#endif
}

View file

@ -0,0 +1,103 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_fft1024_h_
#define analyze_fft1024_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "arm_math.h"
// windows.c
extern "C" {
extern const int16_t AudioWindowHanning1024[];
extern const int16_t AudioWindowBartlett1024[];
extern const int16_t AudioWindowBlackman1024[];
extern const int16_t AudioWindowFlattop1024[];
extern const int16_t AudioWindowBlackmanHarris1024[];
extern const int16_t AudioWindowNuttall1024[];
extern const int16_t AudioWindowBlackmanNuttall1024[];
extern const int16_t AudioWindowWelch1024[];
extern const int16_t AudioWindowHamming1024[];
extern const int16_t AudioWindowCosine1024[];
extern const int16_t AudioWindowTukey1024[];
}
class AudioAnalyzeFFT1024 : public AudioStream
{
public:
AudioAnalyzeFFT1024() : AudioStream(1, inputQueueArray),
window(AudioWindowHanning1024), state(0), outputflag(false) {
arm_cfft_radix4_init_q15(&fft_inst, 1024, 0, 1);
}
bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
float read(unsigned int binNumber) {
if (binNumber > 511) return 0.0;
return (float)(output[binNumber]) * (1.0 / 16384.0);
}
float read(unsigned int binFirst, unsigned int binLast) {
if (binFirst > binLast) {
unsigned int tmp = binLast;
binLast = binFirst;
binFirst = tmp;
}
if (binFirst > 511) return 0.0;
if (binLast > 511) binLast = 511;
uint32_t sum = 0;
do {
sum += output[binFirst++];
} while (binFirst <= binLast);
return (float)sum * (1.0 / 16384.0);
}
void averageTogether(uint8_t n) {
// not implemented yet (may never be, 86 Hz output rate is ok)
}
void windowFunction(const int16_t *w) {
window = w;
}
virtual void update(void);
uint16_t output[512] __attribute__ ((aligned (4)));
private:
void init(void);
const int16_t *window;
audio_block_t *blocklist[8];
int16_t buffer[2048] __attribute__ ((aligned (4)));
//uint32_t sum[512];
//uint8_t count;
uint8_t state;
//uint8_t naverage;
volatile bool outputflag;
audio_block_t *inputQueueArray[1];
arm_cfft_radix4_instance_q15 fft_inst;
};
#endif

View file

@ -0,0 +1,130 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_fft256.h"
#include "sqrt_integer.h"
#include "utility/dspinst.h"
// 140312 - PAH - slightly faster copy
static void copy_to_fft_buffer(void *destination, const void *source)
{
const uint16_t *src = (const uint16_t *)source;
uint32_t *dst = (uint32_t *)destination;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
*dst++ = *src++; // real sample plus a zero for imaginary
}
}
static void apply_window_to_fft_buffer(void *buffer, const void *window)
{
int16_t *buf = (int16_t *)buffer;
const int16_t *win = (int16_t *)window;;
for (int i=0; i < 256; i++) {
int32_t val = *buf * *win++;
//*buf = signed_saturate_rshift(val, 16, 15);
*buf = val >> 15;
buf += 2;
}
}
void AudioAnalyzeFFT256::update(void)
{
audio_block_t *block;
block = receiveReadOnly();
if (!block) return;
#if AUDIO_BLOCK_SAMPLES == 128
if (!prevblock) {
prevblock = block;
return;
}
copy_to_fft_buffer(buffer, prevblock->data);
copy_to_fft_buffer(buffer+256, block->data);
//window = AudioWindowBlackmanNuttall256;
//window = NULL;
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_q15(&fft_inst, buffer);
// G. Heinzel's paper says we're supposed to average the magnitude
// squared, then do the square root at the end.
if (count == 0) {
for (int i=0; i < 128; i++) {
uint32_t tmp = *((uint32_t *)buffer + i);
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp);
sum[i] = magsq / naverage;
}
} else {
for (int i=0; i < 128; i++) {
uint32_t tmp = *((uint32_t *)buffer + i);
uint32_t magsq = multiply_16tx16t_add_16bx16b(tmp, tmp);
sum[i] += magsq / naverage;
}
}
if (++count == naverage) {
count = 0;
for (int i=0; i < 128; i++) {
output[i] = sqrt_uint32_approx(sum[i]);
}
outputflag = true;
}
release(prevblock);
prevblock = block;
#elif AUDIO_BLOCK_SAMPLES == 64
if (prevblocks[2] == NULL) {
prevblocks[2] = prevblocks[1];
prevblocks[1] = prevblocks[0];
prevblocks[0] = block;
return;
}
if (count == 0) {
count = 1;
copy_to_fft_buffer(buffer, prevblocks[2]->data);
copy_to_fft_buffer(buffer+128, prevblocks[1]->data);
copy_to_fft_buffer(buffer+256, prevblocks[1]->data);
copy_to_fft_buffer(buffer+384, block->data);
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_q15(&fft_inst, buffer);
} else {
count = 2;
const uint32_t *p = (uint32_t *)buffer;
for (int i=0; i < 128; i++) {
uint32_t tmp = *p++;
int16_t v1 = tmp & 0xFFFF;
int16_t v2 = tmp >> 16;
output[i] = sqrt_uint32_approx(v1 * v1 + v2 * v2);
}
}
release(prevblocks[2]);
prevblocks[2] = prevblocks[1];
prevblocks[1] = prevblocks[0];
prevblocks[0] = block;
#endif
}

View file

@ -0,0 +1,118 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_fft256_h_
#define analyze_fft256_h_
#include "Arduino.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() : AudioStream(1, inputQueueArray),
window(AudioWindowHanning256), count(0), outputflag(false) {
arm_cfft_radix4_init_q15(&fft_inst, 256, 0, 1);
#if AUDIO_BLOCK_SAMPLES == 128
prevblock = NULL;
naverage = 8;
#elif AUDIO_BLOCK_SAMPLES == 64
prevblocks[0] = NULL;
prevblocks[1] = NULL;
prevblocks[2] = NULL;
#endif
}
bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
float read(unsigned int binNumber) {
if (binNumber > 127) return 0.0;
return (float)(output[binNumber]) * (1.0 / 16384.0);
}
float read(unsigned int binFirst, unsigned int binLast) {
if (binFirst > binLast) {
unsigned int tmp = binLast;
binLast = binFirst;
binFirst = tmp;
}
if (binFirst > 127) return 0.0;
if (binLast > 127) binLast = 127;
uint32_t sum = 0;
do {
sum += output[binFirst++];
} while (binFirst <= binLast);
return (float)sum * (1.0 / 16384.0);
}
void averageTogether(uint8_t n) {
#if AUDIO_BLOCK_SAMPLES == 128
if (n == 0) n = 1;
naverage = n;
#endif
}
void windowFunction(const int16_t *w) {
window = w;
}
virtual void update(void);
uint16_t output[128] __attribute__ ((aligned (4)));
private:
const int16_t *window;
#if AUDIO_BLOCK_SAMPLES == 128
audio_block_t *prevblock;
#elif AUDIO_BLOCK_SAMPLES == 64
audio_block_t *prevblocks[3];
#endif
int16_t buffer[512] __attribute__ ((aligned (4)));
#if AUDIO_BLOCK_SAMPLES == 128
uint32_t sum[128];
uint8_t naverage;
#endif
uint8_t count;
volatile bool outputflag;
audio_block_t *inputQueueArray[1];
arm_cfft_radix4_instance_q15 fft_inst;
};
#endif

View file

@ -0,0 +1,267 @@
/* Audio Library Note Frequency Detection & Guitar/Bass Tuner
* Copyright (c) 2015, Colin Duffy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_notefreq.h"
#include "utility/dspinst.h"
#include "arm_math.h"
#define HALF_BLOCKS AUDIO_GUITARTUNER_BLOCKS * 64
/**
* Copy internal blocks of data to class buffer
*
* @param destination destination address
* @param source source address
*/
static void copy_buffer(void *destination, const void *source) {
const uint16_t *src = ( const uint16_t * )source;
uint16_t *dst = ( uint16_t * )destination;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) *dst++ = (*src++);
}
/**
* Virtual function to override from Audio Library
*/
void AudioAnalyzeNoteFrequency::update( void ) {
audio_block_t *block;
block = receiveReadOnly();
if (!block) return;
if ( !enabled ) {
release( block );
return;
}
if ( next_buffer ) {
blocklist1[state++] = block;
if ( !first_run && process_buffer ) process( );
} else {
blocklist2[state++] = block;
if ( !first_run && process_buffer ) process( );
}
if ( state >= AUDIO_GUITARTUNER_BLOCKS ) {
if ( next_buffer ) {
if ( !first_run && process_buffer ) process( );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) copy_buffer( AudioBuffer+( i * 0x80 ), blocklist1[i]->data );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) release( blocklist1[i] );
next_buffer = false;
} else {
if ( !first_run && process_buffer ) process( );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) copy_buffer( AudioBuffer+( i * 0x80 ), blocklist2[i]->data );
for ( int i = 0; i < AUDIO_GUITARTUNER_BLOCKS; i++ ) release( blocklist2[i] );
next_buffer = true;
}
process_buffer = true;
first_run = false;
state = 0;
}
}
/**
* Start the Yin algorithm
*
* TODO: Significant speed up would be to use spectral domain to find fundamental frequency.
* This paper explains: https://aubio.org/phd/thesis/brossier06thesis.pdf -> Section 3.2.4
* page 79. Might have to downsample for low fundmental frequencies because of fft buffer
* size limit.
*/
void AudioAnalyzeNoteFrequency::process( void ) {
const int16_t *p;
p = AudioBuffer;
uint16_t cycles = 64;
uint16_t tau = tau_global;
do {
uint16_t x = 0;
uint64_t sum = 0;
do {
int16_t current, lag, delta;
lag = *( ( int16_t * )p + ( x+tau ) );
current = *( ( int16_t * )p+x );
delta = ( current-lag );
sum += delta * delta;
x += 4;
lag = *( ( int16_t * )p + ( x+tau ) );
current = *( ( int16_t * )p+x );
delta = ( current-lag );
sum += delta * delta;
x += 4;
lag = *( ( int16_t * )p + ( x+tau ) );
current = *( ( int16_t * )p+x );
delta = ( current-lag );
sum += delta * delta;
x += 4;
lag = *( ( int16_t * )p + ( x+tau ) );
current = *( ( int16_t * )p+x );
delta = ( current-lag );
sum += delta * delta;
x += 4;
} while ( x < HALF_BLOCKS );
uint64_t rs = running_sum;
rs += sum;
yin_buffer[yin_idx] = sum*tau;
rs_buffer[yin_idx] = rs;
running_sum = rs;
yin_idx = ( ++yin_idx >= 5 ) ? 0 : yin_idx;
tau = estimate( yin_buffer, rs_buffer, yin_idx, tau );
if ( tau == 0 ) {
process_buffer = false;
new_output = true;
yin_idx = 1;
running_sum = 0;
tau_global = 1;
return;
}
} while ( --cycles );
//digitalWriteFast(10, LOW);
if ( tau >= HALF_BLOCKS ) {
process_buffer = false;
new_output = false;
yin_idx = 1;
running_sum = 0;
tau_global = 1;
return;
}
tau_global = tau;
}
/**
* check the sampled data for fundamental frequency
*
* @param yin buffer to hold sum*tau value
* @param rs buffer to hold running sum for sampled window
* @param head buffer index
* @param tau lag we are currently working on gets incremented
*
* @return tau
*/
uint16_t AudioAnalyzeNoteFrequency::estimate( uint64_t *yin, uint64_t *rs, uint16_t head, uint16_t tau ) {
const uint64_t *y = ( uint64_t * )yin;
const uint64_t *r = ( uint64_t * )rs;
uint16_t _tau, _head;
const float thresh = yin_threshold;
_tau = tau;
_head = head;
if ( _tau > 4 ) {
uint16_t idx0, idx1, idx2;
idx0 = _head;
idx1 = _head + 1;
idx1 = ( idx1 >= 5 ) ? 0 : idx1;
idx2 = head + 2;
idx2 = ( idx2 >= 5 ) ? 0 : idx2;
float s0, s1, s2;
s0 = ( ( float )*( y+idx0 ) / *( r+idx0 ) );
s1 = ( ( float )*( y+idx1 ) / *( r+idx1 ) );
s2 = ( ( float )*( y+idx2 ) / *( r+idx2 ) );
if ( s1 < thresh && s1 < s2 ) {
uint16_t period = _tau - 3;
periodicity = 1 - s1;
data = period + 0.5f * ( s0 - s2 ) / ( s0 - 2.0f * s1 + s2 );
return 0;
}
}
return _tau + 1;
}
/**
* Initialise
*
* @param threshold Allowed uncertainty
*/
void AudioAnalyzeNoteFrequency::begin( float threshold ) {
__disable_irq( );
process_buffer = false;
yin_threshold = threshold;
periodicity = 0.0f;
next_buffer = true;
running_sum = 0;
tau_global = 1;
first_run = true;
yin_idx = 1;
enabled = true;
state = 0;
data = 0.0f;
__enable_irq( );
}
/**
* available
*
* @return true if data is ready else false
*/
bool AudioAnalyzeNoteFrequency::available( void ) {
__disable_irq( );
bool flag = new_output;
if ( flag ) new_output = false;
__enable_irq( );
return flag;
}
/**
* read processes the data samples for the Yin algorithm.
*
* @return frequency in hertz
*/
float AudioAnalyzeNoteFrequency::read( void ) {
__disable_irq( );
float d = data;
__enable_irq( );
return AUDIO_SAMPLE_RATE_EXACT / d;
}
/**
* Periodicity of the sampled signal from Yin algorithm from read function.
*
* @return periodicity
*/
float AudioAnalyzeNoteFrequency::probability( void ) {
__disable_irq( );
float p = periodicity;
__enable_irq( );
return p;
}
/**
* Initialise parameters.
*
* @param thresh Allowed uncertainty
*/
void AudioAnalyzeNoteFrequency::threshold( float p ) {
__disable_irq( );
yin_threshold = p;
__enable_irq( );
}

View file

@ -0,0 +1,134 @@
/* Audio Library Note Frequency Detection & Guitar/Bass Tuner
* Copyright (c) 2015, Colin Duffy
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef AudioAnalyzeNoteFrequency_h_
#define AudioAnalyzeNoteFrequency_h_
#include "Arduino.h"
#include "AudioStream.h"
/***********************************************************************
* Safe to adjust these values below *
* *
* This parameter defines the size of the buffer. *
* *
* 1. AUDIO_GUITARTUNER_BLOCKS - Buffer size is 128 * AUDIO_BLOCKS. *
* The more AUDIO_GUITARTUNER_BLOCKS the lower *
* the frequency you can detect. The default *
* (24) is set to measure down to 29.14 Hz *
* or B(flat)0. *
* *
***********************************************************************/
#define AUDIO_GUITARTUNER_BLOCKS 24
/***********************************************************************/
class AudioAnalyzeNoteFrequency : public AudioStream {
public:
/**
* constructor to setup Audio Library and initialize
*
* @return none
*/
AudioAnalyzeNoteFrequency( void ) : AudioStream( 1, inputQueueArray ), enabled( false ), new_output(false) {
}
/**
* initialize variables and start conversion
*
* @param threshold Allowed uncertainty
* @param cpu_max How much cpu usage before throttling
*
* @return none
*/
void begin( float threshold );
/**
* sets threshold value
*
* @param thresh
* @return none
*/
void threshold( float p );
/**
* triggers true when valid frequency is found
*
* @return flag to indicate valid frequency is found
*/
bool available( void );
/**
* get frequency
*
* @return frequency in hertz
*/
float read( void );
/**
* get predicitity
*
* @return probability of frequency found
*/
float probability( void );
/**
* Audio Library calls this update function ~2.9ms
*
* @return none
*/
virtual void update( void );
private:
/**
* check the sampled data for fundamental frequency
*
* @param yin buffer to hold sum*tau value
* @param rs buffer to hold running sum for sampled window
* @param head buffer index
* @param tau lag we are currently working on this gets incremented
*
* @return tau
*/
uint16_t estimate( uint64_t *yin, uint64_t *rs, uint16_t head, uint16_t tau );
/**
* process audio data
*
* @return none
*/
void process( void );
/**
* Variables
*/
uint64_t running_sum;
uint16_t tau_global;
uint64_t yin_buffer[5];
uint64_t rs_buffer[5];
int16_t AudioBuffer[AUDIO_GUITARTUNER_BLOCKS*128] __attribute__ ( ( aligned ( 4 ) ) );
uint8_t yin_idx, state;
float periodicity, yin_threshold, cpu_usage_max, data;
bool enabled, next_buffer, first_run;
volatile bool new_output, process_buffer;
audio_block_t *blocklist1[AUDIO_GUITARTUNER_BLOCKS];
audio_block_t *blocklist2[AUDIO_GUITARTUNER_BLOCKS];
audio_block_t *inputQueueArray[1];
};
#endif

View file

@ -0,0 +1,56 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_peak.h"
void AudioAnalyzePeak::update(void)
{
audio_block_t *block;
const int16_t *p, *end;
int32_t min, max;
block = receiveReadOnly();
if (!block) {
return;
}
p = block->data;
end = p + AUDIO_BLOCK_SAMPLES;
min = min_sample;
max = max_sample;
do {
int16_t d=*p++;
// TODO: can we speed this up with SSUB16 and SEL
// http://www.m4-unleashed.com/parallel-comparison/
if (d<min) min=d;
if (d>max) max=d;
} while (p < end);
min_sample = min;
max_sample = max;
new_output = true;
release(block);
}

View file

@ -0,0 +1,77 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_peakdetect_h_
#define analyze_peakdetect_h_
#include "Arduino.h"
#include "AudioStream.h"
class AudioAnalyzePeak : public AudioStream
{
public:
AudioAnalyzePeak(void) : AudioStream(1, inputQueueArray) {
min_sample = 32767;
max_sample = -32768;
}
bool available(void) {
__disable_irq();
bool flag = new_output;
if (flag) new_output = false;
__enable_irq();
return flag;
}
float read(void) {
__disable_irq();
int min = min_sample;
int max = max_sample;
min_sample = 32767;
max_sample = -32768;
__enable_irq();
min = abs(min);
max = abs(max);
if (min > max) max = min;
return (float)max / 32767.0f;
}
float readPeakToPeak(void) {
__disable_irq();
int min = min_sample;
int max = max_sample;
min_sample = 32767;
max_sample = -32768;
__enable_irq();
return (float)(max - min) / 32767.0f;
}
virtual void update(void);
private:
audio_block_t *inputQueueArray[1];
volatile bool new_output;
int16_t min_sample;
int16_t max_sample;
};
#endif

View file

@ -0,0 +1,101 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_print.h"
#define STATE_IDLE 0 // doing nothing
#define STATE_WAIT_TRIGGER 1 // looking for trigger condition
#define STATE_DELAY 2 // waiting from trigger to print
#define STATE_PRINTING 3 // printing data
void AudioAnalyzePrint::update(void)
{
audio_block_t *block;
uint32_t offset = 0;
uint32_t remain, n;
block = receiveReadOnly();
if (!block) return;
while (offset < AUDIO_BLOCK_SAMPLES) {
remain = AUDIO_BLOCK_SAMPLES - offset;
switch (state) {
case STATE_WAIT_TRIGGER:
// TODO: implement this....
offset = AUDIO_BLOCK_SAMPLES;
break;
case STATE_DELAY:
//Serial.printf("STATE_DELAY, count = %u\n", count);
if (remain < count) {
count -= remain;
offset = AUDIO_BLOCK_SAMPLES;
} else {
offset += count;
count = print_length;
state = STATE_PRINTING;
}
break;
case STATE_PRINTING:
n = count;
if (n > remain) n = remain;
count -= n;
while (n > 0) {
Serial.println(block->data[offset++]);
n--;
}
if (count == 0) state = STATE_IDLE;
break;
default: // STATE_IDLE
offset = AUDIO_BLOCK_SAMPLES;
break;
}
}
release(block);
}
void AudioAnalyzePrint::trigger(void)
{
uint32_t n = delay_length;
if (n > 0) {
Serial.print("trigger ");
if (myname) Serial.print(myname);
Serial.print(", delay=");
Serial.println(n);
count = n;
state = 2;
} else {
Serial.print("trigger ");
if (myname) Serial.println(myname);
count = print_length;
state = 3;
}
}

View file

@ -0,0 +1,55 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_print_h_
#define analyze_print_h_
#include "Arduino.h"
#include "AudioStream.h"
class AudioAnalyzePrint : public AudioStream
{
public:
AudioAnalyzePrint(void) : AudioStream(1, inputQueueArray),
myname(NULL), state(0), trigger_edge(0), delay_length(0), print_length(500) {}
virtual void update(void);
void name(const char *str) { myname = str; }
void trigger(void);
void trigger(float level, int edge);
void delay(uint32_t num) { delay_length = num; }
void length(uint32_t num) { print_length = num; }
private:
const char *myname;
uint8_t state;
uint8_t trigger_edge; // trigger type, 0=none, 2=RISING, 3=FALLING
int16_t trigger_level;
uint32_t delay_length; // number of samples between trigger and printing
uint32_t print_length; // number of samples to print
uint32_t count;
audio_block_t *inputQueueArray[1];
};
#endif

View file

@ -0,0 +1,82 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_rms.h"
#include "utility/dspinst.h"
void AudioAnalyzeRMS::update(void)
{
audio_block_t *block = receiveReadOnly();
if (!block) {
count++;
return;
}
#if defined(KINETISK)
uint32_t *p = (uint32_t *)(block->data);
uint32_t *end = p + AUDIO_BLOCK_SAMPLES/2;
int64_t sum = accum;
do {
uint32_t n1 = *p++;
uint32_t n2 = *p++;
uint32_t n3 = *p++;
uint32_t n4 = *p++;
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n1, n1);
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n2, n2);
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n3, n3);
sum = multiply_accumulate_16tx16t_add_16bx16b(sum, n4, n4);
} while (p < end);
accum = sum;
count++;
#else
int16_t *p = block->data;
int16_t *end = p + AUDIO_BLOCK_SAMPLES;
int64_t sum = accum;
do {
int32_t n = *p++;
sum += n * n;
} while (p < end);
accum = sum;
count++;
#endif
release(block);
}
float AudioAnalyzeRMS::read(void)
{
__disable_irq();
int64_t sum = accum;
accum = 0;
uint32_t num = count;
count = 0;
__enable_irq();
float meansq = sum / (num * AUDIO_BLOCK_SAMPLES);
// TODO: shift down to 32 bits and use sqrt_uint32
// but is that really any more efficient?
return sqrtf(meansq) / 32767.0;
}

View file

@ -0,0 +1,53 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_rms_h_
#define analyze_rms_h_
#include "Arduino.h"
#include "AudioStream.h"
class AudioAnalyzeRMS : public AudioStream
{
private:
audio_block_t *inputQueueArray[1];
int64_t accum;
uint32_t count;
public:
AudioAnalyzeRMS(void) : AudioStream(1, inputQueueArray) {
accum = 0;
count = 0;
}
bool available(void) {
return count > 0;
}
float read(void);
virtual void update(void);
};
#endif

View file

@ -0,0 +1,171 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_tonedetect.h"
#include "utility/dspinst.h"
#if defined(KINETISK)
static inline int32_t multiply_32x32_rshift30(int32_t a, int32_t b) __attribute__((always_inline));
static inline int32_t multiply_32x32_rshift30(int32_t a, int32_t b)
{
return ((int64_t)a * (int64_t)b) >> 30;
}
//#define TONE_DETECT_FAST
void AudioAnalyzeToneDetect::update(void)
{
audio_block_t *block;
int32_t q0, q1, q2, coef;
const int16_t *p, *end;
uint16_t n;
block = receiveReadOnly();
if (!block) return;
if (!enabled) {
release(block);
return;
}
p = block->data;
end = p + AUDIO_BLOCK_SAMPLES;
n = count;
coef = coefficient;
q1 = s1;
q2 = s2;
do {
// the Goertzel algorithm is kinda magical ;-)
#ifdef TONE_DETECT_FAST
q0 = (*p++) + (multiply_32x32_rshift32_rounded(coef, q1) << 2) - q2;
#else
q0 = (*p++) + multiply_32x32_rshift30(coef, q1) - q2;
// TODO: is this only 1 cycle slower? if so, always use it
#endif
q2 = q1;
q1 = q0;
if (--n == 0) {
out1 = q1;
out2 = q2;
q1 = 0; // TODO: does clearing these help or hinder?
q2 = 0;
new_output = true;
n = length;
}
} while (p < end);
count = n;
s1 = q1;
s2 = q2;
release(block);
}
void AudioAnalyzeToneDetect::set_params(int32_t coef, uint16_t cycles, uint16_t len)
{
__disable_irq();
coefficient = coef;
ncycles = cycles;
length = len;
count = len;
s1 = 0;
s2 = 0;
enabled = true;
__enable_irq();
//Serial.printf("Tone: coef=%d, ncycles=%d, length=%d\n", coefficient, ncycles, length);
}
float AudioAnalyzeToneDetect::read(void)
{
int32_t coef, q1, q2, power;
uint16_t len;
__disable_irq();
coef = coefficient;
q1 = out1;
q2 = out2;
len = length;
__enable_irq();
#ifdef TONE_DETECT_FAST
power = multiply_32x32_rshift32_rounded(q2, q2);
power = multiply_accumulate_32x32_rshift32_rounded(power, q1, q1);
power = multiply_subtract_32x32_rshift32_rounded(power,
multiply_32x32_rshift30(q1, q2), coef);
power <<= 4;
#else
int64_t power64;
power64 = (int64_t)q2 * (int64_t)q2;
power64 += (int64_t)q1 * (int64_t)q1;
power64 -= (((int64_t)q1 * (int64_t)q2) >> 30) * (int64_t)coef;
power = power64 >> 28;
#endif
return sqrtf((float)power) / (float)len;
}
AudioAnalyzeToneDetect::operator bool()
{
int32_t coef, q1, q2, power, trigger;
uint16_t len;
__disable_irq();
coef = coefficient;
q1 = out1;
q2 = out2;
len = length;
__enable_irq();
#ifdef TONE_DETECT_FAST
power = multiply_32x32_rshift32_rounded(q2, q2);
power = multiply_accumulate_32x32_rshift32_rounded(power, q1, q1);
power = multiply_subtract_32x32_rshift32_rounded(power,
multiply_32x32_rshift30(q1, q2), coef);
power <<= 4;
#else
int64_t power64;
power64 = (int64_t)q2 * (int64_t)q2;
power64 += (int64_t)q1 * (int64_t)q1;
power64 -= (((int64_t)q1 * (int64_t)q2) >> 30) * (int64_t)coef;
power = power64 >> 28;
#endif
trigger = (uint32_t)len * thresh;
trigger = multiply_32x32_rshift32(trigger, trigger);
//Serial.printf("bool: power=%d, trig=%d\n", power, trigger);
return (power >= trigger);
// TODO: this should really remember if it's retuned true previously,
// so it can give a single true response each time a tone is seen.
}
#elif defined(KINETISL)
void AudioAnalyzeToneDetect::update(void)
{
audio_block_t *block;
block = receiveReadOnly();
if (block) release(block);
}
#endif

View file

@ -0,0 +1,73 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_tonedetect_h_
#define analyze_tonedetect_h_
#include "Arduino.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

View file

@ -0,0 +1,302 @@
/*
* HiFi Audio Codec Module support library for Teensy 3.x
*
* Copyright 2015, Michele Perla
*
*/
#include <Arduino.h>
#include "control_ak4558.h"
#include "Wire.h"
void AudioControlAK4558::initConfig(void)
{
// puts all default registers values inside an array
// this allows us to modify registers locally using annotation like follows:
//
// registers[AK4558_CTRL_1] &= ~AK4558_DIF2;
// registers[AK4558_CTRL_1] |= AK4558_DIF1 | AK4558_DIF0;
//
// after manipulation, we can write the entire register value on the CODEC
uint8_t n = 0;
Wire.requestFrom(AK4558_I2C_ADDR,10);
while(Wire.available()) {
#if AK4558_SERIAL_DEBUG > 0
Serial.print("Register ");
Serial.print(n);
Serial.print(" = ");
#endif
registers[n++] = Wire.read();
#if AK4558_SERIAL_DEBUG > 0
Serial.println(registers[n-1], BIN);
#endif
}
}
void AudioControlAK4558::readConfig(void)
{
// reads registers values
uint8_t n = 0;
uint8_t c = 0;
Wire.requestFrom(AK4558_I2C_ADDR, 10);
while(Wire.available()) {
Serial.print("Register ");
Serial.print(n++);
Serial.print(" = ");
c = Wire.read();
Serial.println(c, BIN);
}
}
bool AudioControlAK4558::write(unsigned int reg, unsigned int val)
{
Wire.beginTransmission(AK4558_I2C_ADDR);
Wire.write(reg);
Wire.write(val);
return (Wire.endTransmission(true)==0);
}
bool AudioControlAK4558::enableIn(void)
{
// ADC setup (datasheet page 74
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable ADC");
#endif
// ignore this, leaving default values - ADC: Set up the de-emphasis filter (Addr = 07H).
registers[AK4558_PWR_MNGT] |= AK4558_PMADR | AK4558_PMADL;
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: PWR_MNGT set to ");
Serial.println(registers[AK4558_PWR_MNGT], BIN);
#endif
delay(300);
// Power up the ADC: PMADL = PMADR bits = “0” → “1”
// Initialization cycle of the ADC is 5200/fs @Normal mode. The SDTO pin outputs “L” during initialization.
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable ADC - Done");
#endif
return true;
}
bool AudioControlAK4558::enableOut(void)
{
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable DAC");
#endif
// DAC Output setup (datasheet page 75)
registers[AK4558_MODE_CTRL] |= AK4558_LOPS;
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: MODE_CTRL set to ");
Serial.println(registers[AK4558_MODE_CTRL], BIN);
#endif
// Set the DAC output to power-save mode: LOPS bit “0” → “1”
// ignore this, leaving default values - DAC: Set up the digital filter mode.
// ignore this, leaving default values - Set up the digital output volume (Address = 08H, 09H).
registers[AK4558_PWR_MNGT] |= AK4558_PMDAR | AK4558_PMDAL;
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: PWR_MNGT set to ");
Serial.println(registers[AK4558_PWR_MNGT], BIN);
#endif
delay(300);
// Power up the DAC: PMDAL = PMDAR bits = “0” → “1”
// Outputs of the LOUT and ROUT pins start rising. Rise time is 300ms (max.) when C = 1μF.
registers[AK4558_MODE_CTRL] &= ~AK4558_LOPS;
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: MODE_CTRL set to ");
Serial.println(registers[AK4558_MODE_CTRL], BIN);
#endif
// Release power-save mode of the DAC output: LOPS bit = “1” → “0”
// Set LOPS bit to “0” after the LOUT and ROUT pins output “H”. Sound data will be output from the
// LOUT and ROUT pins after this setting.
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable DAC - Done");
#endif
return true;
}
bool AudioControlAK4558::enable(void)
{
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable device");
#endif
// Power Up and Reset
// Clock Setup (datasheet page 72)
pinMode(PIN_PDN, OUTPUT);
digitalWrite(0, LOW);
delay(1);
digitalWrite(0, HIGH);
// After Power Up: PDN pin “L” → “H”
// “L” time of 150ns or more is needed to reset the AK4558.
delay(20);
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: PDN is HIGH (device reset)");
#endif
// Control register settings become available in 10ms (min.) when LDOE pin = “H”
Wire.begin();
initConfig();
// access all registers to store locally their default values
// DIF2-0, DFS1-0 and ACKS bits must be set before MCKI, LRCK and BICK are supplied
// PMPLL = 0 (EXT Slave Mode; disables internal PLL and uses ext. clock) (by DEFAULT)
// ACKS = 0 (Manual Setting Mode; disables automatic clock selection) (by DEFAULT)
// DFS1-0 = 00 (Sampling Speed = Normal Speed Mode) (by DEFAULT)
// TDM1-0 = 00 (Time Division Multiplexing mode OFF) (by DEFAULT)
registers[AK4558_CTRL_1] &= ~AK4558_DIF2;
registers[AK4558_CTRL_1] |= AK4558_DIF1 | AK4558_DIF0;
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: CTRL_1 set to ");
Serial.println(registers[AK4558_CTRL_1], BIN);
#endif
// DIF2-1-0 = 011 ( 16 bit I2S compatible when BICK = 32fs)
registers[AK4558_CTRL_2] &= ~AK4558_MCKS1;
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: CTRL_2 set to ");
Serial.println(registers[AK4558_CTRL_2], BIN);
#endif
// MCKS1-0 = 00 (Master Clock Input Frequency Select, set 256fs for Normal Speed Mode -> 11.2896 MHz)
registers[AK4558_MODE_CTRL] &= ~AK4558_BCKO0;
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz)
registers[AK4558_MODE_CTRL] |= AK4558_FS1;
// Set up the sampling frequency (FS3-0 bits). The ADC must be powered-up in consideration of PLL
// lock time. (in this case (ref. table 17): Set clock to mode 5 / 44.100 KHz)
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: MODE_CTRL set to ");
Serial.println(registers[AK4558_MODE_CTRL], BIN);
#endif
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz)
Wire.beginTransmission(AK4558_I2C_ADDR);
Wire.write(AK4558_CTRL_1);
Wire.write(registers[AK4558_CTRL_1]);
Wire.write(registers[AK4558_CTRL_2]);
Wire.write(registers[AK4558_MODE_CTRL]);
Wire.endTransmission();
// Write configuration registers in a single write operation (datasheet page 81):
// The AK4558 can perform more than one byte write operation per sequence. After receipt of the third byte
// the AK4558 generates an acknowledge and awaits the next data. The master can transmit more than
// one byte instead of terminating the write cycle after the first data byte is transferred. After receiving each
// data packet the internal address counter is incremented by one, and the next data is automatically taken
// into the next address.
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable device - Done");
#endif
return true;
}
bool AudioControlAK4558::disableIn(void)
{
// ADC power-down (datasheet page 74
registers[AK4558_PWR_MNGT] &= ~AK4558_PMADR | ~AK4558_PMADL;
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: PWR_MNGT set to ");
Serial.println(registers[AK4558_PWR_MNGT], BIN);
#endif
// Power down ADC: PMADL = PMADR bits = “1” → “0”
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Enable ADC - Done");
#endif
return true;
}
bool AudioControlAK4558::disableOut(void)
{
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Disable DAC");
#endif
// DAC Output power-down (datasheet page 75)
registers[AK4558_MODE_CTRL] |= AK4558_LOPS;
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: MODE_CTRL set to ");
Serial.println(registers[AK4558_MODE_CTRL], BIN);
#endif
// Set the DAC output to power-save mode: LOPS bit “0” → “1”
registers[AK4558_PWR_MNGT] &= ~AK4558_PMDAR | ~AK4558_PMDAL;
write(AK4558_PWR_MNGT, registers[AK4558_PWR_MNGT]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: PWR_MNGT set to ");
Serial.println(registers[AK4558_PWR_MNGT], BIN);
#endif
delay(300);
// Power down the DAC: PMDAL = PMDAR bits = “1” → “0”
// Outputs of the LOUT and ROUT pins start falling. Rise time is 300ms (max.) when C = 1μF.
registers[AK4558_MODE_CTRL] &= ~AK4558_LOPS;
write(AK4558_MODE_CTRL, registers[AK4558_MODE_CTRL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: MODE_CTRL set to ");
Serial.println(registers[AK4558_MODE_CTRL], BIN);
#endif
// Release power-save mode of the DAC output: LOPS bit = “1” → “0”
// Set LOPS bit to “0” after outputs of the LOUT and ROUT pins fall to “L”.
#if AK4558_SERIAL_DEBUG > 0
Serial.println("AK4558: Disable DAC - Done");
#endif
return true;
}
uint8_t AudioControlAK4558::convertVolume(float vol)
{
// Convert float (range 0.0-1.0) to unsigned char (range 0x00-0xFF)
uint8_t temp = ((uint32_t)vol)>>22;
return temp;
}
bool AudioControlAK4558::volume(float n)
{
// Set DAC output volume
uint8_t vol = convertVolume(n);
registers[AK4558_LOUT_VOL] = vol;
registers[AK4558_ROUT_VOL] = vol;
Wire.beginTransmission(AK4558_I2C_ADDR);
Wire.write(AK4558_LOUT_VOL);
Wire.write(registers[AK4558_LOUT_VOL]);
Wire.write(registers[AK4558_ROUT_VOL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: LOUT_VOL set to ");
Serial.println(registers[AK4558_LOUT_VOL], BIN);
Serial.print("AK4558: ROUT_VOL set to ");
Serial.println(registers[AK4558_ROUT_VOL], BIN);
#endif
return (Wire.endTransmission(true)==0);
}
bool AudioControlAK4558::volumeLeft(float n)
{
// Set DAC left output volume
uint8_t vol = convertVolume(n);
registers[AK4558_LOUT_VOL] = vol;
bool ret = write(AK4558_LOUT_VOL, registers[AK4558_LOUT_VOL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: LOUT_VOL set to ");
Serial.println(registers[AK4558_LOUT_VOL], BIN);
#endif
return ret;
}
bool AudioControlAK4558::volumeRight(float n)
{
// Set DAC right output volume
uint8_t vol = convertVolume(n);
registers[AK4558_ROUT_VOL] = vol;
bool ret = write(AK4558_ROUT_VOL, registers[AK4558_ROUT_VOL]);
#if AK4558_SERIAL_DEBUG > 0
Serial.print("AK4558: ROUT_VOL set to ");
Serial.println(registers[AK4558_ROUT_VOL], BIN);
#endif
return ret;
}

View file

@ -0,0 +1,255 @@
/*
* HiFi Audio Codec Module support library for Teensy 3.x
*
* Copyright 2015, Michele Perla
*
*/
#ifndef control_ak4558_h_
#define control_ak4558_h_
#include "AudioControl.h"
#define AK4558_SERIAL_DEBUG 1
//if 1, then Serial Monitor will show debug information about configuration of the AK4558
// for Teensy audio lib operation the following settings are needed
// 1fs = 44.1 KHz
// sample size = 16 bits
// MCKI : 11.2896 MHz
// BICK : 1.4112 MHz
// LRCK : 44.100 KHz
// to do so we need to set the following bits:
// PMPLL = 0 (EXT Slave Mode; disables internal PLL and uses ext. clock) (by DEFAULT)
// ACKS = 0 (Manual Setting Mode; disables automatic clock selection) (by DEFAULT)
// DFS1-0 = 00 (Sampling Speed = Normal Speed Mode, default)
// MCKS1-0 = 00 (Master Clock Input Frequency Select, set 256fs for Normal Speed Mode -> 11.2896 MHz)
// BCKO1-0 = 00 (BICK Output Frequency at Master Mode = 32fs = 1.4112 MHz)
// TDM1-0 = 00 (Time Division Multiplexing mode OFF) (by DEFAULT)
// DIF2-1-0 = 011 ( 16 bit I2S compatible when BICK = 32fs)
#ifndef PIN_PDN
#define PIN_PDN 1
#endif
// Power-Down & Reset Mode Pin
// “L”: Power-down and Reset, “H”: Normal operation
// The AK4558 should be reset once by bringing PDN pin = “L”
#ifndef AK4558_CAD1
#define AK4558_CAD1 1
#endif
// Chip Address 1 pin
// set to 'H' by default, configurable to 'L' via a jumper on bottom side of the board
#ifndef AK4558_CAD0
#define AK4558_CAD0 1
#endif
// Chip Address 0 pin
// set to 'H' by default, configurable to 'L' via a jumper on bottom side of the board
#define AK4558_I2C_ADDR (0x10 + (AK4558_CAD1<<1) + AK4558_CAD0)
// datasheet page 81:
// This address is 7 bits long followed by the eighth bit that is a data direction bit (R/W).
// The most significant five bits of the slave address are fixed as “00100”. The next bits are
// CAD1 and CAD0 (device address bit). These bits identify the specific device on the bus.
// The hard-wired input pins (CAD1 and CAD0) set these device address bits (Figure 69)
// Power Management register
#define AK4558_PWR_MNGT 0x00
// D4 D3 D2 D1 D0
// PMADR PMADL PMDAR PMDAL RSTN
#define AK4558_PMADR (1u<<4)
#define AK4558_PMADL (1u<<3)
// PMADL/R: ADC L/Rch Power Management
// 0: ADC L/Rch Power Down (default)
// 1: Normal Operation
#define AK4558_PMDAR (1u<<2)
#define AK4558_PMDAL (1u<<1)
// PMDAL/R: DAC L/Rch Power Management
// 0: DAC L/Rch Power Down (default)
// 1: Normal Operation
#define AK4558_RSTN (1u)
// RSTN: Internal Timing Reset
// 0: Reset Register values are not reset.
// 1: Normal Operation (default)
// PLL Control register
#define AK4558_PLL_CTRL 0X01
// D4 D3 D2 D1 D0
// PLL3 PLL2 PLL1 PLL0 PMPLL
#define AK4558_PLL3 (1u<<4)
#define AK4558_PLL2 (1u<<3)
#define AK4558_PLL1 (1u<<2)
#define AK4558_PLL0 (1u<<1)
// PLL3-0: PLL Reference Clock Select (Table 16)
// Default: “0010” (BICK pin=64fs)
#define AK4558_PMPLL (1u)
// PMPLL: PLL Power Management
// 0: EXT Mode and Power down (default)
// 1: PLL Mode and Power up
// DAC TDM register
#define AK4558_DAC_TDM 0X02
// D1 D0
// SDS1 SDS0
#define AK4558_SDS1 (1u<<1)
#define AK4558_SDS0 (1u)
// SDS1-0: DAC TDM Data Select (Table 24)
// Default: “00”
// Control 1 register
#define AK4558_CTRL_1 0X03
// D7 D6 D5 D4 D3 D2 D1 D0
// TDM1 TDM0 DIF2 DIF1 DIF0 ATS1 ATS0 SMUTE
#define AK4558_TDM1 (1u<<7)
#define AK4558_TDM0 (1u<<6)
// TDM1-0: TDM Format Select (Table 23, Table 25, Table 26)
// Default: “00” (Stereo Mode)
#define AK4558_DIF2 (1u<<5)
#define AK4558_DIF1 (1u<<4)
#define AK4558_DIF0 (1u<<3)
// DIF2-0: Audio Interface Format Mode Select (Table 23)
// Default: “111” (32bit I2S)
#define AK4558_ATS1 (1u<<2)
#define AK4558_ATS0 (1u<<1)
// ATS1-0: Transition Time Setting of Digital Attenuator (Table 31)
// Default: “00”
#define AK4558_SMUTE (1u)
// SMUTE: Soft Mute Enable
// 0: Normal Operation (default)
// 1: All DAC outputs are soft muted.
// Control 2 register
#define AK4558_CTRL_2 0X04
// D4 D3 D2 D1 D0
// MCKS1 MCKS0 DFS1 DFS0 ACKS
#define AK4558_MCKS1 (1u<<4)
#define AK4558_MCKS0 (1u<<3)
// MCKS1-0: Master Clock Input Frequency Select (Table 9, follows):
// MCKS1 MCKS0 NSM DSM QSM
// 0 0 256fs 256fs 128fs
// 0 1 384fs 256fs 128fs
// 1 0 512fs 256fs 128fs (default)
// 1 1 768fs 256fs 128fs
#define AK4558_DFS1 (1u<<2)
#define AK4558_DFS0 (1u<<1)
// DFS1-0: Sampling Speed Control (Table 8)
// The setting of DFS1-0 bits is ignored when ACKS bit =“1”.
#define AK4558_ACKS (1u)
// ACKS: Automatic Clock Recognition Mode
// 0: Disable, Manual Setting Mode (default)
// 1: Enable, Auto Setting Mode
// When ACKS bit = “1”, master clock frequency is detected automatically. In this case, the setting of
// DFS1-0 bits is ignored. When ACKS bit = “0”, DFS1-0 bits set the sampling speed mode. The MCKI
// frequency of each mode is detected automatically.
// Mode Control register
#define AK4558_MODE_CTRL 0X05
// D6 D5 D4 D3 D2 D1 D0
// FS3 FS2 FS1 FS0 BCKO1 BCKO0 LOPS
#define AK4558_FS3 (1u<<6)
#define AK4558_FS2 (1u<<5)
#define AK4558_FS1 (1u<<4)
#define AK4558_FS0 (1u<<3)
// FS3-0: Sampling Frequency (Table 17, Table 18)
// Default: “0101”
#define AK4558_BCKO1 (1u<<2)
#define AK4558_BCKO0 (1u<<1)
// BCKO1-0: BICK Output Frequency Setting in Master Mode (Table 21)
// Default: “01” (64fs)
#define AK4558_LOPS (1u<<0)
// LOPS: Power-save Mode of LOUT/ROUT
// 0: Normal Operation (default)
// 1: Power-save Mode
// Filter Setting register
#define AK4558_FLTR_SET 0x06
// D7 D6 D5 D4 D3 D2 D1 D0
// FIRDA2 FIRDA1 FIRDA0 SLDA SDDA SSLOW DEM1 DEM0
#define AK4558_FIRDA2 (1u<<7)
#define AK4558_FIRDA1 (1u<<6)
#define AK4558_FIRDA0 (1u<<5)
// FIRDA2-0: Out band noise eliminating Filters Setting (Table 32)
// default: “001” (48kHz)
#define AK4558_SLDA (1u<<4)
// SLDA: DAC Slow Roll-off Filter Enable (Table 28)
// 0: Sharp Roll-off filter (default)
// 1: Slow Roll-off Filter
#define AK4558_SDDA (1u<<3)
// SDDA: DAC Short delay Filter Enable (Table 28)
// 0: Normal filter
// 1: Short delay Filter (default)
#define AK4558_SSLOW (1u<<2)
// SSLOW: Digital Filter Bypass Mode Enable
// 0: Roll-off filter (default)
// 1: Super Slow Roll-off Mode
#define AK4558_DEM1 (1u<<1)
#define AK4558_DEM0 (1u)
// DEM1-0: De-emphasis response control for DAC (Table 22)
// Default: “01”, OFF
// HPF Enable, Filter Setting
#define AK4558_HPF_EN_FLTR_SET 0x07
// D3 D2 D1 D0
// SLAD SDAD HPFER HPFEL
#define AK4558_SLAD (1u<<3)
// SLAD: ADC Slow Roll-off Filter Enable (Table 27)
// 0: Sharp Roll-off filter (default)
// 1: Slow Roll-off Filter
#define AK4558_SDAD (1u<<2)
// SDAD: ADC Short delay Filter Enable (Table 27)
// 0: Normal filter
// 1: Short delay Filter (default)
#define AK4558_HPFER (1u<<1)
#define AK4558_HPFEL (1u)
// HPFEL/R: ADC HPF L/Rch Setting
// 0: HPF L/Rch OFF
// 1: HPF L/Rch ON (default)
// LOUT Volume Control register
#define AK4558_LOUT_VOL 0X08
// D7 D6 D5 D4 D3 D2 D1 D0
// ATL7 ATL6 ATL5 ATL4 ATL3 ATL2 ATL1 ATL0
//
// ATL 7-0: Attenuation Level (Table 30)
// Default:FF(0dB)
// ROUT Volume Control register
#define AK4558_ROUT_VOL 0X09
// D7 D6 D5 D4 D3 D2 D1 D0
// ATR7 ATR6 ATR5 ATR4 ATR3 ATR2 ATR1 ATR0
//
// ATR 7-0: Attenuation Level (Table 30)
// Default:FF(0dB)
class AudioControlAK4558 : public AudioControl
{
public:
bool enable(void); //enables the CODEC, does not power up ADC nor DAC (use enableIn() and enableOut() for selective power up)
bool enableIn(void); //powers up ADC
bool enableOut(void); //powers up DAC
bool disable(void) { return (disableIn()&&disableOut()); } //powers down ADC/DAC
bool disableIn(void); //powers down ADC
bool disableOut(void); //powers down DAC
bool volume(float n); //sets LOUT/ROUT volume to n (range 0.0 - 1.0)
bool volumeLeft(float n); //sets LOUT volume to n (range 0.0 - 1.0)
bool volumeRight(float n); //sets ROUT volume to n (range 0.0 - 1.0)
bool inputLevel(float n) { return false; } //not supported by AK4558
bool inputSelect(int n) { return false; } //sets inputs to mono left, mono right, stereo (default stereo), not yet implemented
private:
uint8_t registers[10];
void initConfig(void);
void readConfig(void);
bool write(unsigned int reg, unsigned int val);
uint8_t convertVolume(float vol);
};
#endif

View file

@ -0,0 +1,149 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "control_cs42448.h"
#include "Wire.h"
#define CS42448_Chip_ID 0x01
#define CS42448_Power_Control 0x02
#define CS42448_Functional_Mode 0x03
#define CS42448_Interface_Formats 0x04
#define CS42448_ADC_Control_DAC_DeEmphasis 0x05
#define CS42448_Transition_Control 0x06
#define CS42448_DAC_Channel_Mute 0x07
#define CS42448_AOUT1_Volume_Control 0x08
#define CS42448_AOUT2_Volume_Control 0x09
#define CS42448_AOUT3_Volume_Control 0x0A
#define CS42448_AOUT4_Volume_Control 0x0B
#define CS42448_AOUT5_Volume_Control 0x0C
#define CS42448_AOUT6_Volume_Control 0x0D
#define CS42448_AOUT7_Volume_Control 0x0E
#define CS42448_AOUT8_Volume_Control 0x0F
#define CS42448_DAC_Channel_Invert 0x10
#define CS42448_AIN1_Volume_Control 0x11
#define CS42448_AIN2_Volume_Control 0x12
#define CS42448_AIN3_Volume_Control 0x13
#define CS42448_AIN4_Volume_Control 0x14
#define CS42448_AIN5_Volume_Control 0x15
#define CS42448_AIN6_Volume_Control 0x16
#define CS42448_ADC_Channel_Invert 0x17
#define CS42448_Status_Control 0x18
#define CS42448_Status 0x19
#define CS42448_Status_Mask 0x1A
#define CS42448_MUTEC_Pin_Control 0x1B
// 4.9 Recommended Power-Up Sequence
// 1. Hold RST low until the power supply and clocks are stable. In this state,
// the control port is reset to its default settings and VQ will remain low.
// 2. Bring RST high. The device will initially be in a low power state with VQ
// low. All features will default as described in the "Register Quick Reference"
// on page 40.
// 3. Perform a write operation to the Power Control register ("Power Control
// (Address 02h)" on page 43) to set bit 0 to a '1'b. This will place the
// device in a power down state.
// 4. Load the desired register settings while keeping the PDN bit set to '1'b.
// 5. Mute all DACs. Muting the DACs suppresses any noise associated with the
// CODEC's first initialization after power is applied.
// 6. Set the PDN bit in the power control register to '0'b. VQ will ramp to
// approximately VA/2 according to the Popguard specification in section
// "Popguard" on page 29.
// 7. Following approximately 2000 LRCK cycles, the device is initialized and
// ready for normal operation.
// 8. After the CODEC is initialized, wait ~90 LRCK cycles (~1.9 ms @48 kHz) and
// then un-mute the DACs.
// 9. Normal operation begins.
static const uint8_t default_config[] = {
0xF4, // CS42448_Functional_Mode = slave mode, MCLK 25.6 MHz max
0x76, // CS42448_Interface_Formats = TDM mode
0x1C, // CS42448_ADC_Control_DAC_DeEmphasis = single ended ADC
0x63, // CS42448_Transition_Control = soft vol control
0xFF // CS42448_DAC_Channel_Mute = all outputs mute
};
bool AudioControlCS42448::enable(void)
{
Wire.begin();
// TODO: wait for reset signal high??
if (!write(CS42448_Power_Control, 0xFF)) return false; // power down
if (!write(CS42448_Functional_Mode, default_config, sizeof(default_config))) return false;
if (!write(CS42448_Power_Control, 0)) return false; // power up
return true;
}
bool AudioControlCS42448::volumeInteger(uint32_t n)
{
uint8_t data[9];
data[0] = 0;
for (int i=1; i < 9; i++) {
data[i] = n;
}
return write(CS42448_DAC_Channel_Mute, data, 9);
}
bool AudioControlCS42448::volumeInteger(int channel, uint32_t n)
{
return true;
}
bool AudioControlCS42448::inputLevelInteger(int32_t n)
{
return true;
}
bool AudioControlCS42448::inputLevelInteger(int chnnel, int32_t n)
{
return true;
}
bool AudioControlCS42448::write(uint32_t address, uint32_t data)
{
Wire.beginTransmission(i2c_addr);
Wire.write(address);
Wire.write(data);
if (Wire.endTransmission() == 0) return true;
return false;
}
bool AudioControlCS42448::write(uint32_t address, const void *data, uint32_t len)
{
Wire.beginTransmission(i2c_addr);
Wire.write(address | 0x80);
const uint8_t *p = (const uint8_t *)data;
const uint8_t *end = p + len;
while (p < end) {
Wire.write(*p++);
}
if (Wire.endTransmission() == 0) return true;
return false;
}

View file

@ -0,0 +1,84 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef control_cs42448_h_
#define control_cs42448_h_
#include "AudioControl.h"
#include <math.h>
class AudioControlCS42448 : public AudioControl
{
public:
AudioControlCS42448(void) : i2c_addr(0x48), muted(true) { }
void setAddress(uint8_t addr) {
i2c_addr = 0x48 | (addr & 3);
}
bool enable(void);
bool disable(void) {
return false;
}
bool volume(float level) {
return volumeInteger(volumebyte(level));
}
bool inputLevel(float level) {
return inputLevelInteger(inputlevelbyte(level));
}
bool inputSelect(int n) {
return (n == 0) ? true : false;
}
bool volume(int channel, float level) {
if (channel < 1 || channel > 8) return false;
return volumeInteger(channel, volumebyte(level));
}
bool inputLevel(int channel, float level) {
if (channel < 1 || channel > 6) return false;
return inputLevelInteger(channel, inputlevelbyte(level));
}
private:
bool volumeInteger(uint32_t n);
bool volumeInteger(int channel, uint32_t n);
bool inputLevelInteger(int32_t n);
bool inputLevelInteger(int chnnel, int32_t n);
// convert level to volume byte, section 6.9.1, page 50
uint32_t volumebyte(float level) {
if (level >= 1.0) return 0;
if (level <= 0.0000003981) return 128;
return roundf(log10f(level) * -20.0);
}
// convert level to input gain, section 6.11.1, page 51
int32_t inputlevelbyte(float level) {
if (level > 15.8489) return 48;
if (level < 0.00063095734) return -128;
return roundf(log10f(level) * 40.0);
}
bool write(uint32_t address, uint32_t data);
bool write(uint32_t address, const void *data, uint32_t len);
uint8_t i2c_addr;
bool muted;
};
#endif

View file

@ -0,0 +1,241 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* https://hackaday.io/project/5912-teensy-super-audio-board
* https://github.com/whollender/Audio/tree/SuperAudioBoard
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "control_cs4272.h"
#include "Wire.h"
#define CS4272_ADDR 0x10 // TODO: need to double check
// Section 8.1 Mode Control
#define CS4272_MODE_CONTROL (uint8_t)0x01
#define CS4272_MC_FUNC_MODE(x) (uint8_t)(((x) & 0x03) << 6)
#define CS4272_MC_RATIO_SEL(x) (uint8_t)(((x) & 0x03) << 4)
#define CS4272_MC_MASTER_SLAVE (uint8_t)0x08
#define CS4272_MC_SERIAL_FORMAT(x) (uint8_t)(((x) & 0x07) << 0)
// Section 8.2 DAC Control
#define CS4272_DAC_CONTROL (uint8_t)0x02
#define CS4272_DAC_CTRL_AUTO_MUTE (uint8_t)0x80
#define CS4272_DAC_CTRL_FILTER_SEL (uint8_t)0x40
#define CS4272_DAC_CTRL_DE_EMPHASIS(x) (uint8_t)(((x) & 0x03) << 4)
#define CS4272_DAC_CTRL_VOL_RAMP_UP (uint8_t)0x08
#define CS4272_DAC_CTRL_VOL_RAMP_DN (uint8_t)0x04
#define CS4272_DAC_CTRL_INV_POL(x) (uint8_t)(((x) & 0x03) << 0)
// Section 8.3 DAC Volume and Mixing
#define CS4272_DAC_VOL (uint8_t)0x03
#define CS4272_DAC_VOL_CH_VOL_TRACKING (uint8_t)0x40
#define CS4272_DAC_VOL_SOFT_RAMP(x) (uint8_t)(((x) & 0x03) << 4)
#define CS4272_DAC_VOL_ATAPI(x) (uint8_t)(((x) & 0x0F) << 0)
// Section 8.4 DAC Channel A volume
#define CS4272_DAC_CHA_VOL (uint8_t)0x04
#define CS4272_DAC_CHA_VOL_MUTE (uint8_t)0x80
#define CS4272_DAC_CHA_VOL_VOLUME(x) (uint8_t)(((x) & 0x7F) << 0)
// Section 8.5 DAC Channel B volume
#define CS4272_DAC_CHB_VOL (uint8_t)0x05
#define CS4272_DAC_CHB_VOL_MUTE (uint8_t)0x80
#define CS4272_DAC_CHB_VOL_VOLUME(x) (uint8_t)(((x) & 0x7F) << 0)
// Section 8.6 ADC Control
#define CS4272_ADC_CTRL (uint8_t)0x06
#define CS4272_ADC_CTRL_DITHER (uint8_t)0x20
#define CS4272_ADC_CTRL_SER_FORMAT (uint8_t)0x10
#define CS4272_ADC_CTRL_MUTE(x) (uint8_t)(((x) & 0x03) << 2)
#define CS4272_ADC_CTRL_HPF(x) (uint8_t)(((x) & 0x03) << 0)
// Section 8.7 Mode Control 2
#define CS4272_MODE_CTRL2 (uint8_t)0x07
#define CS4272_MODE_CTRL2_LOOP (uint8_t)0x10
#define CS4272_MODE_CTRL2_MUTE_TRACK (uint8_t)0x08
#define CS4272_MODE_CTRL2_CTRL_FREEZE (uint8_t)0x04
#define CS4272_MODE_CTRL2_CTRL_PORT_EN (uint8_t)0x02
#define CS4272_MODE_CTRL2_POWER_DOWN (uint8_t)0x01
// Section 8.8 Chip ID
#define CS4272_CHIP_ID (uint8_t)0x08
#define CS4272_CHIP_ID_PART(x) (uint8_t)(((x) & 0x0F) << 4)
#define CS4272_CHIP_ID_REV(x) (uint8_t)(((x) & 0x0F) << 0)
#define CS4272_RESET_PIN 2
bool AudioControlCS4272::enable(void)
{
Wire.begin();
delay(5);
initLocalRegs();
// Setup Reset pin
pinMode(CS4272_RESET_PIN, OUTPUT);
// Drive pin low
digitalWriteFast(CS4272_RESET_PIN, LOW);
delay(1);
// Release Reset
digitalWriteFast(CS4272_RESET_PIN, HIGH);
delay(2);
// Set power down and control port enable as spec'd in the
// datasheet for control port mode
write(CS4272_MODE_CTRL2, CS4272_MODE_CTRL2_POWER_DOWN
| CS4272_MODE_CTRL2_CTRL_PORT_EN);
// Wait for further setup
delay(1);
// Set ratio select for MCLK=512*LRCLK (BCLK = 64*LRCLK), and master mode
write(CS4272_MODE_CONTROL, CS4272_MC_RATIO_SEL(3) | CS4272_MC_MASTER_SLAVE);
delay(10);
// Release power down bit to start up codec
// TODO: May need other bits set in this reg
write(CS4272_MODE_CTRL2, CS4272_MODE_CTRL2_CTRL_PORT_EN);
// Wait for everything to come up
delay(10);
return true;
}
bool AudioControlCS4272::volumeInteger(unsigned int n)
{
unsigned int val = 0x7F - (n & 0x7F);
write(CS4272_DAC_CHA_VOL,CS4272_DAC_CHA_VOL_VOLUME(val));
write(CS4272_DAC_CHB_VOL,CS4272_DAC_CHB_VOL_VOLUME(val));
return true;
}
bool AudioControlCS4272::volume(float left, float right)
{
unsigned int leftInt,rightInt;
leftInt = left*127 + 0.499;
rightInt = right*127 + 0.499;
unsigned int val = 0x7F - (leftInt & 0x7F);
write(CS4272_DAC_CHA_VOL,CS4272_DAC_CHA_VOL_VOLUME(val));
val = 0x7F - (rightInt & 0x7F);
write(CS4272_DAC_CHB_VOL,CS4272_DAC_CHB_VOL_VOLUME(val));
return true;
}
bool AudioControlCS4272::dacVolume(float left, float right)
{
return volume(left,right);
}
bool AudioControlCS4272::muteOutput(void)
{
write(CS4272_DAC_CHA_VOL,
regLocal[CS4272_DAC_CHA_VOL] | CS4272_DAC_CHA_VOL_MUTE);
write(CS4272_DAC_CHB_VOL,
regLocal[CS4272_DAC_CHB_VOL] | CS4272_DAC_CHB_VOL_MUTE);
return true;
}
bool AudioControlCS4272::unmuteOutput(void)
{
write(CS4272_DAC_CHA_VOL,
regLocal[CS4272_DAC_CHA_VOL] & ~CS4272_DAC_CHA_VOL_MUTE);
write(CS4272_DAC_CHB_VOL,
regLocal[CS4272_DAC_CHB_VOL] & ~CS4272_DAC_CHB_VOL_MUTE);
return true;
}
bool AudioControlCS4272::muteInput(void)
{
uint8_t val = regLocal[CS4272_ADC_CTRL] | CS4272_ADC_CTRL_MUTE(3);
write(CS4272_ADC_CTRL,val);
return true;
}
bool AudioControlCS4272::unmuteInput(void)
{
uint8_t val = regLocal[CS4272_ADC_CTRL] & ~CS4272_ADC_CTRL_MUTE(3);
write(CS4272_ADC_CTRL,val);
return true;
}
bool AudioControlCS4272::enableDither(void)
{
uint8_t val = regLocal[CS4272_ADC_CTRL] | CS4272_ADC_CTRL_DITHER;
write(CS4272_ADC_CTRL,val);
return true;
}
bool AudioControlCS4272::disableDither(void)
{
uint8_t val = regLocal[CS4272_ADC_CTRL] & ~CS4272_ADC_CTRL_DITHER;
write(CS4272_ADC_CTRL,val);
return true;
}
bool AudioControlCS4272::write(unsigned int reg, unsigned int val)
{
// Write local copy first
if(reg > 7)
return false;
regLocal[reg] = val;
Wire.beginTransmission(CS4272_ADDR);
Wire.write(reg & 0xFF);
Wire.write(val & 0xFF);
Wire.endTransmission();
return true;
}
// Initialize local registers to CS4272 reset status
void AudioControlCS4272::initLocalRegs(void)
{
regLocal[CS4272_MODE_CONTROL] = 0x00;
regLocal[CS4272_DAC_CONTROL] = CS4272_DAC_CTRL_AUTO_MUTE;
regLocal[CS4272_DAC_VOL] = CS4272_DAC_VOL_SOFT_RAMP(2) | CS4272_DAC_VOL_ATAPI(9);
regLocal[CS4272_DAC_CHA_VOL] = 0x00;
regLocal[CS4272_DAC_CHB_VOL] = 0x00;
regLocal[CS4272_ADC_CTRL] = 0x00;
regLocal[CS4272_MODE_CTRL2] = 0x00;
}

View file

@ -0,0 +1,71 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* https://hackaday.io/project/5912-teensy-super-audio-board
* https://github.com/whollender/Audio/tree/SuperAudioBoard
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef control_cs4272_h_
#define control_cs4272_h_
#include "AudioControl.h"
class AudioControlCS4272 : public AudioControl
{
public:
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 127 + 0.499); }
bool inputLevel(float n) { return false; }
bool inputSelect(int n) { return false; }
bool volume(float left, float right);
bool dacVolume(float n) { return volumeInteger(n * 127 + 0.499); }
bool dacVolume(float left, float right);
bool muteOutput(void);
bool unmuteOutput(void);
bool muteInput(void);
bool unmuteInput(void);
bool enableDither(void);
bool disableDither(void);
protected:
bool write(unsigned int reg, unsigned int val);
bool volumeInteger(unsigned int n); // range: 0x0 to 0x7F
uint8_t regLocal[8];
void initLocalRegs(void);
};
// For sample rate ratio select (only single speed tested)
#define CS4272_RATIO_SINGLE 0
#define CS4272_RATIO_DOUBLE 2
#define CS4272_RATIO_QUAD 3
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,127 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef control_sgtl5000_h_
#define control_sgtl5000_h_
#include "AudioControl.h"
class AudioControlSGTL5000 : public AudioControl
{
public:
AudioControlSGTL5000(void) : i2c_addr(0x0A) { }
void setAddress(uint8_t level);
bool enable(void);
bool disable(void) { return false; }
bool volume(float n) { return volumeInteger(n * 129 + 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(0x0020, 0x055) // +7.5dB gain (1.3Vp-p full scale)
&& write(0x0024, ana_ctrl | (1<<2)); // enable linein
} else if (n == AUDIO_INPUT_MIC) {
return write(0x002A, 0x0173) // mic preamp gain = +40dB
&& write(0x0020, 0x088) // input gain +12dB (is this enough?)
&& write(0x0024, ana_ctrl & ~(1<<2)); // enable mic
} else {
return false;
}
}
bool volume(float left, float right);
bool micGain(unsigned int dB);
bool lineInLevel(uint8_t n) { return lineInLevel(n, n); }
bool lineInLevel(uint8_t left, uint8_t right);
unsigned short lineOutLevel(uint8_t n);
unsigned short lineOutLevel(uint8_t left, uint8_t right);
unsigned short dacVolume(float n);
unsigned short dacVolume(float left, float right);
bool dacVolumeRamp();
bool dacVolumeRampLinear();
bool dacVolumeRampDisable();
unsigned short adcHighPassFilterEnable(void);
unsigned short adcHighPassFilterFreeze(void);
unsigned short adcHighPassFilterDisable(void);
unsigned short audioPreProcessorEnable(void);
unsigned short audioPostProcessorEnable(void);
unsigned short audioProcessorDisable(void);
unsigned short eqFilterCount(uint8_t n);
unsigned short eqSelect(uint8_t n);
unsigned short eqBand(uint8_t bandNum, float n);
void eqBands(float bass, float mid_bass, float midrange, float mid_treble, float treble);
void eqBands(float bass, float treble);
void eqFilter(uint8_t filterNum, int *filterParameters);
unsigned short autoVolumeControl(uint8_t maxGain, uint8_t lbiResponse, uint8_t hardLimit, float threshold, float attack, float decay);
unsigned short autoVolumeEnable(void);
unsigned short autoVolumeDisable(void);
unsigned short enhanceBass(float lr_lev, float bass_lev);
unsigned short enhanceBass(float lr_lev, float bass_lev, uint8_t hpf_bypass, uint8_t cutoff);
unsigned short enhanceBassEnable(void);
unsigned short enhanceBassDisable(void);
unsigned short surroundSound(uint8_t width);
unsigned short surroundSound(uint8_t width, uint8_t select);
unsigned short surroundSoundEnable(void);
unsigned short surroundSoundDisable(void);
void killAutomation(void) { semi_automated=false; }
protected:
bool muted;
bool volumeInteger(unsigned int n); // range: 0x00 to 0x80
uint16_t ana_ctrl;
uint8_t i2c_addr;
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);
unsigned short dap_audio_eq_band(uint8_t bandNum, float n);
private:
bool semi_automated;
void automate(uint8_t dap, uint8_t eq);
void automate(uint8_t dap, uint8_t eq, uint8_t filterCount);
};
//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
//For frequency adjustment
#define FLAT_FREQUENCY 0
#define PARAMETRIC_EQUALIZER 1
#define TONE_CONTROLS 2
#define GRAPHIC_EQUALIZER 3
void calcBiquad(uint8_t filtertype, float fC, float dB_Gain, float Q, uint32_t quantization_unit, uint32_t fS, int *coef);
#endif

View file

@ -0,0 +1,745 @@
/*
control_tlv320aic3206
Created: Brendan Flynn (http://www.flexvoltbiosensor.com/) for Tympan, Jan-Feb 2017
Purpose: Control module for Texas Instruments TLV320AIC3206 compatible with Teensy Audio Library
License: MIT License. Use at your own risk.
*/
#include "control_tlv320aic3206.h"
#include <Wire.h>
//******************************** Constants *******************************//
#define AIC3206_I2C_ADDR 0x18
#ifndef AIC_FS
# define AIC_FS 44100UL
#endif
#define AIC_BITS 16
//#define AIC_BITS 32
#define AIC_I2S_SLAVE 1
#if AIC_I2S_SLAVE
// Direction of BCLK and WCLK (reg 27) is input if a slave:
# define AIC_CLK_DIR 0
#else
// If master, make outputs:
# define AIC_CLK_DIR 0x0C
#endif
//#ifndef AIC_CODEC_CLKIN_BCLK
//# define AIC_CODEC_CLKIN_BCLK 0
//#endif
//**************************** Clock Setup **********************************//
//********************************** 44100 *********************************//
#if AIC_FS == 44100
// MCLK = 180000000 * 16 / 255 = 11.294117 MHz // FROM TEENSY, FIXED
// PLL setup. PLL_OUT = MCLK * R * J.D / P
//// J.D = 7.5264, P = 1, R = 1 => 90.32 MHz // FROM 12MHz CHA AND WHF //
// J.D = 7.9968, P = 1, R = 1 => 90.3168 MHz // For 44.1kHz exact
// J.D = 8.0000000002, P = 1, R = 1 => 9.35294117888MHz // for TEENSY 44.11764706kHz
#define PLL_J 8
#define PLL_D 0
// Bitclock divisor.
// BCLK = DAC_CLK/N = PLL_OUT/NDAC/N = 32*fs or 16*fs
// PLL_OUT = fs*NDAC*MDAC*DOSR
// BLCK = 32*fs = 1411200 = PLL
#if AIC_BITS == 16
#define BCLK_N 8
#elif AIC_BITS == 32
#define BCLK_N 4
#endif
// ADC/DAC FS setup.
// ADC_MOD_CLK = CODEC_CLKIN / (NADC * MADC)
// DAC_MOD_CLK = CODEC_CLKIN / (NDAC * MDAC)
// ADC_FS = PLL_OUT / (NADC*MADC*AOSR)
// DAC_FS = PLL_OUT / (NDAC*MDAC*DOSR)
// FS = 90.3168MHz / (8*2*128) = 44100 Hz.
// MOD = 90.3168MHz / (8*2) = 5644800 Hz
// Actual from Teensy: 44117.64706Hz * 128 => 5647058.82368Hz * 8*2 => 90352941.17888Hz
// DAC clock config.
// Note: MDAC*DOSR/32 >= RC, where RC is 8 for the default filter.
// See Table 2-21
// http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
// PB1 - RC = 8. Use M8, N2
// PB25 - RC = 12. Use M8, N2
#define DOSR 128
#define NDAC 2
#define MDAC 8
#define AOSR 128
#define NADC 2
#define MADC 8
// Signal Processing Modes, Playback and Recording.
#define PRB_P 1
#define PRB_R 1
#endif // end fs if block
//**************************** Chip Setup **********************************//
//******************* INPUT DEFINITIONS *****************************//
// MIC routing registers
#define AIC3206_MICPGA_LEFT_POSITIVE_REG 0x0134 // page 1 register 52
#define AIC3206_MICPGA_LEFT_NEGATIVE_REG 0x0136 // page 1 register 54
#define AIC3206_MICPGA_RIGHT_POSITIVE_REG 0x0137 // page 1 register 55
#define AIC3206_MICPGA_RIGHT_NEGATIVE_REG 0x0139 // page 1 register 57
#define AIC3206_MIC_ROUTING_POSITIVE_IN1 0b11000000 //
#define AIC3206_MIC_ROUTING_POSITIVE_IN2 0b00110000 //
#define AIC3206_MIC_ROUTING_POSITIVE_IN3 0b00001100 //
#define AIC3206_MIC_ROUTING_POSITIVE_REVERSE 0b00000011 //
#define AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L 0b11000000 //
#define AIC3206_MIC_ROUTING_NEGATIVE_IN2_REVERSE 0b00110000 //
#define AIC3206_MIC_ROUTING_NEGATIVE_IN3_REVERSE 0b00001100 //
#define AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM2L 0b00000011 //
#define AIC3206_MIC_ROUTING_RESISTANCE_10k 0b01010101
#define AIC3206_MIC_ROUTING_RESISTANCE_20k 0b10101010
#define AIC3206_MIC_ROUTING_RESISTANCE_40k 0b11111111
#define AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT AIC3206_MIC_ROUTING_RESISTANCE_10k //datasheet (application notes) defaults to 20K...why?
#define AIC3206_MICPGA_LEFT_VOLUME_REG 0x013B // page 1 register 59 // 0 to 47.5dB in 0.5dB steps
#define AIC3206_MICPGA_RIGHT_VOLUME_REG 0x013C // page 1 register 60 // 0 to 47.5dB in 0.5dB steps
#define AIC3206_MICPGA_VOLUME_ENABLE 0x00 // default is 0b11000000 - clear to 0 to enable
#define AIC3206_MIC_BIAS_REG 0x0133 // page 1 reg 51
#define AIC3206_MIC_BIAS_POWER_ON 0x40
#define AIC3206_MIC_BIAS_POWER_OFF 0x00
#define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_25 0x00
#define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_7 0x01
#define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_2_5 0x10
#define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY 0x11
#define AIC3206_ADC_PROCESSING_BLOCK_REG 0x003d // page 0 register 61
#define AIC3206_ADC_CHANNEL_POWER_REG 0x0051 // page 0 register81
#define AIC3206_ADC_CHANNELS_ON 0b11000000 // power up left and right
#define AIC3206_ADC_MUTE_REG 0x0052 // page 0, register 82
#define AIC3206_ADC_UNMUTE 0x00
bool AudioControlTLV320AIC3206::enable(void)
{
delay(100);
// Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
Wire.begin();
delay(5);
//hard reset the AIC
//Serial.println("Hardware reset of AIC...");
//define RESET_PIN 21
#define RESET_PIN (resetPinAIC)
pinMode(RESET_PIN,OUTPUT);
digitalWrite(RESET_PIN,HIGH);delay(50); //not reset
digitalWrite(RESET_PIN,LOW);delay(50); //reset
digitalWrite(RESET_PIN,HIGH);delay(50);//not reset
aic_reset(); delay(100); //soft reset
aic_init(); delay(100);
aic_initADC(); delay(100);
aic_initDAC(); delay(100);
aic_readPage(0, 27); // check a specific register - a register read test
if (debugToSerial) Serial.println("TLV320 enable done");
return true;
}
bool AudioControlTLV320AIC3206::disable(void) {
return true;
}
//dummy function to keep compatible with Teensy Audio Library
bool AudioControlTLV320AIC3206::inputLevel(float volume) {
return false;
}
bool AudioControlTLV320AIC3206::inputSelect(int n) {
if (n == AIC3206_INPUT_IN1) {
aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN1 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN1 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS OFF
setMicBias(AIC3206_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to IN1");
return true;
} else if (n == AIC3206_INPUT_IN3_MICBIAS) {
aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS on, using default
setMicBias(AIC3206_DEFAULT_MIC_BIAS);
if (debugToSerial) Serial.println("Set Audio Input to IN3, BIAS SET TO DEFAULT 2.5V");
return true;
} else if (n == AIC3206_INPUT_IN3) {
aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS Off
setMicBias(AIC3206_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to IN3, BIAS OFF");
return true;
} else if (n == AIC3206_INPUT_IN2) {
aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS Off
setMicBias(AIC3206_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to IN2, BIAS OFF");
return true;
}
Serial.print("controlTLV320AIC3206: ERROR: Unable to Select Input - Value not supported: ");
Serial.println(n);
return false;
}
bool AudioControlTLV320AIC3206::setMicBias(int n) {
if (n == AIC3206_MIC_BIAS_1_25) {
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_25); // power up mic bias
return true;
} else if (n == AIC3206_MIC_BIAS_1_7) {
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_7); // power up mic bias
return true;
} else if (n == AIC3206_MIC_BIAS_2_5) {
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_2_5); // power up mic bias
return true;
} else if (n == AIC3206_MIC_BIAS_VSUPPLY) {
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY); // power up mic bias
return true;
} else if (n == AIC3206_MIC_BIAS_OFF) {
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_OFF); // power up mic bias
return true;
}
Serial.print("controlTLV320AIC3206: ERROR: Unable to set MIC BIAS - Value not supported: ");
Serial.println(n);
return false;
}
void AudioControlTLV320AIC3206::aic_reset() {
if (debugToSerial) Serial.println("INFO: Reseting AIC");
aic_writePage(0x00, 0x01, 0x01);
// aic_writeAddress(0x0001, 0x01);
delay(10);
}
// example - turn on IN3 - mic jack, with negatives routed to CM1L and with 10k resistance
// aic_writeAddress(AIC3206_LEFT_MICPGA_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(AIC3206_LEFT_MICPGA_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(AIC3206_RIGHT_MICPGA_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(AIC3206_RIGHT_MICPGA_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
void AudioControlTLV320AIC3206::aic_initADC() {
if (debugToSerial) Serial.println("INFO: Initializing AIC ADC");
aic_writeAddress(AIC3206_ADC_PROCESSING_BLOCK_REG, PRB_R); // processing blocks - ADC
aic_writePage(1, 61, 0); // 0x3D // Select ADC PTM_R4 Power Tune? (this line is from datasheet (application guide, Section 4.2)
aic_writePage(1, 71, 0b00110001); // 0x47 // Set MicPGA startup delay to 3.1ms
aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_2_5); // power up mic bias
aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(AIC3206_MICPGA_LEFT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE); // enable Left MicPGA, set gain to 0 dB
aic_writeAddress(AIC3206_MICPGA_RIGHT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE); // enable Right MicPGA, set gain to 0 dB
aic_writeAddress(AIC3206_ADC_MUTE_REG, AIC3206_ADC_UNMUTE); // Unmute Left and Right ADC Digital Volume Control
aic_writeAddress(AIC3206_ADC_CHANNEL_POWER_REG, AIC3206_ADC_CHANNELS_ON); // Unmute Left and Right ADC Digital Volume Control
}
// set MICPGA volume, 0-47.5dB in 0.5dB setps
bool AudioControlTLV320AIC3206::setInputGain_dB(float volume) {
if (volume < 0.0) {
volume = 0.0; // 0.0 dB
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
}
if (volume > 47.5) {
volume = 47.5; // 47.5 dB
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
}
volume = volume * 2.0; // convert to value map (0.5 dB steps)
int8_t volume_int = (int8_t) (round(volume)); // round
if (debugToSerial) {
Serial.print("INFO: Setting MIC volume to ");
Serial.print(volume, 1);
Serial.print(". Converted to volume map => ");
Serial.println(volume_int);
}
aic_writeAddress(AIC3206_MICPGA_LEFT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE | volume_int); // enable Left MicPGA, set gain to 0 dB
aic_writeAddress(AIC3206_MICPGA_RIGHT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE | volume_int); // enable Right MicPGA, set gain to 0 dB
return true;
}
//******************* OUTPUT DEFINITIONS *****************************//
#define AIC3206_DAC_PROCESSING_BLOCK_REG 0x003c // page 0 register 60
#define AIC3206_DAC_VOLUME_LEFT_REG 0x0041 // page 0 reg 65
#define AIC3206_DAC_VOLUME_RIGHT_REG 0x0042 // page 0 reg 66
//volume control, similar to Teensy Audio Board
// value between 0.0 and 1.0. Set to span -58 to +15 dB
bool AudioControlTLV320AIC3206::volume(float volume) {
volume = max(0.0, min(1.0, volume));
float vol_dB = -58.f + (15.0 - (-58.0f)) * volume;
volume_dB(vol_dB);
return true;
}
bool AudioControlTLV320AIC3206::enableAutoMuteDAC(bool enable, uint8_t mute_delay_code=7) {
if (enable) {
mute_delay_code = max(0,min(mute_delay_code,7));
if (mute_delay_code == 0) enable = false;
} else {
mute_delay_code = 0; //this disables the auto mute
}
uint8_t val = aic_readPage(0,64);
val = val & 0b10001111; //clear these bits
val = val | (mute_delay_code << 4); //set these bits
aic_writePage(0,64,val);
return enable;
}
// -63.6 to +24 dB in 0.5dB steps. uses signed 8-bit
bool AudioControlTLV320AIC3206::volume_dB(float volume) {
// Constrain to limits
if (volume > 24.0) {
volume = 24.0;
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
}
if (volume < -63.5) {
volume = -63.5;
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
}
volume = volume * 2.0; // convert to value map (0.5 dB steps)
int8_t volume_int = (int8_t) (round(volume)); // round
if (debugToSerial) {
Serial.print("controlTLV320AIC3206: Setting DAC volume to ");
Serial.print(volume, 1);
Serial.print(". Converted to volume map => ");
Serial.println(volume_int);
}
aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, volume_int);
aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, volume_int);
return true;
}
void AudioControlTLV320AIC3206::aic_initDAC() {
if (debugToSerial) Serial.println("controlTLV320AIC3206: Initializing AIC DAC");
outputSelect(AIC3206_OUTPUT_HEADPHONE_JACK_OUT); //default
}
bool AudioControlTLV320AIC3206::outputSelect(int n) {
// PLAYBACK SETUP:
// HPL/HPR are headphone output left and right
// LOL/LOR are line output left and right
aic_writeAddress(AIC3206_DAC_PROCESSING_BLOCK_REG, PRB_P); // processing blocks - DAC
//mute, disable, then power-down everything
aic_writePage(1, 16, 0b01000000); // mute HPL Driver, 0 gain
aic_writePage(1, 17, 0b01000000); // mute HPR Driver, 0 gain
aic_writePage(1, 18, 0b01000000); // mute LOL Driver, 0 gain
aic_writePage(1, 19, 0b01000000); // mute LOR Driver, 0 gain
aic_writePage(0, 63, 0); //disable LDAC/RDAC
aic_writePage(1, 9, 0); // Power down HPL/HPR and LOL/LOR drivers
aic_writePage(1,12,0); //unroute from HPL
aic_writePage(1,13,0); //unroute from HPR
aic_writePage(1,14,0); //unroute from LOL
aic_writePage(1,15,0); //unroute from LOR
if (n == AIC3206_OUTPUT_HEADPHONE_JACK_OUT) {
//aic_writePage(1, 20, 0x25); // 0x14 De-Pop
//aic_writePage(1, 12, 8); // route LDAC/RDAC to HPL/HPR
//aic_writePage(1, 13, 8); // route LDAC/RDAC to HPL/HPR
aic_writePage(1, 12, 0b00001000); // route LDAC/RDAC to HPL/HPR
aic_writePage(1, 13, 0b00001000); // route LDAC/RDAC to HPL/HPR
aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
aic_writePage(1, 16, 0); // unmute HPL Driver, 0 gain
aic_writePage(1, 17, 0); // unmute HPR Driver, 0 gain
aic_writePage(1, 9, 0x30); // Power up HPL/HPR drivers 0b00110000
delay(100);
aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Headphone Jack");
return true;
} else if (n == AIC3206_OUTPUT_LINE_OUT) {
//aic_writePage(1, 20, 0x25); // 0x14 De-Pop
aic_writePage(1, 14, 0b00001000); // route LDAC/RDAC to LOL/LOR
aic_writePage(1, 15, 0b00001000); // route LDAC/RDAC to LOL/LOR
aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
aic_writePage(1, 18, 0); // unmute LOL Driver, 0 gain
aic_writePage(1, 19, 0); // unmute LOR Driver, 0 gain
aic_writePage(1, 9, 0b00001100); // Power up LOL/LOR drivers
delay(100);
aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Line Out");
return true;
} else if (n == AIC3206_OUTPUT_HEADPHONE_AND_LINE_OUT) {
aic_writePage(1, 12, 0b00001000); // route LDAC/RDAC to HPL/HPR
aic_writePage(1, 13, 0b00001000); // route LDAC/RDAC to HPL/HPR
aic_writePage(1, 14, 0b00001000); // route LDAC/RDAC to LOL/LOR
aic_writePage(1, 15, 0b00001000); // route LDAC/RDAC to LOL/LOR
aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
aic_writePage(1, 18, 0); // unmute LOL Driver, 0 gain
aic_writePage(1, 19, 0); // unmute LOR Driver, 0 gain
aic_writePage(1, 16, 0); // unmute HPL Driver, 0 gain
aic_writePage(1, 17, 0); // unmute HPR Driver, 0 gain
aic_writePage(1, 9, 0b00111100); // Power up both the HPL/HPR and the LOL/LOR drivers
delay(100);
aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Headphone Jack and Line out");
return true;
}
Serial.print("controlTLV320AIC3206: ERROR: Unable to Select Output - Value not supported: ");
Serial.println(n);
return false;
}
void AudioControlTLV320AIC3206::aic_init() {
if (debugToSerial) Serial.println("controlTLV320AIC3206: Initializing AIC");
// PLL
aic_writePage(0, 4, 3); // 0x04 low PLL clock range, MCLK is PLL input, PLL_OUT is CODEC_CLKIN
aic_writePage(0, 5, (PLL_J != 0 ? 0x91 : 0x11));
aic_writePage(0, 6, PLL_J);
aic_writePage(0, 7, PLL_D >> 8);
aic_writePage(0, 8, PLL_D &0xFF);
// CLOCKS
aic_writePage(0, 11, 0x80 | NDAC); // 0x0B
aic_writePage(0, 12, 0x80 | MDAC); // 0x0C
aic_writePage(0, 13, 0); // 0x0D
aic_writePage(0, 14, DOSR); // 0x0E
// aic_writePage(0, 18, 0); // 0x12 // powered down, ADC_CLK same as DAC_CLK
// aic_writePage(0, 19, 0); // 0x13 // powered down, ADC_MOD_CLK same as DAC_MOD_CLK
aic_writePage(0, 18, 0x80 | NADC); // 0x12
aic_writePage(0, 19, 0x80 | MADC); // 0x13
aic_writePage(0, 20, AOSR);
aic_writePage(0, 30, 0x80 | BCLK_N); // power up BLCK N Divider, default is 128
// POWER
aic_writePage(1, 0x01, 8); // Reg 1, Val = 8 = 0b00001000 = disable weak connection AVDD to DVDD. Keep headphone charge pump disabled.
aic_writePage(1, 0x02, 0); // Reg 2, Val = 0 = 0b00000000 = Enable Master Analog Power Control
aic_writePage(1, 0x7B, 1); // Reg 123, Val = 1 = 0b00000001 = Set reference to power up in 40ms when analog blocks are powered up
aic_writePage(1, 0x7C, 6); // Reg 124, Val = 6 = 0b00000110 = Charge Pump, full peak current (000), clock divider (110) to Div 6 = 333 kHz
aic_writePage(1, 0x01, 10); // Reg 1, Val = 10 = 0x0A = 0b00001010. Activate headphone charge pump.
aic_writePage(1, 0x0A, 0); // Reg 10, Val = 0 = common mode 0.9 for full chip, HP, LO // from WHF/CHA
aic_writePage(1, 0x47, 0x31); // Reg 71, val = 0x31 = 0b00110001 = Set input power-up time to 3.1ms (for ADC)
aic_writePage(1, 0x7D, 0x53); // Reg 125, Val = 0x53 = 0b01010011 = 0 10 1 00 11: HPL is master gain, Enable ground-centered mode, 100% output power, DC offset correction // from WHF/CHA
// !!!!!!!!! The below writes are from WHF/CHA - probably don't need?
// aic_writePage(1, 1, 10); // 10 = 0b00001010 // weakly connect AVDD to DVDD. Activate charge pump
aic_writePage(0, 27, 0x01 | AIC_CLK_DIR | (AIC_BITS == 32 ? 0x30 : 0)); // 0x1B
// aic_writePage(0, 28, 0); // 0x1C
}
unsigned int AudioControlTLV320AIC3206::aic_readPage(uint8_t page, uint8_t reg)
{
unsigned int val;
if (aic_goToPage(page)) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(reg);
unsigned int result = Wire.endTransmission();
if (result != 0) {
Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(". Received Error During Read Page: ");
Serial.println(result);
val = 300 + result;
return val;
}
if (Wire.requestFrom(AIC3206_I2C_ADDR, 1) < 1) {
Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.println(". Nothing to return");
val = 400;
return val;
}
if (Wire.available() >= 1) {
uint16_t val = Wire.read();
if (debugToSerial) {
Serial.print("controlTLV320AIC3206: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(". Received: ");
Serial.println(val, HEX);
}
return val;
}
} else {
Serial.print("controlTLV320AIC3206: INFO: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.println(". Failed to go to read page. Could not go there.");
val = 500;
return val;
}
val = 600;
return val;
}
bool AudioControlTLV320AIC3206::aic_writeAddress(uint16_t address, uint8_t val) {
uint8_t reg = (uint8_t) (address & 0xFF);
uint8_t page = (uint8_t) ((address >> 8) & 0xFF);
return aic_writePage(page, reg, val);
}
bool AudioControlTLV320AIC3206::aic_writePage(uint8_t page, uint8_t reg, uint8_t val) {
if (debugToSerial) {
Serial.print("controlTLV320AIC3206: Write Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(" Val: ");Serial.println(val);
}
if (aic_goToPage(page)) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(reg);delay(10);
Wire.write(val);delay(10);
uint8_t result = Wire.endTransmission();
if (result == 0) return true;
else {
Serial.print("controlTLV320AIC3206: Received Error During writePage(): Error = ");
Serial.println(result);
}
}
return false;
}
bool AudioControlTLV320AIC3206::aic_goToPage(byte page) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(0x00); delay(10);// page register //was delay(10) from BPF
Wire.write(page); delay(10);// go to page //was delay(10) from BPF
byte result = Wire.endTransmission();
if (result != 0) {
Serial.print("controlTLV320AIC3206: Received Error During goToPage(): Error = ");
Serial.println(result);
if (result == 2) {
// failed to transmit address
//return aic_goToPage(page);
} else if (result == 3) {
// failed to transmit data
//return aic_goToPage(page);
}
return false;
}
return true;
}
bool AudioControlTLV320AIC3206::updateInputBasedOnMicDetect(int setting) {
//read current mic detect setting
int curMicDetVal = readMicDetect();
if (curMicDetVal != prevMicDetVal) {
if (curMicDetVal) {
//enable the microphone input jack as our input
inputSelect(setting);
} else {
//switch back to the on-board mics
inputSelect(AIC3206_INPUT_IN2);
}
}
prevMicDetVal = curMicDetVal;
return (bool)curMicDetVal;
}
bool AudioControlTLV320AIC3206::enableMicDetect(bool state) {
//page 0, register 67
byte curVal = aic_readPage(0,67);
byte newVal = curVal;
if (state) {
//enable
newVal = 0b111010111 & newVal; //set bits 4-2 to be 010 to set debounce to 64 msec
newVal = 0b10000000 | curVal; //force bit 1 to 1 to enable headset to detect
aic_writePage(0,67,newVal); //bit 7 (=1) enable headset detect, bits 4-2 (=010) debounce to 64ms
} else {
//disable
newVal = 0b01111111 & newVal; //force bit 7 to zero to disable headset detect
aic_writePage(0,67,newVal); //bit 7 (=1) enable headset detect, bits 4-2 (=010) debounce to 64ms
}
return state;
}
int AudioControlTLV320AIC3206::readMicDetect(void) {
//page 0, register 46, bit D4 (for D7-D0)
byte curVal = aic_readPage(0,46);
curVal = (curVal & 0b00010000);
curVal = (curVal != 0);
return curVal;
}
void computeFirstOrderHPCoeff_F32(float cutoff_Hz, float fs_Hz, float *coeff) {
//cutoff_Hz is the cutoff frequency in Hz
//fs_Hz is the sample rate in Hz
//First-order Butterworth IIR
//From https://www.dsprelated.com/showcode/199.php
const float pi = 3.141592653589793;
float T = 1.0f/fs_Hz; //sample period
float w = cutoff_Hz * 2.0 * pi;
float A = 1.0f / (tan( (w*T) / 2.0));
coeff[0] = A / (1.0 + A); // first b coefficient
coeff[1] = -coeff[0]; // second b coefficient
coeff[2] = (1.0 - A) / (1.0 + A); //second a coefficient (Matlab sign convention)
coeff[2] = -coeff[2]; //flip to be TI sign convention
}
#define CONST_2_31_m1 (2147483647) //2^31 - 1
void computeFirstOrderHPCoeff_i32(float cutoff_Hz, float fs_Hz, int32_t *coeff) {
float coeff_f32[3];
computeFirstOrderHPCoeff_F32(cutoff_Hz,fs_Hz,coeff_f32);
for (int i=0; i<3; i++) {
//scale
coeff_f32[i] *= (float)CONST_2_31_m1;
//truncate
coeff[i] = (int32_t)coeff_f32[i];
}
}
void AudioControlTLV320AIC3206::setHPFonADC(bool enable, float cutoff_Hz, float fs_Hz) { //fs_Hz is sample rate
//see TI application guide Section 2.3.3.1.10.1: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
uint32_t coeff[3];
if (enable) {
HP_cutoff_Hz = cutoff_Hz;
sample_rate_Hz = fs_Hz;
computeFirstOrderHPCoeff_i32(cutoff_Hz,fs_Hz,(int32_t *)coeff);
//Serial.print("enableHPFonADC: coefficients, Hex: ");
//Serial.print(coeff[0],HEX);
//Serial.print(", ");
//Serial.print(coeff[1],HEX);
//Serial.print(", ");
//Serial.print(coeff[2],HEX);
//Serial.println();
} else {
//disable
HP_cutoff_Hz = cutoff_Hz;
//see Table 5-4 in TI application guide Coeff C4, C5, C6
coeff[0] = 0x7FFFFFFF; coeff[1] = 0; coeff[2]=0;
}
setIIRCoeffOnADC(AIC3206_BOTH_CHAN, coeff); //needs twos-compliment
}
//set first-order IIR filter coefficients on ADC
void AudioControlTLV320AIC3206::setIIRCoeffOnADC(int chan, uint32_t *coeff) {
//power down the AIC to allow change in coefficients
uint32_t prev_state = aic_readPage(0x00,0x51);
aic_writePage(0x00,0x51,prev_state & (0b00111111)); //clear first two bits
if (chan == AIC3206_BOTH_CHAN) {
setIIRCoeffOnADC_Left(coeff);
setIIRCoeffOnADC_Right(coeff);
} else if (chan == AIC3206_LEFT_CHAN) {
setIIRCoeffOnADC_Left(coeff);
} else {
setIIRCoeffOnADC_Right(coeff);
}
//power the ADC back up
aic_writePage(0x00,0x51,prev_state); //clear first two bits
}
void AudioControlTLV320AIC3206::setIIRCoeffOnADC_Left(uint32_t *coeff) {
int page;
uint32_t c;
//See TI AIC3206 Application Guide, Table 2-13: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
//Coeff N0, Coeff C4
page = 8;
c = coeff[0];
aic_writePage(page,24,(uint8_t)(c>>24));
aic_writePage(page,25,(uint8_t)(c>>16));
aic_writePage(page,26,(uint8_t)(c>>8));
//int foo = aic_readPage(page,24); Serial.print("setIIRCoeffOnADC: first coefficient: "); Serial.println(foo);
//Coeff N1, Coeff C5
c = coeff[1];
aic_writePage(page,28,(uint8_t)(c>>24));
aic_writePage(page,29,(uint8_t)(c>>16));
aic_writePage(page,30,(uint8_t)(c>>8));
//Coeff N2, Coeff C6
c = coeff[2];
aic_writePage(page,32,(uint8_t)(c>>24));
aic_writePage(page,33,(uint8_t)(c>>16));
aic_writePage(page,34,(uint8_t)(c>>9));
}
void AudioControlTLV320AIC3206::setIIRCoeffOnADC_Right(uint32_t *coeff) {
int page;
uint32_t c;
//See TI AIC3206 Application Guide, Table 2-13: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
//Coeff N0, Coeff C36
page = 9;
c = coeff[0];
aic_writePage(page,32,(uint8_t)(c>>24));
aic_writePage(page,33,(uint8_t)(c>>16));
aic_writePage(page,34,(uint8_t)(c>>8));
//Coeff N1, Coeff C37
c = coeff[1];
aic_writePage(page,36,(uint8_t)(c>>24));
aic_writePage(page,37,(uint8_t)(c>>16));
aic_writePage(page,38,(uint8_t)(c>>8));
//Coeff N2, Coeff C39
c = coeff[2];;
aic_writePage(page,40,(uint8_t)(c>>24));
aic_writePage(page,41,(uint8_t)(c>>16));
aic_writePage(page,42,(uint8_t)(c>>8));
}

View file

@ -0,0 +1,128 @@
/*
control_tlv320aic3206
Created: Brendan Flynn (http://www.flexvoltbiosensor.com/) for Tympan, Jan-Feb 2017
Modified: Chip Audette (https://openaudio.blogspot.com) for Tympan 2017-2018
Purpose: Control module for Texas Instruments TLV320AIC3206 compatible with Teensy Audio Library
License: MIT License. Use at your own risk.
Note that the TLV320AIC3206 has a reset that should be connected to microcontroller.
This code defaults to Teensy Pin 21, which was used on Tympan Rev C.
You can set the reset pin in the constructor
Note that this can configure the AIC for 32-bit per sample I2S transfers or 16-bit per sample.
Defaults to 16 bits per sample to allow it to work with default Teensy audio library.
Example Usage for Teensy:
#include <Audio.h> //Teensy Audio Library
int AIC3206_RESET_PIN=21; //What pin is your AIC3206 reset pin connected to?
AudioControlTLV320AIC3206 audioHardware(AIC3206_RESET_PIN);
AudioInputI2S i2s_in; //Digital audio *from* the AIC.
AudioOutputI2S i2s_out; //Digital audio *to* the AIC.
AudioConnection patchCord1(i2s_in, 0, i2s_out, 0); //connect left input to left output
AudioConnection patchCord2(i2s_in, 1, i2s_out, 1); //connect right input to right output
void setup(void)
{
//begin the serial comms (for debugging)
Serial.begin(115200); delay(500);
Serial.println("AudioPassThru: Starting setup()...");
//allocate the dynamic memory for audio processing blocks
AudioMemory(10);
//Enable the TLV32AIC3206 to start the audio flowing!
audioHardware.enable(); // activate AIC
//Choose the desired input
audioHardware.inputSelect(AIC3206_INPUT_IN1); // use Input 1
//Set the desired volume levels
audioHardware.volume_dB(0); // headphone amplifier. -63.6 to +24 dB in 0.5dB steps.
audioHardware.setInputGain_dB(10.0); // set input volume, 0-47.5dB in 0.5dB setps
}
void loop(void)
{
// Nothing to do
}
*/
#ifndef control_tlv320aic3206_h_
#define control_tlv320aic3206_h_
#include "AudioControl.h"
#include <Arduino.h>
//convenience names to use with inputSelect() to set whnch analog inputs to use
#define AIC3206_INPUT_IN1 1 //uses IN1
#define AIC3206_INPUT_IN2 2 //uses IN2 analog inputs
#define AIC3206_INPUT_IN3 3 //uses IN3 analog inputs
#define AIC3206_INPUT_IN3_MICBIAS 4 //uses IN3 analog inputs *and* enables mic bias
//convenience names to use with outputSelect()
#define AIC3206_OUTPUT_HEADPHONE_JACK_OUT 1
#define AIC3206_OUTPUT_LINE_OUT 2
#define AIC3206_OUTPUT_HEADPHONE_AND_LINE_OUT 3
//names to use with setMicBias() to set the amount of bias voltage to use
#define AIC3206_MIC_BIAS_OFF 0
#define AIC3206_MIC_BIAS_1_25 1
#define AIC3206_MIC_BIAS_1_7 2
#define AIC3206_MIC_BIAS_2_5 3
#define AIC3206_MIC_BIAS_VSUPPLY 4
#define AIC3206_DEFAULT_MIC_BIAS AIC3206_MIC_BIAS_2_5
#define AIC3206_BOTH_CHAN 0
#define AIC3206_LEFT_CHAN 1
#define AIC3206_RIGHT_CHAN 2
class AudioControlTLV320AIC3206: public AudioControl
{
public:
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
AudioControlTLV320AIC3206(void) { debugToSerial = false; };
AudioControlTLV320AIC3206(bool _debugToSerial) { debugToSerial = _debugToSerial; };
AudioControlTLV320AIC3206(int _resetPin) { debugToSerial = false; resetPinAIC = _resetPin; }
AudioControlTLV320AIC3206(int _resetPin, bool _debugToSerial) { resetPinAIC = _resetPin; debugToSerial = _debugToSerial; };
bool enable(void);
bool disable(void);
bool outputSelect(int n); //use AIC3206_OUTPUT_HEADPHONE_JACK_OUT or one of other choices defined earlier
bool volume(float n);
bool volume_dB(float n);
bool inputLevel(float n); //dummy to be compatible with Teensy Audio Library
bool inputSelect(int n); //use AIC3206_INPUT_IN1 or one of other choices defined earlier
bool setInputGain_dB(float n);
bool setMicBias(int n); //use AIC3206_MIC_BIAS_OFF or AIC3206_MIC_BIAS_2_5 or one of other choices defined earlier
bool updateInputBasedOnMicDetect(int setting = AIC3206_INPUT_IN1); //which input to monitor
bool enableMicDetect(bool);
int readMicDetect(void);
bool debugToSerial;
unsigned int aic_readPage(uint8_t page, uint8_t reg);
bool aic_writePage(uint8_t page, uint8_t reg, uint8_t val);
void setHPFonADC(bool enable, float cutoff_Hz, float fs_Hz);
float getHPCutoff_Hz(void) { return HP_cutoff_Hz; }
float getSampleRate_Hz(void) { return sample_rate_Hz; }
void setIIRCoeffOnADC(int chan, uint32_t *coeff); //for chan, use AIC3206_BOTH_CHAN or AIC3206_LEFT_CHAN or AIC3206_RIGHT_CHAN
bool enableAutoMuteDAC(bool, uint8_t);
private:
void aic_reset(void);
void aic_init(void);
void aic_initDAC(void);
void aic_initADC(void);
bool aic_writeAddress(uint16_t address, uint8_t val);
bool aic_goToPage(uint8_t page);
int prevMicDetVal = -1;
int resetPinAIC = 21; //AIC reset pin, Tympan Rev C
float HP_cutoff_Hz = 0.0f;
float sample_rate_Hz = 44100; //only used with HP_cutoff_Hz to design HP filter on ADC, if used
void setIIRCoeffOnADC_Left(uint32_t *coeff);
void setIIRCoeffOnADC_Right(uint32_t *coeff);
};
#endif

View file

@ -0,0 +1,159 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "control_wm8731.h"
#include "Wire.h"
#define WM8731_I2C_ADDR 0x1A
//#define WM8731_I2C_ADDR 0x1B
#define WM8731_REG_LLINEIN 0
#define WM8731_REG_RLINEIN 1
#define WM8731_REG_LHEADOUT 2
#define WM8731_REG_RHEADOUT 3
#define WM8731_REG_ANALOG 4
#define WM8731_REG_DIGITAL 5
#define WM8731_REG_POWERDOWN 6
#define WM8731_REG_INTERFACE 7
#define WM8731_REG_SAMPLING 8
#define WM8731_REG_ACTIVE 9
#define WM8731_REG_RESET 15
bool AudioControlWM8731::enable(void)
{
Wire.begin();
delay(5);
//write(WM8731_REG_RESET, 0);
write(WM8731_REG_INTERFACE, 0x02); // I2S, 16 bit, MCLK slave
write(WM8731_REG_SAMPLING, 0x20); // 256*Fs, 44.1 kHz, MCLK/1
// In order to prevent pops, the DAC should first be soft-muted (DACMU),
// the output should then be de-selected from the line and headphone output
// (DACSEL), then the DAC powered down (DACPD).
write(WM8731_REG_DIGITAL, 0x08); // DAC soft mute
write(WM8731_REG_ANALOG, 0x00); // disable all
write(WM8731_REG_POWERDOWN, 0x00); // codec powerdown
write(WM8731_REG_LHEADOUT, 0x80); // volume off
write(WM8731_REG_RHEADOUT, 0x80);
delay(100); // how long to power up?
write(WM8731_REG_ACTIVE, 1);
delay(5);
write(WM8731_REG_DIGITAL, 0x00); // DAC unmuted
write(WM8731_REG_ANALOG, 0x10); // DAC selected
return true;
}
bool AudioControlWM8731::write(unsigned int reg, unsigned int val)
{
Wire.beginTransmission(WM8731_I2C_ADDR);
Wire.write((reg << 1) | ((val >> 8) & 1));
Wire.write(val & 0xFF);
Wire.endTransmission();
return true;
}
bool AudioControlWM8731::volumeInteger(unsigned int n)
{
// n = 127 for max volume (+6 dB)
// n = 48 for min volume (-73 dB)
// n = 0 to 47 for mute
if (n > 127) n = 127;
//Serial.print("volumeInteger, n = ");
//Serial.println(n);
write(WM8731_REG_LHEADOUT, n | 0x180);
write(WM8731_REG_RHEADOUT, n | 0x80);
return true;
}
bool AudioControlWM8731::inputLevel(float n)
{
// range is 0x00 (min) - 0x1F (max)
int _level = int(n * 31.f);
_level = _level > 0x1F ? 0x1F : _level;
write(WM8731_REG_LLINEIN, _level);
write(WM8731_REG_RLINEIN, _level);
return true;
}
bool AudioControlWM8731::inputSelect(int n)
{
if (n == AUDIO_INPUT_LINEIN) {
write(WM8731_REG_ANALOG, 0x12);
} else if (n == AUDIO_INPUT_MIC) {
write(WM8731_REG_ANALOG, 0x15);
} else {
return false;
}
return true;
}
/******************************************************************/
bool AudioControlWM8731master::enable(void)
{
Wire.begin();
delay(5);
//write(WM8731_REG_RESET, 0);
write(WM8731_REG_INTERFACE, 0x42); // I2S, 16 bit, MCLK master
write(WM8731_REG_SAMPLING, 0x20); // 256*Fs, 44.1 kHz, MCLK/1
// In order to prevent pops, the DAC should first be soft-muted (DACMU),
// the output should then be de-selected from the line and headphone output
// (DACSEL), then the DAC powered down (DACPD).
write(WM8731_REG_DIGITAL, 0x08); // DAC soft mute
write(WM8731_REG_ANALOG, 0x00); // disable all
write(WM8731_REG_POWERDOWN, 0x00); // codec powerdown
write(WM8731_REG_LHEADOUT, 0x80); // volume off
write(WM8731_REG_RHEADOUT, 0x80);
delay(100); // how long to power up?
write(WM8731_REG_ACTIVE, 1);
delay(5);
write(WM8731_REG_DIGITAL, 0x00); // DAC unmuted
write(WM8731_REG_ANALOG, 0x10); // DAC selected
return true;
}

View file

@ -0,0 +1,51 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#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 * 80.0 + 47.499); }
bool inputLevel(float n); // range: 0.0f to 1.0f
bool inputSelect(int n);
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

View file

@ -0,0 +1,120 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
const int16_t ulaw_decode_table[256] = {
4, 12, 20, 28, 36, 44, 52, 60, 68, 76,
84, 92, 100, 108, 116, 124, 136, 152, 168, 184,
200, 216, 232, 248, 264, 280, 296, 312, 328, 344,
360, 376, 400, 432, 464, 496, 528, 560, 592, 624,
656, 688, 720, 752, 784, 816, 848, 880, 928, 992,
1056, 1120, 1184, 1248, 1312, 1376, 1440, 1504, 1568, 1632,
1696, 1760, 1824, 1888, 1984, 2112, 2240, 2368, 2496, 2624,
2752, 2880, 3008, 3136, 3264, 3392, 3520, 3648, 3776, 3904,
4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, 6144, 6400,
6656, 6912, 7168, 7424, 7680, 7936, 8320, 8832, 9344, 9856,
10368, 10880, 11392, 11904, 12416, 12928, 13440, 13952, 14464, 14976,
15488, 16000, 16768, 17792, 18816, 19840, 20864, 21888, 22912, 23936,
24960, 25984, 27008, 28032, 29056, 30080, 31104, 32128, -4, -12,
-20, -28, -36, -44, -52, -60, -68, -76, -84, -92,
-100, -108, -116, -124, -136, -152, -168, -184, -200, -216,
-232, -248, -264, -280, -296, -312, -328, -344, -360, -376,
-400, -432, -464, -496, -528, -560, -592, -624, -656, -688,
-720, -752, -784, -816, -848, -880, -928, -992, -1056, -1120,
-1184, -1248, -1312, -1376, -1440, -1504, -1568, -1632, -1696, -1760,
-1824, -1888, -1984, -2112, -2240, -2368, -2496, -2624, -2752, -2880,
-3008, -3136, -3264, -3392, -3520, -3648, -3776, -3904, -4096, -4352,
-4608, -4864, -5120, -5376, -5632, -5888, -6144, -6400, -6656, -6912,
-7168, -7424, -7680, -7936, -8320, -8832, -9344, -9856,-10368,-10880,
-11392,-11904,-12416,-12928,-13440,-13952,-14464,-14976,-15488,-16000,
-16768,-17792,-18816,-19840,-20864,-21888,-22912,-23936,-24960,-25984,
-27008,-28032,-29056,-30080,-31104,-32128
};
/*
#! /usr/bin/perl
print "const int16_t ulaw_decode_table[256] = {\n";
for ($i=0; $i < 256; $i++) {
$r = ($i >> 4) & 7;
$n = ($i & 0xF) << ($r + 3);
$n |= 1 << ($r + 7);
$n |= 1 << ($r + 2);
$n -= 128;
$n *= -1 if $i > 127;
printf "%6d", $n + 0;
print "," if ($i < 255);
print "\n" if ($i % 10) == 9;
}
print "\n};\n";
*/
/*
const int16_t ulaw_decode_table[256] = {
0, 8, 16, 24, 32, 40, 48, 56, 64, 72,
80, 88, 96, 104, 112, 120, 128, 144, 160, 176,
192, 208, 224, 240, 256, 272, 288, 304, 320, 336,
352, 368, 384, 416, 448, 480, 512, 544, 576, 608,
640, 672, 704, 736, 768, 800, 832, 864, 896, 960,
1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600,
1664, 1728, 1792, 1856, 1920, 2048, 2176, 2304, 2432, 2560,
2688, 2816, 2944, 3072, 3200, 3328, 3456, 3584, 3712, 3840,
3968, 4224, 4480, 4736, 4992, 5248, 5504, 5760, 6016, 6272,
6528, 6784, 7040, 7296, 7552, 7808, 8064, 8576, 9088, 9600,
10112, 10624, 11136, 11648, 12160, 12672, 13184, 13696, 14208, 14720,
15232, 15744, 16256, 17280, 18304, 19328, 20352, 21376, 22400, 23424,
24448, 25472, 26496, 27520, 28544, 29568, 30592, 31616, 0, -8,
-16, -24, -32, -40, -48, -56, -64, -72, -80, -88,
-96, -104, -112, -120, -128, -144, -160, -176, -192, -208,
-224, -240, -256, -272, -288, -304, -320, -336, -352, -368,
-384, -416, -448, -480, -512, -544, -576, -608, -640, -672,
-704, -736, -768, -800, -832, -864, -896, -960, -1024, -1088,
-1152, -1216, -1280, -1344, -1408, -1472, -1536, -1600, -1664, -1728,
-1792, -1856, -1920, -2048, -2176, -2304, -2432, -2560, -2688, -2816,
-2944, -3072, -3200, -3328, -3456, -3584, -3712, -3840, -3968, -4224,
-4480, -4736, -4992, -5248, -5504, -5760, -6016, -6272, -6528, -6784,
-7040, -7296, -7552, -7808, -8064, -8576, -9088, -9600,-10112,-10624,
-11136,-11648,-12160,-12672,-13184,-13696,-14208,-14720,-15232,-15744,
-16256,-17280,-18304,-19328,-20352,-21376,-22400,-23424,-24448,-25472,
-26496,-27520,-28544,-29568,-30592,-31616
};
*/
/*
#! /usr/bin/perl
print "const int16_t ulaw_decode_table[256] = {\n";
for ($i=0; $i < 256; $i++) {
$r = ($i >> 4) & 7;
$n = ($i & 0xF) << ($r + 3);
$n |= 1 << ($r + 7);
$n -= 128;
$n *= -1 if $i > 127;
printf "%6d", $n + 0;
print "," if ($i < 255);
print "\n" if ($i % 10) == 9;
}
print "\n};\n";
*/

View file

@ -0,0 +1,123 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
// These audio waveforms have a period of 256 points, plus a 257th
// point that is a duplicate of the first point. This duplicate
// is needed because the waveform generator uses linear interpolation
// between each point and the next point in the waveform.
const int16_t AudioWaveformSine[257] = {
0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179,
7962, 8739, 9512, 10278, 11039, 11793, 12539, 13279, 14010, 14732,
15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403,
22005, 22594, 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790,
27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956, 30273, 30571,
30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521,
32609, 32678, 32728, 32757, 32767, 32757, 32728, 32678, 32609, 32521,
32412, 32285, 32137, 31971, 31785, 31580, 31356, 31113, 30852, 30571,
30273, 29956, 29621, 29268, 28898, 28510, 28105, 27683, 27245, 26790,
26319, 25832, 25329, 24811, 24279, 23731, 23170, 22594, 22005, 21403,
20787, 20159, 19519, 18868, 18204, 17530, 16846, 16151, 15446, 14732,
14010, 13279, 12539, 11793, 11039, 10278, 9512, 8739, 7962, 7179,
6393, 5602, 4808, 4011, 3212, 2410, 1608, 804, 0, -804,
-1608, -2410, -3212, -4011, -4808, -5602, -6393, -7179, -7962, -8739,
-9512,-10278,-11039,-11793,-12539,-13279,-14010,-14732,-15446,-16151,
-16846,-17530,-18204,-18868,-19519,-20159,-20787,-21403,-22005,-22594,
-23170,-23731,-24279,-24811,-25329,-25832,-26319,-26790,-27245,-27683,
-28105,-28510,-28898,-29268,-29621,-29956,-30273,-30571,-30852,-31113,
-31356,-31580,-31785,-31971,-32137,-32285,-32412,-32521,-32609,-32678,
-32728,-32757,-32767,-32757,-32728,-32678,-32609,-32521,-32412,-32285,
-32137,-31971,-31785,-31580,-31356,-31113,-30852,-30571,-30273,-29956,
-29621,-29268,-28898,-28510,-28105,-27683,-27245,-26790,-26319,-25832,
-25329,-24811,-24279,-23731,-23170,-22594,-22005,-21403,-20787,-20159,
-19519,-18868,-18204,-17530,-16846,-16151,-15446,-14732,-14010,-13279,
-12539,-11793,-11039,-10278, -9512, -8739, -7962, -7179, -6393, -5602,
-4808, -4011, -3212, -2410, -1608, -804, 0
};
#if 0
#! /usr/bin/perl
use Math::Trig ':pi';
$len = 256;
print "const int16_t AudioWaveformSine[257] = {\n";
for ($i=0; $i <= $len; $i++) {
$f = sin($i / $len * 2 * pi);
$d = sprintf "%.0f", $f * 32767.0;
#print $d;
printf "%6d", $d + 0;
print "," if ($i < $len);
print "\n" if ($i % 10) == 9;
}
print "\n" unless ($len % 10) == 9;
print "};\n";
#endif
const int16_t fader_table[257] = {
0, 1, 4, 11, 19, 30, 44, 60, 78, 99,
123, 149, 177, 208, 241, 276, 314, 355, 398, 443,
490, 541, 593, 648, 705, 764, 826, 891, 957, 1026,
1097, 1171, 1247, 1325, 1405, 1488, 1572, 1660, 1749, 1840,
1934, 2030, 2128, 2228, 2330, 2435, 2541, 2650, 2761, 2873,
2988, 3105, 3224, 3344, 3467, 3592, 3718, 3847, 3977, 4109,
4243, 4379, 4517, 4657, 4798, 4941, 5086, 5232, 5380, 5530,
5682, 5835, 5989, 6145, 6303, 6462, 6623, 6785, 6949, 7114,
7281, 7448, 7618, 7788, 7960, 8133, 8307, 8483, 8660, 8838,
9017, 9197, 9378, 9560, 9743, 9928,10113,10299,10486,10674,
10863,11053,11244,11435,11627,11820,12013,12207,12402,12597,
12793,12989,13186,13384,13582,13780,13979,14178,14377,14577,
14777,14977,15177,15378,15579,15780,15981,16182,16383,16584,
16785,16986,17187,17387,17588,17788,17989,18188,18388,18588,
18787,18985,19184,19382,19579,19776,19972,20168,20364,20558,
20752,20946,21139,21331,21522,21712,21902,22091,22279,22466,
22652,22838,23022,23205,23388,23569,23749,23928,24106,24283,
24458,24633,24806,24977,25148,25317,25485,25651,25817,25980,
26142,26303,26463,26620,26776,26931,27084,27236,27385,27534,
27680,27825,27968,28109,28249,28386,28522,28656,28789,28919,
29048,29174,29299,29422,29542,29661,29778,29893,30006,30116,
30225,30331,30436,30538,30638,30736,30832,30926,31017,31107,
31194,31279,31361,31442,31520,31596,31669,31740,31809,31876,
31940,32002,32062,32119,32174,32226,32276,32324,32369,32412,
32452,32490,32526,32559,32590,32618,32644,32667,32688,32707,
32723,32737,32748,32756,32763,32766,32767
};
#if 0
#! /usr/bin/perl
print "const int16_t fader_table[257] = {\n";
$len = 256;
for ($i=0; $i < $len+1; $i++) {
$a = cos(3.14149 * $i / $len);
$in = (1 - $a) / 2;
$d = $in * 32768;
$d = 32767 if $d >= 32767.5;
printf "%5d", $d;
print "," if ($i < $len);
print "\n" if ($i % 10) == 9;
}
print "\n};\n";
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
Please use this form only to report code defects or bugs.
For any question, even questions directly pertaining to this code, post your question on the forum.
Teensy: forum.pjrc.com
If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code!
Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software.
----------------------------- Remove above -----------------------------
### Description
Describe your problem.
### Steps To Reproduce Problem
Please give detailed instructions needed for anyone to attempt to reproduce the problem.
### Hardware & Software
Board
Shields / modules used
Arduino IDE version
Teensyduino version
Operating system & version
Any other software or hardware?
### Arduino Sketch
```cpp
// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem)
#include <Arduino.h>
// libraries: give links/details so anyone can compile your code for the same result
void setup() {
}
void loop() {
}
```
### Errors or Incorrect Output
If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears.

View file

@ -0,0 +1,97 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Jonathan Payne (jon@jonnypayne.com)
* Based on Effect_Fade by Paul Stoffregen
* Also samplerate reduction based on Pete Brown's bitcrusher here:
* http://10rem.net/blog/2013/01/13/a-simple-bitcrusher-and-sample-rate-reducer-in-cplusplus-for-a-windows-store-app
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_bitcrusher.h"
void AudioEffectBitcrusher::update(void)
{
audio_block_t *block;
uint32_t i;
uint32_t sampleSquidge, sampleSqueeze; //squidge is bitdepth, squeeze is for samplerate
if (crushBits == 16 && sampleStep <= 1) {
// nothing to do. Output is sent through clean, then exit the function
block = receiveReadOnly();
if (!block) return;
transmit(block);
release(block);
return;
}
// start of processing functions. Could be more elegant based on external
// functions but left like this to enable code optimisation later.
block = receiveWritable();
if (!block) return;
if (sampleStep <= 1) { //no sample rate mods, just crush the bitdepth.
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
// shift bits right to cut off fine detail sampleSquidge is a
// uint32 so sign extension will not occur, fills with zeroes.
sampleSquidge = block->data[i] >> (16-crushBits);
// shift bits left again to regain the volume level.
// fills with zeroes.
block->data[i] = sampleSquidge << (16-crushBits);
}
} else if (crushBits == 16) { //bitcrusher not being used, samplerate mods only.
i=0;
while (i < AUDIO_BLOCK_SAMPLES) {
// save the root sample. this will pick up a root
// sample every _sampleStep_ samples.
sampleSqueeze = block->data[i];
for (int j = 0; j < sampleStep && i < AUDIO_BLOCK_SAMPLES; j++) {
// for each repeated sample, paste in the current
// root sample, then move onto the next step.
block->data[i] = sampleSqueeze;
i++;
}
}
} else { //both being used. crush those bits and mash those samples.
i=0;
while (i < AUDIO_BLOCK_SAMPLES) {
// save the root sample. this will pick up a root sample
// every _sampleStep_ samples.
sampleSqueeze = block->data[i];
for (int j = 0; j < sampleStep && i < AUDIO_BLOCK_SAMPLES; j++) {
// shift bits right to cut off fine detail sampleSquidge
// is a uint32 so sign extension will not occur, fills
// with zeroes.
sampleSquidge = sampleSqueeze >> (16-crushBits);
// shift bits left again to regain the volume level.
// fills with zeroes. paste into buffer sample +
// sampleStep offset.
block->data[i] = sampleSquidge << (16-crushBits);
i++;
}
}
}
transmit(block);
release(block);
}

View file

@ -0,0 +1,58 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Jonathan Payne (jon@jonnypayne.com)
* Based on Effect_Fade by Paul Stoffregen
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_bitcrusher_h_
#define effect_bitcrusher_h_
#include "Arduino.h"
#include "AudioStream.h"
class AudioEffectBitcrusher : public AudioStream
{
public:
AudioEffectBitcrusher(void)
: AudioStream(1, inputQueueArray) {}
void bits(uint8_t b) {
if (b > 16) b = 16;
else if (b == 0) b = 1;
crushBits = b;
}
void sampleRate(float hz) {
int n = (AUDIO_SAMPLE_RATE_EXACT / hz) + 0.5;
if (n < 1) n = 1;
else if (n > 64) n = 64;
sampleStep = n;
}
virtual void update(void);
private:
uint8_t crushBits; // 16 = off
uint8_t sampleStep; // the number of samples to double up. This simple technique only allows a few stepped positions.
audio_block_t *inputQueueArray[1];
};
#endif

View file

@ -0,0 +1,131 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Pete (El Supremo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_chorus.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
// 140529 - change to handle mono stream - change modify() to voices()
// 140219 - correct storage class (not static)
boolean AudioEffectChorus::begin(short *delayline,int d_length,int n_chorus)
{
#if 0
Serial.print("AudioEffectChorus.begin(Chorus delay line length = ");
Serial.print(d_length);
Serial.print(", n_chorus = ");
Serial.print(n_chorus);
Serial.println(")");
#endif
l_delayline = NULL;
delay_length = 0;
l_circ_idx = 0;
if(delayline == NULL) {
return(false);
}
if(d_length < 10) {
return(false);
}
if(n_chorus < 1) {
return(false);
}
l_delayline = delayline;
delay_length = d_length/2;
num_chorus = n_chorus;
return(true);
}
void AudioEffectChorus::voices(int n_chorus)
{
num_chorus = n_chorus;
}
//int last_idx = 0;
void AudioEffectChorus::update(void)
{
audio_block_t *block;
short *bp;
int sum;
int c_idx;
if(l_delayline == NULL)return;
// do passthru
// It stores the unmodified data in the delay line so that
// it isn't as likely to click
if(num_chorus <= 1) {
// Just passthrough
block = receiveWritable(0);
if(block) {
bp = block->data;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
l_circ_idx++;
if(l_circ_idx >= delay_length) {
l_circ_idx = 0;
}
l_delayline[l_circ_idx] = *bp++;
}
transmit(block,0);
release(block);
}
return;
}
// L E F T C H A N N E L
block = receiveWritable(0);
if(block) {
bp = block->data;
uint32_t tmp = delay_length/(num_chorus - 1) - 1;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
l_circ_idx++;
if(l_circ_idx >= delay_length) {
l_circ_idx = 0;
}
l_delayline[l_circ_idx] = *bp;
sum = 0;
c_idx = l_circ_idx;
for(int k = 0; k < num_chorus; k++) {
sum += l_delayline[c_idx];
if(num_chorus > 1)c_idx -= tmp;
if(c_idx < 0) {
c_idx += delay_length;
}
}
*bp++ = sum/num_chorus;
}
// transmit the block
transmit(block,0);
release(block);
}
}

View file

@ -0,0 +1,57 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Pete (El Supremo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_chorus_h_
#define effect_chorus_h_
#include "Arduino.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
// 140219 - correct storage class (not static)
#define CHORUS_DELAY_PASSTHRU -1
class AudioEffectChorus :
public AudioStream
{
public:
AudioEffectChorus(void):
AudioStream(1,inputQueueArray), num_chorus(2)
{ }
boolean begin(short *delayline,int delay_length,int n_chorus);
virtual void update(void);
void voices(int n_chorus);
private:
audio_block_t *inputQueueArray[1];
short *l_delayline;
short l_circ_idx;
int num_chorus;
int delay_length;
};
#endif

View file

@ -0,0 +1,80 @@
/*
* Copyright (c) 2018 John-Michael Reed
* bleeplabs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Combine analog signals with bitwise expressions like XOR.
// Combining two simple oscillators results in interesting new waveforms,
// Combining white noise or dynamic incoming audio results in aggressive digital distortion.
#include <Arduino.h>
#include "effect_combine.h"
void AudioEffectDigitalCombine::update(void)
{
audio_block_t *blocka, *blockb;
uint32_t *pa, *pb, *end;
uint32_t a12, a34; //, a56, a78;
uint32_t b12, b34; //, b56, b78;
blocka = receiveWritable(0);
blockb = receiveReadOnly(1);
if (!blocka) {
if (blockb) release(blockb);
return;
}
if (!blockb) {
release(blocka);
return;
}
pa = (uint32_t *)(blocka->data);
pb = (uint32_t *)(blockb->data);
end = pa + AUDIO_BLOCK_SAMPLES / 2;
while (pa < end) {
a12 = *pa;
a34 = *(pa + 1);
b12 = *pb++;
b34 = *pb++;
if (mode_sel == OR) {
a12 = a12 | b12;
a34 = a34 | b34;
}
if (mode_sel == XOR) {
a12 = a12 ^ b12;
a34 = a34 ^ b34;
}
if (mode_sel == AND) {
a12 = a12 & b12;
a34 = a34 & b34;
}
if (mode_sel == MODULO) {
a12 = a12 % b12;
a34 = a34 % b34;
}
*pa++ = a12;
*pa++ = a34;
}
transmit(blocka);
release(blocka);
release(blockb);
}

View file

@ -0,0 +1,58 @@
/* Copyright (c) 2018 John-Michael Reed
* bleeplabs.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Combine analog signals with bitwise expressions like XOR.
* Combining two simple oscillators results in interesting new waveforms,
* Combining white noise or dynamic incoming audio results in aggressive digital distortion.
*/
#ifndef effect_digital_combine_h_
#define effect_digital_combine_h_
#include <Arduino.h>
#include "AudioStream.h"
class AudioEffectDigitalCombine : public AudioStream
{
public:
enum combineMode {
OR = 0,
XOR = 1,
AND = 2,
MODULO = 3,
};
AudioEffectDigitalCombine() : AudioStream(2, inputQueueArray), mode_sel(OR) { }
void setCombineMode(int mode_in) {
if (mode_in > 3) {
mode_in = 3;
}
mode_sel = mode_in;
}
virtual void update(void);
private:
short mode_sel;
audio_block_t *inputQueueArray[2];
};
#endif

View file

@ -0,0 +1,138 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_delay.h"
void AudioEffectDelay::update(void)
{
audio_block_t *output;
uint32_t head, tail, count, channel, index, prev, offset;
const int16_t *src, *end;
int16_t *dst;
// grab incoming data and put it into the queue
head = headindex;
tail = tailindex;
if (++head >= DELAY_QUEUE_SIZE) head = 0;
if (head == tail) {
if (queue[tail] != NULL) release(queue[tail]);
if (++tail >= DELAY_QUEUE_SIZE) tail = 0;
}
queue[head] = receiveReadOnly();
headindex = head;
// testing only.... don't allow null pointers into the queue
// instead, fill the empty times with blocks of zeros
//if (queue[head] == NULL) {
// queue[head] = allocate();
// if (queue[head]) {
// dst = queue[head]->data;
// end = dst + AUDIO_BLOCK_SAMPLES;
// do {
// *dst++ = 0;
// } while (dst < end);
// } else {
// digitalWriteFast(2, HIGH);
// delayMicroseconds(5);
// digitalWriteFast(2, LOW);
// }
//}
// discard unneeded blocks from the queue
if (head >= tail) {
count = head - tail;
} else {
count = DELAY_QUEUE_SIZE + head - tail;
}
if (count > maxblocks) {
count -= maxblocks;
do {
if (queue[tail] != NULL) {
release(queue[tail]);
queue[tail] = NULL;
}
if (++tail >= DELAY_QUEUE_SIZE) tail = 0;
} while (--count > 0);
}
tailindex = tail;
// transmit the delayed outputs using queue data
for (channel = 0; channel < 8; channel++) {
if (!(activemask & (1<<channel))) continue;
index = position[channel] / AUDIO_BLOCK_SAMPLES;
offset = position[channel] % AUDIO_BLOCK_SAMPLES;
if (head >= index) {
index = head - index;
} else {
index = DELAY_QUEUE_SIZE + head - index;
}
if (offset == 0) {
// delay falls on the block boundary
if (queue[index]) {
transmit(queue[index], channel);
}
} else {
// delay requires grabbing data from 2 blocks
output = allocate();
if (!output) continue;
dst = output->data;
if (index > 0) {
prev = index - 1;
} else {
prev = DELAY_QUEUE_SIZE-1;
}
if (queue[prev]) {
end = queue[prev]->data + AUDIO_BLOCK_SAMPLES;
src = end - offset;
while (src < end) {
*dst++ = *src++; // TODO: optimize
}
} else {
end = dst + offset;
while (dst < end) {
*dst++ = 0;
}
}
end = output->data + AUDIO_BLOCK_SAMPLES;
if (queue[index]) {
src = queue[index]->data;
while (dst < end) {
*dst++ = *src++; // TODO: optimize
}
} else {
while (dst < end) {
*dst++ = 0;
}
}
transmit(output, channel);
release(output);
}
}
}

View file

@ -0,0 +1,115 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_delay_h_
#define effect_delay_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "utility/dspinst.h"
#if defined(__MK66FX1M0__)
// 2.41 second maximum on Teensy 3.6
#define DELAY_QUEUE_SIZE (106496 / AUDIO_BLOCK_SAMPLES)
#elif defined(__MK64FX512__)
// 1.67 second maximum on Teensy 3.5
#define DELAY_QUEUE_SIZE (73728 / AUDIO_BLOCK_SAMPLES)
#elif defined(__MK20DX256__)
// 0.45 second maximum on Teensy 3.1 & 3.2
#define DELAY_QUEUE_SIZE (19826 / AUDIO_BLOCK_SAMPLES)
#else
// 0.14 second maximum on Teensy 3.0
#define DELAY_QUEUE_SIZE (6144 / AUDIO_BLOCK_SAMPLES)
#endif
class AudioEffectDelay : public AudioStream
{
public:
AudioEffectDelay() : AudioStream(1, inputQueueArray) {
activemask = 0;
headindex = 0;
tailindex = 0;
maxblocks = 0;
memset(queue, 0, sizeof(queue));
}
void delay(uint8_t channel, float milliseconds) {
if (channel >= 8) return;
if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0))+0.5;
uint32_t nmax = AUDIO_BLOCK_SAMPLES * (DELAY_QUEUE_SIZE-1);
if (n > nmax) n = nmax;
uint32_t blks = (n + (AUDIO_BLOCK_SAMPLES-1)) / AUDIO_BLOCK_SAMPLES + 1;
if (!(activemask & (1<<channel))) {
// enabling a previously disabled channel
position[channel] = n;
if (blks > maxblocks) maxblocks = blks;
activemask |= (1<<channel);
} else {
if (n > position[channel]) {
// new delay is greater than previous setting
if (blks > maxblocks) maxblocks = blks;
position[channel] = n;
} else {
// new delay is less than previous setting
position[channel] = n;
recompute_maxblocks();
}
}
}
void disable(uint8_t channel) {
if (channel >= 8) return;
// diable this channel
activemask &= ~(1<<channel);
// recompute maxblocks for remaining enabled channels
recompute_maxblocks();
}
virtual void update(void);
private:
void recompute_maxblocks(void) {
uint32_t max=0;
uint32_t channel = 0;
do {
if (activemask & (1<<channel)) {
uint32_t n = position[channel];
n = (n + (AUDIO_BLOCK_SAMPLES-1)) / AUDIO_BLOCK_SAMPLES + 1;
if (n > max) max = n;
}
} while(++channel < 8);
maxblocks = max;
}
uint8_t activemask; // which output channels are active
uint16_t headindex; // head index (incoming) data in quueu
uint16_t tailindex; // tail index (outgoing) data from queue
uint16_t maxblocks; // number of blocks needed in queue
#if DELAY_QUEUE_SIZE * AUDIO_BLOCK_SAMPLES < 65535
uint16_t position[8]; // # of sample delay for each channel
#else
uint32_t position[8]; // # of sample delay for each channel
#endif
audio_block_t *queue[DELAY_QUEUE_SIZE];
audio_block_t *inputQueueArray[1];
};
#endif

View file

@ -0,0 +1,291 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_delay_ext.h"
//#define INTERNAL_TEST
// While 20 MHz (Teensy actually uses 16 MHz in most cases) and even 24 MHz
// have worked well in testing at room temperature with 3.3V power, to fully
// meet all the worst case timing specs, the SPI clock low time would need
// to be 40ns (12.5 MHz clock) for the single chip case and 51ns (9.8 MHz
// clock) for the 6-chip memoryboard with 74LCX126 buffers.
//
// Timing analysis and info is here:
// https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library?p=97506&viewfull=1#post97506
#define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0)
// Use these with the audio adaptor board (should be adjustable by the user...)
#define SPIRAM_MOSI_PIN 7
#define SPIRAM_MISO_PIN 12
#define SPIRAM_SCK_PIN 14
#define SPIRAM_CS_PIN 6
#define MEMBOARD_CS0_PIN 2
#define MEMBOARD_CS1_PIN 3
#define MEMBOARD_CS2_PIN 4
void AudioEffectDelayExternal::update(void)
{
audio_block_t *block;
uint32_t n, channel, read_offset;
// grab incoming data and put it into the memory
block = receiveReadOnly();
if (memory_type >= AUDIO_MEMORY_UNDEFINED) {
// ignore input and do nothing if undefined memory type
release(block);
return;
}
if (block) {
if (head_offset + AUDIO_BLOCK_SAMPLES <= memory_length) {
// a single write is enough
write(head_offset, AUDIO_BLOCK_SAMPLES, block->data);
head_offset += AUDIO_BLOCK_SAMPLES;
} else {
// write wraps across end-of-memory
n = memory_length - head_offset;
write(head_offset, n, block->data);
head_offset = AUDIO_BLOCK_SAMPLES - n;
write(0, head_offset, block->data + n);
}
release(block);
} else {
// if no input, store zeros, so later playback will
// not be random garbage previously stored in memory
if (head_offset + AUDIO_BLOCK_SAMPLES <= memory_length) {
zero(head_offset, AUDIO_BLOCK_SAMPLES);
head_offset += AUDIO_BLOCK_SAMPLES;
} else {
n = memory_length - head_offset;
zero(head_offset, n);
head_offset = AUDIO_BLOCK_SAMPLES - n;
zero(0, head_offset);
}
}
// transmit the delayed outputs
for (channel = 0; channel < 8; channel++) {
if (!(activemask & (1<<channel))) continue;
block = allocate();
if (!block) continue;
// compute the delayed location where we read
if (delay_length[channel] <= head_offset) {
read_offset = head_offset - delay_length[channel];
} else {
read_offset = memory_length + head_offset - delay_length[channel];
}
if (read_offset + AUDIO_BLOCK_SAMPLES <= memory_length) {
// a single read will do it
read(read_offset, AUDIO_BLOCK_SAMPLES, block->data);
} else {
// read wraps across end-of-memory
n = memory_length - read_offset;
read(read_offset, n, block->data);
read(0, AUDIO_BLOCK_SAMPLES - n, block->data + n);
}
transmit(block, channel);
release(block);
}
}
uint32_t AudioEffectDelayExternal::allocated[2] = {0, 0};
void AudioEffectDelayExternal::initialize(AudioEffectDelayMemoryType_t type, uint32_t samples)
{
uint32_t memsize, avail;
activemask = 0;
head_offset = 0;
memory_type = type;
SPI.setMOSI(SPIRAM_MOSI_PIN);
SPI.setMISO(SPIRAM_MISO_PIN);
SPI.setSCK(SPIRAM_SCK_PIN);
SPI.begin();
if (type == AUDIO_MEMORY_23LC1024) {
#ifdef INTERNAL_TEST
memsize = 8000;
#else
memsize = 65536;
#endif
pinMode(SPIRAM_CS_PIN, OUTPUT);
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
} else if (type == AUDIO_MEMORY_MEMORYBOARD) {
memsize = 393216;
pinMode(MEMBOARD_CS0_PIN, OUTPUT);
pinMode(MEMBOARD_CS1_PIN, OUTPUT);
pinMode(MEMBOARD_CS2_PIN, OUTPUT);
digitalWriteFast(MEMBOARD_CS0_PIN, LOW);
digitalWriteFast(MEMBOARD_CS1_PIN, LOW);
digitalWriteFast(MEMBOARD_CS2_PIN, LOW);
} else if (type == AUDIO_MEMORY_CY15B104) {
#ifdef INTERNAL_TEST
memsize = 8000;
#else
memsize = 262144;
#endif
pinMode(SPIRAM_CS_PIN, OUTPUT);
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
} else {
return;
}
avail = memsize - allocated[type];
if (avail < AUDIO_BLOCK_SAMPLES*2+1) {
memory_type = AUDIO_MEMORY_UNDEFINED;
return;
}
if (samples > avail) samples = avail;
memory_begin = allocated[type];
allocated[type] += samples;
memory_length = samples;
zero(0, memory_length);
}
#ifdef INTERNAL_TEST
static int16_t testmem[8000]; // testing only
#endif
void AudioEffectDelayExternal::read(uint32_t offset, uint32_t count, int16_t *data)
{
uint32_t addr = memory_begin + offset;
#ifdef INTERNAL_TEST
while (count) { *data++ = testmem[addr++]; count--; } // testing only
#else
if (memory_type == AUDIO_MEMORY_23LC1024 ||
memory_type == AUDIO_MEMORY_CY15B104) {
addr *= 2;
SPI.beginTransaction(SPISETTING);
digitalWriteFast(SPIRAM_CS_PIN, LOW);
SPI.transfer16((0x03 << 8) | (addr >> 16));
SPI.transfer16(addr & 0xFFFF);
while (count) {
*data++ = (int16_t)(SPI.transfer16(0));
count--;
}
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
SPI.endTransaction();
} else if (memory_type == AUDIO_MEMORY_MEMORYBOARD) {
SPI.beginTransaction(SPISETTING);
while (count) {
uint32_t chip = (addr >> 16) + 1;
digitalWriteFast(MEMBOARD_CS0_PIN, chip & 1);
digitalWriteFast(MEMBOARD_CS1_PIN, chip & 2);
digitalWriteFast(MEMBOARD_CS2_PIN, chip & 4);
uint32_t chipaddr = (addr & 0xFFFF) << 1;
SPI.transfer16((0x03 << 8) | (chipaddr >> 16));
SPI.transfer16(chipaddr & 0xFFFF);
uint32_t num = 0x10000 - (addr & 0xFFFF);
if (num > count) num = count;
count -= num;
addr += num;
do {
*data++ = (int16_t)(SPI.transfer16(0));
} while (--num > 0);
}
digitalWriteFast(MEMBOARD_CS0_PIN, LOW);
digitalWriteFast(MEMBOARD_CS1_PIN, LOW);
digitalWriteFast(MEMBOARD_CS2_PIN, LOW);
SPI.endTransaction();
}
#endif
}
void AudioEffectDelayExternal::write(uint32_t offset, uint32_t count, const int16_t *data)
{
uint32_t addr = memory_begin + offset;
#ifdef INTERNAL_TEST
while (count) { testmem[addr++] = *data++; count--; } // testing only
#else
if (memory_type == AUDIO_MEMORY_23LC1024) {
addr *= 2;
SPI.beginTransaction(SPISETTING);
digitalWriteFast(SPIRAM_CS_PIN, LOW);
SPI.transfer16((0x02 << 8) | (addr >> 16));
SPI.transfer16(addr & 0xFFFF);
while (count) {
int16_t w = 0;
if (data) w = *data++;
SPI.transfer16(w);
count--;
}
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
SPI.endTransaction();
} else if (memory_type == AUDIO_MEMORY_CY15B104) {
addr *= 2;
SPI.beginTransaction(SPISETTING);
digitalWriteFast(SPIRAM_CS_PIN, LOW);
SPI.transfer(0x06); //write-enable before every write
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
asm volatile ("NOP\n NOP\n NOP\n NOP\n NOP\n NOP\n");
digitalWriteFast(SPIRAM_CS_PIN, LOW);
SPI.transfer16((0x02 << 8) | (addr >> 16));
SPI.transfer16(addr & 0xFFFF);
while (count) {
int16_t w = 0;
if (data) w = *data++;
SPI.transfer16(w);
count--;
}
digitalWriteFast(SPIRAM_CS_PIN, HIGH);
SPI.endTransaction();
} else if (memory_type == AUDIO_MEMORY_MEMORYBOARD) {
SPI.beginTransaction(SPISETTING);
while (count) {
uint32_t chip = (addr >> 16) + 1;
digitalWriteFast(MEMBOARD_CS0_PIN, chip & 1);
digitalWriteFast(MEMBOARD_CS1_PIN, chip & 2);
digitalWriteFast(MEMBOARD_CS2_PIN, chip & 4);
uint32_t chipaddr = (addr & 0xFFFF) << 1;
SPI.transfer16((0x02 << 8) | (chipaddr >> 16));
SPI.transfer16(chipaddr & 0xFFFF);
uint32_t num = 0x10000 - (addr & 0xFFFF);
if (num > count) num = count;
count -= num;
addr += num;
do {
int16_t w = 0;
if (data) w = *data++;
SPI.transfer16(w);
} while (--num > 0);
}
digitalWriteFast(MEMBOARD_CS0_PIN, LOW);
digitalWriteFast(MEMBOARD_CS1_PIN, LOW);
digitalWriteFast(MEMBOARD_CS2_PIN, LOW);
SPI.endTransaction();
}
#endif
}

View file

@ -0,0 +1,88 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_delay_ext_h_
#define effect_delay_ext_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "spi_interrupt.h"
enum AudioEffectDelayMemoryType_t {
AUDIO_MEMORY_23LC1024 = 0, // 128k x 8 S-RAM
AUDIO_MEMORY_MEMORYBOARD = 1,
AUDIO_MEMORY_CY15B104 = 2, // 512k x 8 F-RAM
AUDIO_MEMORY_UNDEFINED = 3
};
class AudioEffectDelayExternal : public AudioStream
{
public:
AudioEffectDelayExternal() : AudioStream(1, inputQueueArray) {
initialize(AUDIO_MEMORY_23LC1024, 65536);
}
AudioEffectDelayExternal(AudioEffectDelayMemoryType_t type, float milliseconds=1e6)
: AudioStream(1, inputQueueArray) {
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
initialize(type, n);
}
void delay(uint8_t channel, float milliseconds) {
if (channel >= 8 || memory_type >= AUDIO_MEMORY_UNDEFINED) return;
if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
n += AUDIO_BLOCK_SAMPLES;
if (n > memory_length - AUDIO_BLOCK_SAMPLES)
n = memory_length - AUDIO_BLOCK_SAMPLES;
delay_length[channel] = n;
uint8_t mask = activemask;
if (activemask == 0) AudioStartUsingSPI();
activemask = mask | (1<<channel);
}
void disable(uint8_t channel) {
if (channel >= 8) return;
uint8_t mask = activemask & ~(1<<channel);
activemask = mask;
if (mask == 0) AudioStopUsingSPI();
}
virtual void update(void);
private:
void initialize(AudioEffectDelayMemoryType_t type, uint32_t samples);
void read(uint32_t address, uint32_t count, int16_t *data);
void write(uint32_t address, uint32_t count, const int16_t *data);
void zero(uint32_t address, uint32_t count) {
write(address, count, NULL);
}
uint32_t memory_begin; // the first address in the memory we're using
uint32_t memory_length; // the amount of memory we're using
uint32_t head_offset; // head index (incoming) data into external memory
uint32_t delay_length[8]; // # of sample delay for each channel (128 = no delay)
uint8_t activemask; // which output channels are active
uint8_t memory_type; // 0=23LC1024, 1=Frank's Memoryboard
static uint32_t allocated[2];
audio_block_t *inputQueueArray[1];
};
#endif

View file

@ -0,0 +1,196 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_envelope.h"
#define STATE_IDLE 0
#define STATE_DELAY 1
#define STATE_ATTACK 2
#define STATE_HOLD 3
#define STATE_DECAY 4
#define STATE_SUSTAIN 5
#define STATE_RELEASE 6
#define STATE_FORCED 7
void AudioEffectEnvelope::noteOn(void)
{
__disable_irq();
if (state == STATE_IDLE || state == STATE_DELAY || release_forced_count == 0) {
mult_hires = 0;
count = delay_count;
if (count > 0) {
state = STATE_DELAY;
inc_hires = 0;
} else {
state = STATE_ATTACK;
count = attack_count;
inc_hires = 0x40000000 / (int32_t)count;
}
} else if (state != STATE_FORCED) {
state = STATE_FORCED;
count = release_forced_count;
inc_hires = (-mult_hires) / (int32_t)count;
}
__enable_irq();
}
void AudioEffectEnvelope::noteOff(void)
{
__disable_irq();
if (state != STATE_IDLE && state != STATE_FORCED) {
state = STATE_RELEASE;
count = release_count;
inc_hires = (-mult_hires) / (int32_t)count;
}
__enable_irq();
}
void AudioEffectEnvelope::update(void)
{
audio_block_t *block;
uint32_t *p, *end;
uint32_t sample12, sample34, sample56, sample78, tmp1, tmp2;
block = receiveWritable();
if (!block) return;
if (state == STATE_IDLE) {
release(block);
return;
}
p = (uint32_t *)(block->data);
end = p + AUDIO_BLOCK_SAMPLES/2;
while (p < end) {
// we only care about the state when completing a region
if (count == 0) {
if (state == STATE_ATTACK) {
count = hold_count;
if (count > 0) {
state = STATE_HOLD;
mult_hires = 0x40000000;
inc_hires = 0;
} else {
state = STATE_DECAY;
count = decay_count;
inc_hires = (sustain_mult - 0x40000000) / (int32_t)count;
}
continue;
} else if (state == STATE_HOLD) {
state = STATE_DECAY;
count = decay_count;
inc_hires = (sustain_mult - 0x40000000) / (int32_t)count;
continue;
} else if (state == STATE_DECAY) {
state = STATE_SUSTAIN;
count = 0xFFFF;
mult_hires = sustain_mult;
inc_hires = 0;
} else if (state == STATE_SUSTAIN) {
count = 0xFFFF;
} else if (state == STATE_RELEASE) {
state = STATE_IDLE;
while (p < end) {
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
}
break;
} else if (state == STATE_FORCED) {
mult_hires = 0;
count = delay_count;
if (count > 0) {
state = STATE_DELAY;
inc_hires = 0;
} else {
state = STATE_ATTACK;
count = attack_count;
inc_hires = 0x40000000 / (int32_t)count;
}
} else if (state == STATE_DELAY) {
state = STATE_ATTACK;
count = attack_count;
inc_hires = 0x40000000 / count;
continue;
}
}
int32_t mult = mult_hires >> 14;
int32_t inc = inc_hires >> 17;
// process 8 samples, using only mult and inc (16 bit resolution)
sample12 = *p++;
sample34 = *p++;
sample56 = *p++;
sample78 = *p++;
p -= 4;
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample12);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample12);
sample12 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample34);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample34);
sample34 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample56);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample56);
sample56 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample78);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample78);
sample78 = pack_16b_16b(tmp2, tmp1);
*p++ = sample12;
*p++ = sample34;
*p++ = sample56;
*p++ = sample78;
// adjust the long-term gain using 30 bit resolution (fix #102)
// https://github.com/PaulStoffregen/Audio/issues/102
mult_hires += inc_hires;
count--;
}
transmit(block);
release(block);
}
bool AudioEffectEnvelope::isActive()
{
uint8_t current_state = *(volatile uint8_t *)&state;
if (current_state == STATE_IDLE) return false;
return true;
}
bool AudioEffectEnvelope::isSustain()
{
uint8_t current_state = *(volatile uint8_t *)&state;
if (current_state == STATE_SUSTAIN) return true;
return false;
}

View file

@ -0,0 +1,107 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2017, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_envelope_h_
#define effect_envelope_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "utility/dspinst.h"
#define SAMPLES_PER_MSEC (AUDIO_SAMPLE_RATE_EXACT/1000.0)
class AudioEffectEnvelope : public AudioStream
{
public:
AudioEffectEnvelope() : AudioStream(1, inputQueueArray) {
state = 0;
delay(0.0f); // default values...
attack(10.5f);
hold(2.5f);
decay(35.0f);
sustain(0.5f);
release(300.0f);
releaseNoteOn(5.0f);
}
void noteOn();
void noteOff();
void delay(float milliseconds) {
delay_count = milliseconds2count(milliseconds);
}
void attack(float milliseconds) {
attack_count = milliseconds2count(milliseconds);
if (attack_count == 0) attack_count = 1;
}
void hold(float milliseconds) {
hold_count = milliseconds2count(milliseconds);
}
void decay(float milliseconds) {
decay_count = milliseconds2count(milliseconds);
if (decay_count == 0) decay_count = 1;
}
void sustain(float level) {
if (level < 0.0) level = 0;
else if (level > 1.0) level = 1.0;
sustain_mult = level * 1073741824.0;
}
void release(float milliseconds) {
release_count = milliseconds2count(milliseconds);
if (release_count == 0) release_count = 1;
}
void releaseNoteOn(float milliseconds) {
release_forced_count = milliseconds2count(milliseconds);
if (release_count == 0) release_count = 1;
}
bool isActive();
bool isSustain();
using AudioStream::release;
virtual void update(void);
private:
uint16_t milliseconds2count(float milliseconds) {
if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t c = ((uint32_t)(milliseconds*SAMPLES_PER_MSEC)+7)>>3;
if (c > 65535) c = 65535; // allow up to 11.88 seconds
return c;
}
audio_block_t *inputQueueArray[1];
// state
uint8_t state; // idle, delay, attack, hold, decay, sustain, release, forced
uint16_t count; // how much time remains in this state, in 8 sample units
int32_t mult_hires; // attenuation, 0=off, 0x40000000=unity gain
int32_t inc_hires; // amount to change mult_hires every 8 samples
// settings
uint16_t delay_count;
uint16_t attack_count;
uint16_t hold_count;
uint16_t decay_count;
int32_t sustain_mult;
uint16_t release_count;
uint16_t release_forced_count;
};
#undef SAMPLES_PER_MSEC
#endif

View file

@ -0,0 +1,98 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_fade.h"
#include "utility/dspinst.h"
extern "C" {
extern const int16_t fader_table[257];
};
void AudioEffectFade::update(void)
{
audio_block_t *block;
uint32_t i, pos, inc, index, scale;
int32_t val1, val2, val, sample;
uint8_t dir;
pos = position;
if (pos == 0) {
// output is silent
block = receiveReadOnly();
if (block) release(block);
return;
} else if (pos == 0xFFFFFFFF) {
// output is 100%
block = receiveReadOnly();
if (!block) return;
transmit(block);
release(block);
return;
}
block = receiveWritable();
if (!block) return;
inc = rate;
dir = direction;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
index = pos >> 24;
val1 = fader_table[index];
val2 = fader_table[index+1];
scale = (pos >> 8) & 0xFFFF;
val2 *= scale;
val1 *= 0x10000 - scale;
val = (val1 + val2) >> 16;
sample = block->data[i];
sample = (sample * val) >> 15;
block->data[i] = sample;
if (dir > 0) {
// output is increasing
if (inc < 0xFFFFFFFF - pos) pos += inc;
else pos = 0xFFFFFFFF;
} else {
// output is decreasing
if (inc < pos) pos -= inc;
else pos = 0;
}
}
position = pos;
transmit(block);
release(block);
}
void AudioEffectFade::fadeBegin(uint32_t newrate, uint8_t dir)
{
__disable_irq();
uint32_t pos = position;
if (pos == 0) position = 1;
else if (pos == 0xFFFFFFFF) position = 0xFFFFFFFE;
rate = newrate;
direction = dir;
__enable_irq();
}

View file

@ -0,0 +1,57 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_fade_h_
#define effect_fade_h_
#include "Arduino.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

View file

@ -0,0 +1,220 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Pete (El Supremo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_flange.h"
#include "arm_math.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
// 140529 - change to handle mono stream and change modify() to voices()
// 140207 - fix calculation of delay_rate_incr which is expressed as
// a fraction of 2*PI
// 140207 - cosmetic fix to begin()
// 140219 - correct the calculation of "frac"
// circular addressing indices for left and right channels
//short AudioEffectFlange::l_circ_idx;
//short AudioEffectFlange::r_circ_idx;
//short * AudioEffectFlange::l_delayline = NULL;
//short * AudioEffectFlange::r_delayline = NULL;
// User-supplied offset for the delayed sample
// but start with passthru
//int AudioEffectFlange::delay_offset_idx = FLANGE_DELAY_PASSTHRU;
//int AudioEffectFlange::delay_length;
//int AudioEffectFlange::delay_depth;
//int AudioEffectFlange::delay_rate_incr;
//unsigned int AudioEffectFlange::l_delay_rate_index;
//unsigned int AudioEffectFlange::r_delay_rate_index;
// fails if the user provides unreasonable values but will
// coerce them and go ahead anyway. e.g. if the delay offset
// is >= CHORUS_DELAY_LENGTH, the code will force it to
// CHORUS_DELAY_LENGTH-1 and return false.
// delay_rate is the rate (in Hz) of the sine wave modulation
// delay_depth is the maximum variation around delay_offset
// i.e. the total offset is delay_offset + delay_depth * sin(delay_rate)
boolean AudioEffectFlange::begin(short *delayline,int d_length,int delay_offset,int d_depth,float delay_rate)
{
boolean all_ok = true;
if(0) {
Serial.print("AudioEffectFlange.begin(offset = ");
Serial.print(delay_offset);
Serial.print(", depth = ");
Serial.print(d_depth);
Serial.print(", rate = ");
Serial.print(delay_rate,3);
Serial.println(")");
Serial.print(" FLANGE_DELAY_LENGTH = ");
Serial.println(d_length);
}
delay_length = d_length/2;
l_delayline = delayline;
delay_depth = d_depth;
// initial index
l_delay_rate_index = 0;
l_circ_idx = 0;
delay_rate_incr =(delay_rate * 2147483648.0)/ AUDIO_SAMPLE_RATE_EXACT;
//Serial.println(delay_rate_incr,HEX);
delay_offset_idx = delay_offset;
// Allow the passthru code to go through
if(delay_offset_idx < -1) {
delay_offset_idx = 0;
all_ok = false;
}
if(delay_offset_idx >= delay_length) {
delay_offset_idx = delay_length - 1;
all_ok = false;
}
return(all_ok);
}
boolean AudioEffectFlange::voices(int delay_offset,int d_depth,float delay_rate)
{
boolean all_ok = true;
delay_depth = d_depth;
delay_rate_incr =(delay_rate * 2147483648.0)/ AUDIO_SAMPLE_RATE_EXACT;
delay_offset_idx = delay_offset;
// Allow the passthru code to go through
if(delay_offset_idx < -1) {
delay_offset_idx = 0;
all_ok = false;
}
if(delay_offset_idx >= delay_length) {
delay_offset_idx = delay_length - 1;
all_ok = false;
}
l_delay_rate_index = 0;
l_circ_idx = 0;
return(all_ok);
}
void AudioEffectFlange::update(void)
{
audio_block_t *block;
int idx;
short *bp;
short frac;
int idx1;
if(l_delayline == NULL)return;
// do passthru
if(delay_offset_idx == FLANGE_DELAY_PASSTHRU) {
// Just passthrough
block = receiveWritable(0);
if(block) {
bp = block->data;
// fill the delay line
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
l_circ_idx++;
if(l_circ_idx >= delay_length) {
l_circ_idx = 0;
}
l_delayline[l_circ_idx] = *bp++;
}
// transmit the unmodified block
transmit(block,0);
release(block);
}
return;
}
// L E F T C H A N N E L
block = receiveWritable(0);
if(block) {
bp = block->data;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
// increment the index into the circular delay line buffer
l_circ_idx++;
// wrap the index around if necessary
if(l_circ_idx >= delay_length) {
l_circ_idx = 0;
}
// store the current sample in the delay line
l_delayline[l_circ_idx] = *bp;
// The argument to the arm_sin_q15 function is NOT in radians. It is
// actually, in effect, the fraction remaining after the division
// of radians/(2*PI) which is then expressed as a positive Q15
// fraction in the interval [0 , +1) - this is l_delay_rate_index.
// l_delay_rate_index should probably be called l_delay_rate_phase
// (sorry about that!)
// It is a Q31 positive number of which the high order 16 bits are
// used when calculating the sine. idx will have a value in the
// interval [-1 , +1)
frac = arm_sin_q15( (q15_t)((l_delay_rate_index >> 16) & 0x7fff));
// multiply the sin by the delay depth
idx = (frac * delay_depth) >> 15;
//Serial.println(idx);
// Calculate the offset into the buffer
idx = l_circ_idx - (delay_offset_idx + idx);
// and adjust idx to point into the circular buffer
if(idx < 0) {
idx += delay_length;
}
if(idx >= delay_length) {
idx -= delay_length;
}
// Here we interpolate between two indices but if the sine was negative
// then we interpolate between idx and idx-1, otherwise the
// interpolation is between idx and idx+1
if(frac < 0)
idx1 = idx - 1;
else
idx1 = idx + 1;
// adjust idx1 in the circular buffer
if(idx1 < 0) {
idx1 += delay_length;
}
if(idx1 >= delay_length) {
idx1 -= delay_length;
}
// Do the interpolation
frac = (l_delay_rate_index >> 1) &0x7fff;
frac = (( (int)(l_delayline[idx1] - l_delayline[idx])*frac) >> 15);
*bp++ = (l_delayline[l_circ_idx]+ l_delayline[idx] + frac)/2;
l_delay_rate_index += delay_rate_incr;
if(l_delay_rate_index & 0x80000000) {
l_delay_rate_index &= 0x7fffffff;
}
}
// send the effect output to the left channel
transmit(block,0);
release(block);
}
}

View file

@ -0,0 +1,59 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Pete (El Supremo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_flange_h_
#define effect_flange_h_
#include "Arduino.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
// 140529 - change to handle mono stream and change modify() to voices()
#define FLANGE_DELAY_PASSTHRU 0
class AudioEffectFlange :
public AudioStream
{
public:
AudioEffectFlange(void):
AudioStream(1,inputQueueArray) {
}
boolean begin(short *delayline,int d_length,int delay_offset,int d_depth,float delay_rate);
boolean voices(int delay_offset,int d_depth,float delay_rate);
virtual void update(void);
private:
audio_block_t *inputQueueArray[1];
short *l_delayline;
int delay_length;
short l_circ_idx;
int delay_depth;
int delay_offset_idx;
int delay_rate_incr;
unsigned int l_delay_rate_index;
};
#endif

View file

@ -0,0 +1,480 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// A fixed point implementation of Freeverb by Jezar at Dreampoint
// http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html
// https://music.columbia.edu/pipermail/music-dsp/2001-October/045433.html
#include <Arduino.h>
#include "effect_freeverb.h"
#include "utility/dspinst.h"
AudioEffectFreeverb::AudioEffectFreeverb() : AudioStream(1, inputQueueArray)
{
memset(comb1buf, 0, sizeof(comb1buf));
memset(comb2buf, 0, sizeof(comb2buf));
memset(comb3buf, 0, sizeof(comb3buf));
memset(comb4buf, 0, sizeof(comb4buf));
memset(comb5buf, 0, sizeof(comb5buf));
memset(comb6buf, 0, sizeof(comb6buf));
memset(comb7buf, 0, sizeof(comb7buf));
memset(comb8buf, 0, sizeof(comb8buf));
comb1index = 0;
comb2index = 0;
comb3index = 0;
comb4index = 0;
comb5index = 0;
comb6index = 0;
comb7index = 0;
comb8index = 0;
comb1filter = 0;
comb2filter = 0;
comb3filter = 0;
comb4filter = 0;
comb5filter = 0;
comb6filter = 0;
comb7filter = 0;
comb8filter = 0;
combdamp1 = 6553;
combdamp2 = 26215;
combfeeback = 27524;
memset(allpass1buf, 0, sizeof(allpass1buf));
memset(allpass2buf, 0, sizeof(allpass2buf));
memset(allpass3buf, 0, sizeof(allpass3buf));
memset(allpass4buf, 0, sizeof(allpass4buf));
allpass1index = 0;
allpass2index = 0;
allpass3index = 0;
allpass4index = 0;
}
#if 1
#define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift))
#else
static int16_t sat16(int32_t n, int rshift)
{
n = n >> rshift;
if (n > 32767) {
return 32767;
}
if (n < -32768) {
return -32768;
}
return n;
}
#endif
// TODO: move this to one of the data files, use in output_adat.cpp, output_tdm.cpp, etc
static const audio_block_t zeroblock = {
0, 0, 0, {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#if AUDIO_BLOCK_SAMPLES > 16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 32
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 48
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 64
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 80
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 96
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
#if AUDIO_BLOCK_SAMPLES > 112
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
#endif
} };
void AudioEffectFreeverb::update()
{
#if defined(KINETISK)
const audio_block_t *block;
audio_block_t *outblock;
int i;
int16_t input, bufout, output;
int32_t sum;
outblock = allocate();
if (!outblock) {
audio_block_t *tmp = receiveReadOnly(0);
if (tmp) release(tmp);
return;
}
block = receiveReadOnly(0);
if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping
input = sat16(block->data[i] * 8738, 17); // for numerical headroom
sum = 0;
bufout = comb1buf[comb1index];
sum += bufout;
comb1filter = sat16(bufout * combdamp2 + comb1filter * combdamp1, 15);
comb1buf[comb1index] = sat16(input + sat16(comb1filter * combfeeback, 15), 0);
if (++comb1index >= sizeof(comb1buf)/sizeof(int16_t)) comb1index = 0;
bufout = comb2buf[comb2index];
sum += bufout;
comb2filter = sat16(bufout * combdamp2 + comb2filter * combdamp1, 15);
comb2buf[comb2index] = sat16(input + sat16(comb2filter * combfeeback, 15), 0);
if (++comb2index >= sizeof(comb2buf)/sizeof(int16_t)) comb2index = 0;
bufout = comb3buf[comb3index];
sum += bufout;
comb3filter = sat16(bufout * combdamp2 + comb3filter * combdamp1, 15);
comb3buf[comb3index] = sat16(input + sat16(comb3filter * combfeeback, 15), 0);
if (++comb3index >= sizeof(comb3buf)/sizeof(int16_t)) comb3index = 0;
bufout = comb4buf[comb4index];
sum += bufout;
comb4filter = sat16(bufout * combdamp2 + comb4filter * combdamp1, 15);
comb4buf[comb4index] = sat16(input + sat16(comb4filter * combfeeback, 15), 0);
if (++comb4index >= sizeof(comb4buf)/sizeof(int16_t)) comb4index = 0;
bufout = comb5buf[comb5index];
sum += bufout;
comb5filter = sat16(bufout * combdamp2 + comb5filter * combdamp1, 15);
comb5buf[comb5index] = sat16(input + sat16(comb5filter * combfeeback, 15), 0);
if (++comb5index >= sizeof(comb5buf)/sizeof(int16_t)) comb5index = 0;
bufout = comb6buf[comb6index];
sum += bufout;
comb6filter = sat16(bufout * combdamp2 + comb6filter * combdamp1, 15);
comb6buf[comb6index] = sat16(input + sat16(comb6filter * combfeeback, 15), 0);
if (++comb6index >= sizeof(comb6buf)/sizeof(int16_t)) comb6index = 0;
bufout = comb7buf[comb7index];
sum += bufout;
comb7filter = sat16(bufout * combdamp2 + comb7filter * combdamp1, 15);
comb7buf[comb7index] = sat16(input + sat16(comb7filter * combfeeback, 15), 0);
if (++comb7index >= sizeof(comb7buf)/sizeof(int16_t)) comb7index = 0;
bufout = comb8buf[comb8index];
sum += bufout;
comb8filter = sat16(bufout * combdamp2 + comb8filter * combdamp1, 15);
comb8buf[comb8index] = sat16(input + sat16(comb8filter * combfeeback, 15), 0);
if (++comb8index >= sizeof(comb8buf)/sizeof(int16_t)) comb8index = 0;
output = sat16(sum * 31457, 17);
bufout = allpass1buf[allpass1index];
allpass1buf[allpass1index] = output + (bufout >> 1);
output = sat16(bufout - output, 1);
if (++allpass1index >= sizeof(allpass1buf)/sizeof(int16_t)) allpass1index = 0;
bufout = allpass2buf[allpass2index];
allpass2buf[allpass2index] = output + (bufout >> 1);
output = sat16(bufout - output, 1);
if (++allpass2index >= sizeof(allpass2buf)/sizeof(int16_t)) allpass2index = 0;
bufout = allpass3buf[allpass3index];
allpass3buf[allpass3index] = output + (bufout >> 1);
output = sat16(bufout - output, 1);
if (++allpass3index >= sizeof(allpass3buf)/sizeof(int16_t)) allpass3index = 0;
bufout = allpass4buf[allpass4index];
allpass4buf[allpass4index] = output + (bufout >> 1);
output = sat16(bufout - output, 1);
if (++allpass4index >= sizeof(allpass4buf)/sizeof(int16_t)) allpass4index = 0;
outblock->data[i] = sat16(output * 30, 0);
}
transmit(outblock);
release(outblock);
if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL)
audio_block_t *block;
block = receiveReadOnly(0);
if (block) release(block);
#endif
}
AudioEffectFreeverbStereo::AudioEffectFreeverbStereo() : AudioStream(1, inputQueueArray)
{
memset(comb1bufL, 0, sizeof(comb1bufL));
memset(comb2bufL, 0, sizeof(comb2bufL));
memset(comb3bufL, 0, sizeof(comb3bufL));
memset(comb4bufL, 0, sizeof(comb4bufL));
memset(comb5bufL, 0, sizeof(comb5bufL));
memset(comb6bufL, 0, sizeof(comb6bufL));
memset(comb7bufL, 0, sizeof(comb7bufL));
memset(comb8bufL, 0, sizeof(comb8bufL));
comb1indexL = 0;
comb2indexL = 0;
comb3indexL = 0;
comb4indexL = 0;
comb5indexL = 0;
comb6indexL = 0;
comb7indexL = 0;
comb8indexL = 0;
comb1filterL = 0;
comb2filterL = 0;
comb3filterL = 0;
comb4filterL = 0;
comb5filterL = 0;
comb6filterL = 0;
comb7filterL = 0;
comb8filterL = 0;
memset(comb1bufR, 0, sizeof(comb1bufR));
memset(comb2bufR, 0, sizeof(comb2bufR));
memset(comb3bufR, 0, sizeof(comb3bufR));
memset(comb4bufR, 0, sizeof(comb4bufR));
memset(comb5bufR, 0, sizeof(comb5bufR));
memset(comb6bufR, 0, sizeof(comb6bufR));
memset(comb7bufR, 0, sizeof(comb7bufR));
memset(comb8bufR, 0, sizeof(comb8bufR));
comb1indexR = 0;
comb2indexR = 0;
comb3indexR = 0;
comb4indexR = 0;
comb5indexR = 0;
comb6indexR = 0;
comb7indexR = 0;
comb8indexR = 0;
comb1filterR = 0;
comb2filterR = 0;
comb3filterR = 0;
comb4filterR = 0;
comb5filterR = 0;
comb6filterR = 0;
comb7filterR = 0;
comb8filterR = 0;
combdamp1 = 6553;
combdamp2 = 26215;
combfeeback = 27524;
memset(allpass1bufL, 0, sizeof(allpass1bufL));
memset(allpass2bufL, 0, sizeof(allpass2bufL));
memset(allpass3bufL, 0, sizeof(allpass3bufL));
memset(allpass4bufL, 0, sizeof(allpass4bufL));
allpass1indexL = 0;
allpass2indexL = 0;
allpass3indexL = 0;
allpass4indexL = 0;
memset(allpass1bufR, 0, sizeof(allpass1bufR));
memset(allpass2bufR, 0, sizeof(allpass2bufR));
memset(allpass3bufR, 0, sizeof(allpass3bufR));
memset(allpass4bufR, 0, sizeof(allpass4bufR));
allpass1indexR = 0;
allpass2indexR = 0;
allpass3indexR = 0;
allpass4indexR = 0;
}
void AudioEffectFreeverbStereo::update()
{
#if defined(KINETISK)
const audio_block_t *block;
audio_block_t *outblockL;
audio_block_t *outblockR;
int i;
int16_t input, bufout, outputL, outputR;
int32_t sum;
block = receiveReadOnly(0);
outblockL = allocate();
outblockR = allocate();
if (!outblockL || !outblockR) {
if (outblockL) release(outblockL);
if (outblockR) release(outblockR);
if (block) release((audio_block_t *)block);
return;
}
if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping
input = sat16(block->data[i] * 8738, 17); // for numerical headroom
sum = 0;
bufout = comb1bufL[comb1indexL];
sum += bufout;
comb1filterL = sat16(bufout * combdamp2 + comb1filterL * combdamp1, 15);
comb1bufL[comb1indexL] = sat16(input + sat16(comb1filterL * combfeeback, 15), 0);
if (++comb1indexL >= sizeof(comb1bufL)/sizeof(int16_t)) comb1indexL = 0;
bufout = comb2bufL[comb2indexL];
sum += bufout;
comb2filterL = sat16(bufout * combdamp2 + comb2filterL * combdamp1, 15);
comb2bufL[comb2indexL] = sat16(input + sat16(comb2filterL * combfeeback, 15), 0);
if (++comb2indexL >= sizeof(comb2bufL)/sizeof(int16_t)) comb2indexL = 0;
bufout = comb3bufL[comb3indexL];
sum += bufout;
comb3filterL = sat16(bufout * combdamp2 + comb3filterL * combdamp1, 15);
comb3bufL[comb3indexL] = sat16(input + sat16(comb3filterL * combfeeback, 15), 0);
if (++comb3indexL >= sizeof(comb3bufL)/sizeof(int16_t)) comb3indexL = 0;
bufout = comb4bufL[comb4indexL];
sum += bufout;
comb4filterL = sat16(bufout * combdamp2 + comb4filterL * combdamp1, 15);
comb4bufL[comb4indexL] = sat16(input + sat16(comb4filterL * combfeeback, 15), 0);
if (++comb4indexL >= sizeof(comb4bufL)/sizeof(int16_t)) comb4indexL = 0;
bufout = comb5bufL[comb5indexL];
sum += bufout;
comb5filterL = sat16(bufout * combdamp2 + comb5filterL * combdamp1, 15);
comb5bufL[comb5indexL] = sat16(input + sat16(comb5filterL * combfeeback, 15), 0);
if (++comb5indexL >= sizeof(comb5bufL)/sizeof(int16_t)) comb5indexL = 0;
bufout = comb6bufL[comb6indexL];
sum += bufout;
comb6filterL = sat16(bufout * combdamp2 + comb6filterL * combdamp1, 15);
comb6bufL[comb6indexL] = sat16(input + sat16(comb6filterL * combfeeback, 15), 0);
if (++comb6indexL >= sizeof(comb6bufL)/sizeof(int16_t)) comb6indexL = 0;
bufout = comb7bufL[comb7indexL];
sum += bufout;
comb7filterL = sat16(bufout * combdamp2 + comb7filterL * combdamp1, 15);
comb7bufL[comb7indexL] = sat16(input + sat16(comb7filterL * combfeeback, 15), 0);
if (++comb7indexL >= sizeof(comb7bufL)/sizeof(int16_t)) comb7indexL = 0;
bufout = comb8bufL[comb8indexL];
sum += bufout;
comb8filterL = sat16(bufout * combdamp2 + comb8filterL * combdamp1, 15);
comb8bufL[comb8indexL] = sat16(input + sat16(comb8filterL * combfeeback, 15), 0);
if (++comb8indexL >= sizeof(comb8bufL)/sizeof(int16_t)) comb8indexL = 0;
outputL = sat16(sum * 31457, 17);
sum = 0;
bufout = comb1bufR[comb1indexR];
sum += bufout;
comb1filterR = sat16(bufout * combdamp2 + comb1filterR * combdamp1, 15);
comb1bufR[comb1indexR] = sat16(input + sat16(comb1filterR * combfeeback, 15), 0);
if (++comb1indexR >= sizeof(comb1bufR)/sizeof(int16_t)) comb1indexR = 0;
bufout = comb2bufR[comb2indexR];
sum += bufout;
comb2filterR = sat16(bufout * combdamp2 + comb2filterR * combdamp1, 15);
comb2bufR[comb2indexR] = sat16(input + sat16(comb2filterR * combfeeback, 15), 0);
if (++comb2indexR >= sizeof(comb2bufR)/sizeof(int16_t)) comb2indexR = 0;
bufout = comb3bufR[comb3indexR];
sum += bufout;
comb3filterR = sat16(bufout * combdamp2 + comb3filterR * combdamp1, 15);
comb3bufR[comb3indexR] = sat16(input + sat16(comb3filterR * combfeeback, 15), 0);
if (++comb3indexR >= sizeof(comb3bufR)/sizeof(int16_t)) comb3indexR = 0;
bufout = comb4bufR[comb4indexR];
sum += bufout;
comb4filterR = sat16(bufout * combdamp2 + comb4filterR * combdamp1, 15);
comb4bufR[comb4indexR] = sat16(input + sat16(comb4filterR * combfeeback, 15), 0);
if (++comb4indexR >= sizeof(comb4bufR)/sizeof(int16_t)) comb4indexR = 0;
bufout = comb5bufR[comb5indexR];
sum += bufout;
comb5filterR = sat16(bufout * combdamp2 + comb5filterR * combdamp1, 15);
comb5bufR[comb5indexR] = sat16(input + sat16(comb5filterR * combfeeback, 15), 0);
if (++comb5indexR >= sizeof(comb5bufR)/sizeof(int16_t)) comb5indexR = 0;
bufout = comb6bufR[comb6indexR];
sum += bufout;
comb6filterR = sat16(bufout * combdamp2 + comb6filterR * combdamp1, 15);
comb6bufR[comb6indexR] = sat16(input + sat16(comb6filterR * combfeeback, 15), 0);
if (++comb6indexR >= sizeof(comb6bufR)/sizeof(int16_t)) comb6indexR = 0;
bufout = comb7bufR[comb7indexR];
sum += bufout;
comb7filterR = sat16(bufout * combdamp2 + comb7filterR * combdamp1, 15);
comb7bufR[comb7indexR] = sat16(input + sat16(comb7filterR * combfeeback, 15), 0);
if (++comb7indexR >= sizeof(comb7bufR)/sizeof(int16_t)) comb7indexR = 0;
bufout = comb8bufR[comb8indexR];
sum += bufout;
comb8filterR = sat16(bufout * combdamp2 + comb8filterR * combdamp1, 15);
comb8bufR[comb8indexR] = sat16(input + sat16(comb8filterR * combfeeback, 15), 0);
if (++comb8indexR >= sizeof(comb8bufR)/sizeof(int16_t)) comb8indexR = 0;
outputR = sat16(sum * 31457, 17);
bufout = allpass1bufL[allpass1indexL];
allpass1bufL[allpass1indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1);
if (++allpass1indexL >= sizeof(allpass1bufL)/sizeof(int16_t)) allpass1indexL = 0;
bufout = allpass2bufL[allpass2indexL];
allpass2bufL[allpass2indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1);
if (++allpass2indexL >= sizeof(allpass2bufL)/sizeof(int16_t)) allpass2indexL = 0;
bufout = allpass3bufL[allpass3indexL];
allpass3bufL[allpass3indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1);
if (++allpass3indexL >= sizeof(allpass3bufL)/sizeof(int16_t)) allpass3indexL = 0;
bufout = allpass4bufL[allpass4indexL];
allpass4bufL[allpass4indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1);
if (++allpass4indexL >= sizeof(allpass4bufL)/sizeof(int16_t)) allpass4indexL = 0;
outblockL->data[i] = sat16(outputL * 30, 0);
bufout = allpass1bufR[allpass1indexR];
allpass1bufR[allpass1indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1);
if (++allpass1indexR >= sizeof(allpass1bufR)/sizeof(int16_t)) allpass1indexR = 0;
bufout = allpass2bufR[allpass2indexR];
allpass2bufR[allpass2indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1);
if (++allpass2indexR >= sizeof(allpass2bufR)/sizeof(int16_t)) allpass2indexR = 0;
bufout = allpass3bufR[allpass3indexR];
allpass3bufR[allpass3indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1);
if (++allpass3indexR >= sizeof(allpass3bufR)/sizeof(int16_t)) allpass3indexR = 0;
bufout = allpass4bufR[allpass4indexR];
allpass4bufR[allpass4indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1);
if (++allpass4indexR >= sizeof(allpass4bufR)/sizeof(int16_t)) allpass4indexR = 0;
outblockR->data[i] = sat16(outputL * 30, 0);
}
transmit(outblockL, 0);
transmit(outblockR, 1);
release(outblockL);
release(outblockR);
if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL)
audio_block_t *block;
block = receiveReadOnly(0);
if (block) release(block);
#endif
}

View file

@ -0,0 +1,185 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_freeverb_h_
#define effect_freeverb_h_
#include <Arduino.h>
#include "AudioStream.h"
class AudioEffectFreeverb : public AudioStream
{
public:
AudioEffectFreeverb();
virtual void update();
void roomsize(float n) {
if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f;
combfeeback = (int)(n * 9175.04f) + 22937;
}
void damping(float n) {
if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f;
int x1 = (int)(n * 13107.2f);
int x2 = 32768 - x1;
__disable_irq();
combdamp1 = x1;
combdamp2 = x2;
__enable_irq();
}
private:
audio_block_t *inputQueueArray[1];
int16_t comb1buf[1116];
int16_t comb2buf[1188];
int16_t comb3buf[1277];
int16_t comb4buf[1356];
int16_t comb5buf[1422];
int16_t comb6buf[1491];
int16_t comb7buf[1557];
int16_t comb8buf[1617];
uint16_t comb1index;
uint16_t comb2index;
uint16_t comb3index;
uint16_t comb4index;
uint16_t comb5index;
uint16_t comb6index;
uint16_t comb7index;
uint16_t comb8index;
int16_t comb1filter;
int16_t comb2filter;
int16_t comb3filter;
int16_t comb4filter;
int16_t comb5filter;
int16_t comb6filter;
int16_t comb7filter;
int16_t comb8filter;
int16_t combdamp1;
int16_t combdamp2;
int16_t combfeeback;
int16_t allpass1buf[556];
int16_t allpass2buf[441];
int16_t allpass3buf[341];
int16_t allpass4buf[225];
uint16_t allpass1index;
uint16_t allpass2index;
uint16_t allpass3index;
uint16_t allpass4index;
};
class AudioEffectFreeverbStereo : public AudioStream
{
public:
AudioEffectFreeverbStereo();
virtual void update();
void roomsize(float n) {
if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f;
combfeeback = (int)(n * 9175.04f) + 22937;
}
void damping(float n) {
if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f;
int x1 = (int)(n * 13107.2f);
int x2 = 32768 - x1;
__disable_irq();
combdamp1 = x1;
combdamp2 = x2;
__enable_irq();
}
private:
audio_block_t *inputQueueArray[1];
int16_t comb1bufL[1116];
int16_t comb2bufL[1188];
int16_t comb3bufL[1277];
int16_t comb4bufL[1356];
int16_t comb5bufL[1422];
int16_t comb6bufL[1491];
int16_t comb7bufL[1557];
int16_t comb8bufL[1617];
uint16_t comb1indexL;
uint16_t comb2indexL;
uint16_t comb3indexL;
uint16_t comb4indexL;
uint16_t comb5indexL;
uint16_t comb6indexL;
uint16_t comb7indexL;
uint16_t comb8indexL;
int16_t comb1filterL;
int16_t comb2filterL;
int16_t comb3filterL;
int16_t comb4filterL;
int16_t comb5filterL;
int16_t comb6filterL;
int16_t comb7filterL;
int16_t comb8filterL;
int16_t comb1bufR[1139];
int16_t comb2bufR[1211];
int16_t comb3bufR[1300];
int16_t comb4bufR[1379];
int16_t comb5bufR[1445];
int16_t comb6bufR[1514];
int16_t comb7bufR[1580];
int16_t comb8bufR[1640];
uint16_t comb1indexR;
uint16_t comb2indexR;
uint16_t comb3indexR;
uint16_t comb4indexR;
uint16_t comb5indexR;
uint16_t comb6indexR;
uint16_t comb7indexR;
uint16_t comb8indexR;
int16_t comb1filterR;
int16_t comb2filterR;
int16_t comb3filterR;
int16_t comb4filterR;
int16_t comb5filterR;
int16_t comb6filterR;
int16_t comb7filterR;
int16_t comb8filterR;
int16_t combdamp1;
int16_t combdamp2;
int16_t combfeeback;
int16_t allpass1bufL[556];
int16_t allpass2bufL[441];
int16_t allpass3bufL[341];
int16_t allpass4bufL[225];
uint16_t allpass1indexL;
uint16_t allpass2indexL;
uint16_t allpass3indexL;
uint16_t allpass4indexL;
int16_t allpass1bufR[579];
int16_t allpass2bufR[464];
int16_t allpass3bufR[364];
int16_t allpass4bufR[248];
uint16_t allpass1indexR;
uint16_t allpass2indexR;
uint16_t allpass3indexR;
uint16_t allpass4indexR;
};
#endif

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2018 John-Michael Reed
* bleeplabs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Arduino.h>
#include "effect_granular.h"
void AudioEffectGranular::begin(int16_t *sample_bank_def, int16_t max_len_def)
{
max_sample_len = max_len_def;
grain_mode = 0;
read_head = 0;
write_head = 0;
prev_input = 0;
playpack_rate = 65536;
accumulator = 0;
allow_len_change = true;
sample_loaded = false;
sample_bank = sample_bank_def;
}
void AudioEffectGranular::beginFreeze_int(int grain_samples)
{
__disable_irq();
grain_mode = 1;
if (grain_samples < max_sample_len) {
freeze_len = grain_samples;
} else {
freeze_len = grain_samples;
}
sample_loaded = false;
write_en = false;
sample_req = true;
__enable_irq();
}
void AudioEffectGranular::beginPitchShift_int(int grain_samples)
{
__disable_irq();
grain_mode = 2;
if (allow_len_change) {
if (grain_samples < 100) grain_samples = 100;
int maximum = (max_sample_len - 1) / 3;
if (grain_samples > maximum) grain_samples = maximum;
glitch_len = grain_samples;
}
sample_loaded = false;
write_en = false;
sample_req = true;
__enable_irq();
}
void AudioEffectGranular::stop()
{
grain_mode = 0;
allow_len_change = true;
}
void AudioEffectGranular::update(void)
{
audio_block_t *block;
if (sample_bank == NULL) {
block = receiveReadOnly(0);
if (block) release(block);
return;
}
block = receiveWritable(0);
if (!block) return;
if (grain_mode == 0) {
// passthrough, no granular effect
prev_input = block->data[AUDIO_BLOCK_SAMPLES-1];
}
else if (grain_mode == 1) {
// Freeze - sample 1 grain, then repeatedly play it back
for (int j = 0; j < AUDIO_BLOCK_SAMPLES; j++) {
if (sample_req) {
// only begin capture on zero cross
int16_t current_input = block->data[j];
if ((current_input < 0 && prev_input >= 0) ||
(current_input >= 0 && prev_input < 0)) {
write_en = true;
write_head = 0;
read_head = 0;
sample_req = false;
} else {
prev_input = current_input;
}
}
if (write_en) {
sample_bank[write_head++] = block->data[j];
if (write_head >= freeze_len) {
sample_loaded = true;
}
if (write_head >= max_sample_len) {
write_en = false;
}
}
if (sample_loaded) {
if (playpack_rate >= 0) {
accumulator += playpack_rate;
read_head = accumulator >> 16;
}
if (read_head >= freeze_len) {
accumulator = 0;
read_head = 0;
}
block->data[j] = sample_bank[read_head];
}
}
}
else if (grain_mode == 2) {
//GLITCH SHIFT
//basic granular synth thingy
// the shorter the sample the max_sample_len the more tonal it is.
// Longer it has more definition. It's a bit roboty either way which
// is obv great and good enough for noise music.
for (int k = 0; k < AUDIO_BLOCK_SAMPLES; k++) {
// only start recording when the audio is crossing zero to minimize pops
if (sample_req) {
int16_t current_input = block->data[k];
if ((current_input < 0 && prev_input >= 0) ||
(current_input >= 0 && prev_input < 0)) {
write_en = true;
} else {
prev_input = current_input;
}
}
if (write_en) {
sample_req = false;
allow_len_change = true; // Reduces noise by not allowing the
// length to change after the sample has been
// recored. Kind of not too much though
if (write_head >= glitch_len) {
write_head = 0;
sample_loaded = true;
write_en = false;
allow_len_change = false;
}
sample_bank[write_head] = block->data[k];
write_head++;
}
if (sample_loaded) {
//move it to the middle third of the bank.
//3 "seperate" banks are used
float fade_len = 20.00;
int16_t m2 = fade_len;
for (int m = 0; m < 2; m++) {
// I'm off by one somewhere? why is there a tick at the
// beginning of this only when it's combined with the
// fade out???? ooor am i osbserving that incorrectly
// either wait it works enough
sample_bank[m + glitch_len] = 0;
}
for (int m = 2; m < glitch_len-m2; m++) {
sample_bank[m + glitch_len] = sample_bank[m];
}
for (int m = glitch_len-m2; m < glitch_len; m++) {
// fade out the end. You can just make fadet=0
// but it's a little too daleky
float fadet = sample_bank[m] * (m2 / fade_len);
sample_bank[m + glitch_len] = (int16_t)fadet;
m2--;
}
sample_loaded = false;
prev_input = block->data[k];
sample_req = true;
}
accumulator += playpack_rate;
read_head = (accumulator >> 16);
if (read_head >= glitch_len) {
read_head -= glitch_len;
accumulator = 0;
for (int m = 0; m < glitch_len; m++) {
sample_bank[m + (glitch_len*2)] = sample_bank[m+glitch_len];
// sample_bank[m + (glitch_len*2)] = (m%20)*1000;
}
}
block->data[k] = sample_bank[read_head + (glitch_len*2)];
}
}
transmit(block);
release(block);
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 John-Michael Reed
* bleeplabs.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "AudioStream.h"
class AudioEffectGranular : public AudioStream
{
public:
AudioEffectGranular(void): AudioStream(1,inputQueueArray) { }
void begin(int16_t *sample_bank_def, int16_t max_len_def);
void setSpeed(float ratio) {
if (ratio < 0.125) ratio = 0.125;
else if (ratio > 8.0) ratio = 8.0;
playpack_rate = ratio * 65536.0 + 0.499;
}
void beginFreeze(float grain_length) {
if (grain_length <= 0.0) return;
beginFreeze_int(grain_length * (AUDIO_SAMPLE_RATE_EXACT * 0.001) + 0.5);
}
void beginPitchShift(float grain_length) {
if (grain_length <= 0.0) return;
beginPitchShift_int(grain_length * (AUDIO_SAMPLE_RATE_EXACT * 0.001) + 0.5);
}
void stop();
virtual void update(void);
private:
void beginFreeze_int(int grain_samples);
void beginPitchShift_int(int grain_samples);
audio_block_t *inputQueueArray[1];
int16_t *sample_bank;
uint32_t playpack_rate;
uint32_t accumulator;
int16_t max_sample_len;
int16_t write_head;
int16_t read_head;
int16_t grain_mode;
int16_t freeze_len;
int16_t prev_input;
int16_t glitch_len;
bool allow_len_change;
bool sample_loaded;
bool write_en;
bool sample_req;
};

View file

@ -0,0 +1,94 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2015, Hedde Bosman
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_midside.h"
void AudioEffectMidSide::update(void)
{
audio_block_t *blocka, *blockb;
uint32_t *pa, *pb, *end;
uint32_t a12, a34; //, a56, a78;
uint32_t b12, b34; //, b56, b78;
blocka = receiveWritable(0); // left (encoding) or mid (decoding)
blockb = receiveWritable(1); // right (encoding) or side (decoding)
if (!blocka || !blockb) {
if (blocka) release(blocka); // maybe an extra if statement here but if one
if (blockb) release(blockb); // of the blocks is NULL then it's trouble anyway
return;
}
#if defined(KINETISK)
pa = (uint32_t *)(blocka->data);
pb = (uint32_t *)(blockb->data);
end = pa + AUDIO_BLOCK_SAMPLES/2;
if (encoding) {
while (pa < end) {
// mid[i] = (blocka[i] + blockb[i])/2; // div2 to prevent overflows
// side[i] = (blocka[i] - blockb[i])/2; // div2 to prevent overflows
// L[i] = (mid[i] + side[i])/2;
// R[i] = (mid[i] - side[i])/2;
a12 = signed_halving_add_16_and_16(*pa, *pb); // mid12
a34 = signed_halving_add_16_and_16(*(pa+1), *(pb+1)); //mid34
b12 = signed_halving_subtract_16_and_16(*pa, *pb); // side12
b34 = signed_halving_subtract_16_and_16(*(pa+1), *(pb+1)); // side34
*pa++ = a12;
*pa++ = a34;
*pb++ = b12;
*pb++ = b34;
}
} else {
while (pa < end) {
// L[i] = mid[i] + side[i]);
// R[i] = mid[i] - side[i]);
// Because the /2 has already been applied in the encoding,
// we shouldn't have to add it here.
// However... because of the posibility that the user has
// modified mid or side such that
// it could overflow, we have to:
// a) preventively do a (x/2+y/2)*2 again, causing bit reduction
// or b) perform saturation or something.
// While (b) could produce artifacts if saturated, I'll go for
// that option to preserve precision
// QADD16 and QSUB16 perform saturating add/sub
a12 = signed_add_16_and_16(*pa, *pb); // left12
a34 = signed_add_16_and_16(*(pa+1), *(pb+1)); // left34
b12 = signed_subtract_16_and_16(*pa, *pb); // right12
b34 = signed_subtract_16_and_16(*(pa+1), *(pb+1)); // right34
*pa++ = a12;
*pa++ = a34;
*pb++ = b12;
*pb++ = b34;
}
}
transmit(blocka, 0); // mid (encoding) or left (decoding)
transmit(blockb, 1); // side (encoding) or right (decoding)
#endif
release(blocka);
release(blockb);
}

View file

@ -0,0 +1,52 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2015, Hedde Bosman
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_midside_decode_h_
#define effect_midside_decode_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "utility/dspinst.h"
/**
* This object performs the decoding of mid/side signals into a stereo signal.
* That is, left = (mid+side), right = (mid-side)
* After encoding and processing, this object decodes the mid/side components
* back into enjoyable stereo audio.
* Caution: processed mid/side signals may cause digital saturation (clipping).
***************************************************************/
class AudioEffectMidSide : public AudioStream
{
public:
AudioEffectMidSide(void): AudioStream(2,inputQueueArray), encoding(true) { }
void encode() { encoding = true; }
void decode() { encoding = false; }
virtual void update(void);
private:
bool encoding;
audio_block_t *inputQueueArray[2];
};
#endif

View file

@ -0,0 +1,90 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "effect_multiply.h"
void AudioEffectMultiply::update(void)
{
#if defined(KINETISK)
audio_block_t *blocka, *blockb;
uint32_t *pa, *pb, *end;
uint32_t a12, a34; //, a56, a78;
uint32_t b12, b34; //, b56, b78;
blocka = receiveWritable(0);
blockb = receiveReadOnly(1);
if (!blocka) {
if (blockb) release(blockb);
return;
}
if (!blockb) {
release(blocka);
return;
}
pa = (uint32_t *)(blocka->data);
pb = (uint32_t *)(blockb->data);
end = pa + AUDIO_BLOCK_SAMPLES/2;
while (pa < end) {
a12 = *pa;
a34 = *(pa+1);
//a56 = *(pa+2); // 8 samples/loop should work, but crashes.
//a78 = *(pa+3); // why?! maybe a compiler bug??
b12 = *pb++;
b34 = *pb++;
//b56 = *pb++;
//b78 = *pb++;
a12 = pack_16b_16b(
signed_saturate_rshift(multiply_16tx16t(a12, b12), 16, 15),
signed_saturate_rshift(multiply_16bx16b(a12, b12), 16, 15));
a34 = pack_16b_16b(
signed_saturate_rshift(multiply_16tx16t(a34, b34), 16, 15),
signed_saturate_rshift(multiply_16bx16b(a34, b34), 16, 15));
//a56 = pack_16b_16b(
// signed_saturate_rshift(multiply_16tx16t(a56, b56), 16, 15),
// signed_saturate_rshift(multiply_16bx16b(a56, b56), 16, 15));
//a78 = pack_16b_16b(
// signed_saturate_rshift(multiply_16tx16t(a78, b78), 16, 15),
// signed_saturate_rshift(multiply_16bx16b(a78, b78), 16, 15));
*pa++ = a12;
*pa++ = a34;
//*pa++ = a56;
//*pa++ = a78;
}
transmit(blocka);
release(blocka);
release(blockb);
#elif defined(KINETISL)
audio_block_t *block;
block = receiveReadOnly(0);
if (block) release(block);
block = receiveReadOnly(1);
if (block) release(block);
#endif
}

View file

@ -0,0 +1,42 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef effect_multiply_h_
#define effect_multiply_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "utility/dspinst.h"
class AudioEffectMultiply : public AudioStream
{
public:
AudioEffectMultiply() : AudioStream(2, inputQueueArray) { }
virtual void update(void);
private:
audio_block_t *inputQueueArray[2];
};
#endif

View file

@ -0,0 +1,207 @@
/*
* Copyright (c) 2016 Joao Rossi Filho
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// https://github.com/joaoRossiFilho/teensy_reverb
#include <Arduino.h>
#include "effect_reverb.h"
#include "utility/dspinst.h"
#include "math_helper.h"
void
AudioEffectReverb::_do_comb_apf(struct comb_apf *apf, int32_t *in_buf, int32_t *out_buf)
{
int32_t acc_x, acc_y, g;
int32_t w, z;
uint32_t n, buf_len;
g = apf->g;
buf_len = apf->buf_len;
for (n = 0; n < AUDIO_BLOCK_SAMPLES; n++) {
acc_y = apf->buffer[apf->rd_idx%buf_len];
acc_x = in_buf[n];
w = multiply_32x32_rshift32_rounded(g, acc_y);
acc_x += (w << 1);
z = multiply_32x32_rshift32_rounded(g, acc_x);
acc_y -= (z << 1);
apf->buffer[apf->wr_idx%buf_len] = acc_x;
out_buf[n] = acc_y;
apf->rd_idx++;
apf->wr_idx++;
}
}
void
AudioEffectReverb::_do_comb_lpf(struct comb_lpf *lpf, int32_t *in_buf, int32_t *out_buf)
{
int32_t x, y, w, z, g1, g2, z1;
uint32_t n, buf_len;
g1 = lpf->g1;
g2 = lpf->g2;
z1 = lpf->z1;
buf_len = lpf->buf_len;
for (n = 0; n < AUDIO_BLOCK_SAMPLES; n++) {
y = lpf->buffer[lpf->rd_idx%buf_len];
x = in_buf[n];
w = multiply_accumulate_32x32_rshift32_rounded(y, g2, z1);
z = multiply_accumulate_32x32_rshift32_rounded(x, g1, w);
z1 = w;
lpf->buffer[lpf->wr_idx%buf_len] = z;
out_buf[n] = y;
lpf->rd_idx++;
lpf->wr_idx++;
}
lpf->z1 = z1;
}
void
AudioEffectReverb::init_comb_filters(void)
{
int i;
g_flt_apf[0] = 0.7;
g_flt_apf[1] = -0.54;
g_flt_apf[2] = 0.6;
g2_flt_lpf = 0.985;
arm_float_to_q31(g_flt_apf, g_q31_apf, 3);
arm_float_to_q31(&g2_flt_lpf, &g2_q31_lpf, 1);
apf[0].buffer = apf1_buf;
apf[0].buf_len = APF1_BUF_LEN;
apf[0].delay = APF1_DLY_LEN;
apf[1].buffer = apf2_buf;
apf[1].buf_len = APF2_BUF_LEN;
apf[1].delay = APF2_DLY_LEN;
apf[2].buffer = apf3_buf;
apf[2].buf_len = APF3_BUF_LEN;
apf[2].delay = APF3_DLY_LEN;
for (i = 0; i < 3; i++) {
apf[i].g = g_q31_apf[i];
apf[i].wr_idx = 0;
apf[i].rd_idx = apf[i].wr_idx - apf[i].delay -1;
}
lpf[0].buffer = lpf1_buf;
lpf[0].buf_len = LPF1_BUF_LEN;
lpf[0].delay = LPF1_DLY_LEN;
lpf[1].buffer = lpf2_buf;
lpf[1].buf_len = LPF2_BUF_LEN;
lpf[1].delay = LPF2_DLY_LEN;
lpf[2].buffer = lpf3_buf;
lpf[2].buf_len = LPF3_BUF_LEN;
lpf[2].delay = LPF3_DLY_LEN;
lpf[3].buffer = lpf4_buf;
lpf[3].buf_len = LPF4_BUF_LEN;
lpf[3].delay = LPF4_DLY_LEN;
for (i = 0; i < 4; i++) {
lpf[i].g1 = g1_q31_lpf[i];
lpf[i].g2 = g2_q31_lpf;
lpf[i].wr_idx = 0;
lpf[i].rd_idx = lpf[i].wr_idx - lpf[i].delay -1;
}
}
void
AudioEffectReverb::clear_buffers(void)
{
memset(apf1_buf, 0, APF1_BUF_LEN);
memset(apf2_buf, 0, APF1_BUF_LEN);
memset(apf3_buf, 0, APF1_BUF_LEN);
memset(lpf1_buf, 0, LPF1_BUF_LEN);
memset(lpf2_buf, 0, LPF2_BUF_LEN);
memset(lpf3_buf, 0, LPF3_BUF_LEN);
memset(lpf4_buf, 0, LPF4_BUF_LEN);
}
void
AudioEffectReverb::reverbTime(float rt)
{
if (rt <= 0.0)
return;
reverb_time_sec = rt;
g1_flt_lpf[0] = powf(10.0, -(3.0*LPF1_DLY_SEC)/(reverb_time_sec));
g1_flt_lpf[1] = powf(10.0, -(3.0*LPF2_DLY_SEC)/(reverb_time_sec));
g1_flt_lpf[2] = powf(10.0, -(3.0*LPF3_DLY_SEC)/(reverb_time_sec));
g1_flt_lpf[3] = powf(10.0, -(3.0*LPF4_DLY_SEC)/(reverb_time_sec));
arm_float_to_q31(g1_flt_lpf, g1_q31_lpf, 4);
for (int i = 0; i < 4; i++)
lpf[i].g1 = g1_q31_lpf[i];
}
void
AudioEffectReverb::update(void)
{
audio_block_t *block;
if (!(block = receiveWritable()))
return;
if (!block->data)
return;
arm_q15_to_q31(block->data, q31_buf, AUDIO_BLOCK_SAMPLES);
_do_comb_apf(&apf[0], q31_buf, q31_buf);
_do_comb_apf(&apf[1], q31_buf, q31_buf);
_do_comb_lpf(&lpf[0], q31_buf, sum_buf);
arm_shift_q31(sum_buf, -3, sum_buf, AUDIO_BLOCK_SAMPLES);
_do_comb_lpf(&lpf[1], q31_buf, aux_buf);
arm_shift_q31(aux_buf, -3, aux_buf, AUDIO_BLOCK_SAMPLES);
arm_add_q31(sum_buf, aux_buf, sum_buf, AUDIO_BLOCK_SAMPLES);
_do_comb_lpf(&lpf[2], q31_buf, aux_buf);
arm_shift_q31(aux_buf, -3, aux_buf, AUDIO_BLOCK_SAMPLES);
arm_add_q31(sum_buf, aux_buf, sum_buf, AUDIO_BLOCK_SAMPLES);
_do_comb_lpf(&lpf[3], q31_buf, aux_buf);
arm_shift_q31(aux_buf, -3, aux_buf, AUDIO_BLOCK_SAMPLES);
arm_add_q31(sum_buf, aux_buf, sum_buf, AUDIO_BLOCK_SAMPLES);
_do_comb_apf(&apf[2], sum_buf, q31_buf);
arm_q31_to_q15(q31_buf, block->data, AUDIO_BLOCK_SAMPLES);
transmit(block, 0);
release(block);
}
/* EOF */

View file

@ -0,0 +1,118 @@
/* Reverb for Teensy
*
* Author: Joao Rossi Filho
* joaorossifilho@gmail.com
*
* Soon I'll make a commit with nice comments and discription
*
* Copyright (c) 2016 Joao Rossi FIlho
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef effect_reverb_
#define effect_reverb_
#include "AudioStream.h"
#define APF1_BUF_LEN 600
#define APF2_BUF_LEN 1300
#define APF3_BUF_LEN 500
#define LPF1_BUF_LEN 1400
#define LPF2_BUF_LEN 1700
#define LPF3_BUF_LEN 1800
#define LPF4_BUF_LEN 2000
#define APF1_DLY_LEN 586
#define APF2_DLY_LEN 1239
#define APF3_DLY_LEN 485
#define LPF1_DLY_LEN 1398
#define LPF2_DLY_LEN 1637
#define LPF3_DLY_LEN 1774
#define LPF4_DLY_LEN 1947
#define LPF1_DLY_SEC 0.03171
#define LPF2_DLY_SEC 0.03711
#define LPF3_DLY_SEC 0.04023
#define LPF4_DLY_SEC 0.04414
class AudioEffectReverb : public AudioStream
{
public:
AudioEffectReverb(void) : AudioStream(1, inputQueueArray) {
init_comb_filters();
clear_buffers();
reverbTime(5.0);
}
virtual void update(void);
void reverbTime(float);
private:
struct comb_apf {
int32_t g;
int32_t *buffer;
uint32_t buf_len;
uint32_t delay, rd_idx, wr_idx;
};
struct comb_lpf {
int32_t g1, g2, z1;
int32_t *buffer;
uint32_t buf_len;
uint32_t delay, rd_idx, wr_idx;
};
void init_comb_filters(void);
void clear_buffers(void);
static void _do_comb_apf(struct comb_apf *apf, int32_t *in_buf, int32_t *out_buf);
static void _do_comb_lpf(struct comb_lpf *lpf, int32_t *in_buf, int32_t *out_buf);
audio_block_t *inputQueueArray[1];
struct comb_apf apf[3];
struct comb_lpf lpf[4];
float reverb_time_sec;
float g_flt_apf[3];
int32_t g_q31_apf[3];
float g1_flt_lpf[4];
int32_t g1_q31_lpf[4];
float g2_flt_lpf;
int32_t g2_q31_lpf;
int32_t apf1_buf[APF1_BUF_LEN];
int32_t apf2_buf[APF2_BUF_LEN];
int32_t apf3_buf[APF3_BUF_LEN];
int32_t lpf1_buf[LPF1_BUF_LEN];
int32_t lpf2_buf[LPF2_BUF_LEN];
int32_t lpf3_buf[LPF3_BUF_LEN];
int32_t lpf4_buf[LPF4_BUF_LEN];
int32_t q31_buf[AUDIO_BLOCK_SAMPLES];
int32_t sum_buf[AUDIO_BLOCK_SAMPLES];
int32_t aux_buf[AUDIO_BLOCK_SAMPLES];
};
#endif

View file

@ -0,0 +1,78 @@
/*
* Waveshaper for Teensy 3.X audio
*
* Copyright (c) 2017 Damien Clarke, http://damienclarke.me
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Arduino.h>
#include "effect_waveshaper.h"
AudioEffectWaveshaper::~AudioEffectWaveshaper()
{
if(this->waveshape) {
delete [] this->waveshape;
}
}
void AudioEffectWaveshaper::shape(float* waveshape, int length)
{
// length must be bigger than 1 and equal to a power of two + 1
// anything else means we don't continue
if(!waveshape || length < 2 || length > 32769 || ((length - 1) & (length - 2))) return;
if(this->waveshape) {
delete [] this->waveshape;
}
this->waveshape = new int16_t[length];
for(int i = 0; i < length; i++) {
this->waveshape[i] = 32767 * waveshape[i];
}
// set lerpshift to the number of bits to shift while interpolating
// to cover the entire waveshape over a uint16_t input range
int index = length - 1;
lerpshift = 16;
while (index >>= 1) --lerpshift;
}
void AudioEffectWaveshaper::update(void)
{
if(!waveshape) return;
audio_block_t *block;
block = receiveWritable();
if (!block) return;
uint16_t x, xa;
int16_t i, ya, yb;
for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
// bring int16_t data into uint16_t range
x = block->data[i] + 32768;
// lerp waveshape (from http://coranac.com/tonc/text/fixed.htm)
xa = x >> lerpshift;
ya = waveshape[xa];
yb = waveshape[xa + 1];
block->data[i] = ya + ((yb - ya) * (x - (xa << lerpshift)) >> lerpshift);
}
transmit(block);
release(block);
}

View file

@ -0,0 +1,44 @@
/*
* Waveshaper for Teensy 3.X audio
*
* Copyright (c) 2017 Damien Clarke, http://damienclarke.me
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef effect_waveshaper_h_
#define effect_waveshaper_h_
#include "Arduino.h"
#include "AudioStream.h"
class AudioEffectWaveshaper : public AudioStream
{
public:
AudioEffectWaveshaper(void): AudioStream(1, inputQueueArray) {}
~AudioEffectWaveshaper();
virtual void update(void);
void shape(float* waveshape, int length);
private:
audio_block_t *inputQueueArray[1];
int16_t* waveshape;
int16_t lerpshift;
};
#endif

View file

@ -0,0 +1,256 @@
// Dial Tone (DTMF) decoding example.
//
// The audio with dial tones is connected to analog input A2,
// without using the audio shield. See the "DialTone_DTMF"
// example for using the audio shield.
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputAnalog audioIn;
AudioAnalyzeToneDetect row1; // 7 tone detectors are needed
AudioAnalyzeToneDetect row2; // to receive DTMF dial tones
AudioAnalyzeToneDetect row3;
AudioAnalyzeToneDetect row4;
AudioAnalyzeToneDetect column1;
AudioAnalyzeToneDetect column2;
AudioAnalyzeToneDetect column3;
// Create Audio connections between the components
//
AudioConnection patchCord1(audioIn, 0, row1, 0);
AudioConnection patchCord2(audioIn, 0, row2, 0);
AudioConnection patchCord3(audioIn, 0, row3, 0);
AudioConnection patchCord4(audioIn, 0, row4, 0);
AudioConnection patchCord5(audioIn, 0, column1, 0);
AudioConnection patchCord6(audioIn, 0, column2, 0);
AudioConnection patchCord7(audioIn, 0, column3, 0);
// pins where the 7 segment LEDs are connected
const int sevenseg_a = 17; // aaa
const int sevenseg_b = 9; // f b
const int sevenseg_c = 11; // f b
const int sevenseg_d = 12; // ggg
const int sevenseg_e = 14; // e c
const int sevenseg_f = 15; // e c
const int sevenseg_g = 10; // ddd
void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(3);
//while (!Serial) ;
//delay(100);
// Configure the tone detectors with the frequency and number
// of cycles to match. These numbers were picked for match
// times of approx 30 ms. Longer times are more precise.
row1.frequency(697, 21);
row2.frequency(770, 23);
row3.frequency(852, 25);
row4.frequency(941, 28);
column1.frequency(1209, 36);
column2.frequency(1336, 40);
column3.frequency(1477, 44);
// The 7 segment display is "common anode), where the
// common pin connects to +3.3V. LOW turns the LED on
// and HIGH turns the LED off. If you use a common
// cathode display, you will need to change all the HIGH
// to LOW and LOW to HIGH.
pinMode(sevenseg_a, OUTPUT);
pinMode(sevenseg_b, OUTPUT);
pinMode(sevenseg_c, OUTPUT);
pinMode(sevenseg_d, OUTPUT);
pinMode(sevenseg_e, OUTPUT);
pinMode(sevenseg_f, OUTPUT);
pinMode(sevenseg_g, OUTPUT);
digitalWrite(sevenseg_a, HIGH);
digitalWrite(sevenseg_b, HIGH);
digitalWrite(sevenseg_c, HIGH);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, HIGH);
}
const float row_threshold = 0.2;
const float column_threshold = 0.2;
void loop() {
float r1, r2, r3, r4, c1, c2, c3;
char digit=0;
// read all seven tone detectors
r1 = row1.read();
r2 = row2.read();
r3 = row3.read();
r4 = row4.read();
c1 = column1.read();
c2 = column2.read();
c3 = column3.read();
// print the raw data, for troubleshooting
Serial.print("tones: ");
Serial.print(r1);
Serial.print(", ");
Serial.print(r2);
Serial.print(", ");
Serial.print(r3);
Serial.print(", ");
Serial.print(r4);
Serial.print(", ");
Serial.print(c1);
Serial.print(", ");
Serial.print(c2);
Serial.print(", ");
Serial.print(c3);
// check all 12 combinations for key press
if (r1 >= row_threshold) {
if (c1 > column_threshold) {
digit = '1';
digitalWrite(sevenseg_a, HIGH);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, HIGH);
} else if (c2 > column_threshold) {
digit = '2';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, HIGH);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, LOW);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, LOW);
} else if (c3 > column_threshold) {
digit = '3';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, LOW);
}
} else if (r2 >= row_threshold) {
if (c1 > column_threshold) {
digit = '4';
digitalWrite(sevenseg_a, HIGH);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
} else if (c2 > column_threshold) {
digit = '5';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, HIGH);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
} else if (c3 > column_threshold) {
digit = '6';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, HIGH);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, LOW);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
}
} else if (r3 >= row_threshold) {
if (c1 > column_threshold) {
digit = '7';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, HIGH);
} else if (c2 > column_threshold) {
digit = '8';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, LOW);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
} else if (c3 > column_threshold) {
digit = '9';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
}
} else if (r4 >= row_threshold) {
if (c1 > column_threshold) {
digit = '*';
digitalWrite(sevenseg_a, HIGH);
digitalWrite(sevenseg_b, HIGH);
digitalWrite(sevenseg_c, HIGH);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, HIGH);
digitalWrite(sevenseg_f, HIGH);
digitalWrite(sevenseg_g, LOW);
} else if (c2 > column_threshold) {
digit = '0';
digitalWrite(sevenseg_a, LOW);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, LOW);
digitalWrite(sevenseg_e, LOW);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, HIGH);
} else if (c3 > column_threshold) {
digit = '#';
digitalWrite(sevenseg_a, HIGH);
digitalWrite(sevenseg_b, LOW);
digitalWrite(sevenseg_c, LOW);
digitalWrite(sevenseg_d, HIGH);
digitalWrite(sevenseg_e, LOW);
digitalWrite(sevenseg_f, LOW);
digitalWrite(sevenseg_g, LOW);
}
}
// print the key, if any found
if (digit > 0) {
Serial.print(" --> Key: ");
Serial.print(digit);
}
Serial.println();
// uncomment these lines to see how much CPU time
// the tone detectors and audio library are using
//Serial.print("CPU=");
//Serial.print(AudioProcessorUsage());
//Serial.print("%, max=");
//Serial.print(AudioProcessorUsageMax());
//Serial.print("% ");
delay(25);
}

View file

@ -0,0 +1,230 @@
// Dial Tone (DTMF) decoding example.
//
// The audio with dial tones is connected to audio shield
// Left Line-In pin. Dial tone output is produced on the
// Line-Out and headphones.
//
// Use the Arduino Serial Monitor to watch for incoming
// dial tones, and to send digits to be played as dial tones.
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S audioIn;
AudioAnalyzeToneDetect row1; // 7 tone detectors are needed
AudioAnalyzeToneDetect row2; // to receive DTMF dial tones
AudioAnalyzeToneDetect row3;
AudioAnalyzeToneDetect row4;
AudioAnalyzeToneDetect column1;
AudioAnalyzeToneDetect column2;
AudioAnalyzeToneDetect column3;
AudioSynthWaveformSine sine1; // 2 sine wave
AudioSynthWaveformSine sine2; // to create DTMF
AudioMixer4 mixer;
AudioOutputI2S audioOut;
// Create Audio connections between the components
//
AudioConnection patchCord01(audioIn, 0, row1, 0);
AudioConnection patchCord02(audioIn, 0, row2, 0);
AudioConnection patchCord03(audioIn, 0, row3, 0);
AudioConnection patchCord04(audioIn, 0, row4, 0);
AudioConnection patchCord05(audioIn, 0, column1, 0);
AudioConnection patchCord06(audioIn, 0, column2, 0);
AudioConnection patchCord07(audioIn, 0, column3, 0);
AudioConnection patchCord10(sine1, 0, mixer, 0);
AudioConnection patchCord11(sine2, 0, mixer, 1);
AudioConnection patchCord12(mixer, 0, audioOut, 0);
AudioConnection patchCord13(mixer, 0, audioOut, 1);
// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;
void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);
// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.volume(0.5);
while (!Serial) ;
delay(100);
// Configure the tone detectors with the frequency and number
// of cycles to match. These numbers were picked for match
// times of approx 30 ms. Longer times are more precise.
row1.frequency(697, 21);
row2.frequency(770, 23);
row3.frequency(852, 25);
row4.frequency(941, 28);
column1.frequency(1209, 36);
column2.frequency(1336, 40);
column3.frequency(1477, 44);
}
const float row_threshold = 0.2;
const float column_threshold = 0.2;
void loop() {
float r1, r2, r3, r4, c1, c2, c3;
char digit=0;
// read all seven tone detectors
r1 = row1.read();
r2 = row2.read();
r3 = row3.read();
r4 = row4.read();
c1 = column1.read();
c2 = column2.read();
c3 = column3.read();
// print the raw data, for troubleshooting
Serial.print("tones: ");
Serial.print(r1);
Serial.print(", ");
Serial.print(r2);
Serial.print(", ");
Serial.print(r3);
Serial.print(", ");
Serial.print(r4);
Serial.print(", ");
Serial.print(c1);
Serial.print(", ");
Serial.print(c2);
Serial.print(", ");
Serial.print(c3);
// check all 12 combinations for key press
if (r1 >= row_threshold) {
if (c1 > column_threshold) {
digit = '1';
} else if (c2 > column_threshold) {
digit = '2';
} else if (c3 > column_threshold) {
digit = '3';
}
} else if (r2 >= row_threshold) {
if (c1 > column_threshold) {
digit = '4';
} else if (c2 > column_threshold) {
digit = '5';
} else if (c3 > column_threshold) {
digit = '6';
}
} else if (r3 >= row_threshold) {
if (c1 > column_threshold) {
digit = '7';
} else if (c2 > column_threshold) {
digit = '8';
} else if (c3 > column_threshold) {
digit = '9';
}
} else if (r4 >= row_threshold) {
if (c1 > column_threshold) {
digit = '*';
} else if (c2 > column_threshold) {
digit = '0';
} else if (c3 > column_threshold) {
digit = '#';
}
}
// print the key, if any found
if (digit > 0) {
Serial.print(" --> Key: ");
Serial.print(digit);
}
Serial.println();
// uncomment these lines to see how much CPU time
// the tone detectors and audio library are using
//Serial.print("CPU=");
//Serial.print(AudioProcessorUsage());
//Serial.print("%, max=");
//Serial.print(AudioProcessorUsageMax());
//Serial.print("% ");
// check if any data has arrived from the serial monitor
if (Serial.available()) {
char key = Serial.read();
int low=0;
int high=0;
if (key == '1') {
low = 697;
high = 1209;
} else if (key == '2') {
low = 697;
high = 1336;
} else if (key == '3') {
low = 697;
high = 1477;
} else if (key == '4') {
low = 770;
high = 1209;
} else if (key == '5') {
low = 770;
high = 1336;
} else if (key == '6') {
low = 770;
high = 1477;
} else if (key == '7') {
low = 852;
high = 1209;
} else if (key == '8') {
low = 852;
high = 1336;
} else if (key == '9') {
low = 852;
high = 1477;
} else if (key == '*') {
low = 941;
high = 1209;
} else if (key == '0') {
low = 941;
high = 1336;
} else if (key == '#') {
low = 941;
high = 1477;
}
// play the DTMF tones, if characters send from the Arduino Serial Monitor
if (low > 0 && high > 0) {
Serial.print("Output sound for key ");
Serial.print(key);
Serial.print(", low freq=");
Serial.print(low);
Serial.print(", high freq=");
Serial.print(high);
Serial.println();
AudioNoInterrupts(); // disable audio library momentarily
sine1.frequency(low);
sine1.amplitude(0.4);
sine2.frequency(high);
sine2.amplitude(0.45);
AudioInterrupts(); // enable, both tones will start together
delay(100); // let the sound play for 0.1 second
AudioNoInterrupts();
sine1.amplitude(0);
sine2.amplitude(0);
AudioInterrupts();
delay(50); // make sure we have 0.05 second silence after
}
}
delay(25);
}

View file

@ -0,0 +1,78 @@
// FFT Test
//
// Compute a 1024 point Fast Fourier Transform (spectrum analysis)
// on audio connected to the Left Line-In pin. By changing code,
// a synthetic sine wave can be input instead.
//
// The first 40 (of 512) frequency analysis bins are printed to
// the Arduino Serial Monitor. Viewing the raw data can help you
// understand how the FFT works and what results to expect when
// using the data to control LEDs, motors, or other fun things!
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioSynthWaveformSine sinewave;
AudioAnalyzeFFT1024 myFFT;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
// Connect either the live input or synthesized sine wave
AudioConnection patchCord1(audioInput, 0, myFFT, 0);
//AudioConnection patchCord1(sinewave, 0, myFFT, 0);
AudioControlSGTL5000 audioShield;
void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);
// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.5);
// Configure the window algorithm to use
myFFT.windowFunction(AudioWindowHanning1024);
//myFFT.windowFunction(NULL);
// Create a synthetic sine wave, for testing
// To use this, edit the connections above
sinewave.amplitude(0.8);
sinewave.frequency(1034.007);
}
void loop() {
float n;
int i;
if (myFFT.available()) {
// each time new FFT data is available
// print it all to the Arduino Serial Monitor
Serial.print("FFT: ");
for (i=0; i<40; i++) {
n = myFFT.read(i);
if (n >= 0.01) {
Serial.print(n);
Serial.print(" ");
} else {
Serial.print(" - "); // don't print "0.00"
}
}
Serial.println();
}
}

View file

@ -0,0 +1,97 @@
/* Detect the frequency of music notes, by Colin Duffy
This example repeatedly plays a guitar note (output to the DAC pin)
and prints an analysis of the frequency to the Arduino Serial Monitor
https://forum.pjrc.com/threads/32252-Different-Range-FFT-Algorithm/page2
https://github.com/duff2013/AudioTuner
*/
/*
C C# D Eb E F F# G G# A Bb B
0 16.35 17.32 18.35 19.45 20.60 21.83 23.12 24.50 25.96 27.50 29.14 30.87
1 32.70 34.65 36.71 38.89 41.20 43.65 46.25 49.00 51.91 55.00 58.27 61.74
2 65.41 69.30 73.42 77.78 82.41 87.31 92.50 98.00 103.8 110.0 116.5 123.5
3 130.8 138.6 146.8 155.6 164.8 174.6 185.0 196.0 207.7 220.0 233.1 246.9
4 261.6 277.2 293.7 311.1 329.6 349.2 370.0 392.0 415.3 440.0 466.2 493.9
5 523.3 554.4 587.3 622.3 659.3 698.5 740.0 784.0 830.6 880.0 932.3 987.8
6 1047 1109 1175 1245 1319 1397 1480 1568 1661 1760 1865 1976
7 2093 2217 2349 2489 2637 2794 2960 3136 3322 3520 3729 3951
8 4186 4435 4699 4978 5274 5588 5920 6272 6645 7040 7459 7902
Guitar strings are E2=82.41Hz, A2=110Hz, D3=146.8Hz, G3=196Hz, B3=246.9Hz, E4=329.6Hz
Bass strings are (5th string) B0=30.87Hz, (4th string) E1=41.20Hz, A1=55Hz, D2=73.42Hz, G2=98Hz
This example tests the yin algorithm with actual notes from nylon string guitar recorded
as wav format at 16B @ 44100 samples/sec. Since the decay of the notes will be longer than what
the teensy can store in flash these notes are truncated to ~120,000B or about 1/2 of the whole
signal.
*/
#include <SerialFlash.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
//---------------------------------------------------------------------------------------
#include "guitar_e2_note.h"
#include "guitar_a2_note.h"
#include "guitar_d3_note.h"
#include "guitar_g3_note.h"
#include "guitar_b3_note.h"
#include "guitar_e4_note.h"
#include "tuba_1.h"
#include "tuba_2.h"
#include "tuba_3.h"
#include "tuba_4.h"
#include "tuba_5.h"
//---------------------------------------------------------------------------------------
AudioAnalyzeNoteFrequency notefreq;
AudioOutputAnalog dac;
AudioPlayMemory wav_note;
AudioMixer4 mixer;
//---------------------------------------------------------------------------------------
AudioConnection patchCord0(wav_note, 0, mixer, 0);
AudioConnection patchCord1(mixer, 0, notefreq, 0);
AudioConnection patchCord2(mixer, 0, dac, 0);
//---------------------------------------------------------------------------------------
IntervalTimer playNoteTimer;
void playNote(void) {
if (!wav_note.isPlaying()) {
// Uncomment one of these sounds to test notefreq
wav_note.play(guitar_e2_note);
//wav_note.play(guitar_a2_note);
//wav_note.play(guitar_d3_note);
//wav_note.play(guitar_g3_note);
//wav_note.play(guitar_b3_note);
//wav_note.play(guitar_e4_note);
//wav_note.play(tuba_1);
//wav_note.play(tuba_2);
//wav_note.play(tuba_3);
//wav_note.play(tuba_4);
//wav_note.play(tuba_5);
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
}
}
//---------------------------------------------------------------------------------------
void setup() {
AudioMemory(30);
/*
* Initialize the yin algorithm's absolute
* threshold, this is good number.
*/
notefreq.begin(.15);
pinMode(LED_BUILTIN, OUTPUT);
// Audio library isr allways gets priority
playNoteTimer.priority(144);
playNoteTimer.begin(playNote, 1000);
}
void loop() {
// read back fundamental frequency
if (notefreq.available()) {
float note = notefreq.read();
float prob = notefreq.probability();
Serial.printf("Note: %3.2f | Probability: %.2f\n", note, prob);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_a2_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_b3_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_d3_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_e2_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_e4_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
extern const unsigned int guitar_g3_note[52184];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
// Audio data converted from WAV file by wav2sketch
extern const unsigned int tuba_1[31041];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
// Audio data converted from WAV file by wav2sketch
extern const unsigned int tuba_2[31873];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
// Audio data converted from WAV file by wav2sketch
extern const unsigned int tuba_3[31425];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
// Audio data converted from WAV file by wav2sketch
extern const unsigned int tuba_4[31425];

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
// Audio data converted from WAV file by wav2sketch
extern const unsigned int tuba_5[33217];

View file

@ -0,0 +1,82 @@
/* Adaptation of Stereo peak meter example, including RMS.
assumes Audio adapter but just uses terminal so no more parts required.
This example code is in the public domain
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
const int myInput = AUDIO_INPUT_LINEIN;
// const int myInput = AUDIO_INPUT_MIC;
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioAnalyzePeak peak_L;
AudioAnalyzePeak peak_R;
AudioAnalyzeRMS rms_L;
AudioAnalyzeRMS rms_R;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
AudioConnection c1(audioInput, 0, peak_L, 0);
AudioConnection c2(audioInput, 1, peak_R, 0);
AudioConnection c3(audioInput, 0, rms_L, 0);
AudioConnection c4(audioInput, 1, rms_R, 0);
AudioConnection c5(audioInput, 0, audioOutput, 0);
AudioConnection c6(audioInput, 1, audioOutput, 1);
AudioControlSGTL5000 audioShield;
void setup() {
AudioMemory(6);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.5);
Serial.begin(9600);
}
// for best effect make your terminal/monitor a minimum of 62 chars wide and as high as you can.
elapsedMillis fps;
uint8_t cnt=0;
void loop() {
if(fps > 24) {
if (peak_L.available() && peak_R.available() && rms_L.available() && rms_R.available()) {
fps=0;
uint8_t leftPeak = peak_L.read() * 30.0;
uint8_t rightPeak = peak_R.read() * 30.0;
uint8_t leftRMS = rms_L.read() * 30.0;
uint8_t rightRMS = rms_R.read() * 30.0;
for (cnt=0; cnt < 30-leftPeak; cnt++) {
Serial.print(" ");
}
while (cnt++ < 29 && cnt < 30-leftRMS) {
Serial.print("<");
}
while (cnt++ < 30) {
Serial.print("=");
}
Serial.print("||");
for(cnt=0; cnt < rightRMS; cnt++) {
Serial.print("=");
}
for(; cnt < rightPeak; cnt++) {
Serial.print(">");
}
while(cnt++ < 30) {
Serial.print(" ");
}
Serial.print(AudioProcessorUsage());
Serial.print("/");
Serial.print(AudioProcessorUsageMax());
Serial.println();
}
}
}

View file

@ -0,0 +1,46 @@
/* Mono Peak Meter
Scrolling peak audio level meter in the Arduino Serial Monitor
Audio input needs to connect to pin 16 (A2). The signal range is 0 to 1.2V.
See the documentation in the Audio System Design Tool for the recommended
circuit to connect an analog signal.
This example code is in the public domain
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioInputAnalog adc1; //xy=164,95
AudioAnalyzePeak peak1; //xy=317,123
AudioConnection patchCord1(adc1, peak1);
// GUItool: end automatically generated code
void setup() {
AudioMemory(4);
Serial.begin(9600);
}
// for best effect make your terminal/monitor a minimum of 31 chars wide and as high as you can.
elapsedMillis fps;
void loop() {
if (fps > 24) {
if (peak1.available()) {
fps = 0;
int monoPeak = peak1.read() * 30.0;
Serial.print("|");
for (int cnt=0; cnt<monoPeak; cnt++) {
Serial.print(">");
}
Serial.println();
}
}
}

View file

@ -0,0 +1,64 @@
/* Stereo peak meter example, assumes Audio adapter but just uses terminal so no more parts required.
This example code is in the public domain
*/
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
const int myInput = AUDIO_INPUT_LINEIN;
// const int myInput = AUDIO_INPUT_MIC;
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioAnalyzePeak peak_L;
AudioAnalyzePeak peak_R;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
AudioConnection c1(audioInput,0,peak_L,0);
AudioConnection c2(audioInput,1,peak_R,0);
AudioConnection c3(audioInput,0,audioOutput,0);
AudioConnection c4(audioInput,1,audioOutput,1);
AudioControlSGTL5000 audioShield;
void setup() {
AudioMemory(6);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.5);
Serial.begin(9600);
}
// for best effect make your terminal/monitor a minimum of 62 chars wide and as high as you can.
elapsedMillis fps;
uint8_t cnt=0;
void loop() {
if(fps > 24) {
if (peak_L.available() && peak_R.available()) {
fps=0;
uint8_t leftPeak=peak_L.read() * 30.0;
uint8_t rightPeak=peak_R.read() * 30.0;
for(cnt=0;cnt<30-leftPeak;cnt++) {
Serial.print(" ");
}
while(cnt++<30) {
Serial.print("<");
}
Serial.print("||");
for(cnt=0;cnt<rightPeak;cnt++) {
Serial.print(">");
}
while(cnt++<30) {
Serial.print(" ");
}
Serial.println();
}
}
}

View file

@ -0,0 +1,145 @@
#include <LiquidCrystal.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioInputI2S i2s1; //xy=139,91
AudioMixer4 mixer1; //xy=312,134
AudioOutputI2S i2s2; //xy=392,32
AudioAnalyzeFFT1024 fft1024; //xy=467,147
AudioConnection patchCord1(i2s1, 0, mixer1, 0);
AudioConnection patchCord2(i2s1, 0, i2s2, 0);
AudioConnection patchCord3(i2s1, 1, mixer1, 1);
AudioConnection patchCord4(i2s1, 1, i2s2, 1);
AudioConnection patchCord5(mixer1, fft1024);
AudioControlSGTL5000 audioShield; //xy=366,225
// GUItool: end automatically generated code
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
// The scale sets how much sound is needed in each frequency range to
// show all 8 bars. Higher numbers are more sensitive.
float scale = 60.0;
// An array to hold the 16 frequency bands
float level[16];
// This array holds the on-screen levels. When the signal drops quickly,
// these are used to lower the on-screen level 1 bar per update, which
// looks more pleasing to corresponds to human sound perception.
int shown[16];
// Use the LiquidCrystal library to display the spectrum
//
LiquidCrystal lcd(0, 1, 2, 3, 4, 5);
byte bar1[8] = {0,0,0,0,0,0,0,255};
byte bar2[8] = {0,0,0,0,0,0,255,255}; // 8 bar graph
byte bar3[8] = {0,0,0,0,0,255,255,255}; // custom
byte bar4[8] = {0,0,0,0,255,255,255,255}; // characters
byte bar5[8] = {0,0,0,255,255,255,255,255};
byte bar6[8] = {0,0,255,255,255,255,255,255};
byte bar7[8] = {0,255,255,255,255,255,255,255};
byte bar8[8] = {255,255,255,255,255,255,255,255};
void setup() {
// Audio requires memory to work.
AudioMemory(12);
// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.5);
// turn on the LCD and define the custom characters
lcd.begin(16, 2);
lcd.print("Audio Spectrum");
lcd.createChar(0, bar1);
lcd.createChar(1, bar2);
lcd.createChar(2, bar3);
lcd.createChar(3, bar4);
lcd.createChar(4, bar5);
lcd.createChar(5, bar6);
lcd.createChar(6, bar7);
lcd.createChar(7, bar8);
// configure the mixer to equally add left & right
mixer1.gain(0, 0.5);
mixer1.gain(1, 0.5);
// pin 21 will select rapid vs animated display
pinMode(21, INPUT_PULLUP);
}
void loop() {
if (fft1024.available()) {
// read the 512 FFT frequencies into 16 levels
// music is heard in octaves, but the FFT data
// is linear, so for the higher octaves, read
// many FFT bins together.
level[0] = fft1024.read(0);
level[1] = fft1024.read(1);
level[2] = fft1024.read(2, 3);
level[3] = fft1024.read(4, 6);
level[4] = fft1024.read(7, 10);
level[5] = fft1024.read(11, 15);
level[6] = fft1024.read(16, 22);
level[7] = fft1024.read(23, 32);
level[8] = fft1024.read(33, 46);
level[9] = fft1024.read(47, 66);
level[10] = fft1024.read(67, 93);
level[11] = fft1024.read(94, 131);
level[12] = fft1024.read(132, 184);
level[13] = fft1024.read(185, 257);
level[14] = fft1024.read(258, 359);
level[15] = fft1024.read(360, 511);
// See this conversation to change this to more or less than 16 log-scaled bands?
// https://forum.pjrc.com/threads/32677-Is-there-a-logarithmic-function-for-FFT-bin-selection-for-any-given-of-bands
// if you have the volume pot soldered to your audio shield
// uncomment this line to make it adjust the full scale signal
//scale = 8.0 + analogRead(A1) / 5.0;
// begin drawing at the first character on the 2nd row
lcd.setCursor(0, 1);
for (int i=0; i<16; i++) {
Serial.print(level[i]);
// TODO: conversion from FFT data to display bars should be
// exponentially scaled. But how keep it a simple example?
int val = level[i] * scale;
if (val > 8) val = 8;
if (val >= shown[i]) {
shown[i] = val;
} else {
if (shown[i] > 0) shown[i] = shown[i] - 1;
val = shown[i];
}
//Serial.print(shown[i]);
Serial.print(" ");
// print each custom digit
if (shown[i] == 0) {
lcd.write(' ');
} else {
lcd.write(shown[i] - 1);
}
}
Serial.print(" cpu:");
Serial.println(AudioProcessorUsageMax());
}
}

View file

@ -0,0 +1,128 @@
/* Waterfall Audio Spectrum Analyzer, adapted from Nathaniel Quillin's
award winning (most over the top) Hackaday SuperCon 2015 Badge Hack.
https://hackaday.io/project/8575-audio-spectrum-analyzer-a-supercon-badge
https://github.com/nqbit/superconbadge
ILI9341 Color TFT Display is used to display spectral data.
Two pots on analog A2 and A3 are required to adjust sensitivity.
Copyright (c) 2015 Nathaniel Quillin
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Audio.h>
#include <ILI9341_t3.h>
#include <SD.h>
#include <SerialFlash.h>
#include <SPI.h>
#include <Wire.h>
// ILI9341 Color TFT Display connections
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
AudioInputI2S i2s1;
AudioOutputI2S i2s2;
AudioAnalyzeFFT1024 fft1024_1;
AudioConnection patchCord5(i2s1, 0, i2s2, 0);
AudioConnection patchCord6(i2s1, 0, i2s2, 1);
AudioConnection patchCord7(i2s1, fft1024_1);
AudioControlSGTL5000 sgtl5000_1;
static int count = 0;
static uint16_t line_buffer[320];
static float scale = 10.0;
static int knob = 0;
static int vol = 0;
void setup(void) {
// Initialize the peripherals.
tft.begin();
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_YELLOW);
tft.setTextSize(2);
AudioMemory(20);
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
sgtl5000_1.micGain(36);
// Uncomment one these to try other window functions
// fft1024_1.windowFunction(NULL);
// fft1024_1.windowFunction(AudioWindowBartlett1024);
// fft1024_1.windowFunction(AudioWindowFlattop1024);
tft.println("Waterfall Spectrum");
tft.println("adapted from");
tft.println("Nathaniel Quillin");
tft.println("SuperCon Badge Hack");
for (int i = 0; i < 100; i++) {
tft.setScroll(count++);
count = count % 320;
delay(12);
}
tft.setRotation(0);
}
void loop() {
knob = analogRead(A2);
vol = analogRead(A3);
scale = 1024 - knob;
sgtl5000_1.micGain((1024 - vol) / 4);
if (fft1024_1.available()) {
for (int i = 0; i < 240; i++) {
line_buffer[240 - i - 1] = colorMap(fft1024_1.output[i]);
}
tft.writeRect(0, count, 240, 1, (uint16_t*) &line_buffer);
tft.setScroll(count++);
count = count % 320;
}
}
uint16_t colorMap(uint16_t val) {
float red;
float green;
float blue;
float temp = val / 65536.0 * scale;
if (temp < 0.5) {
red = 0.0;
green = temp * 2;
blue = 2 * (0.5 - temp);
} else {
red = temp;
green = (1.0 - temp);
blue = 0.0;
}
return tft.color565(red * 256, green * 256, blue * 256);
}

View file

@ -0,0 +1,219 @@
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>
// Bitcrusher example by Jonathan Payne (Pensive) jon@jonnypayne.com
// No rights reserved. Do what you like with it.
// Create the Audio components.
AudioPlaySdWav playWav1; //this will play a looping demo file
AudioOutputI2S headphones; // and it will come out of the headphone socket.
//Audio Effect BitCrusher defs here
AudioEffectBitcrusher left_BitCrusher;
AudioEffectBitcrusher right_BitCrusher;
// Create Audio connections between the components
AudioConnection patchCord1(playWav1, 0, left_BitCrusher, 0);
AudioConnection patchCord2(playWav1, 1, right_BitCrusher, 0);
AudioConnection patchCord3(left_BitCrusher, 0, headphones, 0);
AudioConnection patchCord4(right_BitCrusher, 0, headphones, 1);
// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;
// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN 10
#define SDCARD_MOSI_PIN 7
#define SDCARD_SCK_PIN 14
// Use these with the Teensy 3.5 & 3.6 SD card
//#define SDCARD_CS_PIN BUILTIN_SDCARD
//#define SDCARD_MOSI_PIN 11 // not actually used
//#define SDCARD_SCK_PIN 13 // not actually used
// Use these for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN 4
//#define SDCARD_MOSI_PIN 11
//#define SDCARD_SCK_PIN 13
// Bounce objects to read six pushbuttons (pins 0-5)
//
Bounce button0 = Bounce(0, 5); // cycles the bitcrusher through all bitdepths
Bounce button1 = Bounce(1, 5); //cycles the bitcrusher through some key samplerates
Bounce button2 = Bounce(2, 5); // turns on the compressor (or "Automatic Volume Leveling")
unsigned long SerialMillisecondCounter;
//BitCrusher
int current_CrushBits = 16; //this defaults to passthrough.
int current_SampleRate = 44100; // this defaults to passthrough.
//Compressor
boolean compressorOn = false; // default this to off.
void setup() {
// Configure the pushbutton pins for pullups.
// Each button should connect from the pin to GND.
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
Serial.begin(38400); // open the serial
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(40); //this is WAY more tha nwe need
// turn on the output
audioShield.enable();
audioShield.volume(0.7);
// by default the Teensy 3.1 DAC uses 3.3Vp-p output
// if your 3.3V power has noise, switching to the
// internal 1.2V reference can give you a clean signal
//dac.analogReference(INTERNAL);
// reduce the gain on mixer channels, so more than 1
// sound can play simultaneously without clipping
//SDCard Initialise
SPI.setMOSI(SDCARD_MOSI_PIN);
SPI.setSCK(SDCARD_SCK_PIN);
if (!(SD.begin(SDCARD_CS_PIN))) {
// stop here, but print a message repetitively
while (1) {
Serial.println("Unable to access the SD card");
delay(500);
}
}
// Bitcrusher
left_BitCrusher.bits(current_CrushBits); //set the crusher to defaults. This will passthrough clean at 16,44100
left_BitCrusher.sampleRate(current_SampleRate); //set the crusher to defaults. This will passthrough clean at 16,44100
right_BitCrusher.bits(current_CrushBits); //set the crusher to defaults. This will passthrough clean at 16,44100
right_BitCrusher.sampleRate(current_SampleRate); //set the crusher to defaults. This will passthrough clean at 16,44100
//Bitcrusher
/* Valid values for dap_avc parameters
maxGain; Maximum gain that can be applied
0 - 0 dB
1 - 6.0 dB
2 - 12 dB
lbiResponse; Integrator Response
0 - 0 mS
1 - 25 mS
2 - 50 mS
3 - 100 mS
hardLimit
0 - Hard limit disabled. AVC Compressor/Expander enabled.
1 - Hard limit enabled. The signal is limited to the programmed threshold (signal saturates at the threshold)
threshold
floating point in range 0 to -96 dB
attack
floating point figure is dB/s rate at which gain is increased
decay
floating point figure is dB/s rate at which gain is reduced
*/
// Initialise the AutoVolumeLeveller
audioShield.autoVolumeControl(1, 1, 0, -6, 40, 20); // **BUG** with a max gain of 0, turning the AVC off leaves a hung AVC problem where the attack seems to hang in a loop. with it set 1 or 2, this does not occur.
audioShield.autoVolumeDisable();
audioShield.audioPostProcessorEnable();
SerialMillisecondCounter = millis();
}
int val; //temporary variable for memory usage reporting.
void loop() {
if (millis() - SerialMillisecondCounter >= 5000) {
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
SerialMillisecondCounter = millis();
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}
// Update all the button objects
button0.update();
button1.update();
button2.update();
// Start test sound if it is not playing. This will loop infinitely.
if (! (playWav1.isPlaying())){
playWav1.play("SDTEST1.WAV"); // http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html
}
if (button0.fallingEdge()) {
//Bitcrusher BitDepth
if (current_CrushBits >= 2) { //eachtime you press it, deduct 1 bit from the settings.
current_CrushBits--;
} else {
current_CrushBits = 16; // if you get down to 1 go back to the top.
}
left_BitCrusher.bits(current_CrushBits);
left_BitCrusher.sampleRate(current_SampleRate);
right_BitCrusher.bits(current_CrushBits);
right_BitCrusher.sampleRate(current_SampleRate);
Serial.print("Bitcrusher set to ");
Serial.print(current_CrushBits);
Serial.print(" Bit, Samplerate at ");
Serial.print(current_SampleRate);
Serial.println("Hz");
}
if (button1.fallingEdge()) {
//Bitcrusher SampleRate // the lowest sensible setting is 345. There is a 128 sample buffer, and this will copy sample 1, to each of the other 127 samples.
if (current_SampleRate >= 690) { // 345 * 2, so we can do one more divide
current_SampleRate = current_SampleRate / 2; // half the sample rate each time
} else {
current_SampleRate=44100; // if you get down to the minimum then go back to the top and start over.
}
left_BitCrusher.bits(current_CrushBits);
left_BitCrusher.sampleRate(current_SampleRate);
right_BitCrusher.bits(current_CrushBits);
right_BitCrusher.sampleRate(current_SampleRate);
Serial.print("Bitcrusher set to ");
Serial.print(current_CrushBits);
Serial.print(" Bit, Samplerate at ");
Serial.print(current_SampleRate);
Serial.println("Hz");
}
if (button2.fallingEdge()) {
if (compressorOn) {
//turn off compressor
audioShield.autoVolumeDisable();
compressorOn = false;
} else {
//turn on compressor
audioShield.autoVolumeEnable();
compressorOn = true;
}
Serial.print("Compressor: ");
Serial.println(compressorOn);
}
}

View file

@ -0,0 +1,186 @@
/*
VERSION 2 - use modified library which has been changed to handle
one channel instead of two
140529
Proc = 7 (7), Mem = 4 (4)
2a
- default at startup is to have passthru ON and the button
switches the chorus effect in.
previous performance measures were PROC/MEM 9/4
From: http://www.cs.cf.ac.uk/Dave/CM0268/PDF/10_CM0268_Audio_FX.pdf
about Comb filter effects
Effect Delay range (ms) Modulation
Resonator 0 - 20 None
Flanger 0 - 15 Sinusoidal (approx 1Hz)
Chorus 25 - 50 None
Echo >50 None
FMI:
The audio board uses the following pins.
6 - MEMCS
7 - MOSI
9 - BCLK
10 - SDCS
11 - MCLK
12 - MISO
13 - RX
14 - SCLK
15 - VOL
18 - SDA
19 - SCL
22 - TX
23 - LRCLK
AudioProcessorUsage()
AudioProcessorUsageMax()
AudioProcessorUsageMaxReset()
AudioMemoryUsage()
AudioMemoryUsageMax()
AudioMemoryUsageMaxReset()
The CPU usage is an integer from 0 to 100, and the memory is from 0 to however
many blocks you provided with AudioMemory().
*/
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <SerialFlash.h>
#include <Bounce.h>
// Number of samples in each delay line
#define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES)
// Allocate the delay lines for left and right channels
short l_delayline[CHORUS_DELAY_LENGTH];
short r_delayline[CHORUS_DELAY_LENGTH];
// Default is to just pass the audio through. Grounding this pin
// applies the chorus effect
// Don't use any of the pins listed above
#define PASSTHRU_PIN 1
Bounce b_passthru = Bounce(PASSTHRU_PIN,15);
//const int myInput = AUDIO_INPUT_MIC;
const int myInput = AUDIO_INPUT_LINEIN;
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioEffectChorus l_myEffect;
AudioEffectChorus r_myEffect;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
// Create Audio connections between the components
// Both channels of the audio input go to the chorus effect
AudioConnection c1(audioInput, 0, l_myEffect, 0);
AudioConnection c2(audioInput, 1, r_myEffect, 0);
// both channels chorus effects go to the audio output
AudioConnection c3(l_myEffect, 0, audioOutput, 0);
AudioConnection c4(r_myEffect, 0, audioOutput, 1);
AudioControlSGTL5000 audioShield;
// number of "voices" in the chorus which INCLUDES the original voice
int n_chorus = 2;
// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
void setup() {
Serial.begin(9600);
while (!Serial) ;
delay(3000);
pinMode(PASSTHRU_PIN,INPUT_PULLUP);
// Maximum memory usage was reported as 4
// Proc = 9 (9), Mem = 4 (4)
AudioMemory(4);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.65);
// Warn that the passthru pin is grounded
if(!digitalRead(PASSTHRU_PIN)) {
Serial.print("PASSTHRU_PIN (");
Serial.print(PASSTHRU_PIN);
Serial.println(") is grounded");
}
// Initialize the effect - left channel
// address of delayline
// total number of samples in the delay line
// number of voices in the chorus INCLUDING the original voice
if(!l_myEffect.begin(l_delayline,CHORUS_DELAY_LENGTH,n_chorus)) {
Serial.println("AudioEffectChorus - left channel begin failed");
while(1);
}
// Initialize the effect - right channel
// address of delayline
// total number of samples in the delay line
// number of voices in the chorus INCLUDING the original voice
if(!r_myEffect.begin(r_delayline,CHORUS_DELAY_LENGTH,n_chorus)) {
Serial.println("AudioEffectChorus - left channel begin failed");
while(1);
}
// Initially the effect is off. It is switched on when the
// PASSTHRU button is pushed.
l_myEffect.voices(0);
r_myEffect.voices(0);
Serial.println("setup done");
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}
// audio volume
int volume = 0;
unsigned long last_time = millis();
void loop()
{
// Volume control
int n = analogRead(15);
if (n != volume) {
volume = n;
audioShield.volume((float)n / 1023);
}
if(0) {
if(millis() - last_time >= 5000) {
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
last_time = millis();
}
}
// update the button
b_passthru.update();
// If the passthru button is pushed, switch the chorus on
if(b_passthru.fallingEdge()) {
l_myEffect.voices(n_chorus);
r_myEffect.voices(n_chorus);
}
// If passthru button is released, turn on passthru
if(b_passthru.risingEdge()) {
l_myEffect.voices(0);
r_myEffect.voices(0);
}
}

View file

@ -0,0 +1,54 @@
/*
CHORUS and FLANGE effects
Both effects use a delay line to hold previous samples. This allows
the current sample to be combined in some way with a sample that
occurred in the past. An obvious effect this would allow would be
an echo where the current sample is combined with a sample from,
say, 250 milliseconds ago. The chorus and flange effects do this
as well but they combine samples from only about 50ms (or less) ago.
CHORUS EFFECT
This combines one or more samples up to about 50ms ago. In this
library, the additional samples are evenly spread through the
supplied delay line.
E.G. If the number of voices is specified as 2 then the effect
combines the current sample and the oldest sample (the last one in
the delay line). If the number of voices is 3 then the effect
combines the most recent sample, the oldest sample and the sample
in the middle of the delay line.
For two voices the effect can be represented as:
result = (sample(0) + sample(dt))/2
where sample(0) represents the current sample and sample(dt) is
the sample in the delay line from dt milliseconds ago.
FLANGE EFFECT
This combines only one sample from the delay line but the position
of that sample varies sinusoidally.
In this case the effect can be represented as:
result = sample(0) + sample(dt + depth*sin(2*PI*Fe))
The value of the sine function is always a number from -1 to +1
and so the result of depth*(sinFe) is always a number from
-depth to +depth. Thus, the delayed sample will be selected from
the range (dt-depth) to (dt+depth). This selection will vary
at whatever rate is specified as the frequency of the effect Fe.
Try these settings:
#define FLANGE_DELAY_LENGTH (2*AUDIO_BLOCK_SAMPLES)
and
int s_idx = 2*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/4;
double s_freq = 3;
The flange effect can also produce a chorus effect if a longer
delay line is used with a slower rate, for example try:
#define FLANGE_DELAY_LENGTH (12*AUDIO_BLOCK_SAMPLES)
and
int s_idx = 3*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = .0625;
When trying out these effects with recorded music as input, it is
best to use those where there is a solo voice which is clearly
"in front" of the accompaniment. Tracks which already contain
flange or chorus effects don't work well.
*/

View file

@ -0,0 +1,61 @@
// Delay demonstration example, Teensy Audio Library
// http://www.pjrc.com/teensy/td_libs_Audio.html
//
// Creates a chirp on the left channel, then
// three delayed copies on the right channel.
//
// Requires the audio shield:
// http://www.pjrc.com/store/teensy3_audio.html
//
// This example code is in the public domain.
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioSynthWaveformSine sine1; //xy=158,74
AudioEffectEnvelope envelope1; //xy=232,156
AudioEffectDelay delay1; //xy=393,238
AudioMixer4 mixer1; //xy=532,205
AudioOutputI2S i2s1; //xy=611,61
AudioConnection patchCord1(sine1, envelope1);
AudioConnection patchCord2(envelope1, delay1);
AudioConnection patchCord3(envelope1, 0, i2s1, 0);
AudioConnection patchCord4(delay1, 0, mixer1, 0);
AudioConnection patchCord5(delay1, 1, mixer1, 1);
AudioConnection patchCord6(delay1, 2, mixer1, 2);
AudioConnection patchCord7(delay1, 3, mixer1, 3);
AudioConnection patchCord8(mixer1, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=195,272
// GUItool: end automatically generated code
void setup() {
// allocate enough memory for the delay
AudioMemory(120);
// enable the audio shield
sgtl5000_1.enable();
sgtl5000_1.volume(0.5);
// configure a sine wave for the chirp
// the original is turned on/off by an envelope effect
// and output directly on the left channel
sine1.frequency(1000);
sine1.amplitude(0.5);
// create 3 delay taps, which connect through a
// mixer to the right channel output
delay1.delay(0, 110);
delay1.delay(1, 220);
delay1.delay(2, 330);
}
void loop() {
envelope1.noteOn();
delay(36);
envelope1.noteOff();
delay(4000);
}

View file

@ -0,0 +1,42 @@
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioInputI2S i2s1; //xy=99,60
AudioFilterBiquad biquad1; //xy=257,60
AudioOutputI2S i2s2; //xy=416,60
AudioConnection patchCord1(i2s1, 0, biquad1, 0);
AudioConnection patchCord2(biquad1, 0, i2s2, 0);
AudioConnection patchCord3(biquad1, 0, i2s2, 1);
AudioControlSGTL5000 sgtl5000_1; //xy=305,132
// GUItool: end automatically generated code
const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;
void setup() {
AudioMemory(12);
sgtl5000_1.enable(); // Enable the audio shield
sgtl5000_1.inputSelect(myInput);
sgtl5000_1.volume(0.5);
// Butterworth filter, 12 db/octave
biquad1.setLowpass(0, 800, 0.707);
// Linkwitz-Riley filter, 48 dB/octave
//biquad1.setLowpass(0, 800, 0.54);
//biquad1.setLowpass(1, 800, 1.3);
//biquad1.setLowpass(2, 800, 0.54);
//biquad1.setLowpass(3, 800, 1.3);
}
void loop() {
}

View file

@ -0,0 +1,175 @@
/*
c
- released
b
- Use FIR filters with fast_fft option
The audio board uses the following pins.
6 - MEMCS
7 - MOSI
9 - BCLK
10 - SDCS
11 - MCLK
12 - MISO
13 - RX
14 - SCLK
15 - VOL
18 - SDA
19 - SCL
22 - TX
23 - LRCLK
*/
//#include <arm_math.h>
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <SerialFlash.h>
#include <Bounce.h>
#include "filters.h"
// If this pin is grounded the FIR filter is turned off
// which just passes the audio sraight through
// Don't use any of the pins listed above
#define PASSTHRU_PIN 1
// If this pin goes low the next FIR filter in the list
// is switched in.
#define FILTER_PIN 0
// debounce the passthru and filter switching pins
Bounce b_passthru = Bounce(PASSTHRU_PIN,15);
Bounce b_filter = Bounce(FILTER_PIN,15);
//const int myInput = AUDIO_INPUT_MIC;
const int myInput = AUDIO_INPUT_LINEIN;
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioFilterFIR myFilterL;
AudioFilterFIR myFilterR;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
// Create Audio connections between the components
// Route audio into the left and right filters
AudioConnection c1(audioInput, 0, myFilterL, 0);
AudioConnection c2(audioInput, 1, myFilterR, 0);
// Route the output of the filters to their respective channels
AudioConnection c3(myFilterL, 0, audioOutput, 0);
AudioConnection c4(myFilterR, 0, audioOutput, 1);
AudioControlSGTL5000 audioShield;
struct fir_filter {
short *coeffs;
short num_coeffs; // num_coeffs must be an even number, 4 or higher
};
// index of current filter. Start with the low pass.
int fir_idx = 0;
struct fir_filter fir_list[] = {
{low_pass , 100}, // low pass with cutoff at 1kHz and -60dB at 2kHz
{band_pass, 100}, // bandpass 1200Hz - 1700Hz
{NULL, 0}
};
void setup() {
Serial.begin(9600);
delay(300);
pinMode(PASSTHRU_PIN, INPUT_PULLUP);
pinMode(FILTER_PIN, INPUT_PULLUP);
// allocate memory for the audio library
AudioMemory(8);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.5);
// Warn that the passthru pin is grounded
if(!digitalRead(PASSTHRU_PIN)) {
Serial.print("PASSTHRU_PIN (");
Serial.print(PASSTHRU_PIN);
Serial.println(") is grounded");
}
// Warn that the filter pin is grounded
if(!digitalRead(FILTER_PIN)) {
Serial.print("FILTER_PIN (");
Serial.print(FILTER_PIN);
Serial.println(") is grounded");
}
// Initialize the filter
myFilterL.begin(fir_list[0].coeffs, fir_list[0].num_coeffs);
myFilterR.begin(fir_list[0].coeffs, fir_list[0].num_coeffs);
Serial.println("setup done");
}
// index of current filter when passthrough is selected
int old_idx = -1;
// audio volume
int volume = 0;
unsigned long last_time = millis();
void loop()
{
// Volume control
int n = analogRead(15);
if (n != volume) {
volume = n;
//uncomment this line if your audio shield has the volume pot
//audioShield.volume((float)n / 1023);
}
// update the two buttons
b_passthru.update();
b_filter.update();
// If the passthru button is pushed, save the current
// filter index and then switch the filter to passthru
if (b_passthru.fallingEdge()) {
old_idx = fir_idx;
myFilterL.begin(FIR_PASSTHRU, 0);
myFilterR.begin(FIR_PASSTHRU, 0);
}
// If passthru button is released, restore previous filter
if (b_passthru.risingEdge()) {
if(old_idx != -1) {
myFilterL.begin(fir_list[fir_idx].coeffs, fir_list[fir_idx].num_coeffs);
myFilterR.begin(fir_list[fir_idx].coeffs, fir_list[fir_idx].num_coeffs);
}
old_idx = -1;
}
// switch to next filter in the list
if (b_filter.fallingEdge()) {
fir_idx++;
if (fir_list[fir_idx].num_coeffs == 0) fir_idx = 0;
myFilterL.begin(fir_list[fir_idx].coeffs, fir_list[fir_idx].num_coeffs);
myFilterR.begin(fir_list[fir_idx].coeffs, fir_list[fir_idx].num_coeffs);
}
// print information about resource usage
// Proc = 18 (18), Mem = 4 (5)
if (millis() - last_time >= 2500) {
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
last_time = millis();
}
}

Some files were not shown because too many files have changed in this diff Show more