2016-06-06 35 views
5

Mi chiedevo come si creerebbe una funzione, in PHP, che viene utilizzata per trasporre alcuni accordi musicali.Come trasporre accordi musicali con PHP?

Proverò a spiegare come funziona nella teoria musicale. Spero di non dimenticare qualcosa. Se ci sono degli errori, per favore aiutami a correggerlo.


1. I semplici accordi.

I semplici accordi sono quasi semplice come un alfabeto e va in questo modo:

C, C#, D, D #, E, F, F #, G, G #, A, A # B

Da B torna di nuovo a C. Pertanto, se l'accordo originale è E e vogliamo trasporre +1, l'accordo risultante è F. Se trasponiamo +4, l'accordo risultante è G#.

2. Accordi espansi.

Funzionano quasi come gli accordi semplici, ma contengono alcuni caratteri in più, che possono essere ignorati durante la trasposizione. Per esempio:

Cmi, C# 7, Dsus7, Emi, Fsus4, F # mi, G ...

Così ancora una volta, come per i semplici accordi, se trasponiamo Dsus7 + 3 = Fsus7

3. Tono basso non root.

Un problema si presenta quando il basso suona un tono diverso rispetto al tono della radice dell'accordo. Questo è contrassegnato da una barra dopo l'accordo e deve anche essere trasposto. Esempi:

C/G, Dmi/A, F # sus7/A #

Come esempi 1 e 2, tutto è lo stesso, ma la parte dopo le esigenze di barra trasposizione troppo pertanto :

C/G + 5 = F/C

F#sus7/A# + 1 = Gsus7/B


Quindi, in pratica, immagina di avere una variabile PHP chiamata chord e il valore di trasposizione transpose. Quale codice trasponerebbe l'accordo?

Esempi:

var chord = 'F#sus7/C#'; 
var transpose = 3; // remember this value also may be negative, like "-4" 
... code here ... 
var result; // expected result = 'Asus7/E'; 

ho trovato una domanda esistita sulla StackOverflow, at here. Parlano di algoritmo per progressioni di accordi.


Come faccio trasposizione accordi musicali con PHP, aumentando o diminuendo per semitoni?

+1

Benvenuti in SO. Leggete [Quali argomenti posso chiedere] (http://stackoverflow.com/help/on-topic) e [Come fare una buona domanda] (http://stackoverflow.com/help/how-to -ask) E [la domanda perfetta] (http://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/) SO è ** non una codifica libera o conversione di codice o tutorial o servizio di ricerca della biblioteca ** Devi anche dimostrare di aver fatto qualche sforzo per risolvere il tuo problema. – RiggsFolly

+0

@lvk Leggi i collegamenti nel mio primo commento! – RiggsFolly

+1

Sembra che tu abbia un problema, ma non hai nemmeno provato a capire una soluzione. Hai già provato a scrivere una funzione? Non farai in modo che le persone scrivano il codice per te qui, non è così che funziona. Aiutiamo a sistemare cose che non funzionano ma non sei partito. Sembra che sia necessario creare un array associativo come 'array ('C', 'C#')' etc e quindi è possibile iniziare a confrontare gli indici dell'array per ottenere il valore desiderato. – Jimbo

risposta

0

Ok, quindi ci sono alcune cose che vuoi gestire.

In primo luogo, si desidera essere in grado di aggirare l'array. È semplice: usa l'operatore modulus, che in php è %.

function transpose($chord, $increment) { 
    $map = array('A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#'); 

    // Get the index of the given chord 
    $index = array_search($chord, $map); 
    if($index === false) 
    return false; 

    // Get the transposed index and chord 
    $transpose_index = ($index + $increment) % count($map); 
    if($transpose_index < 0) 
    $transpose_index += count($map); 
    return $map[$transpose_index]; 
} 

In secondo luogo, si desidera essere in grado di rimuovere gli accordi reali che sono importanti per voi. È possibile farlo utilizzando un regular expression (RegEx):

function transposeFull($chords, $increment) { 

    // This RegEx looks for one character (optionally followed by a sharp). 
    //  .\#? 
    // This RegEx looks for an optional series of characters which are not/
    //  [^\/]* 
    // Put them together to get a RegEx that looks for an expanded chord 
    //  (.\#?)([^\/]*) 
    // Then, do it again, but add a/first, and make it optional. 
    //  (\/(.\#?)([^\/]*))? 
    $regex = '%(.\#?)([^\/]*)(\/(.\#?)([^\/]*))?%'; 

    // Note that the() allow us to pull out the matches. 
    // $matches[0] is always the full thing. 
    // $matches[i] is the ith match 
    // (so $matches[3] is the whole optional second chord; which is not useful) 
    $matches = array(); 
    preg_match($regex, $chords, $matches); 

    // Then, we get any parts that were matched and transpose them. 
    $chord1 = (count($matches) >= 2) ? transpose($matches[1], $increment) : false; 
    $expanded1 = (count($matches) >= 2) ? $matches[2] : ''; 
    $chord2 = (count($matches) >= 5) ? transpose($matches[4], $increment) : false; 
    $expanded2 = (count($matches) >= 6) ? $matches[5] : ''; 

    // Finally, put it back together. 
    $chords = ''; 
    if($chord1 !== false) 
    $chords .= $chord1.$expanded1; 
    if($chord2 !== false) 
    $chords .= '/'.$chord2.$expanded2; 

    return $chords; 
} 
1

Una soluzione rapida:

<?php 

// produces the expected result 
echo transpose("F#sus7/C#",3); 

function transpose($chord,$transpose) 
{ 
    // the chords 
    $chords = array("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"); 

    $result = ""; 

    // get root tone 
    $root_arr = explode("/",$chord); 
    $root = strtoupper($root_arr[0]); 

    // the chord is the first character and a # if there is one 
    $root = $root[0].((strpos($root, "#") !== false)?"#":""); 

    // get any extra info 
    $root_extra_info = str_replace("#","",substr($root_arr[0],1)); // assuming that extra info does not have any # 

    // find the index on chords array 
    $root_index = array_search($root,$chords); 
    // transpose the values and modulo by 12 so we always point to existing indexes in our array 
    $root_transpose_index = floor(($root_index + $transpose) % 12); 

    if ($root_transpose_index < 0) 
    { 
     $root_transpose_index += 12; 
    } 

    $result.= $chords[$root_transpose_index].$root_extra_info; 

    if(count($root_arr)>1) 
    { 
     // get the non root tone 
     $non_root = $root_arr[1]; 
     // the chord is the first character and a # if there is one 
     $non_root = strtoupper($non_root[0]).((strpos($non_root, "#") !== false)?"#":""); 
     // get any extra info 
     $non_root_extra_info = str_replace("#","",substr($root_arr[1],1)); // assuming that extra info does not have any # 

     // find the index on chords array 
     $non_root_index = array_search($non_root,$chords); 
     // transpose the values and modulo by 12 so we always point to existing indexes in our array 
     $non_root_transpose_index = floor(($non_root_index + $transpose) % 12); 

     if ($non_root_transpose_index < 0) 
     { 
      $non_root_transpose_index += 12; 
     } 

     $result.= "/".$chords[$non_root_transpose_index].$non_root_extra_info; 
    } 

    return $result; 
} 

https://3v4l.org/Cd9Pg

un sacco di spazio per ulteriori miglioramenti nel codice, ho solo cercato di codice che sia facile da capire .

+0

È possibile evitare alcune ripetizioni di codice se si gestiscono le parti di 'split' in una funzione. Penso che combinando la tua idea in split su '/' con my '(. \ #?) ([^ \ /] *)' RegEx otterresti il ​​codice più pulito. – Kittsil

+0

@Kittsil sì, c'è molto spazio per migliorare. sfortunatamente, sono al lavoro, quindi non ho più tempo per lavorare su questo - l'ho fatto nella mia pausa pranzo:/almeno è facile da capire: D – Sharky

1

Qui la mia idea di regex con preg_replace_callback (l'uso di anonymous function richiede PHP 5.3).

function transpose($str, $t=0) 
{ 
    // the chords 
    $chords = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]; 

    // set transpose, return if none 
    $t = (int)$t % 12 + 12; if($t % 12 == 0) return $str; 

    // regex with callback 
    return preg_replace_callback('~[A-G]#?~', function($m) use (&$chords, &$t) { 
    return $chords[(array_search($m[0], $chords) + $t) % 12]; 
    }, $str); 
} 

Demo at eval.in   (per testare la regex pattern [A-G]#? see regex101)

echo transpose("Cmi, C#7, Dsus7, Emi, Fsus4, F#mi, G C/G, Dmi/A, F#sus7/A#", -3); 

Ami, A # 7, Bsus7, C# mi, Dsus4, D # mi, EA/E, Bmi/F #, D # sus7/G

+1

Bello! Potresti semplificare la normalizzazione di '$ t' con' $ t = (int) $ t% 12 + 12; '. – trincot

+0

@trincot grazie (: testerò il tuo miglioramento e aggiungerò alla risposta. –

+0

@trincot [che ne dici?] (Https://eval.in/587175) –