yaw-audio/lib/scale/scale.h

98 lines
1.9 KiB
C++

#ifndef YAW_SCALE_INCLUDED
#define YAW_SCALE_INCLUDED
#include <vector>
#include <string>
static std::vector<std::string> defaultNoteNames = {
"A",
"A#",
"B",
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#"};
class Scale
{
double sampleRate = 48000.0;
// freqs in hz, periods in samples
std::vector<double> frequencies;
std::vector<double> periods;
std::vector<std::string> names;
public:
void newSampleRate(double rate)
{
double ratio = rate / sampleRate;
sampleRate = rate;
for (double &note : periods)
note *= ratio;
};
// Default ctor: 12TET @ 48kHz
Scale(double hz = 440.0)
{
hz /= 32.0;
for (int oct = 0; oct < 8; ++oct)
{
for (int j = 0; j < 12; ++j)
{
double note = exp2(j / 12.0) * hz * (1 << oct);
frequencies.push_back(note);
periods.push_back(sampleRate / note);
names.push_back(defaultNoteNames[j]);
}
}
}
double getNearestPeriod(double period)
{
for (auto note : periods)
{
if (period > note)
return note;
}
// This should NOT happen.
return 0;
}
double getNearestNoteNumber(double hz)
{
for (unsigned int i = 0; i < frequencies.size(); ++i)
{
if (hz < frequencies[i])
{
if (i == 0)
return i;
return 1.0 * i + (hz - frequencies[i - 1]) / (frequencies[i] - frequencies[i - 1]);
}
}
return 0.0;
}
double getNearestFrequency(double hz)
{
for (auto note : frequencies)
{
if (hz < note)
return note;
}
return 0;
}
// TODO: parse scala files. new ctor that parses arbitrary scales
};
#endif