Upload files to 'Software'

This commit is contained in:
Simon 2021-03-13 11:12:43 +01:00
parent 566bacc562
commit aa98204941
5 changed files with 890 additions and 0 deletions

61
Software/panel-scanner.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef _PANEL_SCANNER_H_
#define _PANEL_SCANNER_H_
#pragma once
#include "editor.h"
static const uint32_t NUM_PANELS = 3;
class PanelScanner
{
public:
PanelScanner();
void initScanning();
void tick();
void clearAllLED();
void setHalfLED(uint32_t num, bool on = true);
void clearHalfLED(uint32_t num);
void clearAllHalfLEDs();
void setBackgroundLED(uint32_t num, bool on = true);
void clearBackgroundLED(uint32_t num);
void clearAllBackgroundLEDs();
void setBlinkingLED(uint32_t num, bool on = true);
void clearBlinkingLED(uint32_t num);
void clearAllBlinkingLEDs();
void setOverlayLED(uint32_t num);
void clearOverlayLED(uint32_t num);
void clearAllOverlayLEDs();
void dumpLEDs();
private:
// internal routines
void readButtons();
void parseButtons();
void doTransaction();
// internal data
uint8_t led_half_buffer[NUM_PANELS];
uint8_t led_background_buffer[NUM_PANELS];
uint8_t led_blinking_buffer[NUM_PANELS];
uint8_t led_overlay_buffer[NUM_PANELS];
uint8_t old_buttons[NUM_PANELS];
uint8_t new_buttons[NUM_PANELS];
};
#endif // keepout

314
Software/pattern.cpp Normal file
View File

@ -0,0 +1,314 @@
#include <Arduino.h>
#include <Audio.h>
#include <SPI.h>
#include <SD.h>
#include "pattern.h"
static const uint32_t sequence[Pattern::PATTERN_LEN] =
{
#if 0
//shaker and toms....
//S123OCSK
0b100001000001,
0b00000000,
0b10100000,
0b10000000,
0b00010001,
0b00000000,
0b10100000,
0b10000000,
0b01000001,
0b01000000,
0b10000000,
0b10100000,
0b00100001,
0b00000000,
0b10010000,
0b10010000,
#else
//kick, snare & hats
0b100000000101,
0b00000100,
0b10000100,
0b10000101,
0b00000110,
0b00000100,
0b10001001,
0b10000010,
0b00000101,
0b00000100,
0b10000100,
0b10000100,
0b00000110,
0b00000100,
0b10010100,
0b10000100,
#endif
};
static const uint8_t SD_CHIPSEL = 10;
// constructor...
Pattern::Pattern()
{
// Only init internal data -
// adding dependencies on other items at this point is tricky, if we aren't really careful
// about order of construction.
for (uint32_t i = 0; i < PATTERN_LEN; i++)
{
for (uint32_t j = 0; j < NUM_PATTERNS; j++)
{
pattern_data[j][i] = sequence[i];
}
}
setCurrentVoice(0);
setCurrentPattern(0);
current_voice_mask = 0x01;
current_accent_mask = 0x010000;
}
bool Pattern::toggleBit(uint32_t index)
{
if (index >= PATTERN_LEN)
{
Serial.println("Overflow in toggle");
index %= PATTERN_LEN;
}
pattern_data[current_pattern][index] ^= current_voice_mask;
return (pattern_data[current_pattern][index] & current_voice_mask);
}
bool Pattern::toggleAccentBit(uint32_t index)
{
if (index >= PATTERN_LEN)
{
Serial.println("Overflow in toggle");
index %= PATTERN_LEN;
}
pattern_data[current_pattern][index] ^= current_accent_mask;
return (pattern_data[current_pattern][index] & current_accent_mask);
}
// Return all of the buts for the current step
uint32_t Pattern::getStepData(uint32_t index)
{
if (index >= PATTERN_LEN)
{
Serial.println("Overflow in pattern req");
index %= PATTERN_LEN;
}
return pattern_data[current_pattern][index];
}
// Get all of the column data for a particular voice
bool Pattern::getVoiceBit(uint32_t step)
{
if (step >= PATTERN_LEN)
{
Serial.println("Overflow in pattern bit");
step %= PATTERN_LEN;
}
#if 0
Serial.print("GVB: curr ") ;
Serial.print(current_pattern) ;
Serial.print(" step ") ;
Serial.println(step) ;
#endif
return (pattern_data[current_pattern][step] & current_voice_mask);
}
bool Pattern::getAccentBit(uint32_t step)
{
if (step >= PATTERN_LEN)
{
Serial.println("Overflow in pattern bit");
step %= PATTERN_LEN;
}
return (pattern_data[current_pattern][step] & current_accent_mask);
}
void Pattern::setCurrentVoice(uint32_t num)
{
current_voice = num;
current_voice_mask = 1 << num;
current_accent_mask = 1 << (num + 16);
}
uint32_t Pattern::getCurrentVoice(void)
{
return current_voice;
}
void Pattern::setCurrentPattern(uint32_t nextpatt)
{
if (nextpatt < NUM_PATTERNS)
{
current_pattern = nextpatt;
}
}
uint32_t Pattern::getCurrentPattern()
{
return current_pattern;
}
void Pattern::clearCurrentPattern()
{
for (uint32_t i = 0; i < PATTERN_LEN; i++)
{
pattern_data[current_pattern][i] = 0;
}
}
void Pattern::randomizeCurrentPattern()
{
for (uint32_t i = 0; i < PATTERN_LEN; i++)
{
pattern_data[current_pattern][i] = random(0x0fff) & random(0x0fff) ;
}
}
////////////////////////////////////////////////////////////////////
////////// file management
////////////////////////////////////////////////////////////////////
bool Pattern::writeToCard()
{
File fd;
size_t len;
bool success = false;
// shouldn't reach here if playing.
Serial.println("***** Attempting pattern file write");
if (SD.exists("test.txt"))
{
Serial.println("** found test file!");
}
else
{
Serial.println("** NO test file!");
}
fd = SD.open("patt.txt", FILE_WRITE);
if (!fd)
{
Serial.println("** no fd!");
goto CLEANUP;
}
fd.seek(0);
len = sizeof(pattern_data);
Serial.print("Pattern memoty total length: ");
Serial.println(len);
if (fd.write((uint8_t*)pattern_data, len) != len)
{
Serial.println("** Bad write length");
goto CLEANUP;
}
success = true;
Serial.println("***** Pattern file completely written.");
CLEANUP:
if (fd)
{
Serial.println("Cleaning up fd");
fd.flush();
fd.close();
}
return success;
}
bool Pattern::readFromCard()
{
File fd;
size_t len, avail;
bool success = false;
uint8_t val;
uint8_t* munge = (uint8_t*)pattern_data;
Serial.println("***** Attempting pattern file read");
if (!SD.exists("patt.txt"))
{
Serial.println("** NO pattern file!");
goto CLEANUP;
}
Serial.println("** found pattern file!");
fd = SD.open("patt.txt", FILE_READ);
if (!fd)
{
Serial.println("** no fd!");
goto CLEANUP;
}
fd.seek(0);
len = sizeof(pattern_data);
Serial.print("Pattern memoty total length: ");
Serial.println(len);
avail = fd.available();
Serial.print("File has bytes: ");
Serial.println(avail);
if (len != avail)
{
Serial.println("File Read error: length/struct mismatch");
goto CLEANUP;
}
for (uint32_t i = 0; i < len; i++)
{
val = fd.read();
munge[i] = val;
}
success = true;
Serial.println("***** Pattern file completely read.");
CLEANUP:
if (fd)
{
Serial.println("Cleaning up fd");
fd.flush();
fd.close();
}
return success;
}

50
Software/pattern.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef _PATTERN_H_
#define _PATTERN_H_
#pragma once
#include <stdint.h>
class Pattern
{
public:
static const uint32_t PATTERN_LEN = 16;
static const uint32_t NUM_PATTERNS = 16;
Pattern();
bool toggleBit(uint32_t step);
bool toggleAccentBit(uint32_t step);
void setCurrentVoice(uint32_t);
uint32_t getCurrentVoice(void);
void setCurrentPattern(uint32_t);
uint32_t getCurrentPattern();
void clearCurrentPattern();
void randomizeCurrentPattern();
uint32_t getStepData(uint32_t index);
bool getVoiceBit(uint32_t step);
bool getAccentBit(uint32_t step);
bool writeToCard();
bool readFromCard();
private:
uint32_t pattern_data[NUM_PATTERNS][PATTERN_LEN];
uint32_t current_pattern;
uint32_t current_voice;
uint32_t current_voice_mask;
uint32_t current_accent_mask;
};
#endif // keepout

439
Software/voice.cpp Normal file
View File

@ -0,0 +1,439 @@
#include "voice.h"
#include <TeensyBoomVoiceLibrary.h>
//#include "Synth-Clatter.h"
//#include "Synth-Decay.h"
//#include "Synth-DrumHeart.h"
//#include "synth_simple_drum.h"
#include "player.h" // required so we can update tempo param from knob update func.
extern Player thePlayer;
#define HAT
#define KICK
#define SNARE
#define TOM
#define SHAKER
#define BELL
#define CYMBAL
#define CLAP
// Used by multiple instruments:
AudioSynthNoiseWhite noise;
#ifdef HAT
// hats
AudioSynthClatter clat1;
AudioSynthDecay hatdecay;
AudioFilterBiquad hatfilter;
AudioEffectMultiply hatmult;
#endif
#ifdef BELL
AudioSynthDecay belldecay;
AudioEffectMultiply bellmult;
#endif
#ifdef KICK
// kick
AudioSynthSimpleDrum kick;
#endif
#ifdef SNARE
// snare
AudioSynthDrumHeart snare;
AudioMixer4 snaremix;
AudioEffectMultiply snaremult;
#endif
#ifdef TOM
// tom
AudioSynthSimpleDrum tom;
#endif
#ifdef SHAKER
// shaker
AudioSynthDecay shakedecay;
AudioFilterBiquad shakefilter;
AudioEffectMultiply shakemult;
#endif
#ifdef CYMBAL
AudioSynthDecay cymbaldecay;
AudioFilterBiquad cymbalfilter;
AudioEffectMultiply cymbalmult;
#endif
#ifdef CLAP
AudioSynthDecay clapdecay;
AudioEffectMultiply clapmult;
AudioFilterBiquad clapfilter;
AudioEffectClapEnvelope clapenv;
#endif
// outputs
AudioMixer4 mixer1;
AudioMixer4 mixer2;
AudioMixer4 mixer3;
// Master volume control between mixers and output,
// because the output level controls are independent between
// phones and line outputs.
AudioEffectMultiply mastervol;
AudioSynthWaveformDc volcontrol;
AudioOutputI2S i2s1; //xy=968,448
#ifdef HAT
AudioConnection patchCord01(clat1, 0, hatfilter, 0);
AudioConnection patchCord02(hatfilter, 0, hatmult, 0);
//AudioConnection patchCord03(hatfilter, 0, hatmult, 0);
//AudioConnection patchCord01(hatdecay, 0, hatmult, 0);
AudioConnection patchCord03(hatdecay, 0, hatmult, 1);
AudioConnection patchCord90(hatmult, 0, mixer1, 0);
#endif
#ifdef BELL
AudioConnection patchCord04(clat1, 1, bellmult, 0);
AudioConnection patchCord05(belldecay, 0, bellmult, 1);
AudioConnection patchCord96(bellmult, 0, mixer2, 2);
#endif
#ifdef KICK
AudioConnection patchCord10(kick, 0, mixer1, 1);
#endif
#ifdef SNARE
AudioConnection patchCord20(noise, 0, snaremix, 0);
AudioConnection patchCord21(snare, 0, snaremix, 1);
AudioConnection patchCord22(snare, 1, snaremult, 1);
AudioConnection patchCord23(snaremix, 0, snaremult, 0);
AudioConnection patchCord92(snaremult, 0, mixer1, 2);
#endif
#ifdef TOM
AudioConnection patchCord30(tom, 0, mixer2, 0);
#endif
#ifdef SHAKER
AudioConnection patchCord40(noise, 0, shakefilter, 0);
AudioConnection patchCord41(shakefilter, 0, shakemult, 0);
AudioConnection patchCord42(shakedecay, 0, shakemult, 1);
AudioConnection patchCord95(shakemult, 0, mixer2, 1);
#endif
#ifdef CYMBAL
AudioConnection patchCord50(clat1, 0, cymbalfilter, 0);
AudioConnection patchCord51(cymbalfilter, cymbalmult);
AudioConnection patchCord52(cymbaldecay, 0, cymbalmult, 1);
AudioConnection patchCord97(cymbalmult, 0, mixer3, 2);
#endif
#ifdef CLAP
AudioConnection patchCord60(noise, 0, clapenv, 0);
AudioConnection patchCord61(clapenv, 0, mixer3, 0);
AudioConnection patchCord62(noise, 0, clapfilter, 0);
AudioConnection patchCord63(clapfilter, 0, clapmult, 0);
AudioConnection patchCord64(clapdecay, 0, clapmult, 1);
AudioConnection patchCord65(clapmult, 0, mixer3, 1);
#endif
AudioConnection patchCord93(mixer2, 0, mixer1, 3);
AudioConnection patchCord967(mixer3, 0, mixer2, 3);
AudioConnection patchCord965(mixer1, 0, mastervol, 0);
AudioConnection patchCord966(volcontrol, 0 , mastervol, 1);
AudioConnection patchCord98(mastervol, 0, i2s1, 0);
AudioConnection patchCord99(mastervol, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;
// Globals for params on shared voices
uint16_t openlen, closedlen;
uint16_t t1, t2, t3;
void voiceInit()
{
AudioNoInterrupts();
sgtl5000_1.enable();
sgtl5000_1.volume(0.7);
sgtl5000_1.lineOutLevel(13);
paramInit();
AudioInterrupts();
}
void paramInit()
{
// common to severl instruments
noise.amplitude(0.5);
#ifdef HAT
// hat stuff
//clat1; - no params
//hatdecay.length(150);
openlen = 300;
closedlen = 50;
hatfilter.setHighpass(0, 700, 0.2);
hatfilter.setLowpass(1, 10000, 0.8);
//hatdecay.frequency(1500);
//hatdecay.length(50);
#endif
#ifdef BELL
belldecay.length(333);
#endif
#ifdef KICK
// kick
kick.frequency(60);
kick.length(100);
kick.pitchMod(0x2f0); // 0x200 is no mod...
#endif
#ifdef SNARE
// snare
snare.frequency(200);
snare.length(100);
snare.second(true);
snare.pitchMod(0x280);
snaremix.gain(0, 0.75);
snaremix.gain(1, 0.5);
#endif
#ifdef TOM
// tom
//tom.frequency(80);
t1 = 60;
tom.secondMix(1.0);
tom.length(250);
tom.pitchMod(0.75);
#endif
#ifdef SHAKER
// shaker
shakefilter.setLowpass(0, 3500, 0.7);
shakefilter.setHighpass(1, 400, 0.3);
shakedecay.length(50);
#endif
#ifdef CYMBAL
//cymbalfilter.setLowpass(0, 4500, 0.3);
//cymbalfilter.setHighpass(1, 770, 0.7);
cymbalfilter.setBandpass(0, 3000, .2);
cymbaldecay.length(1000);
#endif
#ifdef CLAP
clapdecay.length(200);
mixer3.gain(0, 0.5);
mixer3.gain(1, 0.4);
clapfilter.setLowpass(0, 6500, 0.4);
clapfilter.setHighpass(1, 200, 0.3);
#endif
// Master
mixer1.gain(0, 0.75);// hat
mixer1.gain(1, 0.75);// kik
mixer1.gain(2, 0.65);// snr
mixer1.gain(3, 0.75);// mix2
mixer2.gain(0, 0.75);// tom
mixer2.gain(1, 0.3);//shaker
mixer2.gain(2, 0.5);// bell
mixer2.gain(3, 0.75);// mix3
// 0 and 1 are set in the clap portion, above.
mixer3.gain(2, 0.75);//cymbal
}
void paramUpdate1()
{
uint16_t pitch, mod, len;
uint16_t snpitch, snmix, snlen;
uint16_t ohdec, chdec;
pitch = analogRead(A1);
mod = analogRead(A12);
len = analogRead(A13);
snpitch = analogRead(A2);
snmix = analogRead(A3);
snlen = analogRead(A14);
ohdec = analogRead(A6);
chdec = analogRead(A16);
#ifdef KICK
kick.frequency(30 + (pitch >> 3));
kick.pitchMod((float)mod/0x3ff);
kick.length(len + 10);
#endif
#ifdef SNARE
float mix = (float)snmix / 1024.0;
snare.frequency(80 + (snpitch >> 2));
snaremix.gain(0, 1.0 - mix);
snaremix.gain(1, mix);
snare.length((snlen/2) + 10);
#endif
#ifdef HAT
openlen = (ohdec/2) + 10;
closedlen = (chdec/2) + 10;
#endif
}
#if 1
void paramUpdate2()
{
uint16_t p1;
uint16_t len, mod;
uint16_t secondskin;
uint16_t tonebal, cymlen;;
p1 = analogRead(A10);
secondskin = analogRead(A11);
// mod = analogRead(A18);
// len = analogRead(A19);
mod = 500;
len = 500;
tonebal = analogRead(A7);
cymlen = analogRead(A17);
// toms pitched as minor triad from base
t3 = 30 + (p1 >> 1);
t2 = (t3 * 6)/5; // 6/5 = minor 3rd
t1 = t3 + (t3 >> 1);// 3/2 = perfect 5th
tom.length(len + 10);
tom.pitchMod((float)mod/0x3ff);
tom.secondMix((float)secondskin/0x3ff);
cymbaldecay.length((cymlen*4) + 50);
cymbalfilter.setLowpass(0, 600+(tonebal*3), 0.3);
cymbalfilter.setHighpass(1, 600+tonebal, 0.2);
//shakedecay.length(slen + 10);
}
#endif
void paramUpdate3()
{
uint16_t volume;
uint32_t tempo;
//volume = analogRead(A20);
volume = 1000-analogRead(A19);
volume = (volume * volume) >> 10;
volcontrol.amplitude(((float)volume)/0x3ff, 3);
// tempo = analogRead(A15);
tempo = 1000-analogRead(A18);
tempo = 0x3ff - tempo;
tempo *= 225;
tempo >>= 10;
tempo &= 0x3ff;
//pause = tempo + 75;
thePlayer.setPause(tempo+75);
}
void triggerKick(bool loud)
{
if(loud)
{
kick.noteOn();
}
else
{
kick.noteOn();
}
}
void triggerSnare(bool loud)
{
if(loud)
{
snare.noteOn();
}
else
{
snare.noteOn(0x5000);
}
}
void triggerTom(int32_t num, bool loud)
{
if (num == 1)
{
tom.frequency(t1);
tom.noteOn();
}
else if (num == 2)
{
tom.frequency(t2);
tom.noteOn();
}
else if (num == 3)
{
tom.frequency(t3);
tom.noteOn();
}
}
void triggerShaker(bool loud)
{
shakedecay.noteOn(loud?0x7fff:0x6000);
}
void triggerHat(bool open, bool loud)
{
if (!open)
{
hatdecay.length(closedlen);
hatdecay.noteOn(loud?0x7fff:0x6000);
}
else
{
hatdecay.length(openlen);
hatdecay.noteOn(loud?0x7fff:0x6000);
}
}
void triggerBell(bool loud)
{
belldecay.noteOn(loud?0x7fff:0x6000);
}
void triggerCymbal(bool loud)
{
cymbaldecay.noteOn(loud?0x7fff:0x6000);
}
void triggerClap(bool loud)
{
// Serial.println("cymbal");
clapdecay.noteOn(loud?0x7fff:0x6000);
clapenv.noteOn();
}

26
Software/voice.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _VOICE_H_
#define _VOICE_H_
#pragma once
#include <stdint.h>
#include <Audio.h>
void voiceInit();
void paramInit();
void paramUpdate1();
void paramUpdate2();
void paramUpdate3();
void triggerKick(bool loud = true);
void triggerSnare(bool loud = true);
void triggerTom(int32_t num, bool loud = true);
void triggerShaker(bool loud = true);
void triggerHat(bool open, bool loud = true);
void triggerBell(bool loud = true);
void triggerCymbal(bool loud = true);
void triggerClap(bool loud = true);
#endif // keepout