Generazione di tablature per chitarra?


24

Scrivi il programma più breve che genera le tablature per chitarra per gli accordi dati come input.

In modo che i chitarristi tra di voi non abbiano un vantaggio e per renderlo deterministico (e probabilmente più facile da codificare), ecco le uniche forme di accordi autorizzati:

Major chords:

  E   F   F#  G   G#  A   A#  B   C   C#  D   D#
e 0---1---2---3---4---0---1---2---3---4---5---6---
B 0---1---2---3---4---2---3---4---5---6---7---8---
G 1---2---3---4---5---2---3---4---5---6---7---8---
D 2---3---4---5---6---2---3---4---5---6---7---8---
A 2---3---4---5---6---0---1---2---3---4---5---6---
E 0---1---2---3---4---0---1---2---3---4---5---6---

Minor chords:

  Em  Fm  F#m Gm  G#m Am  A#m Bm  Cm  C#m Dm  D#m
e 0---1---2---3---4---0---1---2---3---4---5---6---
B 0---1---2---3---4---1---2---3---4---5---6---7---
G 0---1---2---3---4---2---3---4---5---6---7---8---
D 2---3---4---5---6---2---3---4---5---6---7---8---
A 2---3---4---5---6---0---1---2---3---4---5---6---
E 0---1---2---3---4---0---1---2---3---4---5---6---

Notare che i primi 5 accordi e gli ultimi 7 accordi di ciascuna serie hanno forme diverse.

Tutti gli accordi sono semplici accordi maggiori o minori (non 7 o altre variazioni).

Dovresti occuparti anche degli appartamenti. Promemoria:

A# = Bb
C# = Db
D# = Eb
F# = Gb
G# = Ab

B#, Cb, E# and Fb are not used

L'output deve includere la prima colonna con i nomi dei cavi, come mostrato sopra. Essa non deve includere il nome dell'accordo sulla parte superiore. Gli accordi devono essere separati da 3 -come mostrato sopra. I 3 finali -sono opzionali.

L'input è una stringa composta da nomi di accordi, separati da spazi.

Un esempio di input è:

Bm Gb A E G D Em F#

e l'output corrispondente è:

e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

... e domanda secondaria: qual è la canzone di esempio? :)
Jules Olléon il

5
Hotel California: P
Matthew Leggi il

Sì, hai vinto! :)
Jules Olléon il

Bella idea. Vorrei avere il tempo di giocare!
Igby Largeman,

Risposte:


9

JavaScript, 297 277 262 235 223 caratteri

I ritorni a capo nella versione golfata non sono significativi; sono lì solo per rendere leggibile la risposta. I punti e virgola sono significativi.

Modifica: ha sostituito l'esterno mapcon un ciclo while e altre modifiche. Finalmente all'interno di 2 × le dimensioni della versione Golfscript (per ora)!

Modifica: sostituito indexOfcon matematica, abbattuto la tabella di ricerca, altri piccoli miglioramenti.

Modifica: un altro mapper fore messo in un finale \nche avevo mangiato inutilmente. Finalmente all'interno della versione Python di Jules.

i=prompt(o='').split(' ');for(r=6;o+=' EADGBe'[r]+' ',r--;o+='\n')
for(j=0;n=i[j++];o+=(([84,13,52,5][2*/m/.test(n)+x]*8>>2*r&3)+y-7*x)+'---')
y=n.charCodeAt(0),y=(2*y-(y>66)-(y>69)+(n[1]<'$')-(n[1]=='b')+2)%12,x=y>6;alert(o)

L'output non sfrutta più il fatto che il trailing ---sia facoltativo in quanto:

e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

Accidenti, ho javascript peen-envy penso. Ben fatto.
kekekela,

7

Golfscript, 136 caratteri

[["eBGDAE"{[]+" "+}/]]\" "/{.-2\{"bm#A B C D E F G"?.)!!*(+}/14%.3>-.8>-.7/@109?0>2*+[963 780 882 753]{3base(;}%=\7%{+'---'+}+%}%+zip n*

Completamente 23 caratteri (17,5%) si occupano di questi due caratteri all'inizio di ogni riga di output.

Esempio di output, test dei casi limite:

$ golfscript.rb tabs.gs <<<"E G# Ab A Db D# Em G#m Abm Am D#m"
e 0---4---4---0---4---6---0---4---4---0---5---
B 0---4---4---2---6---8---0---4---4---1---6---
G 1---5---5---2---6---8---0---4---4---2---7---
D 2---6---6---2---6---8---2---6---6---2---7---
A 2---6---6---0---4---6---2---6---6---0---5---
E 0---4---4---0---4---6---0---4---4---0---5---

Ho trascorso solo un'ora su questo, quindi probabilmente può essere ridotto da 5 a 10 caratteri almeno. Concettualmente risulta essere abbastanza simile alla soluzione di DocMax: tabella di ricerca per quattro casi, quindi incrementare di un offset e unire le stringhe nell'ordine giusto.


+1: Man I love Golfscript! Più volte oggi ho trovato posti per tagliare il mio codice, ma non del 50%! Non ho un interprete a portata di mano: restituisce D # per Eb?
DocMax,

A proposito, l'ultima nota nel tuo campione corrisponde a C # m sebbene la riga di comando mostri D # m. Errore di battitura o bug?
DocMax,

@DocMax, bug. Non capisco perché influisce solo su D # me non su D # - sarà interessante eseguire il debug. Riordino le cose perché è conveniente avere prima il blocco di 7, quindi Eb non è davvero un caso limite.
Peter Taylor,

Si scopre che l'ultimo stava ottenendo un \ n incluso, che non trovandosi nella tabella di ricerca stava abbassando il valore dell'equivalente di una lettera.
Peter Taylor,

4

Dopo averlo codificato, mi sono reso conto che avrei potuto farlo in modo molto più intelligente ... forse farò un'altra voce. Spero di ottenere punti per essere il più veloce!

Comunque, ci sono 962 personaggi di Perl.

%c =(B=>{E=>0,F=>1,Gb=>2,G=>3,Ab=>4,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>0,Am=>1,Bbm=>2,Bm=>3,Cm=>4,Dbm=>5,Dm=>6,Ebm=>7},G=>{E=>1,F=>2,Gb=>3,G=>4,Ab=>5,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>4,Am=>2,Bbm=>3,Bm=>4,Cm=>5,Dbm=>6,Dm=>7,Ebm=>8},D=>{E=>2,F=>3,Gb=>4,G=>5,Ab=>6,A=>2,Bb=>3,B=>4,C=>5,Db=>6,D=>7,Eb=>8,Em=>2,Fm=>3,Gbm=>4,Gm=>5,Abm=>6,Am=>2,Bbm=>3,Bm=>4,Cm=>5,Dbm=>6,Dm=>7,Ebm=>8},A=>{E=>2,F=>3,Gb=>4,G=>5,Ab=>6,A=>0,Bb=>1,B=>2,C=>3,Db=>4,D=>5,Eb=>6,Em=>2,Fm=>3,Gbm=>4,Gm=>5,Abm=>6,Am=>0,Bbm=>1,Bm=>2,Cm=>3,Dbm=>4,Dm=>5,Ebm=>6},E=>{E=>0,F=>1,Gb=>2,G=>3,Ab=>4,A=>0,Bb=>1,B=>2,C=>3,Db=>4,D=>5,Eb=>6,Em=>0,Fm=>1,Gbm=>2,Gm=>3,Abm=>4,Am=>0,Bbm=>1,Bm=>2,Cm=>3,Dbm=>4,Dm=>5,Ebm=>6});
%b=('A#'=>'Bb','C#'=>'Db','D#'=>'Eb','F#'=>'Gb','G#'=>'Ab');
foreach(qw(e B G D A E)){p($_,@ARGV)}
sub p{$s = shift;print "$s ";$s = uc($s);foreach(@_){while(($h,$f)=each(%b)){s/$h/$f/}print "$c{$s}->{$_}---"}print "\n"}

Ecco l'output corrispondente.

dhrasmus:Desktop standage$ perl guitar Bm Gb A E G D Em F#
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

4

Poiché sono già state fornite soluzioni più brevi (maledetto GolfScript!), Ecco la mia:

Python, 229 caratteri

s=[("E EmF FmF#GbG GmG#AbA AmA#BbB BmC CmC#DbD DmD#Eb".find("%-02s"%s[:2])/4,s[-1]!='m')for s in raw_input().split()]
for c in range(6):
 l='eBGDAE'[c]+' '
 for(i,M)in s:x=i>4;l+=`i-5*x+2*(2<c+x<5)+(M+x)*(c==2-x)`+"---"
 print l

Produzione:

> echo "Bm Gb A E G D Em F#" | python guitar.py
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

3

Python, 449 caratteri

z=int
f=str
r=range
j=''.join
n='E F F# G G# A A# B C C# D D#'.split()
n+=[x+'m'for x in n]
c=[j([f(z(x)+i)for x in'001220'])for i in r(5)]+[j([f(z(x)+i)for x in'022200'])for i in r(7)]
c+=[x[:2]+f(z(x[2])-1)+x[3:]for x in c[:5]]+[x[0]+f(z(x[1])-1)+x[2:]for x in c[5:]]
a=[c[n.index((chr(ord(i[0])-1)+'#'+i[2:]).replace('@','G')if len(i)-1 and i[1]=='b'else i)]for i in raw_input().split()] 
for i in r(6):print'eBGDAE'[i],j([x[i]+'-'*3 for x in a])

3

C99 - 231 caratteri

Gli accordi vengono forniti sulla riga di comando, un argomento per accordo e, naturalmente, non esiste alcuna convalida di input di alcun tipo.

#include<stdio.h>
int main(int c,char**v){for(char*o="e0)B2)G2*D2+A0+E0)",i,m;*o;o+=3,v-=c,puts(""))for(printf("%c ",*o);*++v;printf("%c---",i-(i>2)-i/9+o[1+i/8]-(*o-66-i/8*5?0:m?m+2[*v]>99:0)))m=1[*v],i=(**v*2-4+m/35-m/98*3)%14;}

Esecuzione di esempio:

$ ./a.out Bm Gb A E G D Em F#
e 2---2---0---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---

Un-golfed

#include<stdio.h>
int main(int c,char**v){
     // o points to three characters per output line:
     //   string name, number for A, adjusted number for E (ASCII code minus 7)
     char* o="e0)B2)G2*D2+A0+E0)",
          i, // chord: A=0, A#=1, ..., G#=13, allowing also 3="E#" and 9="B#"
          m; // second character in chord name
     for (; *o; o+=3) {
          printf("%c ", *o);
          for (; *++v; ) {
               m = 1[*v],
               i = (**v*2-4+m/35-m/98*3)%14; // parse & adjust for sharp, flat
               printf("%c---",
                      i-(i>2)-i/9 // eliminate "E#", "B#"
                      +o[1+i/8] // get the number for a major chord
                      // adjust for minor...
                      -(*o-66-i/8*5
                        ? 0
                        : m ? m+2[*v]>99 : 0));
          }
          v -= c; // rewind argument pointer
          puts("");
     }
}

C non standard - 206 caratteri

Se non ci interessiamo delle specifiche del linguaggio, GCC può compilare il seguente one-liner in un binario funzionale, anche se combina dichiarazioni di variabili C99 con una dichiarazione di argomento in stile K&R (e una dichiarazione implicita di printf).

main(c,v)char**v;{for(char*o="e0)B2)G2*D2+A0+E0)",i,m;*o;o+=3,v-=c,puts(""))for(printf("%c ",*o);*++v;printf("%c---",i-(i>2)-i/9+o[1+i/8]-(*o-66-i/8*5?0:m?m+2[*v]>99:0)))m=1[*v],i=(**v*2-4+m/35-m/98*3)%14;}

2

C ++, 432

#include <cmath>
#include <iostream>
F(int c){c-=65;return c*1.6+sin(c/5.+.3);}
T(int a,int s){if(s)return(a=(T(a,s-1)+2)%3)-=(a==1&s>2);return(a<7)*2;}
#define c(a,b) while(*(++j)==a)b;--j; 
#define O std::cout<<
main(int a,char*p[]){
int P=2;for(int i=-1;++i<6;P=2){O p[1][i];O" ";while(P<a){char*j=p[P++];
int f=F(*j);c('#',++f)c('b',--f)
int t=T(f,i)*3.5;if(*(++j)!='m'){--j;t+=(t==3);}
O(f-F(p[1][i])+t+24)%12;O"---";
}O'\n';}}

Si noti che ciò richiede l'accordatura della chitarra come primo parametro. (La maggior parte delle accordature non standard ti darà risultati ridicoli con le dita, ma immagino che tu sia contento della sintonizzazione standard.)

Per l'Hotel California, puoi farlo $./a.out EBGDAE Cbm Gb Bbb Fb G D Em F# Bm F# G## D## F## C## D##m E##. Risultato:

E 2---2---0---0---3---5---0---2---2---2---5---0---3---5---0---2---
B 3---2---2---0---3---7---0---2---3---2---5---0---3---7---0---2---
G 4---3---2---1---4---7---0---3---4---3---6---1---4---7---0---3---
D 4---4---2---2---5---7---2---4---4---4---7---2---5---7---2---4---
A 2---4---0---2---5---5---2---4---2---4---7---2---5---5---2---4---
E 2---2---0---0---3---5---0---2---2---2---5---0---3---5---0---2---

Sintonizzare le quattro corde superiori su terzi minori rende molto facile suonare accordi a tre e quattro corde in molte inversioni, senza stringhe aperte e senza dover posizionare un dito "sopra" una corda senza toccarla. Usando le stringhe DFG # B, una sequenza di accordi come "Bbm F Bbm Gb Db Ebm Db F Bbm F F7 Bbm" (Mermaid Song) funziona molto facilmente. È solo necessario spostarsi su e giù di un tasto. C'è un cambio di chiave di mezzo passo, ma ciò significa solo salire di un tasto. Tuttavia, non ho capito cosa fare meglio con le altre due corde.
supercat,

@supercat: interessante, lo proverò sulla mia chitarra domani ...
smesso di girare in senso antiorario il

Mi piacerebbe sentire cosa ne pensi. Avevo preso una chitarra alcune volte, a distanza di anni, e avevo continuato a rinunciare perché le dita mi sembravano sia arbitrarie che scomode. Poi ho pensato a quali accordature avrebbero permesso la semplice diteggiatura. Poiché gli accordi a forma chiusa hanno intervalli che vanno da un terzo minore a un quarto perfetto, accordando le stringhe ai terzi minori significa che ogni stringa verrà smorzata in un punto che non è inferiore alla stringa sottostante. Se posso provare una chitarra per mancini, potrei provare i quarti perfetti con l'ordine delle corde invertito, poiché dovrebbe essere simile.
supercat,

Così com'è, l'accordatura ai terzi minori significa che per ciascuna posizione del primo dito sulla corda più bassa, saranno disponibili tre inversioni di accordi principali e tre inversioni di accordi minori. Si può anche suonare un settimo accordo posizionando il secondo dito sulle prime tre corde. Per Mermaid Song, inizia dal terzo tasto e suona F-Bb-DF (con le dita 1-3-3-4). Quindi F è FACF (1-2-2-4). Gb è su un tasto, dita 1-2-2-4 (come F). Db è tornato indietro di un tasto, 1-3-4-4. Ebm esegue il backup, 1-2-4-4.
supercat,

Mi ci sono volute solo poche ore per arrivare al punto in cui avrei potuto facilmente suonare alcuni brani (tra cui il già citato Mermaid Song) dopo aver lavorato con l'aiuto di una tastiera quali dovrebbero essere le note dell'accordo. Una volta provato questo stile, mi è sembrato incredibilmente naturale e mi piace molto il modo in cui si possono usare tutte e tre le inversioni di ciascun accordo maggiore e minore. Se si volessero semplicemente accordi maggiori e minori, un'accordatura come F-Ab-B-Eb-Gb-D potrebbe teoricamente consentire accordi maggiori e minori a sei dita con facili fingerings (1-2-2-3-4-4 o 1 -1-2-3-3-4) ma senza inversioni.
supercat,

2

390 345 340 Postscript

Semplificato con un approccio pragmatico per chitarra (la forma E è solo una variazione della forma A, spostata verso il basso di una corda, con un cambio di dito). Ho preso in prestito l'idea della stringa codificata dalle altre risposte.

[/p{print}/x{exch}/e{cvx exec}/d{dup 0
get}/f{forall}(A0#1B2C3D5E7F8G:b;){}forall/m{dup
4 2 copy get 1 sub put}109{m 48}/+{[3 1 roll x{1
index add x}f]}/*{[0 0 2 2 2 0 0]x{load e 48 sub
+}f d 12 gt{-12 +}if d 6 gt{m -7 + 1}{0}ifelse 6
getinterval}>>begin[ARGUMENTS{*}f][(E)(A)(D)(G)(B)(e)]6{[x
e p( )p]x[x{[x e( )cvs p(---)p]}f]x()=}repeat

In precedenza:

450 442 418 Postscript

Ho risolto il formato di output anche con questo. (Le versioni precedenti hanno iniziato con "E ---" anziché "e".)

<</i{index}/a{add}/p{pop}/x{exch}/g{getinterval}/r{print}/f{forall}/e{exec}>>begin<<65[0
2 3 5 -5 -4 -2]{1 i 1 a}f p 35{1 a}98{1 sub}109{x dup
4 20 put x}>>begin[ARGUMENTS{[x[0 5 12 17 21 24 29
0]x{load e}f x{1 i a x}f]dup 0 get 0 ge{0}{1}ifelse 7
g[0 -5 -10 -15 -19 -24 -29]0 1 6{2 copy get 3 i 2 i
get a 3 copy put p p}for x p 0 6
g}f][(E)(A)(D)(G)(B)(e)]6{[x cvx e r( )r]x[x{[x cvx
e( )cvs r(---)r]}f]x(\n)r}repeat

Come eseguirlo: gsnd -q -- tab.ps Bm Gb A E G D Em F\#(nascondi il sharp dalla shell).

La versione senza golf era quasi più difficile di quella con il golf. Ma ho cercato di essere accurato. Modifica: qualche altro commento sui trucchi.

%!PS
<<    %axioms and operations
/t{2 2 1}    %major tetrachord
/m{t t 2}    %mixolydian mode
/u{2 1 2}    %minor tetrachord
/a{u u}      %aolian mode
/s{m m t}    %2.5-octave mixolydian intervals
/r{3 1 roll}
/${[exch 0 exch{1 index add}forall]}    %running sum: convert (relative)intervals to (abstract)fretstops
/+{[r exch{1 index add exch}forall pop]}    %scale array by scalar
/@{[r{2 copy get r pop}forall pop]}    %select array elements from array of indices
/&{0 1 3 index length 1 sub{    %array2 += array1
    2 copy get 3 index 2 index get add 3 copy put pop pop}for exch pop}
>>begin<<    %map ascii values to scaling functions
65[a]$    %generate fretstops of the A aolian scale to assign scalars to note names
[0 0 0 0 -12 -12 -12]&    %drop E F and G down an octave
{[exch/+ cvx]cvx 1 index 1 add}forall pop    %generate the pairs 'A'->{0 +}, 'B'->{2 +}
35{1 +}     %'#'-> scale up by one
98{-1 +}    %'b'-> scale down by one
109{dup 4 2 copy get 1 sub put}     %'m'-> tweak the 'third' down by one
%generate chord pattern from (string)
/*{[s]$       %generate fretstops of the E mixolydian scale
  [1 4 8 11 13 15 18]    %A-shape figured bass: IV chord of E mixolydian
  -1 +       %convert scale degrees to array indices
  @       %generate chord template by selecting indices from mixolydian scale
  exch{load exec}forall       %execute ascii values, scaling the pattern
  dup 0 get 0 ge{0}{1}ifelse 6 getinterval    %discard first note if it has fallen off the bottom
  [0 -5 -10 -15 -19 -24]&}    %subtract the string offsets
>>begin    %activate definitions
%(A)* pstack()= clear    %[0 0 2 2 2 0]
%(B)* pstack()= clear    %[2 2 4 4 4 2]
%(F#)* pstack()= clear    %[2 4 4 3 2 2]
%(Abm)* pstack()=    %[4 6 6 4 4 4]
[ARGUMENTS{*}forall]    %convert array of strings to array of patterns
[(E)(A)(D)(G)(B)(e)]    %array of string names
6{    %for each "string"
    [exch cvx exec print( )print]    %pop string name and print with space
    exch       %put names behind numbers
    [exch{     %for each "chord"
        [exch cvx exec( )cvs print(---)print]    %pop number, convert, print with trailing hyphens
    }forall]    %zip up chord array for next iteration
    ()=         %print a newline
    exch        %put numbers behind names
}repeat

E che ne dici di House of the Rising Sun come test?

04:51 PM:~ 0> gsnd -q -- tabb.ps Em G A C Em G B B Em G A C Em B Em B|sed 's/^/    /'
e 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---
B 0---3---2---5---0---3---4---4---0---3---2---5---0---4---0---4---
G 0---4---2---5---0---4---4---4---0---4---2---5---0---4---0---4---
D 2---5---2---5---2---5---4---4---2---5---2---5---2---4---2---4---
A 2---5---0---3---2---5---2---2---2---5---0---3---2---2---2---2---
E 0---3---0---3---0---3---2---2---0---3---0---3---0---2---0---2---

Ho scritto un commento di questo codice in un'altra risposta qui .
Luser droog
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.