2

我正在编写一个 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 以将其变为“第三”,并将其值更改为“第三”。但是如果它以root开始并进行两次跳转,我需要加4,加3,然后将其值更改为“第五”。

4

1 回答 1

1

TL;博士;

嗯..你可以用数学来做。更重要的是,通过您提供的限制,实际上可以使用一个功能来完成。二次函数。

它是如何完成的

您需要做的就是以某种方式创建一个数学函数,它将您的反转作为参数,并通过给定的“函数”返回某个位置(如何在 PHP 函数中调用它)。由于“反转”具有三个值,因此可以使用二次函数来完成此操作:

f(x) = ax 2 + bx + c

在这里,您需要通过给定的值(对于您的情况)和函数值(每个“反转”块中的“位置”值)来查找系数ab和。cx$inversionif

但是,每个“函数”(位于foreach块内部)都有四个不同的位置开关 - 这就是为什么实际上,您必须处理四个二次函数。

现在,关于路口。我不确定它在逻辑意义上是什么,但是,当然,依赖性是显而易见的:给定所有可能结点的数组,某些“函数”的值只是位置“当前”+“反转”的结点。所以,如果我们有 junctions array ['r', '3', '5', '7'],那么,如果 inversion is1并且 current is 3,那么 result 就是5。如果反转是2,那么结果将是7e tc

和代码

开始了:

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,23(原始反演值)转置为-1,0和- 这样计算我们的,和1就容易多了。abc

$pos包含每个“函数”(即$f循环内)的二次函数的系数数组。由于解析线性方程组,它们都是“半整数”(所以,有一个观点W/2,所以分数的分母是2)。这就是为什么我刚刚将它们全部相乘2并除以 2 来计算位置。

测试

我已经对你的函数和这个新的“数学”模拟进行了测试 - 取得了成功的结果,这些结果当然是反演为123,例如:

//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

于 2014-06-24T10:37:55.140 回答