Now you can adjust pitch and intonation
This commit is contained in:
parent
c915b0ee69
commit
036dcf592e
|
@ -0,0 +1,3 @@
|
||||||
|
BasedOnStyle: Chromium
|
||||||
|
ColumnLimit: 0
|
||||||
|
PointerAlignment: Right
|
140
fingering.h
140
fingering.h
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
struct Fingering {
|
struct Fingering {
|
||||||
Note note;
|
Note note;
|
||||||
bool alt; // Alternate fingering: sounds more choked
|
bool alt; // Alternate fingering: sounds more choked
|
||||||
};
|
};
|
||||||
|
|
||||||
#define n(note) {note, false}
|
#define n(note) \
|
||||||
#define P(note) {note, true}
|
{ note, false }
|
||||||
|
#define P(note) \
|
||||||
|
{ note, true }
|
||||||
|
|
||||||
#define CCCC n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5)
|
#define CCCC n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5)
|
||||||
#define CCDD n(NOTE_CS5), n(NOTE_CS5), n(NOTE_D5), n(NOTE_D5)
|
#define CCDD n(NOTE_CS5), n(NOTE_CS5), n(NOTE_D5), n(NOTE_D5)
|
||||||
|
@ -15,71 +17,71 @@ struct Fingering {
|
||||||
#define DDDD n(NOTE_D5), n(NOTE_D5), n(NOTE_D5), n(NOTE_D5)
|
#define DDDD n(NOTE_D5), n(NOTE_D5), n(NOTE_D5), n(NOTE_D5)
|
||||||
|
|
||||||
struct Fingering uilleann_matrix[] = {
|
struct Fingering uilleann_matrix[] = {
|
||||||
// Open Back D
|
// Open Back D
|
||||||
n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), n(NOTE_D5), // OOO OO..
|
n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), n(NOTE_D5), // OOO OO..
|
||||||
CCDD, // OOO OX..
|
CCDD, // OOO OX..
|
||||||
CDCD, // OOO XO..
|
CDCD, // OOO XO..
|
||||||
DDDD, // OOO XX..
|
DDDD, // OOO XX..
|
||||||
CDCD, // OOX OO..
|
CDCD, // OOX OO..
|
||||||
DDDD, // OOX OX..
|
DDDD, // OOX OX..
|
||||||
CDCD, // OOX XO..
|
CDCD, // OOX XO..
|
||||||
DDDD, // OOX XX..
|
DDDD, // OOX XX..
|
||||||
CCDD, // OXO OO..
|
CCDD, // OXO OO..
|
||||||
CCDD, // OXO OX..
|
CCDD, // OXO OX..
|
||||||
DDDD, // OXO XO..
|
DDDD, // OXO XO..
|
||||||
DDDD, // OXO XX..
|
DDDD, // OXO XX..
|
||||||
DDDD, // OXX OO..
|
DDDD, // OXX OO..
|
||||||
DDDD, // OXX OX..
|
DDDD, // OXX OX..
|
||||||
DDDD, // OXX XO..
|
DDDD, // OXX XO..
|
||||||
DDDD, // OXX XX..
|
DDDD, // OXX XX..
|
||||||
CDCD, // XOO OO..
|
CDCD, // XOO OO..
|
||||||
DDDD, // XOO OX..
|
DDDD, // XOO OX..
|
||||||
CDCD, // XOO XO..
|
CDCD, // XOO XO..
|
||||||
DDDD, // XOO XX..
|
DDDD, // XOO XX..
|
||||||
CDCD, // XOX OO..
|
CDCD, // XOX OO..
|
||||||
DDDD, // XOX OX..
|
DDDD, // XOX OX..
|
||||||
CDCD, // XOX XO..
|
CDCD, // XOX XO..
|
||||||
DDDD, // XOX XX..
|
DDDD, // XOX XX..
|
||||||
DDDD, // XXO OO..
|
DDDD, // XXO OO..
|
||||||
DDDD, // XXO OX..
|
DDDD, // XXO OX..
|
||||||
DDDD, // XXO XO..
|
DDDD, // XXO XO..
|
||||||
DDDD, // XXO XX..
|
DDDD, // XXO XX..
|
||||||
DDDD, // XXX OO..
|
DDDD, // XXX OO..
|
||||||
DDDD, // XXX OX..
|
DDDD, // XXX OX..
|
||||||
n(NOTE_D5), n(NOTE_D5), n(NOTE_D5), P(NOTE_D5), // XXX XO..
|
n(NOTE_D5), n(NOTE_D5), n(NOTE_D5), P(NOTE_D5), // XXX XO..
|
||||||
DDDD, // XXX XX..
|
DDDD, // XXX XX..
|
||||||
|
|
||||||
// Closed Back D
|
// Closed Back D
|
||||||
CCCC, // OOO OO...
|
CCCC, // OOO OO...
|
||||||
n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OOO OX..
|
n(NOTE_CS5), n(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OOO OX..
|
||||||
CCCC, // OOO XO..
|
CCCC, // OOO XO..
|
||||||
CCCC, // OOO XX..
|
CCCC, // OOO XX..
|
||||||
CCCC, // OOX OO..
|
CCCC, // OOX OO..
|
||||||
n(NOTE_CS5), P(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OOX OX..
|
n(NOTE_CS5), P(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OOX OX..
|
||||||
CCCC, // OOX XO..
|
CCCC, // OOX XO..
|
||||||
CCCC, // OOX XX..
|
CCCC, // OOX XX..
|
||||||
CCCC, // OXO OO..
|
CCCC, // OXO OO..
|
||||||
n(NOTE_CS5), P(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OXO OX..
|
n(NOTE_CS5), P(NOTE_CS5), n(NOTE_CS5), P(NOTE_CS5), // OXO OX..
|
||||||
CCCC, // OXO XO..
|
CCCC, // OXO XO..
|
||||||
CCCC, // OXO XX..
|
CCCC, // OXO XX..
|
||||||
P(NOTE_C5), P(NOTE_C5), P(NOTE_C5), P(NOTE_C5), // OXX OO..
|
P(NOTE_C5), P(NOTE_C5), P(NOTE_C5), P(NOTE_C5), // OXX OO..
|
||||||
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), // OXX OX..
|
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), // OXX OX..
|
||||||
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), P(NOTE_C5), // OXX XO..
|
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), P(NOTE_C5), // OXX XO..
|
||||||
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), n(NOTE_CS5), // OXX XX..
|
n(NOTE_C5), n(NOTE_C5), n(NOTE_C5), n(NOTE_CS5), // OXX XX..
|
||||||
n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), // XOO OO..
|
n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), // XOO OO..
|
||||||
P(NOTE_B4), P(NOTE_B4), n(NOTE_B4), P(NOTE_B4), // XOO OX..
|
P(NOTE_B4), P(NOTE_B4), n(NOTE_B4), P(NOTE_B4), // XOO OX..
|
||||||
n(NOTE_AS4), n(NOTE_B4), n(NOTE_AS4), n(NOTE_B4), // XOO XO..
|
n(NOTE_AS4), n(NOTE_B4), n(NOTE_AS4), n(NOTE_B4), // XOO XO..
|
||||||
n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), // XOO XX..
|
n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), n(NOTE_B4), // XOO XX..
|
||||||
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX OO..
|
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX OO..
|
||||||
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX OX..
|
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX OX..
|
||||||
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX XO..
|
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX XO..
|
||||||
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX XX..
|
P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), P(NOTE_B4), // XOX XX..
|
||||||
n(NOTE_A4), n(NOTE_A4), P(NOTE_A4), n(NOTE_A4), // XXO OO..
|
n(NOTE_A4), n(NOTE_A4), P(NOTE_A4), n(NOTE_A4), // XXO OO..
|
||||||
P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), // XXO OX..
|
P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), // XXO OX..
|
||||||
n(NOTE_GS4), P(NOTE_GS4), n(NOTE_A4), n(NOTE_A4), // XXO XO..
|
n(NOTE_GS4), P(NOTE_GS4), n(NOTE_A4), n(NOTE_A4), // XXO XO..
|
||||||
P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), n(NOTE_A4), // XXO XX..
|
P(NOTE_A4), P(NOTE_A4), P(NOTE_A4), n(NOTE_A4), // XXO XX..
|
||||||
n(NOTE_G4), n(NOTE_G4), P(NOTE_G4), n(NOTE_G4), // XXX OO..
|
n(NOTE_G4), n(NOTE_G4), P(NOTE_G4), n(NOTE_G4), // XXX OO..
|
||||||
P(NOTE_G4), P(NOTE_G4), P(NOTE_G4), P(NOTE_G4), // XXX OX..
|
P(NOTE_G4), P(NOTE_G4), P(NOTE_G4), P(NOTE_G4), // XXX OX..
|
||||||
n(NOTE_FS4), n(NOTE_FS4), n(NOTE_F4), P(NOTE_FS4), // XXX XO..
|
n(NOTE_FS4), n(NOTE_FS4), n(NOTE_F4), P(NOTE_FS4), // XXX XO..
|
||||||
n(NOTE_E4), P(NOTE_E4), n(NOTE_DS4), n(NOTE_D4), // XXX XX..
|
n(NOTE_E4), P(NOTE_E4), n(NOTE_DS4), n(NOTE_D4), // XXX XX..
|
||||||
};
|
};
|
||||||
|
|
126
pipe.cpp
126
pipe.cpp
|
@ -1,6 +1,6 @@
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
#include "tuning.h"
|
|
||||||
#include "fingering.h"
|
#include "fingering.h"
|
||||||
|
#include "tuning.h"
|
||||||
|
|
||||||
// Kludge time: this is something I did just to make my breadboard look nicer.
|
// Kludge time: this is something I did just to make my breadboard look nicer.
|
||||||
#define KEY_OFFSET 2
|
#define KEY_OFFSET 2
|
||||||
|
@ -10,89 +10,89 @@
|
||||||
#define GLISSANDO_STEPS (OPENVAL - CLOSEDVAL)
|
#define GLISSANDO_STEPS (OPENVAL - CLOSEDVAL)
|
||||||
|
|
||||||
Pipe::Pipe() {
|
Pipe::Pipe() {
|
||||||
keysLast = 0;
|
keysLast = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pipe::Init() {
|
bool Pipe::Init() {
|
||||||
// Capacative touch sensor
|
// Capacative touch sensor
|
||||||
if (!capSensor.begin(0x5A)) {
|
if (!capSensor.begin(0x5A)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proximity sensor
|
// Proximity sensor
|
||||||
if (paj7620Init()) {
|
if (paj7620Init()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bag button
|
// Bag button
|
||||||
bagSensor.begin();
|
bagSensor.begin();
|
||||||
// This library takes the entire program out if you poll it 5-40 times without anything connected
|
// This library takes the entire program out if you poll it 5-40 times without anything connected
|
||||||
bag_enabled = bagSensor.isConnected();
|
bag_enabled = bagSensor.isConnected();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pipe::Update() {
|
void Pipe::Update() {
|
||||||
uint8_t glissandoKeys = 0;
|
uint8_t glissandoKeys = 0;
|
||||||
|
|
||||||
// Read the bag state, if there's a bag.
|
// Read the bag state, if there's a bag.
|
||||||
// if there isn't a bag, don't try, or this library will crash the program.
|
// if there isn't a bag, don't try, or this library will crash the program.
|
||||||
if (bag_enabled) {
|
if (bag_enabled) {
|
||||||
bag = bagSensor.isPressed();
|
bag = bagSensor.isPressed();
|
||||||
} else {
|
} else {
|
||||||
bag = false;
|
bag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x6c is actually 8 bytes, but all 8 are always the same...
|
||||||
|
paj7620ReadReg(0x6c, 1, &kneeClosedness);
|
||||||
|
|
||||||
|
keysLast = keys;
|
||||||
|
keys = 0;
|
||||||
|
glissandoKeys = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
uint16_t val = max(capSensor.filteredData(i + KEY_OFFSET), CLOSEDVAL);
|
||||||
|
float openness = ((val - CLOSEDVAL) / float(GLISSANDO_STEPS));
|
||||||
|
|
||||||
|
// keys = all keys which are at least touched
|
||||||
|
// glissandoKeys = all keys which are fully closed
|
||||||
|
// The glissando operation computes the difference.
|
||||||
|
if (openness < 1.0) {
|
||||||
|
glissandoOpenness = max(glissandoOpenness, openness);
|
||||||
|
bitSet(keys, i);
|
||||||
}
|
}
|
||||||
|
if (openness == 0.0) {
|
||||||
// 0x6c is actually 8 bytes, but all 8 are always the same...
|
bitSet(glissandoKeys, i);
|
||||||
paj7620ReadReg(0x6c, 1, &kneeClosedness);
|
|
||||||
|
|
||||||
keysLast = keys;
|
|
||||||
keys = 0;
|
|
||||||
glissandoKeys = 0;
|
|
||||||
for (int i=0; i<8; i++) {
|
|
||||||
uint16_t val = max(capSensor.filteredData(i+KEY_OFFSET), CLOSEDVAL);
|
|
||||||
float openness = ((val - CLOSEDVAL) / float(GLISSANDO_STEPS));
|
|
||||||
|
|
||||||
// keys = all keys which are at least touched
|
|
||||||
// glissandoKeys = all keys which are fully closed
|
|
||||||
// The glissando operation computes the difference.
|
|
||||||
if (openness < 1.0) {
|
|
||||||
glissandoOpenness = max(glissandoOpenness, openness);
|
|
||||||
bitSet(keys, i);
|
|
||||||
}
|
|
||||||
if (openness == 0.0) {
|
|
||||||
bitSet(glissandoKeys, i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Look up notes in the big table
|
// Look up notes in the big table
|
||||||
struct Fingering f = uilleann_matrix[keys];
|
struct Fingering f = uilleann_matrix[keys];
|
||||||
struct Fingering gf = uilleann_matrix[glissandoKeys];
|
struct Fingering gf = uilleann_matrix[glissandoKeys];
|
||||||
|
|
||||||
note = f.note;
|
note = f.note;
|
||||||
glissandoNote = gf.note;
|
glissandoNote = gf.note;
|
||||||
|
|
||||||
// Was the high bit set? That indicates "alternate fingering", which sounds different.
|
// Was the high bit set? That indicates "alternate fingering", which sounds different.
|
||||||
altFingering = f.alt;
|
altFingering = f.alt;
|
||||||
|
|
||||||
// If the bag is squished, jump up an octave
|
// If the bag is squished, jump up an octave
|
||||||
// But only if the left thumb is down!
|
// But only if the left thumb is down!
|
||||||
if (bag && (keys & bit(7))) {
|
if (bag && (keys & bit(7))) {
|
||||||
note += NOTE_OCTAVE;
|
note += NOTE_OCTAVE;
|
||||||
glissandoNote += NOTE_OCTAVE;
|
glissandoNote += NOTE_OCTAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All keys closed + knee = no sound
|
// All keys closed + knee = no sound
|
||||||
silent = ((kneeClosedness > 240) && (keys == 0xff));
|
silent = ((kneeClosedness > 240) && (keys == 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pipe::Pressed(uint8_t key) {
|
bool Pipe::Pressed(uint8_t key) {
|
||||||
return bitRead(keys, key);
|
return bitRead(keys, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pipe::JustPressed(uint8_t key) {
|
bool Pipe::JustPressed(uint8_t key) {
|
||||||
if (bitRead(keys, key)) {
|
if (bitRead(keys, key)) {
|
||||||
return !bitRead(keysLast, key);
|
return !bitRead(keysLast, key);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
76
pipe.h
76
pipe.h
|
@ -1,59 +1,59 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <SparkFun_Qwiic_Button.h>
|
|
||||||
#include <Adafruit_MPR121.h>
|
#include <Adafruit_MPR121.h>
|
||||||
|
#include <SparkFun_Qwiic_Button.h>
|
||||||
#include <paj7620.h>
|
#include <paj7620.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "tuning.h"
|
#include "tuning.h"
|
||||||
|
|
||||||
class Pipe {
|
class Pipe {
|
||||||
public:
|
public:
|
||||||
// kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open.
|
// kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open.
|
||||||
uint8_t kneeClosedness;
|
uint8_t kneeClosedness;
|
||||||
|
|
||||||
// keys are which keys are being pressed.
|
// keys are which keys are being pressed.
|
||||||
uint8_t keys;
|
uint8_t keys;
|
||||||
uint8_t keysLast;
|
uint8_t keysLast;
|
||||||
|
|
||||||
// note holds the note being played, according to the fingering chart.
|
// note holds the note being played, according to the fingering chart.
|
||||||
Note note;
|
Note note;
|
||||||
|
|
||||||
// glissandoNote is the note that would be played if partially open keys were fully open.
|
// glissandoNote is the note that would be played if partially open keys were fully open.
|
||||||
Note glissandoNote;
|
Note glissandoNote;
|
||||||
|
|
||||||
// glissandoOpenness is how "open" the holes are in the direction of the glissandoNote.
|
// glissandoOpenness is how "open" the holes are in the direction of the glissandoNote.
|
||||||
float glissandoOpenness;
|
float glissandoOpenness;
|
||||||
|
|
||||||
// silent is true if all keys and the knee are closed.
|
// silent is true if all keys and the knee are closed.
|
||||||
bool silent;
|
bool silent;
|
||||||
|
|
||||||
// bag is true if the bag is being squished.
|
// bag is true if the bag is being squished.
|
||||||
bool bag;
|
bool bag;
|
||||||
|
|
||||||
// altFingering is true if the "alternate fingering" is being played.
|
// altFingering is true if the "alternate fingering" is being played.
|
||||||
// This should sound different than the standard fingering.
|
// This should sound different than the standard fingering.
|
||||||
bool altFingering;
|
bool altFingering;
|
||||||
|
|
||||||
Pipe();
|
Pipe();
|
||||||
|
|
||||||
// Init initializes everything.
|
// Init initializes everything.
|
||||||
//
|
//
|
||||||
// Returns true if it all worked. You can run it again if it didn't.
|
// Returns true if it all worked. You can run it again if it didn't.
|
||||||
bool Init();
|
bool Init();
|
||||||
|
|
||||||
// Update reads sensors and updates pipe state.
|
// Update reads sensors and updates pipe state.
|
||||||
//
|
//
|
||||||
// It should be run once per loop.
|
// It should be run once per loop.
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
// Pressed returns whether the given key is pressed.
|
// Pressed returns whether the given key is pressed.
|
||||||
bool Pressed(uint8_t key);
|
bool Pressed(uint8_t key);
|
||||||
|
|
||||||
// JustPressed returns whether the given key was just pressed.
|
// JustPressed returns whether the given key was just pressed.
|
||||||
bool JustPressed(uint8_t key);
|
bool JustPressed(uint8_t key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Adafruit_MPR121 capSensor;
|
Adafruit_MPR121 capSensor;
|
||||||
QwiicButton bagSensor;
|
QwiicButton bagSensor;
|
||||||
bool bag_enabled;
|
bool bag_enabled;
|
||||||
};
|
};
|
||||||
|
|
51
tuning.cpp
51
tuning.cpp
|
@ -2,9 +2,6 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
// 12th root of 2, used for Twelvetone Equal Temperament
|
|
||||||
#define TET_CONST 1.059463
|
|
||||||
|
|
||||||
Tuning::Tuning(Note base, float pitch, TuningSystem system) {
|
Tuning::Tuning(Note base, float pitch, TuningSystem system) {
|
||||||
Setup(base, pitch, system);
|
Setup(base, pitch, system);
|
||||||
}
|
}
|
||||||
|
@ -14,18 +11,20 @@ Tuning::Tuning(Note base, float pitch) {
|
||||||
|
|
||||||
// I like just Intonation.
|
// I like just Intonation.
|
||||||
Tuning::Tuning() {
|
Tuning::Tuning() {
|
||||||
#if 0
|
|
||||||
Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Note Tuning::GetBaseNote() { return baseNote; }
|
Note Tuning::GetBaseNote() {
|
||||||
|
return baseNote;
|
||||||
|
}
|
||||||
|
|
||||||
void Tuning::SetTuningSystem(TuningSystem system) {
|
void Tuning::SetTuningSystem(TuningSystem system) {
|
||||||
Setup(baseNote, GetPitch(baseNote), system);
|
Setup(baseNote, GetPitch(baseNote), system);
|
||||||
}
|
}
|
||||||
|
|
||||||
TuningSystem Tuning::GetSystem() { return system; }
|
TuningSystem Tuning::GetTuningSystem() {
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
|
||||||
// setupOctaves computes the entire tuning frequency chart.
|
// setupOctaves computes the entire tuning frequency chart.
|
||||||
//
|
//
|
||||||
|
@ -53,7 +52,7 @@ void Tuning::setupOctaves(Note base) {
|
||||||
void Tuning::setupEqual(Note base, float pitch) {
|
void Tuning::setupEqual(Note base, float pitch) {
|
||||||
pitches[base] = pitch;
|
pitches[base] = pitch;
|
||||||
for (int i = 1; i < 12; i++) {
|
for (int i = 1; i < 12; i++) {
|
||||||
pitches[base + i] = pitches[base + i - 1] * TET_CONST;
|
pitches[base + i] = pitches[base + i - 1] * TET_SEMITONE_MULTIPLIER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,17 +94,43 @@ void Tuning::Setup(Note base, float pitch, TuningSystem system) {
|
||||||
setupOctaves(base);
|
setupOctaves(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tuning::Setup(Note base, float pitch) { Setup(base, pitch, system); }
|
void Tuning::Setup(Note base, float pitch) {
|
||||||
|
Setup(base, pitch, system);
|
||||||
|
}
|
||||||
|
|
||||||
float Tuning::GetPitch(Note note) { return pitches[note]; }
|
float Tuning::GetPitch(Note note) {
|
||||||
|
return pitches[note];
|
||||||
|
}
|
||||||
|
|
||||||
Note NearestNote(float pitch) {
|
Note NearestNote(float pitch) {
|
||||||
return Note(round(log2(pitch / PITCH_CONCERT_C0)));
|
return Note(round(log(pitch / PITCH_CONCERT_C0) / log(TET_SEMITONE_MULTIPLIER)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *noteNames[]{
|
const char *noteNames[]{
|
||||||
"C ", "C#", "D ", "Eb", "E ", "F ", "F#", "G ", "Ab", "A ", "Bb", "B ",
|
"C",
|
||||||
|
"C#",
|
||||||
|
"D",
|
||||||
|
"Eb",
|
||||||
|
"E",
|
||||||
|
"F",
|
||||||
|
"F#",
|
||||||
|
"G",
|
||||||
|
"Ab",
|
||||||
|
"A",
|
||||||
|
"Bb",
|
||||||
|
"B",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *NoteName(Note note) { return noteNames[note % 12]; }
|
const char *NoteName(Note note) {
|
||||||
|
return noteNames[note % 12];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *TuningSystemName(TuningSystem system) {
|
||||||
|
switch (system) {
|
||||||
|
case TUNINGSYSTEM_EQUAL:
|
||||||
|
return "Equal";
|
||||||
|
case TUNINGSYSTEM_JUST:
|
||||||
|
default:
|
||||||
|
return "Just";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
208
tuning.h
208
tuning.h
|
@ -2,21 +2,120 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
enum TuningSystem {
|
enum TuningSystem {
|
||||||
TUNINGSYSTEM_JUST,
|
TUNINGSYSTEM_JUST,
|
||||||
TUNINGSYSTEM_EQUAL,
|
TUNINGSYSTEM_EQUAL,
|
||||||
|
TUNINGSYSTEM_MAX = TUNINGSYSTEM_EQUAL,
|
||||||
};
|
};
|
||||||
#define TUNINGSYSTEM_MAX TUNINGSYSTEM_EQUAL
|
|
||||||
|
|
||||||
enum Note {
|
enum Note {
|
||||||
NOTE_C0, NOTE_CS0, NOTE_D0, NOTE_DS0, NOTE_E0, NOTE_F0, NOTE_FS0, NOTE_G0, NOTE_GS0, NOTE_A0, NOTE_AS0, NOTE_B0,
|
NOTE_C0,
|
||||||
NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1, NOTE_B1,
|
NOTE_CS0,
|
||||||
NOTE_C2, NOTE_CS2, NOTE_D2, NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2, NOTE_B2,
|
NOTE_D0,
|
||||||
NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3, NOTE_B3,
|
NOTE_DS0,
|
||||||
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
|
NOTE_E0,
|
||||||
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
|
NOTE_F0,
|
||||||
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
|
NOTE_FS0,
|
||||||
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7,
|
NOTE_G0,
|
||||||
NOTE_C8, NOTE_CS8, NOTE_D8, NOTE_DS8, NOTE_E8, NOTE_F8, NOTE_FS8, NOTE_G8, NOTE_GS8, NOTE_A8, NOTE_AS8, NOTE_B8,
|
NOTE_GS0,
|
||||||
|
NOTE_A0,
|
||||||
|
NOTE_AS0,
|
||||||
|
NOTE_B0,
|
||||||
|
NOTE_C1,
|
||||||
|
NOTE_CS1,
|
||||||
|
NOTE_D1,
|
||||||
|
NOTE_DS1,
|
||||||
|
NOTE_E1,
|
||||||
|
NOTE_F1,
|
||||||
|
NOTE_FS1,
|
||||||
|
NOTE_G1,
|
||||||
|
NOTE_GS1,
|
||||||
|
NOTE_A1,
|
||||||
|
NOTE_AS1,
|
||||||
|
NOTE_B1,
|
||||||
|
NOTE_C2,
|
||||||
|
NOTE_CS2,
|
||||||
|
NOTE_D2,
|
||||||
|
NOTE_DS2,
|
||||||
|
NOTE_E2,
|
||||||
|
NOTE_F2,
|
||||||
|
NOTE_FS2,
|
||||||
|
NOTE_G2,
|
||||||
|
NOTE_GS2,
|
||||||
|
NOTE_A2,
|
||||||
|
NOTE_AS2,
|
||||||
|
NOTE_B2,
|
||||||
|
NOTE_C3,
|
||||||
|
NOTE_CS3,
|
||||||
|
NOTE_D3,
|
||||||
|
NOTE_DS3,
|
||||||
|
NOTE_E3,
|
||||||
|
NOTE_F3,
|
||||||
|
NOTE_FS3,
|
||||||
|
NOTE_G3,
|
||||||
|
NOTE_GS3,
|
||||||
|
NOTE_A3,
|
||||||
|
NOTE_AS3,
|
||||||
|
NOTE_B3,
|
||||||
|
NOTE_C4,
|
||||||
|
NOTE_CS4,
|
||||||
|
NOTE_D4,
|
||||||
|
NOTE_DS4,
|
||||||
|
NOTE_E4,
|
||||||
|
NOTE_F4,
|
||||||
|
NOTE_FS4,
|
||||||
|
NOTE_G4,
|
||||||
|
NOTE_GS4,
|
||||||
|
NOTE_A4,
|
||||||
|
NOTE_AS4,
|
||||||
|
NOTE_B4,
|
||||||
|
NOTE_C5,
|
||||||
|
NOTE_CS5,
|
||||||
|
NOTE_D5,
|
||||||
|
NOTE_DS5,
|
||||||
|
NOTE_E5,
|
||||||
|
NOTE_F5,
|
||||||
|
NOTE_FS5,
|
||||||
|
NOTE_G5,
|
||||||
|
NOTE_GS5,
|
||||||
|
NOTE_A5,
|
||||||
|
NOTE_AS5,
|
||||||
|
NOTE_B5,
|
||||||
|
NOTE_C6,
|
||||||
|
NOTE_CS6,
|
||||||
|
NOTE_D6,
|
||||||
|
NOTE_DS6,
|
||||||
|
NOTE_E6,
|
||||||
|
NOTE_F6,
|
||||||
|
NOTE_FS6,
|
||||||
|
NOTE_G6,
|
||||||
|
NOTE_GS6,
|
||||||
|
NOTE_A6,
|
||||||
|
NOTE_AS6,
|
||||||
|
NOTE_B6,
|
||||||
|
NOTE_C7,
|
||||||
|
NOTE_CS7,
|
||||||
|
NOTE_D7,
|
||||||
|
NOTE_DS7,
|
||||||
|
NOTE_E7,
|
||||||
|
NOTE_F7,
|
||||||
|
NOTE_FS7,
|
||||||
|
NOTE_G7,
|
||||||
|
NOTE_GS7,
|
||||||
|
NOTE_A7,
|
||||||
|
NOTE_AS7,
|
||||||
|
NOTE_B7,
|
||||||
|
NOTE_C8,
|
||||||
|
NOTE_CS8,
|
||||||
|
NOTE_D8,
|
||||||
|
NOTE_DS8,
|
||||||
|
NOTE_E8,
|
||||||
|
NOTE_F8,
|
||||||
|
NOTE_FS8,
|
||||||
|
NOTE_G8,
|
||||||
|
NOTE_GS8,
|
||||||
|
NOTE_A8,
|
||||||
|
NOTE_AS8,
|
||||||
|
NOTE_B8,
|
||||||
NOTE_ZERO = 0,
|
NOTE_ZERO = 0,
|
||||||
NOTE_SEMITONE = 1,
|
NOTE_SEMITONE = 1,
|
||||||
NOTE_WHOLETONE = 2,
|
NOTE_WHOLETONE = 2,
|
||||||
|
@ -28,72 +127,85 @@ enum Note {
|
||||||
#define PITCH_CONCERT_A4 440.00
|
#define PITCH_CONCERT_A4 440.00
|
||||||
#define PITCH_CONCERT_D4 293.66
|
#define PITCH_CONCERT_D4 293.66
|
||||||
|
|
||||||
|
// Twelvetone Equal Temperament semitone multiplier
|
||||||
|
// Take any frequency and multiply it by this magic number to get a semitone higher!
|
||||||
|
// Divide to get a semitone lower!
|
||||||
|
// This is an approximation of exp(2, 1/12),
|
||||||
|
// which was worked out in around the 1500s.
|
||||||
|
#define TET_SEMITONE_MULTIPLIER 1.059463
|
||||||
|
|
||||||
class Tuning {
|
class Tuning {
|
||||||
public:
|
public:
|
||||||
// name contains the name of the current tuning system
|
// name contains the name of the current tuning system
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
Tuning(Note base, float pitch, TuningSystem system);
|
Tuning(Note base, float pitch, TuningSystem system);
|
||||||
Tuning(Note base, float pitch);
|
Tuning(Note base, float pitch);
|
||||||
Tuning();
|
Tuning();
|
||||||
void Setup(Note base, float pitch, TuningSystem system);
|
void Setup(Note base, float pitch, TuningSystem system);
|
||||||
void Setup(Note base, float pitch);
|
void Setup(Note base, float pitch);
|
||||||
void SetTuningSystem(TuningSystem system);
|
void SetTuningSystem(TuningSystem system);
|
||||||
TuningSystem GetSystem();
|
TuningSystem GetTuningSystem();
|
||||||
Note GetBaseNote();
|
Note GetBaseNote();
|
||||||
float GetPitch(Note note);
|
float GetPitch(Note note);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TuningSystem system;
|
TuningSystem system;
|
||||||
Note baseNote;
|
Note baseNote;
|
||||||
float pitches[NOTE_MAX];
|
float pitches[NOTE_MAX];
|
||||||
|
|
||||||
void setupOctaves(Note base);
|
void setupOctaves(Note base);
|
||||||
void setupJust(Note base, float pitch);
|
void setupJust(Note base, float pitch);
|
||||||
void setupEqual(Note base, float pitch);
|
void setupEqual(Note base, float pitch);
|
||||||
};
|
};
|
||||||
|
|
||||||
// NearestNote returns the note nearest to pitch.
|
// NearestNote returns the note nearest to pitch.
|
||||||
Note NearestNote(float pitch);
|
Note NearestNote(float pitch);
|
||||||
|
|
||||||
// NoteName return the name of a note (without octave).
|
// NoteName returns the name of a note (without octave).
|
||||||
const char *NoteName(Note note);
|
const char *NoteName(Note note);
|
||||||
|
|
||||||
|
// TuningSystemName returns the name of a tuning system.
|
||||||
|
const char *TuningSystemName(TuningSystem system);
|
||||||
|
|
||||||
// Make notes support some arithmetic
|
// Make notes support some arithmetic
|
||||||
inline Note toNote(int a) {
|
inline Note toNote(int a) {
|
||||||
if (a < NOTE_ZERO) {
|
if (a < NOTE_ZERO) {
|
||||||
return NOTE_ZERO;
|
return NOTE_ZERO;
|
||||||
} else if (a > NOTE_MAX) {
|
} else if (a > NOTE_MAX) {
|
||||||
return NOTE_MAX;
|
return NOTE_MAX;
|
||||||
} else {
|
} else {
|
||||||
return Note(a);
|
return Note(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline Note operator+(const Note &a, const Note b) {
|
inline Note operator+(const Note &a, const Note b) {
|
||||||
return toNote(int(a) + int(b));
|
return toNote(int(a) + int(b));
|
||||||
}
|
}
|
||||||
inline Note &operator+=(Note &a, const Note b) {
|
inline Note &operator+=(Note &a, const Note b) {
|
||||||
return a = a + b;
|
return a = a + b;
|
||||||
}
|
}
|
||||||
inline Note &operator++(Note &a) {
|
inline Note &operator++(Note &a) {
|
||||||
return a += NOTE_SEMITONE;
|
return a += NOTE_SEMITONE;
|
||||||
}
|
}
|
||||||
inline Note operator-(const Note a, const Note b) {
|
inline Note operator-(const Note a, const Note b) {
|
||||||
return toNote(int(a) - int(b));
|
return toNote(int(a) - int(b));
|
||||||
}
|
}
|
||||||
inline Note &operator-=(Note &a, const Note b) {
|
inline Note &operator-=(Note &a, const Note b) {
|
||||||
return a = a - b;
|
return a = a - b;
|
||||||
}
|
}
|
||||||
inline Note &operator--(Note &a) {
|
inline Note &operator--(Note &a) {
|
||||||
return a -= NOTE_SEMITONE;
|
return a -= NOTE_SEMITONE;
|
||||||
}
|
}
|
||||||
inline Note operator*(const Note a, const int b) {
|
inline Note operator*(const Note a, const int b) {
|
||||||
return toNote(int(a) * b);
|
return toNote(int(a) * b);
|
||||||
}
|
}
|
||||||
inline int operator/(const Note a, const int b) {
|
inline int operator/(const Note a, const int b) {
|
||||||
return int(a)/b;
|
return int(a) / b;
|
||||||
}
|
}
|
||||||
inline int operator/(const Note a, const Note b) {
|
inline int operator/(const Note a, const Note b) {
|
||||||
return int(a)/b;
|
return int(a) / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TuningSystem operator++(TuningSystem &a) {
|
||||||
|
return a = TuningSystem((int(a) + 1) % int(TUNINGSYSTEM_MAX + 1));
|
||||||
}
|
}
|
||||||
|
|
109
uilleann.ino
109
uilleann.ino
|
@ -3,7 +3,6 @@
|
||||||
#include <Adafruit_SSD1306.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
#include <Audio.h>
|
#include <Audio.h>
|
||||||
#include <Fonts/FreeSans9pt7b.h>
|
#include <Fonts/FreeSans9pt7b.h>
|
||||||
#include <SparkFun_Qwiic_Button.h>
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <paj7620.h>
|
#include <paj7620.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -22,14 +21,12 @@ Pipe pipe;
|
||||||
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
||||||
|
|
||||||
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
||||||
int currentPatch = 0;
|
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
uint8_t intonation = 0;
|
|
||||||
int16_t pitchAdjust = 0;
|
|
||||||
uint8_t patch[4] = {0};
|
uint8_t patch[4] = {0};
|
||||||
float volume[4] = {0};
|
float volume[4] = {0};
|
||||||
const char *settingNames[4] = {"c", "r", "d", "*"};
|
const char *settingNames[4] = {"c", "r", "d", "*"};
|
||||||
|
const char *buildDate = __DATE__;
|
||||||
|
|
||||||
// Pipes
|
// Pipes
|
||||||
FMVoice Chanter;
|
FMVoice Chanter;
|
||||||
|
@ -100,7 +97,7 @@ void diag(const char *fmt, ...) {
|
||||||
char s[80];
|
char s[80];
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(s, sizeof(s)-1, fmt, args);
|
vsnprintf(s, sizeof(s) - 1, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
|
@ -109,7 +106,7 @@ void diag(const char *fmt, ...) {
|
||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
|
|
||||||
display.setCursor(56, 24);
|
display.setCursor(56, 24);
|
||||||
display.print(__DATE__);
|
display.print(buildDate);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
display.setCursor(0, 16);
|
display.setCursor(0, 16);
|
||||||
|
@ -171,8 +168,7 @@ void setup() {
|
||||||
// Turn on drones
|
// Turn on drones
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Note note = NOTE_D4 - (NOTE_OCTAVE * i);
|
Note note = NOTE_D4 - (NOTE_OCTAVE * i);
|
||||||
float pitch =
|
float pitch = tuning.GetPitch(note) * (0.01 * (i - 1)); // Detune just a touch
|
||||||
tuning.GetPitch(note) * (0.01 * (i - 1)); // Detune just a touch
|
|
||||||
Drones[i].LoadPatch(&Bank[0]);
|
Drones[i].LoadPatch(&Bank[0]);
|
||||||
Drones[i].NoteOn(pitch);
|
Drones[i].NoteOn(pitch);
|
||||||
}
|
}
|
||||||
|
@ -187,25 +183,22 @@ void setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
static bool forceDisplayUpdate = true;
|
||||||
|
|
||||||
pipe.Update();
|
pipe.Update();
|
||||||
diag("loop %d", millis());
|
|
||||||
|
|
||||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||||
trellis.tick();
|
trellis.tick();
|
||||||
|
|
||||||
trellis.setPixelColor(1, trellis.ColorHSV(millis(), 255, 120));
|
|
||||||
{
|
|
||||||
uint16_t color = trellis.ColorHSV(64 * pipe.kneeClosedness, 255, 120);
|
|
||||||
trellis.setPixelColor(0, color);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If we're infinitely (for the sensor) off the knee,
|
// If we're infinitely (for the sensor) off the knee,
|
||||||
// go into setup mode!
|
// go into setup mode!
|
||||||
if (pipe.kneeClosedness == 0) {
|
if (pipe.kneeClosedness == 0) {
|
||||||
doSetup();
|
doSetup();
|
||||||
|
forceDisplayUpdate = true;
|
||||||
} else {
|
} else {
|
||||||
doPlay();
|
doPlay(forceDisplayUpdate);
|
||||||
|
forceDisplayUpdate = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,12 +218,21 @@ void loop() {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void doSetup() {
|
void doSetup() {
|
||||||
|
static unsigned long quietUntil = 0;
|
||||||
|
|
||||||
|
// Stuff can set quietUntil to stop responding to keys for a bit
|
||||||
|
#define quiet() quietUntil = millis() + 200
|
||||||
|
if (millis() < quietUntil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
|
|
||||||
bool alt = pipe.Pressed(7);
|
bool alt = pipe.Pressed(7);
|
||||||
|
|
||||||
// Draw indicator bar
|
// Draw indicator bar
|
||||||
display.fillRect(126, 0, 2, 32, SSD1306_WHITE);
|
display.fillRect(126, 0, 2, 32, SSD1306_WHITE);
|
||||||
|
display.setFont(0);
|
||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
display.setCursor(0, 0);
|
display.setCursor(0, 0);
|
||||||
|
|
||||||
|
@ -238,7 +240,7 @@ void doSetup() {
|
||||||
// Show settings for each of Chanter, Regulators, Drones
|
// Show settings for each of Chanter, Regulators, Drones
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
int p = patch[i];
|
int p = patch[i];
|
||||||
int16_t x = 0;
|
int16_t x = 1;
|
||||||
int16_t y = i * 8;
|
int16_t y = i * 8;
|
||||||
|
|
||||||
display.setCursor(x, y);
|
display.setCursor(x, y);
|
||||||
|
@ -265,31 +267,71 @@ void doSetup() {
|
||||||
display.print(Bank[p].name);
|
display.print(Bank[p].name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pipe.Pressed(6)) {
|
|
||||||
float freq = PITCH_CONCERT_D4 + pitchAdjust;
|
|
||||||
Note note = NearestNote(freq);
|
|
||||||
|
|
||||||
display.setCursor(0, 0);
|
if (pipe.Pressed(6)) {
|
||||||
|
TuningSystem system = tuning.GetTuningSystem();
|
||||||
|
float freq = tuning.GetPitch(NOTE_D4);
|
||||||
|
Note note = NearestNote(freq);
|
||||||
|
int octave = int(note) / 12;
|
||||||
|
|
||||||
|
if (pipe.JustPressed(3) || pipe.JustPressed(2)) {
|
||||||
|
tuning.Setup(NOTE_A4, PITCH_CONCERT_A4, TUNINGSYSTEM_EQUAL);
|
||||||
|
if (pipe.Pressed(3) && pipe.Pressed(2)) {
|
||||||
|
++system;
|
||||||
|
} else if (pipe.Pressed(3)) {
|
||||||
|
freq = tuning.GetPitch(++note);
|
||||||
|
} else if (pipe.Pressed(2)) {
|
||||||
|
freq = tuning.GetPitch(--note);
|
||||||
|
}
|
||||||
|
tuning.Setup(NOTE_D4, freq, system);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipe.Pressed(1) || pipe.Pressed(0)) {
|
||||||
|
if (pipe.Pressed(1) && pipe.Pressed(0)) {
|
||||||
|
freq = PITCH_CONCERT_D4;
|
||||||
|
quiet();
|
||||||
|
} else if (pipe.Pressed(1)) {
|
||||||
|
freq *= 1.001;
|
||||||
|
} else if (pipe.Pressed(0)) {
|
||||||
|
freq /= 1.001;
|
||||||
|
}
|
||||||
|
tuning.Setup(NOTE_D4, freq);
|
||||||
|
note = NearestNote(freq);
|
||||||
|
}
|
||||||
|
|
||||||
|
display.setFont(&FreeSans9pt7b);
|
||||||
|
display.setCursor(0, 12);
|
||||||
display.print(NoteName(note));
|
display.print(NoteName(note));
|
||||||
display.setCursor(6 + 6, 0);
|
display.print(octave);
|
||||||
|
display.setCursor(48, 12);
|
||||||
display.print(freq);
|
display.print(freq);
|
||||||
|
|
||||||
|
display.setCursor(0, 27);
|
||||||
|
display.print(TuningSystemName(system));
|
||||||
} else if (pipe.Pressed(5)) {
|
} else if (pipe.Pressed(5)) {
|
||||||
display.print("fn2");
|
display.print("fn2");
|
||||||
} else if (pipe.Pressed(4)) {
|
} else if (pipe.Pressed(4)) {
|
||||||
display.print("fn3");
|
display.print("fn3");
|
||||||
} else {
|
} else {
|
||||||
display.setCursor(56, 8);
|
display.setFont(&FreeSans9pt7b);
|
||||||
display.setTextSize(2);
|
display.setCursor(64, 18);
|
||||||
display.print("Setup");
|
display.print("Setup");
|
||||||
|
|
||||||
|
display.setFont();
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setCursor(0, 16);
|
||||||
|
display.print("build");
|
||||||
|
display.setCursor(0, 24);
|
||||||
|
display.print(buildDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
void doPlay() {
|
void doPlay(bool forceUpdate) {
|
||||||
static uint8_t last_note = 0;
|
static uint8_t last_note = 0;
|
||||||
bool updateDisplay = false;
|
bool updateDisplay = forceUpdate;
|
||||||
|
|
||||||
if (pipe.silent) {
|
if (pipe.silent) {
|
||||||
Chanter.NoteOff();
|
Chanter.NoteOff();
|
||||||
|
@ -332,19 +374,16 @@ void doPlay() {
|
||||||
|
|
||||||
if (updateDisplay) {
|
if (updateDisplay) {
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
|
display.setFont(&FreeSans9pt7b);
|
||||||
|
|
||||||
|
if (Chanter.patch) {
|
||||||
|
display.setCursor(0, 32);
|
||||||
|
display.print(Chanter.patch->name);
|
||||||
|
}
|
||||||
|
|
||||||
display.setCursor(0, 16);
|
display.setCursor(0, 16);
|
||||||
display.setTextSize(2);
|
|
||||||
display.print(Chanter.patch->name);
|
|
||||||
|
|
||||||
display.setCursor(0, 0);
|
|
||||||
display.setTextSize(2);
|
|
||||||
display.print(note_name);
|
display.print(note_name);
|
||||||
|
|
||||||
display.setCursor(40, 0);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.print(pipe.kneeClosedness);
|
|
||||||
|
|
||||||
display.display();
|
display.display();
|
||||||
last_note = pipe.note;
|
last_note = pipe.note;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue