Яка частота цієї ноти?


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)без пробілів. Якщо вхід знаходиться за межами діапазону клавіатури (нижче А0 або вище С8), або є недійсні, відсутні або зайві символи, це вхід недійсний, і вам не потрібно його обробляти. Ви також можете з упевненістю припустити, що ви не отримаєте жодних дивних вкладів, таких як E # або Cb.

Точність

Оскільки нескінченна точність насправді неможлива, ми скажемо, що будь-що в межах одного цента від справжнього значення є прийнятним. Не вдаючись до зайвих деталей, цент - це 1200-й корінь з двох, або 1.0005777895. Скористаємося конкретним прикладом, щоб зробити це більш зрозумілим. Скажімо, ваш внесок був A4. Точне значення цього слід відзначити 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.

Майте на увазі, що вам не доведеться обробляти недійсні введення. Якщо ваша програма робить вигляд, що вони є реальними вхідними даними та виводить значення, це прийнятно. Якщо ваша програма виходить з ладу, це також прийнятно. Все, що може статися, коли ви отримаєте його. Повний список входів і виходів див. На цій сторінці

Як завжди, це код-гольф, тому застосовуються стандартні лазівки, і найкоротша відповідь у байтах виграє.


9
"H # 4 -> H - це не реальна примітка, недійсний ввід." За винятком Європи.
Луї

6
@Lui, що це за Європа, ніби ціла Європа використовує H? Hзначення B - AFAIK використовується лише в німецькомовних країнах. (де Bдо речі означає Bb.) Те, що британці та ірландці називають B, в Іспанії та Італії називають Si або Ti, як у Do Re Mi Fa Sol La Si.
Річка рівня Св.

3
Раніше я грав на B2 на артілі, це цілком розумна нота і зовсім не дивно.
Ніл

3
@steveverrill Hвикористовується в Німеччині, Чехії, Словаччині, Польщі, Угорщині, Сербії, Данії, Норвегії, Фінляндії, Естонії та Австрії, повідомляє Wikipedia . (Я також можу це підтвердити для Фінляндії самостійно.)
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!)

13
+ ¾ за використання ¾ :)
анатоліг

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 Japt , так що йому належить за це.

Пояснення

                                            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

Пояснення


Це цікаво. Як Pyth пакує рядки?
Луїс Мендо

@LuisMendo Інформацію про це можна знайти в документах . В основному, він знаходить найменшу базу для перетворення даних, а потім кодує результат у базі 256.
PurkkaKoodari

7

Математика, 77 байт

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

Пояснення :

Основна ідея цієї функції - перетворити рядок ноти у її відносну висоту, а потім обчислити її частоту.

Я використовую метод - експортувати звук до міді та імпортувати необроблені дані, але я підозрюю, що існує більш елегантний спосіб.


Тестові приклади :

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

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

Рубі, 69 65

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

Ungolfed в тестовій програмі

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

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виконувати тернар. Інші два завдання укладені в трійці, тому вони є особливим випадком.
користувач81655

@ user81655 Як e=fвсередині тернару ?
Ніл

Розглянемо a=b?c=d:e=f?g:h. Якщо вони будуть однаковим пріоритетом, а перший термінал закінчився =після e, це призведе до помилки присвоєння лівій ліві.
користувач81655

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

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 

1

Пітон, 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'для якогось порожнього чи іншого символу. Я використовую ітерабельне розпакування для розбору рядка примітки без умовних умов. Я зробив трохи алгебри в кінці, щоб спростити вираз перетворення. Не знаю, чи можу я скоротити її, не змінюючи підходу.


1
Я думаю, що b==['#']можна скоротити '#'in bі not bдо b>[].
Згарб

Приємні очки! Дякую моєму тестовому набору, дякую. Я думаю, що я можу вдосконалитись на тендерному майданчику в Python, спасибі.
Огадай

1

Мова Вольфрама (Mathematica), 69 байт

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

Використання музичного пакету , за допомогою якого просто введення ноти як виразу оцінює її частоту, наприклад:

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.