Converter entre claves de música

12

Antes de sair, você não precisa entender muita notação musical para fazer esse desafio.

EXPLICAÇÃO

Nas partituras padrão, claves duplos atravessam a página, servindo como pontos de referência para as notas, informando que nota deve ser tocada. Se você ainda não está familiarizado com a clave de sol e os agudos, aqui está uma descrição da Wikipedia:

Clave é um símbolo musical usado para indicar o tom das notas escritas. Colocado em uma das linhas no início da pauta, indica o nome e o tom das notas nessa linha. Esta linha serve como um ponto de referência pelo qual os nomes das notas em qualquer outra linha ou espaço da pauta podem ser determinados.

Partitura

Na imagem acima, a metade superior das linhas é a clave de sol, denotada com um Clave de Sol

A metade inferior é a clave de sol, denotada com um Clef baixo

Como você pode ver na Clave de Sol, uma nota na parte inferior mais-line é um E . (Eu não estou contando notas fora das linhas clef para este desafio) Na clave de fá, a linha mais baixa é um G . Para concluir esse desafio, você deve fazer o seguinte:

DESAFIO

Dada uma entrada de uma das seguintes formas (sua escolha), converta-a na clave oposta. Seja a clave de sol ou a clave de sol, pode ser um valor Truthey / Falsey no seu idioma (não apenas dois valores), por exemplo

F # T ou F # Verdadeiro ou F # Treble

mas não

F # -1 ou F # 4

Espaços e letras maiúsculas são opcionais, Flats não aparecerão e espaços em branco à direita não são permitidos.

Input          Expected Output
E   Treble     G
F   Treble     A
F#  Treble     A#
G   Treble     B
G#  Treble     C
A   Treble     C
A#  Treble     C#
B   Treble     D
C   Treble     E
C#  Treble     F
D   Treble     F
D#  Treble     F#
E   Treble     G
F   Treble     A
F#  Treble     A#
G   Bass       E
G#  Bass       F
A   Bass       F
A#  Bass       F#
B   Bass       G
C   Bass       A
C#  Bass       A#
D   Bass       B
D#  Bass       C
E   Bass       C
F   Bass       D
F#  Bass       D#
G   Bass       E
G#  Bass       F
A   Bass       F
A#  Bass       F#

Esteja avisado, este não é um desafio trivial de diferença constante. Observe atentamente as entradas e saídas. Se você olhar para um piano,

Piano

as teclas pretas são cortantes, indicadas por #. Observe que não há um E # ou um B #. Isso significa que, se você receber G # na clave de baixo, em vez de retornar E # , precisará retornar F

Isso é , então a menor contagem de bytes vence.

FantaC
fonte
1
Temos que nos preocupar com apartamentos? Que tal apartamentos duplos / perfurocortantes?
mypetlion
1
Não crie tags para tópicos que não os justifiquem.
Jonathan Allan
3
O espaço em branco à direita (retornando em C vez de C) está ok?
Lynn
2
Está usando 1e -1(ou mesmo dizer, 4e -4) para a entrada de indicador clef permitido ou se isso só será aceitável se forem truthy / Falsey valores em nossa língua?
Jonathan Allan
1
Este é um desafio agradável e bem apresentado, mas teria sido ainda melhor na IMO com formatos de entrada / saída levemente relaxados.
Arnauld

Respostas:

5

Geléia ,  35  34 bytes

Sinto que alguma aritmética pode conquistar esse método.

ØAḣ7µW€ż;€”#$Ẏ
Ç”C4¦”F⁵¦
Ñi+_⁸?4ị¢

Experimente online!

Um programa completo usando 1) o indicador de clave 0ou 1para Bass ou Treble respectivamente e 2) a nota; e imprimir a nota resultante.

Seriam 31 bytes se -4e 4forem aceitáveis ​​como os valores de entrada do indicador de clave (então Ñi+_⁸?4ị¢pode se tornar Ñi+⁸ị¢), mas isso foi esclarecido como não permitido, a menos que -4 seja falsey e 4 seja verdade, o que não é o caso do Jelly.

Quão?

Constrói um teclado com phantom B#e E#teclas, localiza o índice da entrada, compensa que, 4na direção necessária, indexa novamente em um teclado com essas teclas phantom substituídas pelos resultados necessários (a tecla acima deles):

ØAḣ7µW€ż;€”#$Ẏ - Link 1, keyboard with phantoms: no inputs
ØA             - alphabet yield        -> ['A', 'B', ..., 'Z']
   7           - literal seven
  ḣ            - head                  -> ['A','B','C','D','E','F','G']
    µ          - new monadic chain, call that K
     W€        - wrap €ach             -> ["A","B","C","D","E","F","G"] ("" being lists of characters)
            $  - last two links as a monad:
          ”#   -   character '#'
        ;€     -   concatenate to €ach -> ["A#","B#","C#","D#","E#","F#","G#"]
       ż       - zip together          -> [["A","A#"],["B","B#"],["C","C#"],["D","D#"],["E","E#"],["F","F#"],["G","G#"]]
             Ẏ - tighten               -> ["A","A#","B","B#","C","C#","D","D#","E","E#","F","F#","G","G#"]

Ç”C4¦”F⁵¦ - Link 2, keyboard with phantoms replaced: no inputs
Ç         - call the last link (1) as a monad  ["A","A#","B","B#","C","C#","D","D#","E","E#","F","F#","G","G#"]
    ¦     - sparse application:
   4      - ...to index: literal four
 ”C       - ...action: character 'C'    -> ["A","A#","B","C","C","C#","D","D#","E","E#","F","F#","G","G#"]
        ¦ - sparse application:
       ⁵  - ...to index: literal ten
     ”F   - ...action: character 'F'    -> ["A","A#","B","C","C","C#","D","D#","E","F","F","F#","G","G#"]

Ñi+_⁸?4ị¢ - Main link: integer, clef (1 Treble / 0 Bass); list of characters, key
                                      e.g. 0; "D#"
Ñ         - next link (1) as a monad (no atom for next link as a nilad, but this works here anyway)
          -                               ["A","A#","B","B#","C","C#","D","D#","E","E#","F","F#","G","G#"]
 i        - first index of key in that    8
      4   - literal four
     ?    - if:
    ⁸     - ...condition: chain's left argument, clef
  +       - ...then: addition
   _      - ...else: subtraction          4
        ¢ - next link as a nilad          ["A","A#","B","C","C","C#","D","D#","E","F","F","F#","G","G#"]
       ị  - index into                    "C"
Jonathan Allan
fonte
Cheque verde: Hmm, então ninguém ainda venceu esse placar - estou bastante chocado.
Jonathan Allan
9

Befunge, 70 64 bytes

~0~:70p##~+2%00p+"A"-~7%2++7%:3%2%00g*:10p+"A"+,00g!10g+#@_"#",@

Experimente online!

A entrada deve estar no formato C# Trebleou F Bass, embora a clave possa simplesmente ser a primeira letra ( Tou seja B), pois o restante da entrada é ignorado de qualquer maneira.

Explicação

~0        Read the note and push a zero (the purpose of this will become apparent later).
~:70p     Read the following sharp or space and write that out as the next instruction.

Como resultado dessa modificação de código, a próxima sequência de instruções assumirá uma das duas formas:

##~       The first # jumps over the second, and thus we perform the read instruction.
 #~       But if there's only one #, we'll ending up skipping the read instruction.

Neste ponto, a pilha contém note,0,sharp,spaceou note,0,space.

+2%       Add the top two stack items mod 2, returning 1 if we read a sharp, else 0 if not.
00p       Save this 'sharp' boolean for later use.

Neste ponto, a pilha contém note,0ou apenas note(com um zero implícito abaixo).

+         By adding the top two items, we combine the 0 (if present) onto the note below.
"A"-      We can then subtract 'A' to convert the note into a number in the range 0 to 6.
~7%2+     Read the T/B clef, then mod 7 and add 2, returning 2 or 5 (the conversion offset).
+7%       Add that offset to our note number, then mod 7, to get the converted note number.
:3%2%     Make a dup, and calculate mod 3 mod 2 to determine the special cases (B# or E#).
00g*      Multiply that by the 'sharp' boolean, since we only care if the input was sharp.
:10p      Duplicate and save this special case boolean for later.
+         Now add it to the note number, since the special cases need to be offset by 1.
"A"+,     Then we can finally convert the number back into a character and output it.
00g!10g+  Now we check if the original note was not sharp, or if this was a special case.
#@_       If so, we exit immediately.
"#",@     Otherwise, we output a '#'.
James Holderness
fonte
3

Perl 5, 56 bytes

$_=<>;s/./chr 65+(-4*<>+ord$&)%7/e;s/B#/C/;s/E#/F/;print

Lê a nota e a clave como duas linhas de STDIN e imprime a nova nota em STDOUT. A clave é 0para agudos e 1baixos.

faubi
fonte
1
pode economizar 11 bytes usando -pa bandeira tio.run/##K0gtyjH9/79YX08/OaNIwcxUW0PXRMvGTju/KEVFTVPVXD/...
Nahuel FOUILLEUL
3

JavaScript (ES6) 74 bytes

Toma entrada na sintaxe curtimenta (note)(clef)onde clefé 0para baixo e 1para o triplo .

n=>c=>'FC.DAFCGDAEBF'[k=(parseInt(n,36)*15+!n[1]*90+c)%98%13]+(k<5?'#':'')

Demo

Quão?

Na verdade, isso é um pouco menos divertido do que minha versão anterior, mas a tabela de pesquisa subjacente é agora o F#,C#,(unused),D#,A#,F,C,G,D,A,E,B,Fque permite reduzir a condição # , evitando o truque de caracteres NUL - que era um pouco limitado, suponho.


Versão anterior 76 75 bytes

n=>c=>'ACCDFF.CDEFGABCDE'[k=parseInt(4*!!n[1]+c+n,21)%24%17]+'\0#'[45>>k&1]

Demo

Quão?

A entrada (n, c) é processada através das seguintes etapas:

  1. Primeiro, avaliamos 4 * !!n[1] + c + nonde !!n[1]é verdadeiro (coagido a 1 ) se a nota contiver um # e falso (coagido a 0 ) caso contrário. A expressão 4 * !!n[1] + cresulta em um valor numérico que é adicionado na frente da string n .

  2. Etapa implícita: zeros à esquerda e # à direita são ignorados por parseInt(). Por exemplo, "5G#"é realmente analisado como "5G".

  3. Convertemos a nova string em um valor decimal, analisando-a como uma quantidade base-21.

  4. Aplicamos o módulo 24.

  5. Aplicamos o módulo 17.

Abaixo está a tabela de resumo de todos os pares de entrada possíveis, juntamente com a saída esperada. Observe que um # deve ser adicionado à saída se o resultado final for 0 , 2 , 3 ou 5 . Daí o uso da máscara binária 101101 ( 45 em decimal).

 n   | c | (1)   | (2)   | (3) | (4) | (5) | Output
-----+---+-------+-------+-----+-----+-----+-------
"E"  | 1 | "1E"  | "1E"  |  35 |  11 |  11 | "G"
"F"  | 1 | "1F"  | "1F"  |  36 |  12 |  12 | "A"
"F#" | 1 | "5F#" | "5F"  | 120 |   0 |   0 | "A#"
"G"  | 1 | "1G"  | "1G"  |  37 |  13 |  13 | "B"
"G#" | 1 | "5G#" | "5G"  | 121 |   1 |   1 | "C"
"A"  | 1 | "1A"  | "1A"  |  31 |   7 |   7 | "C"
"A#" | 1 | "5A#" | "5A"  | 115 |  19 |   2 | "C#"
"B"  | 1 | "1B"  | "1B"  |  32 |   8 |   8 | "D"
"C"  | 1 | "1C"  | "1C"  |  33 |   9 |   9 | "E"
"C#" | 1 | "5C#" | "5C"  | 117 |  21 |   4 | "F"
"D"  | 1 | "1D"  | "1D"  |  34 |  10 |  10 | "F"
"D#" | 1 | "5D#" | "5D"  | 118 |  22 |   5 | "F#"
-----+---+-------+-------+-----+-----+-----+-------
"E"  | 0 | "0E"  | "E"   |  14 |  14 |  14 | "C"
"F"  | 0 | "0F"  | "F"   |  15 |  15 |  15 | "D"
"F#" | 0 | "4F#" | "4F"  |  99 |   3 |   3 | "D#"
"G"  | 0 | "0G"  | "G"   |  16 |  16 |  16 | "E"
"G#" | 0 | "4G#" | "4G"  | 100 |   4 |   4 | "F"
"A"  | 0 | "0A"  | "A"   |  10 |  10 |  10 | "F"
"A#" | 0 | "4A#" | "4A"  |  94 |  22 |   5 | "F#"
"B"  | 0 | "0B"  | "B"   |  11 |  11 |  11 | "G"
"C"  | 0 | "0C"  | "C"   |  12 |  12 |  12 | "A"
"C#" | 0 | "4C#" | "4C"  |  96 |   0 |   0 | "A#"
"D"  | 0 | "0D"  | "D"   |  13 |  13 |  13 | "B"
"D#" | 0 | "4D#" | "4D"  |  97 |   1 |   1 | "C"
Arnauld
fonte
3

Python 2 , 77 bytes

Função que imprime em STDOUT. Trueconverte graves em agudos e Falseconverte agudos em graves.

def f(n,c):N=ord(n[0])-63-4*c;M=-~N%3<1<len(n);print chr((N+M)%7+65)+n[1:2-M]

Experimente online!

Explicação:

  • A primeira declaração N=ord(n[0])-63-4*c;,, calcula o índice (0 a 7) da carta da nova nota, desconsiderando os objectos cortantes.
    • ord(N[0])-63-4*cobtém o índice da letra atual e adiciona ou subtrai 2, dependendo do valor de c(variável para alternar a direção da conversão)
  • A próxima instrução M=-~N%3<1<len(n);calcula se essa variável precisará ou não ser ajustada. Por exemplo, se a nova nota for Ee a nota original tiver uma nitidez, ela precisará ser ajustada para uma F. A desigualdade encadeada funciona da seguinte maneira:
    • -~N%3<1verifica se o índice da nova nota está na sequência 3n-1. Isso só produzirá verdadeiro para Ee B, as duas notas que não têm um nítido.
    • 1<len(n)verifica se a nota original estava afiada (isso tornaria o comprimento da corda maior que 1). Isso é necessário, pois, se não houver nitidez, não será necessário ajustar as novas letras da nota.
    • Isso define o valor de Mcomo Trueou False, que pode ser usado no cálculo como 1e 0respectivamente, para executar o ajuste, precisamos adicionar apenas M a N e módulo por 7.
  • A declaração final cria e gera o resultado final.
    • chr((N+M)%7+65) adiciona o ajuste, se necessário, e depois converte o valor de um índice em um caractere.
    • +n[1:2-M]acrescentará um símbolo nítido se ambos M=0(nenhum ajuste foi feito) e o valor original também tiver um nítido.
FlipTack
fonte
1
Desculpe, apenas 0 e 1, Truthey & Falsey, ou T & B
FantaC
@tfbninja Obrigado pelo esclarecimento
FlipTack
2

Java 8, 119 bytes

n->b->(b?"C D E F G A B C# F F# A# C":"F G A B C D E F# A# C D# F").split(" ")["A B C D E F G A#C#D#F#G#".indexOf(n)/2]

Explicação:

Experimente aqui.

n->b->         // Method with String and boolean parameters and String return-type
  (b?          //  If it's Treble:
    "C D E F G A B C# F F# A# C"
               //   Use this String
   :           //  Else (it's Bass):
    "F G A B C D E F# A# C D# F")
               //   Use this String
  .split(" ")  //  Split this String by spaces,
   [           //  and then get the item at index:
    "A B C D E F G A#C#D#F#G#".indexOf(n)
               //   Get the index of the String on the left,
    /2]        //   and divide this by 2
               // End of method (implicit / single-line return-statement)
Kevin Cruijssen
fonte
1
outra solução com 99 bytes:n->b->((char)((n.charAt(0)-(b?0:4))%7+65)+n.substring(1)).replaceAll("B#","C").replaceAll("E#","F")
Nahuel Fouilleul 7/11
@NahuelFouilleul Ah nice! Eu estava realmente pensando em algo com um elenco de elenco e algum módulo poderia ser mais curto. Mas como é um pouco diferente da minha resposta atual, fique à vontade para publicá-la como uma resposta separada. Você tem o meu voto positivo, se tiver. :)
Kevin Cruijssen 7/11
0

R , 111 bytes

function(k,C,N=paste0(LETTERS[2:15%/%2],c("","#")))sub("E#","F",sub("B#","C",N[which(k==N[(4:17+6*C)%%14+1])]))

Experimente online!

Ungolfed:

function(k,C){
  N=paste0(LETTERS[2:15%/%2],c("","#")) # Generate a vector of the notes, including E# and B#
  M=N[(4:17+6*C)%%14+1])                # Create a copy that's cycled either up 4 or down 4
  P=N[which(k==M)]                      # Look up the input note in the complementary vector
  P=sub("B#","C",P)                     # Replace B# with C
  P=sub("E#","F",P)                     # Replace E# with F
}
user2390246
fonte