Working on teensy 4.0 + PAJ7620
This commit is contained in:
parent
7f867b3018
commit
458b9eb891
|
@ -1,249 +0,0 @@
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "synth_waveform.h"
|
|
||||||
#include "arm_math.h"
|
|
||||||
#include "utility/dspinst.h"
|
|
||||||
|
|
||||||
void AudioSynthWaveformModulated::update(void)
|
|
||||||
{
|
|
||||||
audio_block_t *block, *moddata, *shapedata;
|
|
||||||
int16_t *bp, *end;
|
|
||||||
int32_t val1, val2;
|
|
||||||
int16_t magnitude15;
|
|
||||||
uint32_t i, ph, index, index2, scale, priorphase;
|
|
||||||
const uint32_t inc = phase_increment;
|
|
||||||
|
|
||||||
moddata = receiveReadOnly(0);
|
|
||||||
shapedata = receiveReadOnly(1);
|
|
||||||
|
|
||||||
// Pre-compute the phase angle for every output sample of this update
|
|
||||||
ph = phase_accumulator;
|
|
||||||
priorphase = phasedata[AUDIO_BLOCK_SAMPLES-1];
|
|
||||||
if (moddata && modulation_type == 0) {
|
|
||||||
// Frequency Modulation
|
|
||||||
bp = moddata->data;
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
int32_t n = (*bp++) * modulation_factor; // n is # of octaves to mod
|
|
||||||
int32_t ipart = n >> 27; // 4 integer bits
|
|
||||||
n &= 0x7FFFFFF; // 27 fractional bits
|
|
||||||
#ifdef IMPROVE_EXPONENTIAL_ACCURACY
|
|
||||||
// exp2 polynomial suggested by Stefan Stenzel on "music-dsp"
|
|
||||||
// mail list, Wed, 3 Sep 2014 10:08:55 +0200
|
|
||||||
int32_t x = n << 3;
|
|
||||||
n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713);
|
|
||||||
int32_t sq = multiply_32x32_rshift32_rounded(x, x);
|
|
||||||
n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615);
|
|
||||||
n = n + (multiply_32x32_rshift32_rounded(sq,
|
|
||||||
multiply_32x32_rshift32_rounded(x, 1358044250)) << 1);
|
|
||||||
n = n << 1;
|
|
||||||
#else
|
|
||||||
// exp2 algorithm by Laurent de Soras
|
|
||||||
// https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html
|
|
||||||
n = (n + 134217728) << 3;
|
|
||||||
n = multiply_32x32_rshift32_rounded(n, n);
|
|
||||||
n = multiply_32x32_rshift32_rounded(n, 715827883) << 3;
|
|
||||||
n = n + 715827882;
|
|
||||||
#endif
|
|
||||||
uint32_t scale = n >> (14 - ipart);
|
|
||||||
uint64_t phstep = (uint64_t)inc * scale;
|
|
||||||
uint32_t phstep_msw = phstep >> 32;
|
|
||||||
if (phstep_msw < 0x7FFE) {
|
|
||||||
ph += phstep >> 16;
|
|
||||||
} else {
|
|
||||||
ph += 0x7FFE0000;
|
|
||||||
}
|
|
||||||
phasedata[i] = ph;
|
|
||||||
}
|
|
||||||
release(moddata);
|
|
||||||
} else if (moddata) {
|
|
||||||
// Phase Modulation
|
|
||||||
bp = moddata->data;
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
// more than +/- 180 deg shift by 32 bit overflow of "n"
|
|
||||||
uint32_t n = (uint16_t)(*bp++) * modulation_factor;
|
|
||||||
phasedata[i] = ph + n;
|
|
||||||
ph += inc;
|
|
||||||
}
|
|
||||||
release(moddata);
|
|
||||||
} else {
|
|
||||||
// No Modulation Input
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
phasedata[i] = ph;
|
|
||||||
ph += inc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
phase_accumulator = ph;
|
|
||||||
|
|
||||||
// If the amplitude is zero, no output, but phase still increments properly
|
|
||||||
if (magnitude == 0) {
|
|
||||||
if (shapedata) release(shapedata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
block = allocate();
|
|
||||||
if (!block) {
|
|
||||||
if (shapedata) release(shapedata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bp = block->data;
|
|
||||||
|
|
||||||
// Now generate the output samples using the pre-computed phase angles
|
|
||||||
switch(tone_type) {
|
|
||||||
case WAVEFORM_SINE:
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
ph = phasedata[i];
|
|
||||||
index = ph >> 24;
|
|
||||||
val1 = AudioWaveformSine[index];
|
|
||||||
val2 = AudioWaveformSine[index+1];
|
|
||||||
scale = (ph >> 8) & 0xFFFF;
|
|
||||||
val2 *= scale;
|
|
||||||
val1 *= 0x10000 - scale;
|
|
||||||
*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAVEFORM_ARBITRARY:
|
|
||||||
if (!arbdata) {
|
|
||||||
release(block);
|
|
||||||
if (shapedata) release(shapedata);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// len = 256
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
ph = phasedata[i];
|
|
||||||
index = ph >> 24;
|
|
||||||
index2 = index + 1;
|
|
||||||
if (index2 >= 256) index2 = 0;
|
|
||||||
val1 = *(arbdata + index);
|
|
||||||
val2 = *(arbdata + index2);
|
|
||||||
scale = (ph >> 8) & 0xFFFF;
|
|
||||||
val2 *= scale;
|
|
||||||
val1 *= 0x10000 - scale;
|
|
||||||
*bp++ = multiply_32x32_rshift32(val1 + val2, magnitude);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAVEFORM_PULSE:
|
|
||||||
if (shapedata) {
|
|
||||||
magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
uint32_t width = ((shapedata->data[i] + 0x8000) & 0xFFFF) << 16;
|
|
||||||
if (phasedata[i] < width) {
|
|
||||||
*bp++ = magnitude15;
|
|
||||||
} else {
|
|
||||||
*bp++ = -magnitude15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} // else fall through to orginary square without shape modulation
|
|
||||||
|
|
||||||
case WAVEFORM_SQUARE:
|
|
||||||
magnitude15 = signed_saturate_rshift(magnitude, 16, 1);
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
if (phasedata[i] & 0x80000000) {
|
|
||||||
*bp++ = -magnitude15;
|
|
||||||
} else {
|
|
||||||
*bp++ = magnitude15;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAVEFORM_SAWTOOTH:
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
*bp++ = signed_multiply_32x16t(magnitude, phasedata[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAVEFORM_SAWTOOTH_REVERSE:
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
*bp++ = signed_multiply_32x16t(0xFFFFFFFFu - magnitude, phasedata[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WAVEFORM_TRIANGLE_VARIABLE:
|
|
||||||
if (shapedata) {
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
uint32_t width = (shapedata->data[i] + 0x8000) & 0xFFFF;
|
|
||||||
uint32_t rise = 0xFFFFFFFF / width;
|
|
||||||
uint32_t fall = 0xFFFFFFFF / (0xFFFF - width);
|
|
||||||
uint32_t halfwidth = width << 15;
|
|
||||||
uint32_t n;
|
|
||||||
ph = phasedata[i];
|
|
||||||
if (ph < halfwidth) {
|
|
||||||
n = (ph >> 16) * rise;
|
|
||||||
*bp++ = ((n >> 16) * magnitude) >> 16;
|
|
||||||
} else if (ph < 0xFFFFFFFF - halfwidth) {
|
|
||||||
n = 0x7FFFFFFF - (((ph - halfwidth) >> 16) * fall);
|
|
||||||
*bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
|
|
||||||
} else {
|
|
||||||
n = ((ph + halfwidth) >> 16) * rise + 0x80000000;
|
|
||||||
*bp++ = (((int32_t)n >> 16) * magnitude) >> 16;
|
|
||||||
}
|
|
||||||
ph += inc;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} // else fall through to orginary triangle without shape modulation
|
|
||||||
|
|
||||||
case WAVEFORM_TRIANGLE:
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
ph = phasedata[i];
|
|
||||||
uint32_t phtop = ph >> 30;
|
|
||||||
if (phtop == 1 || phtop == 2) {
|
|
||||||
*bp++ = ((0xFFFF - (ph >> 15)) * magnitude) >> 16;
|
|
||||||
} else {
|
|
||||||
*bp++ = (((int32_t)ph >> 15) * magnitude) >> 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WAVEFORM_SAMPLE_HOLD:
|
|
||||||
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
|
|
||||||
ph = phasedata[i];
|
|
||||||
if (ph < priorphase) { // does not work for phase modulation
|
|
||||||
sample = random(magnitude) - (magnitude >> 1);
|
|
||||||
}
|
|
||||||
priorphase = ph;
|
|
||||||
*bp++ = sample;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tone_offset) {
|
|
||||||
bp = block->data;
|
|
||||||
end = bp + AUDIO_BLOCK_SAMPLES;
|
|
||||||
do {
|
|
||||||
val1 = *bp;
|
|
||||||
*bp++ = signed_saturate_rshift(val1 + tone_offset, 16, 0);
|
|
||||||
} while (bp < end);
|
|
||||||
}
|
|
||||||
if (shapedata) release(shapedata);
|
|
||||||
transmit(block, 0);
|
|
||||||
release(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
121
synth_waveform.h
121
synth_waveform.h
|
@ -1,121 +0,0 @@
|
||||||
/** Backport modulated waveform to Adafruit fork
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Audio.h>
|
|
||||||
#include "AudioStream.h"
|
|
||||||
#include "arm_math.h"
|
|
||||||
|
|
||||||
#define WAVEFORM_TRIANGLE_VARIABLE 8
|
|
||||||
|
|
||||||
class AudioSynthWaveformModulated : public AudioStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AudioSynthWaveformModulated(void) : AudioStream(2, inputQueueArray),
|
|
||||||
phase_accumulator(0), phase_increment(0), modulation_factor(32768),
|
|
||||||
magnitude(0), arbdata(NULL), sample(0), tone_offset(0),
|
|
||||||
tone_type(WAVEFORM_SINE), modulation_type(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void frequency(float freq) {
|
|
||||||
if (freq < 0.0) {
|
|
||||||
freq = 0.0;
|
|
||||||
} else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) {
|
|
||||||
freq = AUDIO_SAMPLE_RATE_EXACT / 2;
|
|
||||||
}
|
|
||||||
phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
|
|
||||||
if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000;
|
|
||||||
}
|
|
||||||
void amplitude(float n) { // 0 to 1.0
|
|
||||||
if (n < 0) {
|
|
||||||
n = 0;
|
|
||||||
} else if (n > 1.0) {
|
|
||||||
n = 1.0;
|
|
||||||
}
|
|
||||||
magnitude = n * 65536.0;
|
|
||||||
}
|
|
||||||
void offset(float n) {
|
|
||||||
if (n < -1.0) {
|
|
||||||
n = -1.0;
|
|
||||||
} else if (n > 1.0) {
|
|
||||||
n = 1.0;
|
|
||||||
}
|
|
||||||
tone_offset = n * 32767.0;
|
|
||||||
}
|
|
||||||
void begin(short t_type) {
|
|
||||||
tone_type = t_type;
|
|
||||||
}
|
|
||||||
void begin(float t_amp, float t_freq, short t_type) {
|
|
||||||
amplitude(t_amp);
|
|
||||||
frequency(t_freq);
|
|
||||||
tone_type = t_type;
|
|
||||||
}
|
|
||||||
void arbitraryWaveform(const int16_t *data, float maxFreq) {
|
|
||||||
arbdata = data;
|
|
||||||
}
|
|
||||||
void frequencyModulation(float octaves) {
|
|
||||||
if (octaves > 12.0) {
|
|
||||||
octaves = 12.0;
|
|
||||||
} else if (octaves < 0.1) {
|
|
||||||
octaves = 0.1;
|
|
||||||
}
|
|
||||||
modulation_factor = octaves * 4096.0;
|
|
||||||
modulation_type = 0;
|
|
||||||
}
|
|
||||||
void phaseModulation(float degrees) {
|
|
||||||
if (degrees > 9000.0) {
|
|
||||||
degrees = 9000.0;
|
|
||||||
} else if (degrees < 30.0) {
|
|
||||||
degrees = 30.0;
|
|
||||||
}
|
|
||||||
modulation_factor = degrees * (65536.0 / 180.0);
|
|
||||||
modulation_type = 1;
|
|
||||||
}
|
|
||||||
virtual void update(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
audio_block_t *inputQueueArray[2];
|
|
||||||
uint32_t phase_accumulator;
|
|
||||||
uint32_t phase_increment;
|
|
||||||
uint32_t modulation_factor;
|
|
||||||
int32_t magnitude;
|
|
||||||
const int16_t *arbdata;
|
|
||||||
uint32_t phasedata[AUDIO_BLOCK_SAMPLES];
|
|
||||||
int16_t sample; // for WAVEFORM_SAMPLE_HOLD
|
|
||||||
int16_t tone_offset;
|
|
||||||
uint8_t tone_type;
|
|
||||||
uint8_t modulation_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
173
uilleann.ino
173
uilleann.ino
|
@ -1,38 +1,37 @@
|
||||||
#include <Audio.h>
|
#include <Audio.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <Adafruit_NeoTrellisM4.h>
|
#include <Adafruit_GFX.h>
|
||||||
#include <SFE_MicroOLED.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
#include <SparkFun_Qwiic_Button.h>
|
#include <SparkFun_Qwiic_Button.h>
|
||||||
#include <Adafruit_MPR121.h>
|
#include <Adafruit_MPR121.h>
|
||||||
|
#include <paj7620.h>
|
||||||
#include "synth.h"
|
#include "synth.h"
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "notes.h"
|
#include "notes.h"
|
||||||
#include "fingering.h"
|
#include "fingering.h"
|
||||||
|
|
||||||
|
#define DRONES
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#define KNEE_OFFSET 0
|
|
||||||
#define KEY_OFFSET 2
|
#define KEY_OFFSET 2
|
||||||
|
|
||||||
FMVoice Chanter;
|
FMVoice Chanter;
|
||||||
FMVoice Drones[3];
|
FMVoice Drones[3];
|
||||||
FMVoice Regulators[3];
|
FMVoice Regulators[3];
|
||||||
|
|
||||||
AudioFilterBiquad biquad1;
|
AudioFilterBiquad biquad1;
|
||||||
AudioMixer4 mixDrones;
|
AudioMixer4 mixDrones;
|
||||||
AudioMixer4 mixRegulators;
|
AudioMixer4 mixRegulators;
|
||||||
AudioMixer4 mixL;
|
AudioMixer4 mixL;
|
||||||
AudioMixer4 mixR;
|
AudioMixer4 mixR;
|
||||||
AudioOutputAnalogStereo dacs1;
|
AudioOutputI2S out1;
|
||||||
|
AudioSynthNoiseWhite noise;
|
||||||
#ifdef DEBUG
|
|
||||||
AudioSynthNoiseWhite debug;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AudioConnection FMVoicePatchCords[] = {
|
AudioConnection FMVoicePatchCords[] = {
|
||||||
#ifdef DEBUG
|
//{0, 0, 0, 0}, // For some reason, the first one is ignored
|
||||||
{debug, 0, mixL, 3},
|
|
||||||
{debug, 0, mixR, 3},
|
{noise, 0, mixDrones, 3},
|
||||||
#endif
|
{noise, 0, mixL, 3},
|
||||||
|
{noise, 0, mixR, 3},
|
||||||
|
|
||||||
{Chanter.outputMixer, 0, biquad1, 0},
|
{Chanter.outputMixer, 0, biquad1, 0},
|
||||||
{biquad1, 0, mixL, 0},
|
{biquad1, 0, mixL, 0},
|
||||||
|
@ -50,56 +49,71 @@ AudioConnection FMVoicePatchCords[] = {
|
||||||
{mixRegulators, 0, mixL, 2},
|
{mixRegulators, 0, mixL, 2},
|
||||||
{mixRegulators, 0, mixR, 2},
|
{mixRegulators, 0, mixR, 2},
|
||||||
|
|
||||||
{mixL, 0, dacs1, 0},
|
{mixL, 0, out1, 0},
|
||||||
{mixR, 0, dacs1, 1},
|
{mixR, 0, out1, 1},
|
||||||
|
|
||||||
FMVoiceWiring(Chanter),
|
FMVoiceWiring(Chanter),
|
||||||
FMVoiceWiring(Drones[0]),
|
FMVoiceWiring(Drones[0]),
|
||||||
FMVoiceWiring(Drones[1]),
|
FMVoiceWiring(Drones[1]),
|
||||||
FMVoiceWiring(Drones[2]),
|
FMVoiceWiring(Drones[2]),
|
||||||
FMVoiceWiring(Drones[3]),
|
|
||||||
FMVoiceWiring(Regulators[0]),
|
FMVoiceWiring(Regulators[0]),
|
||||||
FMVoiceWiring(Regulators[1]),
|
FMVoiceWiring(Regulators[1]),
|
||||||
FMVoiceWiring(Regulators[2]),
|
FMVoiceWiring(Regulators[2]),
|
||||||
FMVoiceWiring(Regulators[3]),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int currentPatch = 0;
|
int currentPatch = 0;
|
||||||
|
|
||||||
Adafruit_MPR121 cap = Adafruit_MPR121();
|
Adafruit_MPR121 cap = Adafruit_MPR121();
|
||||||
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
|
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
||||||
MicroOLED oled(9, 1);
|
|
||||||
QwiicButton bag;
|
QwiicButton bag;
|
||||||
|
bool use_bag;
|
||||||
|
|
||||||
|
void blink(bool forever) {
|
||||||
|
for (;;) {
|
||||||
|
digitalWrite(LED_BUILTIN, true);
|
||||||
|
delay(200);
|
||||||
|
digitalWrite(LED_BUILTIN, false);
|
||||||
|
delay(200);
|
||||||
|
if (! forever) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
setupJustPitches(NOTE_D4, PITCH_D4);
|
|
||||||
pinMode(LED_BUILTIN, OUTPUT);
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
digitalWrite(LED_BUILTIN, true);
|
||||||
|
|
||||||
|
setupJustPitches(NOTE_D4, PITCH_D4);
|
||||||
|
|
||||||
// Wire.begin needs a moment
|
// Wire.begin needs a moment
|
||||||
delay(100);
|
delay(100);
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
|
|
||||||
// Initialize OLED display
|
// Initialize gesture/proximity sensor
|
||||||
oled.begin();
|
if (paj7620Init()) {
|
||||||
oled.clear(ALL);
|
// XXX: Error handling
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize display display
|
||||||
|
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
|
||||||
|
blink(true);
|
||||||
|
}
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
display.print("Starting");
|
||||||
|
display.display();
|
||||||
|
|
||||||
// Initialize bag
|
// Initialize bag
|
||||||
bag.begin();
|
bag.begin();
|
||||||
|
use_bag = bag.isConnected();
|
||||||
// Initialize the Trellis
|
|
||||||
trellis.begin();
|
|
||||||
|
|
||||||
// Initialize touch sensor
|
// Initialize touch sensor
|
||||||
bool blink = true;
|
|
||||||
while (!cap.begin(0x5A)) {
|
while (!cap.begin(0x5A)) {
|
||||||
oled.clear(PAGE);
|
display.clearDisplay();
|
||||||
oled.setCursor(0, 0);
|
display.setCursor(0, 0);
|
||||||
oled.print("No Pipe?");
|
display.print("Pipe?");
|
||||||
oled.display();
|
display.display();
|
||||||
|
blink(false);
|
||||||
trellis.setPixelColor(0, blink?0xff6666:0);
|
|
||||||
blink = !blink;
|
|
||||||
delay(200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set aside some memory for the audio library
|
// Set aside some memory for the audio library
|
||||||
|
@ -125,17 +139,12 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
debug.amplitude(0.1);
|
noise.amplitude(0.1);
|
||||||
mixL.gain(3, 0.1);
|
mixL.gain(3, 0.1);
|
||||||
mixR.gain(3, 0.1);
|
mixR.gain(3, 0.1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUTTON_UP 0
|
|
||||||
#define BUTTON_DOWN 8
|
|
||||||
#define BUTTON_PITCH 24
|
|
||||||
#define BUTTON_VOLUME 25
|
|
||||||
|
|
||||||
#define INIT_PITCH_ADJUST 0
|
#define INIT_PITCH_ADJUST 0
|
||||||
#define INIT_GAIN 0.7
|
#define INIT_GAIN 0.7
|
||||||
#define INIT_PATCH 0
|
#define INIT_PATCH 0
|
||||||
|
@ -162,7 +171,6 @@ void updateTunables(uint8_t buttons, int note) {
|
||||||
|
|
||||||
float adj = pow(2, pitchAdjust / 32768.0);
|
float adj = pow(2, pitchAdjust / 32768.0);
|
||||||
setupJustPitches(NOTE_D4, PITCH_D4*adj);
|
setupJustPitches(NOTE_D4, PITCH_D4*adj);
|
||||||
trellis.setPixelColor(BUTTON_PITCH, trellis.ColorHSV(uint16_t(pitchAdjust), 255, 80));
|
|
||||||
|
|
||||||
if (!note || (note == NOTE_G4)) {
|
if (!note || (note == NOTE_G4)) {
|
||||||
// Volume adjust if playing G
|
// Volume adjust if playing G
|
||||||
|
@ -178,20 +186,14 @@ void updateTunables(uint8_t buttons, int note) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
mixL.gain(i, chanterGain);
|
mixL.gain(i, chanterGain);
|
||||||
mixR.gain(i, chanterGain);
|
mixR.gain(i, chanterGain);
|
||||||
}
|
}
|
||||||
trellis.setPixelColor(BUTTON_VOLUME, trellis.ColorHSV(uint16_t(chanterGain * 65535), 255, 80));
|
|
||||||
|
|
||||||
if (!note || (note == NOTE_CS5)) {
|
if (!note || (note == NOTE_CS5)) {
|
||||||
if (buttons == 3) {
|
if (buttons == 3) {
|
||||||
patch = INIT_PATCH;
|
patch = INIT_PATCH;
|
||||||
} else if (trellis.justPressed(BUTTON_DOWN)) {
|
|
||||||
patch -= 1;
|
|
||||||
} else if (trellis.justPressed(BUTTON_UP)) {
|
|
||||||
patch += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap
|
// wrap
|
||||||
|
@ -201,14 +203,13 @@ void updateTunables(uint8_t buttons, int note) {
|
||||||
FMPatch *p = &Bank[patch];
|
FMPatch *p = &Bank[patch];
|
||||||
FMVoiceLoadPatch(&Chanter, p);
|
FMVoiceLoadPatch(&Chanter, p);
|
||||||
|
|
||||||
oled.clear(PAGE);
|
display.clearDisplay();
|
||||||
oled.setFontType(0);
|
display.setCursor(0, 0);
|
||||||
oled.setCursor(0, 0);
|
display.print(p->name);
|
||||||
oled.print(p->name);
|
display.setCursor(0, 10);
|
||||||
oled.setCursor(0, 10);
|
display.print("Patch ");
|
||||||
oled.print("Patch ");
|
display.print(patch);
|
||||||
oled.print(patch);
|
display.display();
|
||||||
oled.display();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +217,8 @@ const uint8_t CLOSEDVAL = 0x30;
|
||||||
const uint8_t OPENVAL = 0x70;
|
const uint8_t OPENVAL = 0x70;
|
||||||
const uint8_t GLISSANDO_STEPS = OPENVAL - CLOSEDVAL;
|
const uint8_t GLISSANDO_STEPS = OPENVAL - CLOSEDVAL;
|
||||||
|
|
||||||
bool playing = false;
|
uint8_t loopno = 0;
|
||||||
|
uint8_t last_note = 0;
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
uint8_t keys = 0;
|
uint8_t keys = 0;
|
||||||
|
@ -225,10 +227,15 @@ void loop() {
|
||||||
uint8_t glissandoNote;
|
uint8_t glissandoNote;
|
||||||
float glissandoOpenness = 0;
|
float glissandoOpenness = 0;
|
||||||
bool silent = false;
|
bool silent = false;
|
||||||
bool knee = cap.filteredData(KNEE_OFFSET) < CLOSEDVAL;
|
uint8_t paj_knee = 127;
|
||||||
uint8_t buttons = trellis.isPressed(BUTTON_DOWN)?1:0 | trellis.isPressed(BUTTON_UP)?2:0;
|
bool knee = false;
|
||||||
|
|
||||||
trellis.tick();
|
loopno++;
|
||||||
|
|
||||||
|
paj7620ReadReg(0x6c, 1, &paj_knee);
|
||||||
|
if (paj_knee > 240) {
|
||||||
|
knee = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
uint16_t val = max(cap.filteredData(i+KEY_OFFSET), CLOSEDVAL);
|
uint16_t val = max(cap.filteredData(i+KEY_OFFSET), CLOSEDVAL);
|
||||||
|
@ -246,9 +253,6 @@ void loop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print key states
|
|
||||||
//trellis.setPixelColor(7 - i, trellis.ColorHSV(65536/12, 255, 120*openness));
|
|
||||||
trellis.setPixelColor(7 - i, trellis.ColorHSV(22222*openness, 255, 40));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
note = uilleann_matrix[keys];
|
note = uilleann_matrix[keys];
|
||||||
|
@ -265,20 +269,37 @@ void loop() {
|
||||||
silent = true;
|
silent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Look up the note name
|
||||||
|
char *note_name = NoteNames[note % 12];
|
||||||
|
if (silent) {
|
||||||
|
note_name = "-";
|
||||||
|
}
|
||||||
|
|
||||||
// Jump octave if the bag is squished
|
// Jump octave if the bag is squished
|
||||||
//bag = !digitalRead(BAG);
|
//bag = !digitalRead(BAG);
|
||||||
if (bag.isPressed()) {
|
if (use_bag && bag.isPressed()) {
|
||||||
if (keys & bit(7)) {
|
if (keys & bit(7)) {
|
||||||
note += 12;
|
note += 12;
|
||||||
glissandoNote += 12;
|
glissandoNote += 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read some trellis button states
|
#if 0
|
||||||
if (buttons) {
|
display.clearDisplay();
|
||||||
updateTunables(buttons, note);
|
display.setCursor(0, 0);
|
||||||
}
|
display.print("mem: ");
|
||||||
|
display.print(AudioMemoryUsageMax());
|
||||||
|
display.print(" prx: ");
|
||||||
|
display.print(paj_knee);
|
||||||
|
display.setCursor(0, 24);
|
||||||
|
display.print("Note: ");
|
||||||
|
display.print(note);
|
||||||
|
display.print(" n: ");
|
||||||
|
display.print(loopno);
|
||||||
|
display.display();
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (silent) {
|
if (silent) {
|
||||||
FMVoiceNoteOff(&Chanter);
|
FMVoiceNoteOff(&Chanter);
|
||||||
|
@ -305,4 +326,12 @@ void loop() {
|
||||||
FMVoiceNoteOn(&Chanter, pitch);
|
FMVoiceNoteOn(&Chanter, pitch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note != last_note) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.print(note_name);
|
||||||
|
display.display();
|
||||||
|
last_note = note;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue