¿Generando tablaturas para guitarra?

24

Escriba el programa más corto que genera tablaturas de guitarra para los acordes dados como entrada.

Para que los guitarristas entre ustedes no tengan una ventaja, y para que sea determinista (y probablemente más fácil de codificar), estas son las únicas formas de los acordes autorizados:

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

Tenga en cuenta que los 5 primeros acordes y los 7 últimos acordes de cada serie tienen formas diferentes.

Todos los acordes son simples acordes mayores o menores (sin séptima u otras variaciones).

También debes cuidar los pisos. Recordatorio:

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

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

La salida debe incluir la primera columna con los nombres de los cables, como se muestra arriba. No , no tiene que incluir el nombre del acorde en la parte superior. Los acordes deben estar separados por 3 -como se muestra arriba. Los 3 últimos -son opcionales.

La entrada es una cadena que consiste en nombres de acordes, separados por espacios.

Un ejemplo de entrada es:

Bm Gb A E G D Em F#

y la salida correspondiente es:

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---
Jules Olléon
fuente
... y una pregunta secundaria: ¿cuál es la canción de ejemplo? :)
Jules Olléon
55
Hotel California: P
Matthew Leer
Sí, tú ganas! :)
Jules Olléon
Buena idea. Ojalá tuviera tiempo para jugar!
Igby Largeman

Respuestas:

9

JavaScript, 297 277 262 235 223 caracteres

Ningún retorno de carro en la versión de golf es significativo; solo están ahí para que la respuesta sea legible. Los punto y coma son significativos.

Editar: reemplazó el exterior mapcon un bucle while y otras ediciones. ¡Finalmente dentro de 2 × el tamaño de la versión Golfscript (por ahora)!

Editar: Reemplazó indexOfcon matemáticas, desglosó la tabla de búsqueda, otras pequeñas mejoras.

Editar: Otra mapde fory poner en una final \nque había sido innecesariamente comiendo. Finalmente dentro de la versión Python de 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)

La salida ya no se aprovecha de que el final ---sea ​​opcional como:

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---
DocMax
fuente
Maldición, creo que tengo envidia de JavaScript. Bien hecho.
kekekela
7

Golfscript, 136 caracteres

[["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*

Totalmente 23 caracteres (17.5%) tratan con esos dos caracteres al comienzo de cada fila de salida.

Salida de muestra, probando los casos extremos:

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

Solo he pasado aproximadamente una hora en esto, por lo que probablemente se pueda reducir de 5 a 10 caracteres al menos. Conceptualmente resulta ser bastante similar a la solución de DocMax: tabla de búsqueda para cuatro casos, luego se incrementa en un desplazamiento y une las cadenas en el orden correcto.

Peter Taylor
fuente
+1: ¡Hombre, me encanta Golfscript! Varias veces hoy he encontrado lugares para recortar mi código, ¡pero no en un 50%! No tengo un intérprete a mano: ¿devuelve D # para Eb?
DocMax
Por cierto, la última nota en su muestra coincide con C # m aunque la línea de comando muestra D # m. Error tipográfico o error?
DocMax
@DocMax, error. No entiendo por qué solo afecta a D # my no a D #; será interesante depurarlo. Reordeno las cosas porque es conveniente tener el bloque de 7 primero, por lo que Eb no es realmente un caso límite.
Peter Taylor
Resulta que el último estaba \ n incluido, lo que al no estar en la tabla de búsqueda reducía el valor por el equivalente de una letra.
Peter Taylor
4

Después de codificar esto, me di cuenta de que podría haber hecho esto mucho más inteligente ... tal vez haré otra entrada. ¡Espero obtener puntos por ser el más rápido!

De todos modos, hay 962 personajes de 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"}

Aquí está la salida correspondiente.

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---
Daniel Standage
fuente
4

Como ya se han dado soluciones más cortas (¡maldito GolfScript!), Aquí está la mía:

Python, 229 caracteres

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

Salida:

> 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---
Jules Olléon
fuente
3

Python, 449 caracteres

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])
Fernando Martin
fuente
3

C99 - 231 caracteres

Los acordes se dan en la línea de comando, un argumento por acorde y, por supuesto, no hay validación de entrada de ningún 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;}

Ejecución de muestra:

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

Sin golf

#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("");
     }
}

No estándar C - 206 caracteres

Si no nos interesan las especificaciones del lenguaje, GCC puede compilar la siguiente línea en un binario funcional, a pesar de que combina declaraciones de variables C99 con una declaración de argumento de estilo K&R (y una declaración implícita de 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;}
han
fuente
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';}}

Tenga en cuenta que esto necesita la afinación de la guitarra como primer parámetro. (La mayoría de las afinaciones no estándar le darán resultados ridículos de desgarro de dedos, pero supongo que está contento con la afinación estándar).

Para el Hotel California, puedes hacerlo $./a.out EBGDAE Cbm Gb Bbb Fb G D Em F# Bm F# G## D## F## C## D##m E##. Resultado:

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---
dejó de girar en sentido antihorario
fuente
Al afinar las cuatro cuerdas superiores a tercios menores, es muy fácil tocar acordes de tres y cuatro cuerdas en muchas inversiones, sin cuerdas abiertas, y sin tener que colocar un dedo "sobre" una cuerda sin tocarla. Usando cadenas DFG # B, una secuencia de acordes como "Bbm F Bbm Gb Db Ebm Db F Bbm F F7 Bbm" (Canción de sirena) funciona muy fácilmente. Solo es necesario subir y bajar un traste. Hay un cambio de clave de medio paso, pero eso solo significa subir un traste. Sin embargo, no he descubierto qué mejor hacer con las otras dos cuerdas.
supercat
@supercat: interesante, intentaré esto en mi guitarra mañana ...
dejó de girar en sentido antihorario
Me gustaría escuchar lo que piensas. Cogí una guitarra varias veces, con años de diferencia, y seguí rindiéndome porque las digitaciones parecían arbitrarias e incómodas. Luego me puse a pensar qué ajustes permitirían una digitación simple. Dado que los acordes de forma cerrada tienen intervalos que van desde un tercio menor a un cuarto perfecto, afinar cuerdas a tercios menores significa que cada cuerda se amortiguará en un punto que no sea más bajo que la cadena de abajo. Si puedo probar una guitarra para zurdos, podría probar cuartos perfectos con el orden de las cuerdas invertido, ya que debería ser similar.
supercat
Tal como está, sintonizar tercios menores significa que para cada posición del primer dedo en la cuerda más baja, habrá tres inversiones de acordes principales y tres inversiones de acordes menores disponibles. También se puede tocar un séptimo acorde colocando el segundo dedo sobre las tres cuerdas superiores. Para Mermaid Song, comienza en el tercer traste y juega F-Bb-DF (con los dedos 1-3-3-4). Entonces F es FACF (1-2-2-4). Gb es un traste, digitado 1-2-2-4 (como F). Db retrocede un traste, 1-3-4-4. Ebm está de vuelta, 1-2-4-4.
supercat
Me tomó solo unas pocas horas llegar al punto en el que podía tocar suavemente algunas piezas (incluida la Canción de sirena antes mencionada) después de resolver con la ayuda de un teclado cuáles deberían ser las notas de acordes adecuadas. Una vez que probé este estilo, me pareció increíblemente natural, y realmente me gusta la forma en que uno puede usar las tres inversiones de cada acorde mayor y menor. Si uno solo quisiera acordes mayores y menores, una afinación como F-Ab-B-Eb-Gb-D teóricamente podría permitir acordes mayores y menores de seis dedos con digitaciones fáciles (1-2-2-3-4-4 o 1 -1-2-3-3-4) pero sin las inversiones.
supercat
2

390345340 Postdata

Simplificado a un enfoque pragmático de guitarra (la forma E es solo una variación de la forma A, desplazada hacia abajo por una cuerda, con un cambio de un dedo). Tomó prestada la idea de la cadena codificada de las otras respuestas.

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

Previamente:

450 442 418 Postdata

También arreglé el formato de salida con este. (Las versiones anteriores comenzaron con "E ---" en lugar de "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

Cómo ejecutarlo: gsnd -q -- tab.ps Bm Gb A E G D Em F\#(ocultar el filo del caparazón).

La versión sin golf fue casi más difícil que la de golf. Pero intenté ser minucioso. Editar: algunos comentarios más sobre los trucos engañosos.

%!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

¿Y qué hay de la Casa del Sol Naciente como prueba?

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---
luser droog
fuente
Escribí un comentario de este código en otra respuesta aquí .
luser droog