Какова частота этой заметки?

21

Быстрая музыкальная переподготовка:

Клавиатура фортепиано состоит из 88 нот. На каждую октаву есть 12 нот, C, C♯/D♭, D, D♯/E♭, E, F, F♯/G♭, G, G♯/A♭, A, A♯/B♭и B. Каждый раз, когда вы нажимаете «C», паттерн повторяется на октаву выше.

введите описание изображения здесь

Нота однозначно идентифицируется 1) буквой, включая любые острые или плоские элементы, и 2) октавой, которая является числом от 0 до 8. Первые три ноты клавиатуры, A0, A♯/B♭и B0. После этого наступает полная хроматическая шкала на октаву 1. C1, C♯1/D♭1, D1, D♯1/E♭1, E1, F1, F♯1/G♭1, G1, G♯1/A♭1, A1, A♯1/B♭1а B1. После этого идет полная хроматическая шкала на октавы 2, 3, 4, 5, 6 и 7. Затем последняя нота - это C8.

Каждая нота соответствует частоте в диапазоне 20–4100 Гц. С A0началом ровно 27.500 герц, каждая из которых соответствует нота предыдущих времен примечания двенадцатого корень из двух, или примерно 1.059463. Более общая формула:

введите описание изображения здесь

где n - номер банкноты, где A0 равно 1. (Более подробная информация здесь )

Соревнование

Напишите программу или функцию, которая принимает строку, представляющую заметку, и печатает или возвращает частоту этой заметки. Мы будем использовать знак фунта #для острого символа (или хэштегом для вас, юношей) и строчную букву bдля плоского символа. Все входные данные будут выглядеть (uppercase letter) + (optional sharp or flat) + (number)без пробелов. Если ввод находится за пределами диапазона клавиатуры (ниже, чем A0, или выше, чем C8), или имеются недопустимые, пропущенные или лишние символы, это недопустимый ввод, и вам не нужно обрабатывать его. Вы также можете с уверенностью предположить, что вы не получите никаких странных вводов, таких как E # или Cb.

точность

Поскольку бесконечная точность на самом деле невозможна, мы скажем, что все, что находится в пределах одного цента от истинного значения, является приемлемым. Не вдаваясь в лишние детали, цент - это 1200-й корень из двух, или 1.0005777895. Давайте использовать конкретный пример, чтобы сделать его более понятным. Допустим, ваш вклад был А4. Точное значение этого следует отметить 440 Гц. Однажды центовая квартира 440 / 1.0005777895 = 439.7459. 440 * 1.0005777895 = 440.2542Следовательно, если резкость цента , любое число, большее 439,7459, но меньшее 440,2542, является достаточно точным для подсчета.

Контрольные примеры

A0  --> 27.500
C4  --> 261.626
F#3 --> 184.997
Bb6 --> 1864.66
A#6 --> 1864.66
A4  --> 440
D9  --> Too high, invalid input.
G0  --> Too low, invalid input.
Fb5 --> Invalid input.
E   --> Missing octave, invalid input
b2  --> Lowercase, invalid input
H#4 --> H is not a real note, invalid input.

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

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

DJMcMayhem
источник
9
«H # 4 -> H не настоящая заметка, неверный ввод». Кроме в европе.
Луи
6
@Lui, что это за Европа, как если бы она использовалась всей Европой H? Hзначение B - AFAIK, используется только в немецкоязычных странах. (где B, кстати, означает Bb.) То, что британцы и ирландцы называют B, называется Si или Ti в Испании и Италии, как в Do Re Mi Fa Sol La Si.
Уровень Река Сент
3
Я уже играл на альте B♯2, это совершенно разумная нота и совсем не странно.
Нил
3
@steveverrill Hиспользуется в Германии, Чехии, Словакии, Польше, Венгрии, Сербии, Дании, Норвегии, Финляндии, Эстонии и Австрии, согласно Википедии . (Я также могу подтвердить это для Финляндии.)
PurkkaKoodari
6
@Neil Это было, вероятно, просто случайно. ;)
мензурка

Ответы:

21

Japt, 41 37 35 34 байта

У меня наконец-то появился шанс найти ¾хорошее применение! :-)

55*2pU¬®-1¾ª"C#D EF G A B"bZ /C} x

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

Как это устроено

          // Implicit: U = input string, C = 12
U¨    }  // Take U, split into chars, and map each item Z by this function:
-1¾       //  Subtract 1.75 from Z. This produces NaN for non-digits.
ª"..."bZ  //  If the result is falsy (NaN), instead return the index of Z in this string.
          //  C produces 0, D -> 2, E -> 4, F -> 5, G -> 7, A -> 9, B -> 11.
          //  # -> 1, and b -> -1, so we don't need to calculate them separately.
/C        //  Divide the index by 12.
x         // Sum.
2p        // Take 2 to the power of the result.
55*       // Multiply by 55.

Контрольные примеры

Все действительные тестовые случаи проходят через хорошо. Это недействительные, где это становится странным ...

input --> output       (program's reasoning)
A0  --> 27.5           (Yep, I can do that for you!)
C4  --> 261.625565...  (Yep, I can do that for you!)
F#3 --> 184.997211...  (Yep, I can do that for you!)
Bb6 --> 1864.6550...   (Yep, I can do that for you!)
A#6 --> 1864.6550...   (Yep, I can do that for you!)
A4  --> 440            (Yep, I can do that for you!)
D9  --> 9397.27257...  (Who says that's too high?)
G0  --> 24.49971...    (I've heard that note before.)
Fb5 --> 659.25511...   (Wait, Fb isn't supposed to be a note?)
E   --> 69.295657...   (I'm gonna guess that the missing octave is 1¾.)
b2  --> 61.735412...   (I assume that b means Cb...)
H#4 --> 261.625565...  (H# is C!)
ETHproductions
источник
13
+ ¾ за использование ¾ :)
anatolyg
1
Разве это не 38 байтов ?
Патрик Робертс
@PatrickRoberts Это 38 байтов в UTF-8, но Japt использует кодировку ISO-8859-1 , в которой каждый символ равен ровно одному байту.
ETHproductions
8

Pyth, 46 44 43 42 39 35 байт

*55^2tsm.xsdc-x"C D EF GbA#B"d9 12z

Попробуйте онлайн. Тестирование.

Код теперь использует алгоритм, аналогичный ответу Japt от ETHproductions , так что за это ему заслужили благодарность.

объяснение

                                            implicit: z = input
       m                          z         for each character in input:
          sd                                  try parsing as number
        .x                                    if that fails:
               "C D EF GbA#B"                   string "C D EF GbA#B"
              x              d                  find index of character in that
             -                9                 subtract 9
            c                   12              divide by 12
      s                                     sum results
     t                                      decrement
   ^2                                       get the correct power of 2
*55                                         multiply by 55 (frequency of A1)

Старая версия (42 байта, 39 с упакованной строкой)

*55^2+tsezc+-x"C D EF G A B"hz9-}\#z}\bz12

объяснение

PurkkaKoodari
источник
Это интересно. Как Pyth упаковывает строки?
Луис Мендо
@LuisMendo Вы можете найти информацию об этом в документации . По сути, он находит наименьшую базу для преобразования данных и затем кодирует результат в базе 256.
PurkkaKoodari
7

Mathematica, 77 байтов

2^((Import[".mid"~Export~Sound@SoundNote@#,"RawData"][[1,3,3,1]]-69)/12)440.&

Пояснение :

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

Я использую метод экспорта звука в MIDI и импорта необработанных данных, но я подозреваю, что есть более элегантный способ.


Тестовые случаи :

f=%; (* assign the function above to f *)
f["A4"]    (* 440.    *)
f["A5"]    (* 880.    *)
f["C#-1"]  (* 8.66196 *)
f["Fb4"]   (* 329.628 *)
f["E4"]    (* 329.628 *)
f["E"]     (* 329.628 *)
njpipeorgan
источник
2
Обычно мне грустно видеть встроенные Mathematica, которые тривиально решают проблемы, но на самом деле это довольно вдохновенный способ сделать это.
Роберт Фрейзер
4

MATL , 56 53 50 49 48 байтов

Hj1)'C D EF G A B'=f22-'#b'"G@m]-s+ 12/G0)U+^55*

Использует текущий выпуск (10.1.0) , который является более ранним, чем этот вызов.

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

объяснение

H                   % push 2
j1)                 % get input string. Take first character (note)
'C D EF G A B'=f    % find index of note: 1 for C, 3 for D...
22-                 % subtract 22. This number comes from three parts:
                    % 9; 1 for 0-based indexing; 12 to subtract 1 octave
'#b'"G@m]-s         % For loop. Gives 1 if input contains '#', -1 if 'b', 0 otherwise
+                   % add to previous number. Space needed to separate from next literal
12/                 % divide by 12
G0)                 % push input and get last character (octave)
U+                  % convert to number and add to previous number
^                   % raise 2 (that was initially pushed) to accumulated number 
55*                 % multiply by 55 (=27.5*2). Implicitly display
Луис Мендо
источник
3

JavaScript ES7, 73 70 69 байт

x=>[...x].map(c=>t+=c-1.75||"C#D EF G A B".search(c)/12,t=0)&&2**t*55

Использует ту же технику, что и мой ответ Япта .

ETHproductions
источник
3

Руби, 69 65

->n{2**((n.ord*13/8%12-n.size+(n=~/#/?7:5))/12.0+n[-1].to_i)*55/4}

Неуправляемый в тестовой программе

f=->n{
  2**(                    #raise 2 to the power of the following expression:
   (
     n.ord*13/8%12-       #note name C..B maps to number 0..11 calculated from the ascii code of n[0] 
     n.size+(n=~/#/?7:5)  #Correction for flat: length of n is 1 more for flat (or sharp) than for natural. Then apply correction for sharp
                          #now we have a number 3..14 for C..B (so 12 for A, will be a whole number when divided)
   )/12.0+                #divide by 12 to convert into a fraction of an octave

  n[-1].to_i              #add the octave number, last character in n
  )*                      #end of power expression, now we have A0=2,A1=4,A2=4 etc

  55/4                    #multiply to get correct frequency, this is shorter than 13.75 or 440/32                      
}

#complete octave test case
puts %w{A0 A#0 Bb0 B0 C1 C#1 Db1 D1 D#1 Eb1 E1 F1 F#1 Gb1 G1 G#1 Ab1 A1 A#1}.map{|e|[e,f[e]]}

#test case per OP
puts %w{A0 C4 F#3 Bb6 A#6}.map{|e|[e,f[e]]}

Выход

A0
27.5
A#0
29.13523509488062
Bb0
29.13523509488062
B0
30.867706328507758
C1
32.70319566257483
C#1
34.64782887210901
Db1
34.64782887210901
D1
36.70809598967595
D#1
38.890872965260115
Eb1
38.890872965260115
E1
41.20344461410875
F1
43.653528929125486
F#1
46.2493028389543
Gb1
46.2493028389543
G1
48.999429497718666
G#1
51.91308719749314
Ab1
51.91308719749314
A1
55.0
A#1
58.27047018976123
A0
27.5
C4
261.6255653005986
F#3
184.9972113558172
Bb6
1864.6550460723593
A#6
1864.6550460723593
Уровень реки St
источник
2

ES7, 82 байта

s=>55*2**(+s.slice(-1)+("C D EF G A B".search(s[0])+(s[1]<'0')-(s[1]>'9')-21)/12)

Возвращает 130.8127826502993 на входе «B # 2», как и ожидалось.

Редактировать: 3 байта сохранены благодаря @ user81655.

Нил
источник
@ user81655 2*3**3*2- 108 в консоли браузера Firefox, что соответствует 2*(3**3)*2. Также обратите внимание, что на этой странице также указано, что она ?:имеет более высокий приоритет, чем, =но на самом деле они имеют одинаковый приоритет (рассмотрим a=b?c=d:e=f).
Нил
Ах хорошо. Мой Firefox не имеет, **поэтому я никогда не смог проверить его. Я думаю, ?:что имеет более высокий приоритет, чем, =хотя, потому что в вашем примере aзадан результат троичного, а не bвыполнение троичного. Два других задания заключены в троицу, поэтому они представляют собой особый случай.
user81655
@ user81655 Как e=fвнутри троичного?
Нил
Посмотрим a=b?c=d:e=f?g:h. Если бы они имели одинаковый приоритет и первый троичный конец заканчивался =после e, это привело бы к недопустимой ошибке левого присваивания.
user81655
@ user81655 Но это также было бы проблемой, если бы ?:имело более высокий приоритет, чем в =любом случае. Выражение нужно сгруппировать так, как если бы оно было a=(b?c=d:(e=(f?g:h))). Вы не можете сделать это, если они не имеют одинакового приоритета.
Нил
2

C, 123 байта

float d(char*s){int n=*s++,m=(n*12+(n<67?90:6))/7,o=*s++,a=o^35?o^98?0:-1:1;return exp((m+(a?*s++:o)*12+a)/17.3123-37.12);}

Использование:

#include <stdio.h>
#include <math.h>

float d(char*s){int n=*s++,m=(n*12+(n<67?90:6))/7,o=*s++,a=o^35?o^98?0:-1:1;return exp((m+(a?*s++:o)*12+a)/17.3123-37.12);}

int main()
{
    printf("%f\n", d("A4"));
}

Расчетное значение всегда примерно на 0,8 цента меньше, чем точное значение, потому что я вырезал как можно больше цифр из чисел с плавающей запятой.

Обзор кода:

float d(char*s){
    int n=*s++,        // read the letter
        m=(n*12+       // multiply by 12/7 to convert from A...G to 0...11
        (n<67?90:6)    // if A or B, add 1 octave; also add some fix-up rounding value
        )/7,

        o=*s++,        // read next char: the octave digit or accidental

        a=o^35?o^98?0:-1:1; // if accidental, convert it into +1 or -1; else 0

        return exp((m+ // I adjusted the factors to use exp instead of pow
            (a?*s++:o) // if was accidental, now read the octave digit
            *12+a)/
            17.3123-   // a more exact value is 17.3123404447
            37.12);    // a more exact value is 37.1193996632
}
anatolyg
источник
1

R 157 150 141 136 байт

f=function(x){y=strsplit(x,"")[[1]];55*2^(as.double(y[nchar(x)])-1+(c(10,12,1,3,5,6,8)[LETTERS==y[1]]-switch(y[2],"#"=9,"b"=11,10))/12)}

С отступом и переводом строки:

f=function(x){
     y=strsplit(x,"")[[1]]
     55 * 2^(as.double(y[nchar(x)]) - 1 + 
         (c(10,12,1,3,5,6,8)[LETTERS==y[1]] - 
         switch(y[2],"#"=9,"b"=11,10))/12)
     }

Использование:

> f("A0")
[1] 27.5
> f("C8")
[1] 4186.009
> sapply(c("C4","Bb6","A#6","A4"),f)
       C4       Bb6       A#6        A4 
 261.6256 1864.6550 1864.6550  440.0000 
plannapus
источник
1

Python, 97 95 байт

def f(n):a,*b,c=n;return 2**(int(c)+('C@D@EF@G@A@B'.find(a)-(21,(22,20)['#'in b])[b>[]])/12)*55

Основанный на старом подходе Pietu1998 (и других) поиска индекса примечания в строке 'C@D@EF@G@A@B'для некоторого пустого символа или другого. Я использую итеративную распаковку для разбора строки заметки без условий. В конце я сделал немного алгебры, чтобы упростить выражение преобразования. Не знаю, смогу ли я сделать это короче без изменения моего подхода.

Ogaday
источник
1
Я думаю , b==['#']может быть сокращен до '#'in b, и not bв b>[].
Згарб
Хорошие очки! Работает на мой набор тестов, спасибо. Я думаю, что могу немного улучшить условия игры в Python, спасибо.
Огадай
1

Wolfram Language (Mathematica), 69 байт

ToExpression@("Music`"<>StringReplace[#,{"b"->"flat","#"->"sharp"}])&

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

 In[1]:= Eflat3
Out[1]:= 155.563

Для того, чтобы сохранить байты, избегая импортировать пакет с <<Music, я использую полные имена: Music`Eflat3. Тем не менее, я все еще должен заменить bна flatи #с, sharpчтобы соответствовать формату ввода вопроса, который я делаю с простым StringReplace.

vasilescur
источник