137 lines
3.4 KiB
C++
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";
|
|
}
|
|
}
|