【问题标题】:How can I construct the right chord from one array per piano key?如何从每个钢琴键的一个数组中构建正确的和弦?
【发布时间】:2017-09-02 04:15:15
【问题描述】:

我目前有一个包含音乐中 12 个主要音阶的数组(keyList)。我需要一种循环遍历数组并返回用户输入的和弦的方法,而无需将一堆和弦硬编码到我的程序中。例如,如果用户输入字符串 ceg,程序将响应:“您输入了 C-E-G,C 大调和弦”。我的问题出在我的constructChord 函数中。我无法为我的 keyList 数组返回 3 个单独的索引,所以我需要一种方法来根据用户输入的字符串从我的数组中形成一个新字符串?.. 如果我需要更具体或澄清,请告诉我,但我们将不胜感激。

Github:ChordQuiz-Program

编辑:我以前从未在这里发帖,并试图使其具体化。如果这仍然是一个不好的问题,请告诉我。更好的是,告诉我为什么...

【问题讨论】:

  • 您可能需要一个表示和弦的类型。将和弦表示为间隔的集合,而不是字符串中的音符也可能更好。然后一个大和弦是{root, major third, perfect fifth}不管调。
  • 这肯定会让一切变得不那么精细。少了很多工作。但是随后用户输入将根据数字系统,例如 1 - 3 - 5 而不是 C - E -G 对吗?如果不通过字符串,你将如何区分主要和弦?

标签: c++ arrays string class return-value


【解决方案1】:

我的问题在于我的constructChord 函数。我无法为我的 keyList 数组返回 3 个单独的索引

我真的明白了,对吗?

是的,你可以!使用 c++11 很容易,使用 c++17 很神奇。我在示例中使用了 int,因为您使用了 int,但几乎所有类型都可以进行元组处理。

c++11

#include <tuple>
std::tuple<int, int, int> Music::constructChord(ChordType chord)
{
    // do something to calculate int a, b, c
    return std::make_tuple(a, b, c);   // just an example of course 
}

c++17

#include <tuple>
std::tuple<int, int, int> Music::constructChord(ChordType chord)
{
    // do something to calculate int a, b, c
    return {a, b, c};   // that is really cool, isn´t it? 
}

对输入进行清理和元组化

这是一个关于如何对输入进行清理和元组处理的快速破解示例。我已经放入了一个 main(),因此可以直接编译和使用它:

#include <iostream>
#include <map>
#include <regex>

int main()
{
    // this map is only a stub of course, a lot is missing ...
    std::map<std::string, int> sanitation = {{"a",0}, {"bb",1}, {"c",2}, {"c#",3}, {"#c",3}, {"db",3},  {"bd",3}};

    // input block from your code
    std::string myChord;
    std::cout << "Please enter a chord, at least three different piano keys:\n";
    getline(std::cin, myChord);
    transform(myChord.begin(), myChord.end(), myChord.begin(), ::tolower);

    // parsing the input
    std::regex regex(  R"(([a-g#]{1,2}) ([a-g#]{1,2}) ([a-g#]{1,2}))");
    std::smatch m;
    std::regex_search(myChord, m, regex);

    // sanitizing und tupleing it
    std::vector<int> matched;
    for (int i=1; i<m.size(); i++)
    {
        auto hit = sanitation.find(m[i]);
        if(hit!=sanitation.end())
            matched.push_back(hit->second);
    }

    auto my_tuple = std::make_tuple(matched);
    return 0;
}

【讨论】:

  • 对不起,我知道我的措辞有点混乱。但我不知道我能做到这一点,真的很酷。我将对此进行更多研究,但现在我的任务是弄清楚如何应用这些返回值来与用户输入的内容进行比较。你会推荐一个 int enum 吗?所以每三个返回值都是构造的和弦,按这个顺序......
  • 我可以创建一个用户输入的元组吗?有趣...而且我的阵列的设置方式与钢琴上的键对齐方式相同。所以,0-3-7(小调)和 3-7-10.(Cmajor)。
  • 哎呀,是的,不知道我做了什么,我的计数搞砸了。但通常你从 c 为 0 开始,不是吗?但这没关系。关于解析输入:我认为这就是我会做的。无论如何,您都需要清理输入,不是吗?如果用户输入 C of c 怎么办?或者 fb 代表 e 或 gb 代表 dM 和弦?或 ab 而不是 ba (就像它写在工作人员上一样)。那是我想要消毒的东西。稍后你会想要添加更多的键和 M7 之类的东西,如果你解析输入会更容易,不是吗?
  • 顺便说一句。输入卫生的一个建议是:使用 std::map
  • 酷,我目前正在做的是在收到输入时将其小写,因此它将匹配我数组中的所有内容。但你是对的,我需要对其他物品进行更多消毒。我也一定会检查 std::map 。感谢您的帮助先生!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 1970-01-01
  • 1970-01-01
  • 2019-10-11
  • 2015-06-01
  • 1970-01-01
相关资源
最近更新 更多