#ifndef YAW_SCALE_INCLUDED #define YAW_SCALE_INCLUDED #include #include static std::vector 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 frequencies; std::vector periods; std::vector names; public: void newSampleRate(double rate) { double ratio = rate / sampleRate; sampleRate = rate; for (double ¬e : 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