W co właśnie grałem? Przetłumacz palcowania gitar na akordy

22

Powiązane: Muzyka: co jest w tym akordzie? , Nuty do tabulatury , Generujesz tabulatury na gitarę? , Przetłumacz pary liczb na nuty gitarowe

Biorąc pod uwagę palcowanie gitary, wydaje akord, który reprezentuje. Możesz użyć standardowego wejścia i wyjścia lub napisać funkcję, która zwraca ciąg znaków.

Palce wejściowe będą klasyfikowane jako jeden z następujących akordów, które zostaną wyrażone w następujący sposób (jeśli nutą pierwiastkową było C):

  • główna triada: C
  • niewielka triada: Cm
  • (dominujący) siódmy: C7
  • mniejszy siódmy: Cm7

Akord może być odwrócony, więc nie możesz polegać na najniższej nucie będącej rdzeniem. Nie możesz też polegać na tym, że jest to łatwe lub wspólne palcowanie w prawdziwym świecie. Mówiąc bardziej ogólnie, wynik programu musi ignorować oktawy wysokości i traktować wszystkie wysokości odpowiadające tej samej nucie (tj. A) Jako równe.

To jest , więc wygrywa najkrótszy kod w bajtach.

Format wejściowy

Dane wejściowe to seria 6 wartości, które wskazują, dla każdego struny 6-strunowej gitary w standardowym strojeniu (EADGBE), na które to drażnienie będzie grane. Może to również oznaczać, że ciąg nie jest w ogóle odtwarzany. Próg „zerowy” jest również znany jako pozycja otwarta, a numery progów liczą się od tego momentu. Załóżmy, że gitara ma 21 pozycji progów, tak że najwyższa pozycja progu to liczba 20.

Na przykład wejście X 3 2 0 1 0oznacza umieszczenie palców w następujących pozycjach u góry szyi gitary:

(6th) |---|---|---|---|---
      |-X-|---|---|---|---
      |---|---|---|---|---
      |---|-X-|---|---|---
      |---|---|-X-|---|---
(1st) |---|---|---|---|---

i brzdąkanie od 2 do 6 strun. Odpowiada tej zakładce ASCII :

e |-0-|
B |-1-|
G |-0-|
D |-2-|
A |-3-|
E |---|

Masz pewną elastyczność w wyborze rodzaju danych wejściowych: każda pozycja progu może być wyrażona jako ciąg znaków lub liczba. Ciągi gitarowe, które nie są odtwarzane, są zwykle oznaczone symbolem X, ale możesz wybrać inną wartość wartownika, jeśli to ci ułatwi (np. -1Jeśli używasz liczb). Szereg 6 pozycji progów może być wprowadzany jako dowolny typ listy, tablicy lub sekwencji, pojedynczy ciąg znaków oddzielony spacją lub jako standardowe wejście - po raz kolejny, według własnego wyboru.

Możesz polegać na danych wejściowych odpowiadających jednemu z 4 typów akordów wymienionych powyżej.

Wyjaśnij w swoim poście, jaką formę danych wejściowych bierze twoje rozwiązanie.

Format wyjściowy

Musisz albo zwrócić lub wydrukować na standardowe wyjście ciąg opisujący akord, dla którego ma być palcowanie. Ta struna składa się z dwóch części połączonych razem. Kwestie kapitalizacji. Końcowe białe znaki są dozwolone.

Pierwsza część wskazuje Prymę , jeden A, A#/ Bb, B, C, C#/ Db, D, D#/ Eb, E, F, F#/ Gb, Glub G#/ Ab. (Używam #zamiast , i bzamiast , aby uniknąć konieczności Unicode). Prymy które mogą być wyrażone bez ostry lub mieszkania muszą być wyrażone bez nich (nigdy wyjście B#, Fblub Dbb); tych, które nie mogą być wyrażone muszą jednym ostrym lub płaskiej symbolem (tj albo C#albo Db, ale nigdy B##). Innymi słowy, musisz zminimalizować liczbę przypadkowych (ostrych lub płaskich) w nazwie notatki.

Druga część wskazuje rodzaj akordu, pustego dla dużej triady, mdla małej triady, 7dla dominującej siódmej lub m7dla mniejszej siódmej. Tak więc G-dur jest wyprowadzany po prostu jako G, podczas gdy siódma D-moll może być wyprowadzana jako jedna D#m7lub Ebm7. Więcej przykładów można znaleźć w przypadkach testowych na końcu.

Teoria i wskazówki

Nuty

Skala chromatyczna ma 12 podziałek na oktawę. Po dostrojeniu do równego temperamentu, każdy z tych dźwięków jest jednakowo oddalony od swoich sąsiadów 1 . Tony o 12 półtonach (oktawie) są uważane za tę samą nutę. Oznacza to, że możemy traktować nuty jak liczby całkowite modulo 12, od 0 do 11. Siedem z nich otrzymuje nazwy literowe 2 od A do G. To nie wystarczy, aby nazwać wszystkie 12 wysokości, ale dodanie przypadkowych poprawek powoduje, że: dodanie ♯ ( ostry) do nuty powoduje, że jest o jeden półton wyższy, a dodanie ♭ (płaskiej) powoduje, że jest o półton niżej.

Akordy

Akord to 2 lub więcej nut granych razem. Rodzaj akordu zależy od relacji między nutami, które można określić na podstawie odległości między nimi. Akord ma nutę główną, jak wspomniano wcześniej. W tych przykładach potraktujemy nutę główną jako 0, ale jest to arbitralne, a wszystko, co liczy się w tym wyzwaniu, to odległość między nutami w arytmetyce modulo. W odpowiedzi zawsze będzie jeden unikalny typ akordu, triada lub siódmy akord . Nuta główna nie zawsze będzie miała najniższy ton; wybierz nutę główną, aby opisać akord jako jeden z czterech następujących rodzajów akordów:

  • Głównym triada jest cięciwa z nut 0 4 7.
  • Moll triada jest cięciwa z nut 0 3 7.
  • Dominującą (lub główny / poboczny) siódmy akord ma notatki 0 4 7 10.
  • Moll (lub drobne / minor) siódmy akord ma notatki 0 3 7 10. 3)

Strojenie gitary

Standardowe strojenie na gitarze 6-strunowej zaczyna się od E na najniższej strunie, a następnie uderza nuty w odstępach 5, 5, 5, 4, a następnie 5 półtonów w górę strun. Przyjmując najniższą E jako 0, oznacza to, że uderzenie wszystkich strun gitary daje ci ponumerowane wysokości 0 5 10 15 19 24, których moduł 12 jest równoważny 0 5 10 3 7 0lub nuty E A D G B E.

Sprawdzone przykłady

Jeśli twój wkład brzmi 0 2 2 0 0 0, odpowiada to nutom E B E G B E, więc tylko E, B i G. Tworzą one akord Em, który można zobaczyć, numerując je z rdzeniem jako E, dając nam 0 3 7. (Wynik byłby taki sam dla X 2 X 0 X 0lub 12 14 14 12 12 12.)

Jeśli twój wkład to 4 4 6 4 6 4, numerowanie ich z rdzeniem C♯ daje 7 0 7 10 4 7, lub 0 4 7 10, więc odpowiedź brzmi C#7(lub Db7). Gdyby tak było 4 4 6 4 5 4, numeracja dałaby 7 0 7 10 3 7, lub 0 3 7 10, co jest C#m7(lub Dbm7).

Przypadki testowe

X 3 2 0 1 0  --->  C
0 2 2 0 0 0  --->  Em
X 2 X 0 X 0  --->  Em
4 4 6 4 6 4  --->  C#7  (or Db7)
4 4 6 4 5 4  --->  C#m7 (or Dbm7)
0 2 2 1 0 0  --->  E
0 0 2 2 2 0  --->  A
X X 4 3 2 2  --->  F#   (or Gb)
3 2 0 0 0 1  --->  G7
X X 0 2 1 1  --->  Dm7
3 3 5 5 5 3  --->  C
4 6 6 5 4 4  --->  G#   (or Ab)
2 2 4 4 4 5  --->  B7
0 7 5 5 5 5  --->  Am7
7 6 4 4 X X  --->  B
8 6 1 X 1 3  --->  Cm
8 8 10 10 9 8 -->  Fm
0 19 5 16 8 7 -->  Em
6 20 0 3 11 6 -->  A#   (or Bb)
X 14 9 1 16 X -->  G#m  (or Abm)
12 14 14 12 12 12 --> Em
15 14 12 12 12 15 --> G
20 X 20 20 20 20  --> Cm7
X 13 18 10 11 10  --> A#7 (or Bb7)

1 według logarytmów ich częstotliwości

2 lub, w solfège , nazwy takie jak do, re, mi . W tym wyzwaniu użyj nazw liter.

3 Można to również nazwać głównym szóstym akordem, z innym wyborem nuty korzeniowej. W tym wyzwaniu nazwij go jego mniejszym siódmym imieniem.

Dan Getz
źródło
3
Świetne wyzwanie!
Luis Mendo,
1
Kusiło mnie, by zamknąć jako oszustwo z mojego przyszłego wyzwania: D (miałem na myśli bardzo podobne wyzwanie, ale ty byłeś oczywiście szybszy.)
flawr
Czy końcowe ciąg znaków jest dozwolony w ciągu wyjściowym?
Luis Mendo
@LuisMendo na pewno; w porządku.
Dan Getz
1
@officialaimm nie, nie musisz zajmować się żadnymi innymi sytuacjami. Możesz założyć, że zawsze będzie to jeden z 4 rodzajów akordów. Innymi słowy, twój kod może zrobić co chcesz (w tym błąd lub dać złą odpowiedź), jeśli otrzyma inny akord.
Dan Getz

Odpowiedzi:

9

MATL , 115 114 bajtów

[OAXICO]+tZN~)Y@!"@t1)XH- 12\XzXJK7hm?O.]JI7hm?'m'.]J[KCX]m?'7'.]J[ICX]m?'m7'.]]'FF#GG#AA#BCC#DD#E'l2741B~QY{HX)wh

Format wejściowy to [N 3 2 0 1 0], gdzie Nwskazuje nieużywany ciąg.

Ciąg wyjściowy zawsze używa #, a nie b.

Wypróbuj online! Lub sprawdź wszystkie przypadki testowe w dwóch częściach, aby uniknąć przekroczenia limitu czasu kompilatora online:

Wyjaśnienie

[OAXICO]            % Push [0 5 10 3 7 0]. This represents the pitch of each open
                    % string relative to the lowest string, modulo 12
+                   % Add to implicit input. May contain NaN's, for unused strings
tZN~)               % Remove NaN's
Y@!                 % Matrix of all permutations, each in a column
"                   % For each column
  @                 %   Push current column
  t1)               %   Duplicate and get first entry
  XH                %   Copy into clipboard H
  - 12\             %   Subtract. This amounts to considering that the first note
                    %   of the current permutation is the root, and computing
                    %   all intervals with respect to that
  12\               %   Modulo 12
  Xz                %   Remove zeros
  XJ                %   Copy into clipboard J
  K7hm?             %   Are all intervals 4 or 7? If so: it's a major chord
    O               %     Push 0 (will become space when converted to char)
    .               %     Break for loop
  ]                 %   End if
  J                 %   Push array of nonzero intervals again
  I7hm?             %   Are all intervals 3 or 7? If so: it's a minor chord
    'm'             %     Push this string
    .               %     Break for loop
  ]                 %   End if
  J                 %   Push array of nonzero intervals again
  [KCX]m?           %   Are all intervals 4, 7 or 10? If so: it's a dominant-7th
                    %   chord
    '7'             %     Push this string
    .               %     Break for loop
  ]                 %   End if
  J                 %   Push array of nonzero intervals again
  [ICX]m?           %   Are all intervals 3, 7 or 10? If so: it's a minor 7th chord
    'm7'            %     Push this string
    .               %     Break for loop
  ]                 %   End if
]                   % End for. The loop is always exited via one of the 'break'
                    % statements. When that happens, the stack contains 0, 'm',
                    % '7' or 'm7', indicating the type of chord; and clipboard H
                    % contains a number that tells the root note using the lowest 
                    % string as base (1 is F, 2 is F# etc)
'FF#GG#AA#BCC#DD#E' % Push this string. Will be split into strings of length 1 or 2
l                   % Push 1
2741B~Q             % Push [1 2 1 2 1 2 1 1 2 1 2 1] (obtained as 2741 in binary,
                    % negated, plus 1)
Y{                  % Split string using those lengths. Gives a cell array of
                    % strings: {'F', 'F#', ..., 'E'}
H                   % Push the identified root note
X)                  % Index into cell array of strings
wh                  % Swap and concatenate. Implicitly display
Luis Mendo
źródło
4

Plik MS-DOS .COM (179 bajtów)

Plik (tutaj wyświetlany jako HEX):

fc be 81 00 bf 72 01 31 db b9 06 00 51 e8 73 00
59 e2 f9 b9 0c 00 be 48 01 ad 39 c3 74 0d 40 75
f8 d1 fb 73 03 80 c7 08 e2 ec c3 31 db 88 cb 8a
87 59 01 e8 42 00 8a 87 65 01 e8 3b 00 81 c6 08
00 ac e8 33 00 ac eb 30 91 00 89 00 91 04 89 04
ff ff 00 00 6d 00 37 00 6d 37 42 41 41 47 47 46
46 45 44 44 43 43 00 23 00 23 00 23 00 00 23 00
23 00 04 09 02 07 0b 04 84 c0 74 06 b4 02 88 c2
cd 21 c3 8a 0d 47 ac 3c 20 76 fb 30 ed 3c 41 73
22 2c 30 72 0b 86 c5 b4 0a f6 e4 00 c5 ac eb ed
88 e8 00 c8 30 e4 b1 0c f6 f1 88 e1 b8 01 00 d3
e0 09 c3

Dane wejściowe są podawane z wiersza poleceń. Nieprawidłowe wprowadzenie spowoduje nieprawidłowe działanie programu!

Kod asemblera wygląda następująco:

.text
.code16
ComFileStart:
    cld
    mov $0x81, %si
    mov $(TuneTable-ComFileStart+0x100), %di
    xor %bx, %bx
    # 6 strings: Build the mask of played tones
    mov $6, %cx
NextStringRead:
    push %cx
    call InsertIntoMask
    pop %cx
    loop NextStringRead

    # Check all base tones...
    mov $12, %cx
TestNextTone:
    mov $0x100+ChordTable-ComFileStart, %si
TestNextChord:
    lodsw
    # Is it the chord we are searching for?
    cmp %ax, %bx
    je FoundChord 
    # Is it the end of the table?
    inc %ax
    jnz TestNextChord
    # Transpose the chord we really play
    # and go to the next tone
    # This code rotates the low 12 bits of
    # BX one bit right
    sar $1, %bx
    jnc NoToneRotated
    add $8, %bh
NoToneRotated:
    loop TestNextTone
EndOfProgram:
    ret

FoundChord:
    # Get and print the tone name
    xor %bx, %bx
    mov %cl, %bl
    mov (ToneNamesTable+0x100-1-ComFileStart)(%bx),%al
    call printChar
    mov (ToneNamesTable+0x100+12-1-ComFileStart)(%bx),%al
    call printChar
    # Get the chord name suffix and print it
    add $(ChordNamesTable-ChordTable-2),%si
    lodsb
    call printChar
    lodsb
    # Note: Under MS-DOS 0x0000 is the first word on
    # the stack so the "RET" of printChar will jump
    # to address 0x0000 which contains an "INT $0x21"
    # (end of program) instruction
    jmp printChar

ChordTable:
    # Major, Minor, Major-7, Minor-7
    .word 0x91, 0x89, 0x491, 0x489, 0xFFFF
ChordNamesTable:
    .byte 0,0,'m',0,'7',0,'m','7'
ToneNamesTable:
    .ascii "BAAGGFFEDDCC"
    .byte 0,'#',0,'#',0,'#',0,0,'#',0,'#',0
TuneTable:
    .byte 4,9,2,7,11,4

#
# Subfunction: Print character AL;
#              Do nothing if AL=0
#
printChar:
    test %al, %al
    jz noPrint
    mov $2, %ah
    mov %al, %dl
    int $0x21
noPrint:
    ret

#
# Subfunction: Get one finger position
#              and insert it into a bit mask
#              of tones being played
#
# Input:
#
#   [DS:DI] = 
#        Tuning of current string (0=C, 1=C#, ..., 11=B)
#        Actually only 2=D, 4=E, 7=G, 9=A and 11=B are used
#
#   DS:SI = Next character to read
#
#   DF = Clear
#
# Input and Output:
#
#    BX = Bit mask
#    DI = Will be incremented
#
# Destroys nearly all registers but SI and BX
#
InsertIntoMask:
    mov (%di), %cl
    inc %di
SkipSpaces:
    lodsb
    cmp $' ', %al
    jbe SkipSpaces
# Now evaluate each digit
    xor %ch, %ch
GetNextDigit:
    # Number = 10*Number+Digit
    cmp $'A', %al
    jae DigitIsX
    sub $'0', %al
    jb DigitsDone
    xchg %al, %ch
    mov $10, %ah
    mul %ah
    add %al, %ch
    lodsb
    jmp GetNextDigit
DigitsDone:
    # Add the tune of the string
    # and perform modulus 12
    mov %ch, %al
    add %cl, %al
    xor %ah, %ah
    mov $12, %cl
    div %cl
    mov %ah, %cl
    mov $1, %ax
    shl %cl, %ax
    or %ax, %bx
DigitIsX:
    ret

Przypadki testowe:

6 20 0 3 11 6 -->  A#   (or Bb)

Widziałem już dwóch pianistów grających razem na fortepianie „na cztery ręce”.

Ten przypadek testowy po raz pierwszy czytam o gitarzystach!

Nawet przy stukaniu prawą ręką nie możesz grać na takim kablu!

Martin Rosenau
źródło
Hmm, może kałamarnica mogłaby zagrać ten akord? Myślę, że jest to jeden z tych, które znalazłem podczas losowego wyszukiwania, aby mogły wystąpić „twarde” przypadki testowe.
Dan Getz
3

Ruby, 129 bajtów

Jak poprzednia wersja, ale wykorzystuje pojedynczą pętlę, z operatorem trójskładnikowym, do sekwencjonowania między krokiem analizy i krokiem wyjściowym. Aby to zadziałało, konieczne były inne niewielkie modyfikacje.

->a{r=0
18.times{|j|j<6?a[j]&&r|=8194<<(6--~j%5+a[j]*7)%12:(r/=2)&11==3&&puts("CGDAEBF"[j%7]+?#*(j/13)+['',?m,?7,'m7'][r>>9&3])}}

Rubin, 136 bajtów

Funkcja Llamda przyjmuje tablicę 6 liczb jako argument i wypisuje na standardowe wyjście. Nieużywany ciąg jest reprezentowany przez wartość fałszowania (jedynymi wartościami fałszowania w ruby ​​są nili false.)

->a{r=0
6.times{|j|a[j]&&r|=4097<<(6--~j%5+a[j]*7)%12}
12.times{|j|r&11==3&&puts("FCGDAEB"[j%7]+?#*(j/7)+['',?m,?7,'m7'][r>>9&3]);r/=2}}

Wyjaśnienie

Używam reprezentacji 12 wysokości na podstawie koła piątych . Oznacza to, że po każdym dźwięku następuje dźwięk o 7 półtonów wyżej (lub o 5 półtonów niżej), co daje sekwencję F C G D A E B F# C# G# D# A#. Są to 2 zalety. Jednym z nich jest to, że wszystkie ostre narzędzia pojawiają się razem. Drugim jest to, że otwarte nuty 5-strunowego basu pojawiają się razem: GDAEB (gitara jest spokrewniona, ale nieco bardziej złożona, patrz poniżej).

Pierwsza pętla działa 6 razy. Wyrażenie 6--~j%5(równoważnie 6-(j+1)%5) podaje wartości Uwaga dla strun: E=5 A=4 D=3 G=2 B=6 E=5. Do tego dodajemy liczbę progów pomnożoną przez 7 (jak widać powyżej, dodanie jednego półtonu przesuwa nas o 7 miejsc do przodu w sekwencji). Następnie bierzemy całość modulo 12 i tworzymy mapę bitową obecnych nut (my użyj, 4097<<note valueaby podać 2 kolejne oktawy).

Po skomponowaniu mapy bitowej jesteśmy gotowi przeszukać akord i wygenerować go.

Interesują nas następujące uwagi:

Note       position in      position in             Note      position in 
           semitone domain  circle of fifths                  circle of fifths 
Root       0                0                       Root      0
Minor 3rd  3                9                       Fifth     1
Major 3rd  4                4                       Sixth     3
Fifth      7                1                       Major 3rd 4
Sixth      9                3                       Minor 3rd 9
Minor 7th  10               10                      Minor 7th 10

Zaczynając od sprawdzenia akordu F, sprawdzamy, czy pierwiastek i piąty są obecne: bity 0 i 1 (licząc od najmniej znaczącego: bity 1 i 2). Aby odrzucić szósty akord, musimy również sprawdzić, czy szósty jest nieobecny: bit 3 (bit 8). sprawdzamy to, r&&11==3a jeśli tak, to drukujemy akord.

Ignorujemy główną trzecią część i polegamy całkowicie na bicie 9 (mała trzecia) i bicie 10 (mniejsza 7), aby opracować rodzaj akordu. Wyrażenie r>>9&3służy do wybierania właściwego typu akordu z tablicy.

Pod koniec pętli, możemy przesunąć w prawo o jeden bit bitmapy r/=2do testowania możliwych korzenie akord w kolejności: F C G D A E B F# C# G# D# A#.

Niegolfowany w programie testowym

f=->a{                            #Accept array of 6 numbers as argument.
  r=0                             #Setup an empty bitmap.

  6.times{|j|                     #For each string
    a[j]&&                        #if the fret value is truthy (not nil or false)
    r|=4097<<(6--~j%5+a[j]*7)%12  #calculate the note value in the circle of fifths and add to the bitmap.
  }

  12.times{|j|                    #For each possible root note
    r&11==3&&                     #if root and fifth are present (bits 0 and 1) and sixth is absent (bit 3) 
    puts("FCGDAEB"[j%7]+?#*(j/7)+ #output the note name and a sharp symbol if necessary, followed by
    ['',?m,?7,'m7'][r>>9&3])      #m and/or 7 as indicate by bits 9 and 10.
    r/=2
  }
}

print 1;f[[nil,3,2,0,1,0]]       #  C
print 2;f[[0,2,2,0,0,0]]         #  Em
print 3;f[[nil,2,nil,0,nil,0]]   #  Em
print 4;f[[4,4,6,4,6,4]]         #  C#7 
print 5;f[[4,4,6,4,5,4]]         #  C#m7 
print 6;f[[0,2,2,1,0,0]]         #  E
print 7;f[[0,0,2,2,2,0]]         #  A
print 8;f[[nil,nil,4,3,2,2]]     #  F#  
print 9;f[[3,2,0,0,0,1]]         #  G7
print 10;f[[nil,nil,0,2,1,1]]    #  Dm7
print 11;f[[3,3,5,5,5,3]]        #  C
print 12;f[[4,6,6,5,4,4]]        #  G#  
print 13;f[[2,2,4,4,4,5]]        #  B7
print 14;f[[0,7,5,5,5,5]]        #  Am7
print 15;f[[7,6,4,4,nil,nil]]    #  B
print 16;f[[8,6,1,nil,1,3]]      #  Cm
print 17;f[[8,8,10,10,9,8]]      #  Fm
print 18;f[[0,19,5,16,8,7]]      #  Em
print 19;f[[6,20,0,3,11,6]]      #  A#  
print 20;f[[nil,14,9,1,16,nil]]  #  G#m 
print 21;f[[12,14,14,12,12,12]]  #  Em
print 22;f[[15,14,12,12,12,15]]  #  G
print 23;f[[20,nil,20,20,20,20]] #  Cm7
print 24;f[[nil,13,18,10,11,10]] #  A#7
Level River St
źródło
2

JavaScript (ES6), 335 333 bajtów

Uwielbiam to wyzwanie i PPCG SE! To mój pierwszy golf - sugestie mile widziane, ponieważ jestem pewien, że można by go znacznie poprawić. (strąciłem 2 bajty, ponieważ włączyłem f = do liczby)

Funkcja fprzyjmuje tablicę ciągów znaków, reprezentujących liczby i „X”, f(['X','3','2','0','1','0'])i zwraca akord (naturalny lub ostry) E#m7. Dodano nowe linie dla zachowania przejrzystości (nieuwzględnione w liczbie bajtów)

f=c=>[s=new Map([[435,''],[345,'m'],[4332,7],[3432,'m7']]),
n=[...new Set(c.map((e,i)=>e?(+e+[0,5,10,3,7,0][i])%12:-1)
.filter(e=>++e).sort((a,b)=>a>b))],d=[...n,n[0]+12].reduce(
(a,c,i)=>i?[...a,(c-n[i-1]+12)%12]:[],0).join``.repeat(2),
m=+d.match(/(34|43)(5|32)/g)[0],'E0F0F#0G0G#0A0A#0B0C0C#0D0D#'
.split(0)[n[d.indexOf(m)]]+s.get(m)][4]

Przykład użycia:

console.log(f(['0','2','2','0','0','0'])); // Em

Aby uruchomić przypadki testowe:

tests=`X 3 2 0 1 0 ---> C
0 2 2 0 0 0 ---> Em
X 2 X 0 X 0 ---> Em
4 4 6 4 6 4 ---> C#7 (or Db7)
4 4 6 4 5 4 ---> C#m7 (or Dbm7)`; // and so on...

tests.split`\n`.forEach(e=>{
    console.log(`Test: ${e}
      Result: ${f(e.split(' ').slice(0,6))}`)
})

Wersja bez golfa z wyjaśnieniem:

f = (c) => {
    s = new Map([
        [435,''], [345,'m'], [4332,7], [3432,'m7'] 
    ]) /* Each key in s describes the intervals (semitones)
          between consecutive notes in a chord, when it is
          reduced to a single octave, including the interval
          from highest back to lowest. The values describe
          the corresponding chord suffix. E.g. C-E-G has
          intervals C-4-E-3-G-5-C. 435=major=no suffix. */

    n = [ ...new Set(
        c.map( 
         (e,i) => e ? ( +e + [0,5,10,3,7,0][i] )%12 : -1 
         ).filter( (e) => ++e ).sort( (a,b) => a>b )
        ) ] /* take the input array, c, and transform each fret
               position into a note. remove non-notes (-1), sort
               in tone order, remove duplicates. An input of
               positions X 13 18 10 11 10 becomes notes
               (-1) 6 4 1 6 10 then 1 4 6 10. */

    d = [ ...n, n[0] + 12 ].reduce(
        (a,c,i) => i ? [ ...a, (c - n[i-1] + 12)%12 ] : [], 0
    ).join``.repeat(2)
    /* convert the note array, n, into an interval string, d,
       including the lowest note repeated above it to capture
       all intervals. Repeat it twice so that, regardless of the
       inversion played, the intervals will appear in root order
       somewhere. E.g. notes 1-4-6-10 and 13 (1+12)
       become intervals 3 2 4 3, and string for searching
       32433243 */

    m = +d.match( /(34|43)(5|32)/g )[0];
      /* m is the matched chord pattern. In this case, 4332. */

    return 'E0F0F#0G0G#0A0A#0B0C0C#0D0D#'.split(0)[
    n[ d.indexOf(m) ]
    /* get the position in the interval string where the root
       interval first occurs. this corresponds to the position
       of the chord root note in the note array, n. convert this
       number 0-12 to a note name E - D# */
    ] + s.get(m)
       /* add the suffix corresponding to the matched
       chord interval pattern */
}
Chris M.
źródło
1
Witamy na stronie! Cieszę się, że ci się spodoba. :) Niestety, nie znam żadnego JS, więc nie mam żadnych wskazówek, ale możesz znaleźć trochę tutaj
DJMcMayhem