uilleann/tuning.cpp

137 lines
3.4 KiB
C++

#include "tuning.h"
#include <math.h>
Tuning::Tuning(Note base, float pitch, TuningSystem system) {
Setup(base, pitch, system);
}
Tuning::Tuning(Note base, float pitch) {
Tuning(base, pitch, TUNINGSYSTEM_JUST);
}
// I like just Intonation.
Tuning::Tuning() {
Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
}
Note Tuning::GetBaseNote() {
return baseNote;
}
void Tuning::SetTuningSystem(TuningSystem system) {
Setup(baseNote, GetPitch(baseNote), system);
}
TuningSystem Tuning::GetTuningSystem() {
return system;
}
// setupOctaves computes the entire tuning frequency chart.
//
// You must call this after setting a full octave chromatic scale, rooted at
// base.
void Tuning::setupOctaves(Note base) {
int multiplier = 1;
for (Note octave = NOTE_ZERO; octave < NOTE_MAX; octave += NOTE_OCTAVE) {
for (Note note = base; note < base + NOTE_OCTAVE; note += NOTE_SEMITONE) {
Note upNote = note + octave;
Note dnNote = note - octave;
if (upNote < NOTE_MAX) {
pitches[upNote] = pitches[note] * multiplier;
}
if (dnNote >= NOTE_ZERO) {
pitches[dnNote] = pitches[note] / multiplier;
}
}
multiplier <<= 1;
}
}
// setupEqual sets an even-temperament chromatic scale rooted at base
void Tuning::setupEqual(Note base, float pitch) {
pitches[base] = pitch;
for (int i = 1; i < 12; i++) {
pitches[base + i] = pitches[base + i - 1] * TET_SEMITONE_MULTIPLIER;
}
}
// setupJust sets a just-temperament chromatic scale rooted at base
void Tuning::setupJust(Note base, float pitch) {
// Diatonic scale
pitches[base + 0] = pitch * 1 / 1; // Unison
pitches[base + 2] = pitch * 9 / 8; // Second
pitches[base + 4] = pitch * 5 / 4; // Third
pitches[base + 5] = pitch * 4 / 3; // Fourth
pitches[base + 7] = pitch * 3 / 2; // Fifth
pitches[base + 9] = pitch * 5 / 3; // Sixth
pitches[base + 11] = pitch * 15 / 8; // Seventh
// I got this off various Wikipedia pages.
// The main thing here is that the minor seventh works out to be a diatonic
// fourth up from the fourth computed above, since the music I want to play
// frequently wants to play G major on a D major instrument
pitches[base + 1] = pitch * 16 / 15; // min2
pitches[base + 3] = pitch * 6 / 5; // min3
pitches[base + 6] = pitch * 10 / 7; // dim5
pitches[base + 8] = pitch * 8 / 5; // min6
pitches[base + 10] = pitch * 16 / 9; // min7 = fourth + fourth
}
void Tuning::Setup(Note base, float pitch, TuningSystem system) {
this->baseNote = base;
this->system = system;
switch (system) {
case TUNINGSYSTEM_EQUAL:
setupEqual(base, pitch);
break;
case TUNINGSYSTEM_JUST:
default:
setupJust(base, pitch);
break;
}
setupOctaves(base);
}
void Tuning::Setup(Note base, float pitch) {
Setup(base, pitch, system);
}
float Tuning::GetPitch(Note note) {
return pitches[note];
}
Note NearestNote(float pitch) {
return Note(round(log(pitch / PITCH_CONCERT_C0) / log(TET_SEMITONE_MULTIPLIER)));
}
const char *noteNames[]{
"C",
"C#",
"D",
"Eb",
"E",
"F",
"F#",
"G",
"Ab",
"A",
"Bb",
"B",
};
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";
}
}