Générer des tablatures de guitare?


24

Écrivez le programme le plus court qui génère des tablatures de guitare pour les accords donnés en entrée.

Pour que les guitaristes parmi vous n'aient pas d'avantage, et pour le rendre déterministe (et probablement plus facile à coder), voici les seules formes d'accords autorisées:

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

Notez que les 5 premiers accords et les 7 derniers accords de chaque série ont des formes différentes.

Tous les accords sont de simples accords majeurs ou mineurs (pas de 7e ou d'autres variantes).

Vous devez également prendre soin des appartements. Rappel:

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

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

La sortie doit inclure la première colonne avec les noms des cordons, comme indiqué ci-dessus. Il n'est pas nécessaire d'inclure le nom de l'accord en haut. Les accords doivent être séparés par 3 -comme indiqué ci-dessus. Les 3 derniers -sont facultatifs.

L'entrée est une chaîne composée de noms d'accords, séparés par des espaces.

Un exemple d'entrée est:

Bm Gb A E G D Em F#

et la sortie correspondante est:

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

... et question secondaire: quel est l'exemple de chanson? :)
Jules Olléon

5
Hotel California: P
Matthew Lu

Oui, vous gagnez! :)
Jules Olléon

Idée sympa. J'aimerais avoir le temps de jouer!
Igby Largeman

Réponses:


9

JavaScript, 297 277 262 235 223 caractères

Aucun retour de chariot dans la version golfée n'est significatif; ils ne sont là que pour rendre la réponse lisible. Les points-virgules sont importants.

Édition: remplacement de l'extérieur mappar une boucle while et d'autres modifications. Enfin à l'intérieur de 2 × la taille de la version Golfscript (pour l'instant)!

Edit: Remplacé le indexOfpar des mathématiques, cassé la table de recherche, d'autres petites améliorations.

Edit: Une autre mappour foret de mettre en finale \nj'avais été inutilement manger. Enfin à l'intérieur de la version 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 sortie ne profite plus de la fin ---étant facultative car:

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

Merde, je pense que javascript peen-envie. Bien fait.
kekekela

7

Golfscript, 136 caractères

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

Au total, 23 caractères (17,5%) traitent ces deux caractères au début de chaque ligne de sortie.

Exemple de sortie, test des cas de bord:

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

Je n'ai passé qu'une heure à ce sujet, donc il peut probablement être réduit de 5 à 10 caractères au moins. Sur le plan conceptuel, il s'avère être assez similaire à la solution de DocMax: table de recherche pour quatre cas, puis incrémenter d'un décalage et joindre les chaînes dans le bon ordre.


+1: Homme que j'aime Golfscript! Plusieurs fois aujourd'hui, j'ai trouvé des endroits pour couper mon code, mais pas de 50%! Je n'ai pas d'interprète à portée de main: retourne-t-il D # pour Eb?
DocMax

BTW, la dernière note de votre exemple correspond à C # m bien que la ligne de commande affiche D # m. Faute de frappe ou bug?
DocMax

@DocMax, bug. Je ne comprends pas pourquoi cela n'affecte que D # m et non D # - cela va être intéressant à déboguer. Je réorganise les choses parce que c'est pratique d'avoir le bloc de 7 en premier, donc Eb n'est pas vraiment un cas de bord.
Peter Taylor

Il s'avère que le dernier obtenait un \ n inclus, qui, n'étant pas dans la table de recherche, baissait la valeur de l'équivalent d'une lettre.
Peter Taylor

4

Après avoir codé cela, j'ai réalisé que j'aurais pu le faire beaucoup plus intelligemment ... peut-être que je ferai une autre entrée. J'espère que j'obtiendrai juste des points pour être le plus rapide!

Quoi qu'il en soit, il y a 962 caractères 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"}

Voici la sortie correspondante.

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

Étant donné que des solutions plus courtes ont déjà été données (bon sang GolfScript!), Voici la mienne:

Python, 229 caractères

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

Sortie:

> 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 caractères

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 caractères

Les accords sont donnés sur la ligne de commande, un argument par accord, et bien sûr il n'y a aucune validation d'entrée d'aucune sorte.

#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;}

Exemple d'exécution:

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

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

C non standard - 206 caractères

Si nous ne nous soucions pas des spécifications de langage, GCC peut compiler le one-liner suivant dans un binaire fonctionnel, même s'il mélange des déclarations de variables C99 avec une déclaration d'argument de style K&R (et une déclaration implicite 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;}

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';}}

Notez que cela nécessite l'accordage de la guitare comme premier paramètre. (La plupart des réglages non standard vous donneront des résultats ridicules, mais je suppose que vous vous contentez d'un réglage standard.)

Pour l'hôtel California, vous pouvez le faire $./a.out EBGDAE Cbm Gb Bbb Fb G D Em F# Bm F# G## D## F## C## D##m E##. Résultat:

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

Accorder les quatre cordes supérieures aux tiers mineurs, il est très facile de jouer des accords à trois et quatre cordes dans de nombreuses inversions, sans cordes ouvertes, et sans avoir à placer un doigt "sur" une corde sans la toucher. En utilisant les chaînes DFG # B, une séquence d'accords comme "Bbm F Bbm Gb Db Ebm Db F Bbm F F7 Bbm" (Mermaid Song) fonctionne très facilement. Il suffit de monter et descendre d'une case. Il y a un changement de clé en demi-étape, mais cela signifie simplement monter d'une case. Je n'ai pas encore compris ce qu'il y avait de mieux à faire avec les deux autres cordes.
supercat

@supercat: intéressant, je vais essayer ça sur ma guitare demain ...
cessé de tourner dans le sens inverse des aiguilles d'une montre le

J'aimerais entendre ce que vous en pensez. J'avais ramassé une guitare à quelques reprises, à des années d'intervalle, et j'abandonnais parce que les doigtés semblaient à la fois arbitraires et maladroits. J'ai ensuite réfléchi aux réglages qui permettraient un doigté simple. Étant donné que les accords de forme fermée ont des intervalles qui vont d'un tiers mineur à un quart parfait, le réglage des chaînes en tiers mineurs signifie que chaque chaîne sera atténuée à un point qui n'est pas inférieur à la chaîne ci-dessous. Si je peux essayer une guitare pour gaucher, je pourrais essayer des quarts parfaits avec l'ordre des cordes inversé, car il devrait être similaire.
supercat

Dans l'état actuel des choses, le réglage des tiers mineurs signifie que pour chaque position du premier doigt sur la corde la plus basse, il y aura trois inversions d'accords majeurs et trois inversions d'accords mineurs disponibles. On peut également jouer un septième accord en plaçant le deuxième doigt sur les trois cordes supérieures. Pour Mermaid Song, commencez sur la troisième case et jouez F-Bb-DF (avec les doigts 1-3-3-4). Alors F est FACF (1-2-2-4). Gb est une frette, doigts 1-2-2-4 (comme F). Db est de retour sur une case, 1-3-4-4. Ebm est de retour, 1-2-4-4.
supercat

Il ne m'a fallu que quelques heures pour arriver au point où je pouvais jouer en douceur certaines pièces (y compris la chanson de sirène susmentionnée) après avoir déterminé à l'aide d'un clavier quelles devraient être les bonnes notes d'accord. Une fois que j'ai essayé ce style, c'était incroyablement naturel, et j'aime vraiment la façon dont on peut utiliser les trois inversions de chaque accord majeur et mineur. Si l'on voulait juste des accords majeurs et mineurs, un accordage comme F-Ab-B-Eb-Gb-D pourrait théoriquement permettre des accords majeurs et mineurs à six doigts avec des doigtés faciles (1-2-2-3-4-4 ou 1 -1-2-3-3-4) mais sans les inversions.
supercat

2

390 345 340 Postscript

Simplifié à une approche guitare-pragmatique (la forme E n'est qu'une variation de la forme A, décalée d'une chaîne, avec un changement de doigt). J'ai emprunté l'idée de chaîne codée aux autres réponses.

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

Précédemment:

450 442 418 Postscript

J'ai également corrigé le format de sortie avec celui-ci. (Les versions précédentes commençaient "E ---" plutôt que "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

Comment l'exécuter: gsnd -q -- tab.ps Bm Gb A E G D Em F\#(cacher le tranchant de la coquille).

La version sans golf était presque plus difficile que la version avec golf. Mais j'ai essayé d'être minutieux. Edit: quelques commentaires supplémentaires sur les tricksy-bits.

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

Et que diriez -vous de House of the Rising Sun comme 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---

J'ai écrit un commentaire de ce code dans une autre réponse ici .
luser droog
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.