#php #math #chord-diagram #guitar
#php #математика #диаграмма аккордов #гитара
Вопрос:
Я пишу PHP-приложение, которое представляет шесть струн гитары в виде ряда диапазонов. Таким образом, я могу добавлять или вычитать к набору чисел, чтобы систематически изменять архетипическую структуру, которую я определяю.
Диапазоны:
//E: 1-15, A: 26-40, D: 51-65, G: 76-90, b: 101-115, e: 126-140
У меня возникли проблемы с приведенным ниже кодом.
Функция
//the key of the key value pair represents its position on the guitar, and the value
//represents a theoretical function. If the inversion is "0", do nothing. If the
//inversion is "1", all notes that have the value of "r" should have their key
//incremented by 4 and their value changed to '3'.
//example: 1=>"r",28=>"5",52=>"7",77=>"3"
function invChange($pattern, $inversion) {
if ($inversion == 1) {
foreach ($pattern as $position => $function) {
if ($function == 'r' ) { $position = 4; $junction = '3'; }
if ($function == '3' ) { $position = 3; $junction = '5'; }
if ($function == '5' ) { $position = 4; $junction = '7'; }
if ($function == '7' ) { $position = 1; $junction = 'r'; }
$modScale[$position] = $junction;
}
}
if ($inversion == 2) {
foreach ($pattern as $position => $function) {
if ($function == 'r' ) { $position = 7; $junction = '5';}
if ($function == '3' ) { $position = 7; $junction = '7';}
if ($function == '5' ) { $position = 5; $junction = 'r';}
if ($function == '7' ) { $position = 5; $junction = '3';}
$modScale[$position] = $junction;
}
}
if ($inversion == 3) {
foreach ($pattern as $position => $function) {
if ($function == 'r' ) { $position = 11; $junction = '7';}
if ($function == '3' ) { $position = 8; $junction = 'r';}
if ($function == '5' ) { $position = 9; $junction = '3';}
if ($function == '7' ) { $position = 8; $junction = '5';}
$modScale[$position] = $junction;
}
}
return $modScale;
}
Как вы можете видеть, это довольно часто повторяется. Просто глядя на этот код, я думаю, что должен быть лучший способ. Я думаю, что мне нужно использовать массив бесконечным линейным способом:
array("root" => 4, "third" => 3, "fifth" => 4, "seventh" => 1);
Теперь мне нужно взять любую из предопределенных пар $ note => $offset и перепрыгнуть их через этот массив на 1, 2 или 3 перехода. Например, если он начинается как корень и совершает один скачок, мне нужно добавить 4, чтобы превратить его в «третий», и изменить его значение на «третий». Но если он начинается как корень и совершает два перехода, мне нужно добавить 4, добавить 3, а затем изменить его значение на «пятое».
Ответ №1:
TL; DR;
Хорошо.. вы можете сделать это с помощью математики. Более того, с учетом предоставленных вами ограничений, это можно сделать фактически с помощью одной функции. Квадратичная функция.
Как это делается
Все, что вам нужно сделать — это каким-то образом создать математическую функцию, которая примет вашу инверсию в качестве аргумента и вернет определенную позицию с помощью заданной «функции» (как она вызывается внутри вашей функции PHP). Поскольку у вас есть три значения для «инверсии», вы можете сделать это с помощью квадратичной функции:
f(x) = ax2 bx c
здесь вам нужно будет найти коэффициенты a
, b
, и c
по заданным x
значениям ( $inversion
для вашего случая) и значениям функций (значения для «позиции» в каждом из ваших блоков «инверсии» if
).
Однако у вас есть четыре разных переключателя положения для каждой вашей «функции» (это внутренний foreach
блок) — вот почему, на самом деле, вам придется иметь дело с четырьмя квадратичными функциями.
Теперь о соединениях. Я не уверен, что это такое в логическом смысле, но, безусловно, зависимость очевидна: учитывая массив всех возможных соединений, значение для определенной «функции» — это просто соединение в позиции «current» «inversion». Итак, если у нас есть массив соединений ['r', '3', '5', '7']
, то, если инверсия 1
и ток 3
, то результат будет 5
. Если инверсия есть 2
, то результатом будет 7
e t.c.
И код
Поехали:
function invChangeN($pattern, $inversion)
{
$junc = ['r', '3', '5', '7'];
$pos = [
'r' => [ 1, 7, 14],
'3' => [-3, 5, 14],
'5' => [ 3, 5, 10],
'7' => [-1, 7, 10]
];
$inversion -= 2;
$modScale = [];
foreach ($pattern as $p => $f)
{
$p = ($pos[$f][0]*pow($inversion,2) $pos[$f][1]*$inversion $pos[$f][2])/2;
$j = $junc[(array_search($f, $junc) $inversion 2)%count($junc)];
$modScale[$p] = $j;
}
return $modScale;
}
Немного о том, почему мы делаем $inversion -= 2
. Речь идет о том, чтобы перенести три точки из 1
, 2
и 3
(исходные значения инверсии) в -1
, 0
и 1
— с этим намного проще вычислить наши a
, b
и c
.
$pos
содержит массивы коэффициентов для квадратичной функции для каждой «функции» (то есть $f
внутреннего цикла). Из-за решения системы линейных уравнений все они являются «полуцелыми числами» (итак, имейте в виду W/2
, что знаменатель дроби равен 2
). Вот почему я просто умножил их все на 2
и добавил деление на 2 для вычисления позиции.
Тесты
Я провел тесты вашей функции и этого нового «математического» аналога — с успешными результатами, которые, конечно, для инверсии как 1
, 2
и 3
, как:
//derived from old function:
array(4) {
[8]=>
string(1) "5"
[33]=>
string(1) "r"
[57]=>
string(1) "3"
[84]=>
string(1) "7"
}
//derived from new function:
array(4) {
[8]=>
string(1) "5"
[33]=>
string(1) "r"
[57]=>
string(1) "3"
[84]=>
string(1) "7"
}
Приведенные выше результаты относятся к шаблону [1=>"r",28=>"5",52=>"7",77=>"3"]
и инверсии 2
Комментарии:
1. Прочитав только первый абзац, я просто знал, что это ты 😉
2. @Jack кто еще мог бы вычислить эти коэффициенты четыре раза, чтобы получить четыре функции? : p
3. Ну, ваш код абсолютно работает, как есть, в этом нет сомнений. Снимаю перед вами шляпу. Я надеялся, что ответ будет на один шаг выше моего уровня понимания, но я думаю, что это несколько больше. 😉 Я просматриваю это постепенно, пытаясь понять это. Моя следующая цель — добавить проверку, чтобы проверить, является ли ($ pos [$ f] [0] * pow($ inversion,2) $ pos [$ f][1] * $inversion $ pos [$ f] [2])/ 2 $newthirdarguement > 12, что должно помочь мне решить, следует ли мне вычитать 12 из P или нет. Спасибо за отличный ответ.
4. Я хотел добавить дополнительный вопрос, особенно на случай, если кто-то еще найдет это, потому что это было бы полезно всем, кто программирует аккорды. В некоторых случаях в наборе есть только 1, 3 и 5, и поэтому каждый из них должен пропустить через 7. Чтобы пропустить 7, значение будет увеличено на 1. Будет ли это незначительным изменением коэффициентов, рассчитанных выше, или серьезным изменением?
5. Не уверен. Что такое «1, 3 и 5»? У нас есть «r», «3», «5» и «7» (если вы о них). Итак, вы говорите о том, что входной шаблон $ может состоять из трех элементов — и не будет «7», а также «1» вместо «r»?