Конвертировать между музыкальными ключами


12

Прежде чем уйти, вам не нужно разбираться в музыкальной нотации, чтобы выполнить этот вызов.

ОБЪЯСНЕНИЕ

В стандартных нотах двойные ключи переходят по странице, служа ориентирами к нотам, давая вам понять, какую ноту следует сыграть. Если вы еще не знакомы со скрипичным и басовым ключом, вот описание из Википедии:

Ключ - это музыкальный символ, используемый для обозначения высоты звука записанных нот. Помещенный в одну из строк в начале нотного стана, он указывает название и высоту нот в этой строке. Эта линия служит контрольной точкой, по которой могут быть определены имена нот на любой другой линии или в пространстве нотного стана.

Ноты

На изображении выше верхняя половина строк - это скрипичный ключ, обозначенный Скрипичный ключ

Нижняя половина - это басовый ключ, обозначенный Басовый ключ

Как вы можете видеть на скрипичный ключ запиской на самой нижней строке является E . (Я не считая нот за пределами CLEF линий для этой задачи) На бас - ключах, самая низкая линия является G . Чтобы выполнить эту задачу, вы должны сделать следующее:

ВЫЗОВ

Учитывая вход в одной из следующих форм (ваш выбор), преобразовать его в противоположный ключ. Является ли это скрипичным или басовым ключом, может быть значением Truthey / Falsey в вашем языке (а не просто любыми двумя значениями), например

F # T или F # True или F # Treble

но нет

F # -1 или F # 4

Пробелы и заглавные буквы являются необязательными. Квартиры не отображаются, а завершающие пробелы запрещены.

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#

Будьте предупреждены, это не тривиальная задача постоянной разницы. Посмотрите внимательно на входы и выходы. Если вы посмотрите на пианино,

пиано

черные клавиши - острые, обозначенные #. Обратите внимание, что нет E # или B #. Это означает, что если вы получили G # на басовом ключе, вместо того, чтобы возвращать E # , вам нужно вернуть F

Это , поэтому выигрывает самый маленький счетчик байтов.


1
Должны ли мы беспокоиться о квартирах? Как насчет двойных квартир / острых предметов?
mypetlion

1
Пожалуйста, не создавайте теги для тем, которые не оправдывают их.
Джонатан Аллан

3
Конечный пробел (возвращается C вместо C) хорошо?
Линн

2
Разрешено ли использовать 1и -1(или даже сказать, 4и -4) для ввода индикатора clef, или это будет приемлемо только в том случае, если в нашем языке это значения true / falsey?
Джонатан Аллан

1
Это хорошая и хорошо представленная задача, но она была бы еще лучше для ИМО с немного смягченными форматами ввода / вывода.
Арно

Ответы:


5

Желе ,  35  34 байта

У меня есть ощущение, что какая-то арифметика может победить этот метод.

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

Попробуйте онлайн!

Полная программа, состоящая из 1) индикатора ключа 0или 1для низких или высоких частот соответственно и 2) ноты; и печать полученной заметки.

Было бы 31 байт, если бы -4и 4были приемлемы в качестве входных значений индикатора clef (тогда они Ñi+_⁸?4ị¢могут стать Ñi+⁸ị¢), но это было уточнено как недопустимое, если -4 не является ложным, а 4 является правдивым, что не относится к Jelly.

Как?

Создает клавиатуру с фантомом B#и E#клавишами, находит индекс ввода, смещает его 4в нужном направлении, индексирует обратно в клавиатуру, и эти фантомные клавиши заменяются требуемыми результатами (клавиша над ними):

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

Зеленая проверка: Хм, так что никто еще не побил этот счет - я довольно шокирован.
Джонатан Аллан

9

Befunge, 70 64 байта

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

Попробуйте онлайн!

Ввод должен быть в форме C# Trebleили F Bass, хотя ключ может быть просто первой буквой (т. Е. TИли B), так как остальная часть ввода в любом случае игнорируется.

объяснение

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

В результате этой модификации кода следующая последовательность инструкций примет одну из двух форм:

##~       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.

На этом этапе стек либо содержит, note,0,sharp,spaceлибо 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.

На этом этапе стек либо содержит, note,0либо просто note(с неявным нулем ниже).

+         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 '#'.


3

JavaScript (ES6) 74 байта

Принимает входной сигнал в выделки синтаксиса , (note)(clef)где clefесть 0для баса и 1для высоких частот .

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

демонстрация

Как?

На самом деле это немного менее забавно, чем в моей предыдущей версии, но базовая таблица поиска теперь F#,C#,(unused),D#,A#,F,C,G,D,A,E,B,Fпозволяет сократить условие # , избегая при этом трюка с символами NUL - который, я полагаю, был немного пограничным.


Предыдущая версия 76 75 байт

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

демонстрация

Как?

Ввод (n, c) обрабатывается посредством следующих шагов:

  1. Мы первые оценки , 4 * !!n[1] + c + nгде !!n[1]это верно (принуждаем к 1 ) , если ноте содержит # , и ЛОЖЬ (принуждение к 0 ) в противном случае. Выражение 4 * !!n[1] + cприводит к числовому значению, которое добавляется перед строкой n .

  2. Неявный шаг: начальные нули и конечный # игнорируются parseInt(). Например, "5G#"фактически анализируется как "5G".

  3. Мы конвертируем новую строку в десятичное значение, анализируя ее как величину base-21.

  4. Мы применяем по модулю 24.

  5. Мы применяем по модулю 17.

Ниже приводится сводная таблица для всех возможных входных пар, а также ожидаемый результат. Обратите внимание, что # должен быть добавлен к выводу, если конечный результат 0 , 2 , 3 или 5 . Отсюда использование двоичной маски 101101 ( 45 в десятичной).

 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"

3

Python 2 , 77 байт

Функция, которая печатает в STDOUT. Trueпреобразует низкие и высокие частоты, а Falseвысокие - в низкие

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]

Попробуйте онлайн!

Объяснение:

  • Первая инструкция, N=ord(n[0])-63-4*c;вычисляет индекс (от 0 до 7) буквы новой заметки, не обращая внимания на острые предметы.
    • ord(N[0])-63-4*cполучает индекс текущей буквы и добавляет или вычитает 2 в зависимости от значения c(переменная для переключения направления преобразования)
  • Следующий оператор M=-~N%3<1<len(n);вычисляет, нужно ли корректировать эту переменную. Например, если новая заметка есть E, а исходная заметка имела резкую, это нужно будет скорректировать до F. Цепное неравенство работает следующим образом:
    • -~N%3<1проверяет, находится ли индекс новой заметки в последовательности 3n-1. Это будет только выход верно для Eи B, две ноты , которые не имеют резкий.
    • 1<len(n)проверяет, имел ли резкое примечание оригинал (это сделало бы длину строки больше чем 1). Это необходимо, поскольку, если не было резких, нет необходимости корректировать новые буквы заметки.
    • Это устанавливает значение Mлибо Trueлибо False, либо , что может использоваться в вычислениях как 1и 0соответственно, поэтому для выполнения корректировки нам нужно только добавить M к N и по модулю 7.
  • Последний оператор создает и выводит конечный результат.
    • chr((N+M)%7+65) добавляет корректировку, если необходимо, затем преобразует значение из индекса обратно в символ.
    • +n[1:2-M]добавит резкий символ, если оба M=0(без регулировки) и исходное значение также имели резкий.

1
Извините, только 0 & 1, Truthey & Falsey или T & B
FantaC

@tfbninja спасибо за разъяснения
FlipTack

2

Java 8, 119 байт

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]

Объяснение:

Попробуй это здесь.

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)

1
другое решение с 99 байтами:n->b->((char)((n.charAt(0)-(b?0:4))%7+65)+n.substring(1)).replaceAll("B#","C").replaceAll("E#","F")
Nahuel Fouilleul

@NahuelFouilleul Ах, хорошо! Я действительно думал о чём-то, и по модулю короче. Но так как он немного отличается от моего текущего ответа, не стесняйтесь публиковать его как отдельный ответ. У вас есть мой голос, если вы делаете. :)
Кевин Круйссен

0

R 111 байтов

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

Попробуйте онлайн!

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
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.