c++ - 找到具有非线性级数的最接近值

标签 c++ algorithm dictionary math

这有点复杂,但请耐心等待。我正在尝试创建一张 map ,将音符的名称与其相应的频率联系起来。然后我想编写一个函数,当提供随机频率时将返回最接近该频率的音符。

问题是音符的频率不是用线性公式生成的,因此每个音符之间的确切中间频率也不是线性的。 (这基本上意味着音符之间的中点并不完全在中间,因此通过正常方法找到中点是行不通的。)

一些用于生成笔记 map 的示例代码:

// Ordered starting with "B" so notes line up with frequencies
vector<string> names = {
    "B", "C", "C#/Db", "D", "D#/Eb", "E", "F", "F#/Gb", "G", "G#/Ab", "A", "A#/Bb"
};

double f0 = 440;
map<string, map<int, double> > notes;

// Map notes to their corresponding frequencies
for (int octave = 0; octave < 10; ++octave) {
    for (int index = 0; index < names.size(); ++index) {

        // Get the exact frequency of the musical note
        double frequency               = f0*pow(pow(2, 1.0/12), index       - 10)*pow(pow(2, 1.0/12), 12*(octave + 1 - 5));

        // Get the exact frequency between this note and the next (I'm not doing anything with this yet, but I feel like this is on the right track.)
        double frequency_between_notes = f0*pow(pow(2, 1.0/12), index + 0.5 - 10)*pow(pow(2, 1.0/12), 12*(octave + 1 - 5));

        notes[names[index]][octave] = frequency;
    }
}

我想编写一个给定随机频率的函数,它将返回最接近该频率的音符。

Note& find_note(double frequency) {
    // Provided a random frequency find the ACTUAL nearest note using the non-linear formula that notes are calculated from.
    // Create the note object and return it.
}

Note 类看起来像这样:

class Note {
public:
    Note(string name, int octave, double frequency) {
        name_      = name;
        octave_    = octave;
        frequency_ = frequency;
    }

    const string& get_name() const {
        return name_;
    }

    const int& get_octave() const {
        return octave_;
    }

    const double& get_frequency() const {
        return frequency_;
    }
private:
    string name_;
    int    octave_;
    double frequency_;
};

The equation used to calculate the frequencies of the notes came from https://pages.mtu.edu/~suits/NoteFreqCalcs.html.

如何在给定随机频率的情况下找到最近的音符?

最佳答案

半音频率的对数均匀分布。要找到最接近给定频率的音符,只需获取频率的对数并找到最接近音符频率的对数。

这是一个简单的函数,它接受以 Hz 为单位的频率并返回最接近的半音,作为高于(正)或低于(负)A4 (440Hz) 的半音数

const double LOG_SEMITONE = log(2.0)/12.0;

int getNote(double f)
{
    double note = log(f/440.0) / LOG_SEMITONE;
    return (int)round(note);
}

关于c++ - 找到具有非线性级数的最接近值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48070949/

相关文章:

algorithm - 是否可以通过小块计算哈希?

swift - 下面提到的链表算法的时间复杂度是多少

swift - 使用变量作为键访问 Swift 字典

C++ , Cheat Engine/OllyDBG 从多级指针中找到基址 "static"

c++ - Android NDK r5 不能包含 STL 头文件

C++ - 是否可以在没有继承的情况下使用另一个类的方法?

c# - 快速将多个对象映射到另一个对象的数据结构

c# - 如何在 Dictionary<string, int> 中通过不区分大小写的键获取原始大小写键

python - 如何根据列表的长度将包含列表的字典分成相等的部分

c++ - C++11 标准和免费草稿 N3337 之间的节号是否不同?