Jaka jest częstotliwość tej notatki?

21

Szybkie odświeżanie muzyki:

Klawiatura fortepianowa składa się z 88 nut. W każdej oktawie jest 12 nut C, C♯/D♭, D, D♯/E♭, E, F, F♯/G♭, G, G♯/A♭, A, A♯/B♭i B. Za każdym razem, gdy naciśniesz „C”, wzór powtarza się o oktawę wyżej.

wprowadź opis zdjęcia tutaj

Nuta jest jednoznacznie identyfikowana przez 1) literę, w tym wszelkie ostre i płaskie, oraz 2) oktawę, która jest liczbą od 0 do 8. Pierwsze trzy nuty klawiatury to A0, A♯/B♭i B0. Potem pojawia się pełna skala chromatyczna na oktawie 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♭1i B1. Potem pojawia się pełna skala chromatyczna na oktawach 2, 3, 4, 5, 6 i 7. Następnie ostatnia nuta to C8.

Każda nuta odpowiada częstotliwości w zakresie 20–4100 Hz. Z A0rozpoczęciem dokładnie 27.500 herców, z których każda odpowiada nuta jest wcześniejsze czasy note dwunasty pierwiastek z dwóch, lub około 1.059463. Bardziej ogólna formuła to:

wprowadź opis zdjęcia tutaj

gdzie n jest numerem nuty, przy czym A0 to 1. (Więcej informacji tutaj )

Wyzwanie

Napisz program lub funkcję, która pobiera ciąg reprezentujący notatkę i wypisuje lub zwraca częstotliwość tej notatki. Użyjemy znaku funta #dla ostrego symbolu (lub hashtagu dla was młodych) i małych liter bdla płaskiego symbolu. Wszystkie dane wejściowe będą wyglądały jak (uppercase letter) + (optional sharp or flat) + (number)bez białych znaków. Jeśli dane wejściowe znajdują się poza zakresem klawiatury (niższe niż A0 lub wyższe niż C8) lub występują nieprawidłowe, brakujące lub dodatkowe znaki, jest to nieprawidłowe wejście i nie trzeba go obsługiwać. Możesz również bezpiecznie założyć, że nie otrzymasz żadnych dziwnych danych wejściowych, takich jak E # lub Cb.

Precyzja

Ponieważ nieskończona precyzja nie jest tak naprawdę możliwa, powiemy, że wszystko w granicach jednego centa prawdziwej wartości jest dopuszczalne. Bez wchodzenia w szczegóły, cent jest 1200-tym pierwiastkiem z dwóch lub 1.0005777895. Użyjmy konkretnego przykładu, aby był bardziej przejrzysty. Powiedzmy, że twój wkład to A4. Dokładna wartość tej noty wynosi 440 Hz. Kiedy cent jest płaski 440 / 1.0005777895 = 439.7459. Gdy więc cent jest ostry 440 * 1.0005777895 = 440.2542, każda liczba większa niż 439,7459, ale mniejsza niż 440,2542, jest wystarczająco precyzyjna, aby liczyć.

Przypadki testowe

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.

Pamiętaj, że nie musisz obsługiwać nieprawidłowych danych wejściowych. Jeśli twój program udaje, że są rzeczywistymi danymi wejściowymi i wypisuje wartość, jest to do przyjęcia. Jeśli Twój program ulegnie awarii, jest to również dopuszczalne. Wszystko może się zdarzyć, gdy je dostaniesz. Pełna lista wejść i wyjść znajduje się na tej stronie

Jak zwykle jest to gra w golfa, więc obowiązują standardowe luki i wygrywa najkrótsza odpowiedź w bajtach.

DJMcMayhem
źródło
9
„H # 4 -> H nie jest prawdziwą nutą, niepoprawne wejście”. Z wyjątkiem Europy.
Lui,
6
@Lui, co to takiego w Europie, jak w całej Europie H? Hco oznacza, że ​​B jest AFAIK używanym tylko w krajach niemieckojęzycznych. (gdzie przy okazji Boznacza Bb.) To, co Brytyjczycy i Irlandczycy nazywają B, nazywa się Si lub Ti w Hiszpanii i we Włoszech, jak w Do Re Mi Fa Sol La Si.
Level River St
3
Grałem wcześniej na altówce B♯2, jest to całkowicie rozsądna nuta i wcale nie dziwna.
Neil,
3
@steveverrill Hjest używany w Niemczech, Czechach, Słowacji, Polsce, na Węgrzech, w Serbii, Danii, Norwegii, Finlandii, Estonii i Austrii, zgodnie z Wikipedią . (Mogę to również potwierdzić dla Finlandii.)
PurkkaKoodari
6
@Neil To było prawdopodobnie tylko przypadkowe. ;)
zlewka

Odpowiedzi:

21

Japt, 41 37 35 34 bajtów

Nareszcie mam szansę ¾dobrze wykorzystać! :-)

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

Wypróbuj online!

Jak to działa

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

Przypadki testowe

Wszystkie ważne przypadki testowe przechodzą pomyślnie. To te nieprawidłowe, w których robi się dziwnie ...

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!)
ETHprodukcje
źródło
13
+ ¾ za użycie ¾ :)
anatolyg
1
Czy to nie jest tak naprawdę 38 bajtów ?
Patrick Roberts
@PatrickRoberts W UTF-8 jest to 38 bajtów, ale Japt używa kodowania ISO-8859-1 , w którym każdy znak ma dokładnie jeden bajt.
ETHprodukcje
8

Pyth, 46 44 43 42 39 35 bajtów

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

Wypróbuj online. Zestaw testowy.

Kod używa teraz algorytmu podobnego do odpowiedzi Japt ETHproductions , więc mu to podziękuj .

Wyjaśnienie

                                            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)

Stara wersja (42 bajty, 39 w / pakowany ciąg)

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

Wyjaśnienie

PurkkaKoodari
źródło
To jest interesujące. Jak Pyth pakuje ciągi?
Luis Mendo,
@LuisMendo Informacje na ten temat można znaleźć w dokumentacji . Zasadniczo znajduje najmniejszą bazę do konwersji danych, a następnie koduje wynik w podstawie 256.
PurkkaKoodari 20.01.2016
7

Mathematica, 77 bajtów

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

Objaśnienie :

Główną ideą tej funkcji jest konwersja ciągu nuty na jego względną wysokość, a następnie obliczenie jego częstotliwości.

Metodą, której używam, jest eksportowanie dźwięku do midi i importowanie surowych danych, ale podejrzewam, że istnieje bardziej elegancki sposób.


Przypadki testowe :

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
źródło
2
Zazwyczaj jestem smutny, widząc wbudowane Mathematica, które w prosty sposób rozwiązują problemy, ale w rzeczywistości jest to całkiem inspirujący sposób na zrobienie tego.
Robert Fraser
4

MATL , 56 53 50 49 48 bajtów

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

Wykorzystuje bieżącą wersję (10.1.0) , która jest wcześniejsza niż to wyzwanie.

Wypróbuj online !

Wyjaśnienie

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
Luis Mendo
źródło
3

JavaScript ES7, 73 70 69 bajtów

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

Używa tej samej techniki, co moja odpowiedź Japt .

ETHprodukcje
źródło
3

Ruby, 69 65

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

Niegolfowany w programie testowym

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

Wydajność

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
Level River St
źródło
2

ES7, 82 bajty

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

Zwraca 130,8127826502993 na wejściu „B # 2” zgodnie z oczekiwaniami.

Edycja: Zapisano 3 bajty dzięki @ user81655.

Neil
źródło
@ user81655 2*3**3*2ma 108 w konsoli przeglądarki Firefox, z którą się zgadza 2*(3**3)*2. Zauważ też, że ta strona mówi również, że ?:ma wyższy priorytet niż, =ale w rzeczywistości ma taki sam priorytet (rozważ a=b?c=d:e=f).
Neil,
Ach, okej Mój Firefox nie ma, **więc nigdy nie byłem w stanie go przetestować. Myślę, że ?:ma wyższy priorytet niż =dlatego, że w twoim przykładzie ajest ustawiony na wynik trójki, a nie bwykonanie trójki. Pozostałe dwa zadania są zawarte w trójce, więc są szczególnym przypadkiem.
user81655,
@ user81655 Jak działa e=ftrójskładnik?
Neil,
Zastanów się a=b?c=d:e=f?g:h. Gdyby miały taki sam priorytet, a pierwsza trójka zakończyła się =później e, spowodowałoby to nieprawidłowy błąd przypisania po lewej stronie.
user81655,
@ user81655 Ale byłby to również problem, gdyby ?:miał wyższy priorytet niż w =każdym razie. Wyrażenie musi być grupowane tak, jakby było a=(b?c=d:(e=(f?g:h))). Nie możesz tego zrobić, jeśli nie mają takiego samego pierwszeństwa.
Neil,
2

C, 123 bajty

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);}

Stosowanie:

#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"));
}

Obliczona wartość jest zawsze o około 0,8 centa mniejsza niż dokładna wartość, ponieważ wycinam jak najwięcej cyfr z liczb zmiennoprzecinkowych.

Przegląd kodu:

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
}
anatolig
źródło
1

R, 157 150 141 136 bajtów

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

Z wcięciami i znakami nowej linii:

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

Stosowanie:

> 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
źródło
1

Python, 97 95 bajtów

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

Oparty na starym podejściu Pietu1998 (i innych) polegającym na szukaniu indeksu nuty w łańcuchu 'C@D@EF@G@A@B'dla jakiegoś pustego znaku lub innego. Używam iterowalnego rozpakowywania, aby analizować ciąg nut bez warunków warunkowych. Zrobiłem trochę algebry na końcu, aby uprościć wyrażenie konwersji. Nie wiem, czy uda mi się to skrócić bez zmiany podejścia.

Ogaday
źródło
1
Myślę, że b==['#']można go skrócić '#'in bi not bdo b>[].
Zgarb,
Ładne punkty! Działa dla mojego zestawu testów, dzięki. Myślę, że mogę trochę poprawić grę w golfa w Pythonie, dzięki.
Ogaday
1

Wolfram Language (Mathematica), 69 bajtów

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

Korzystanie z pakietu muzycznego , za pomocą którego po prostu wprowadzenie nuty jako wyrażenia ocenia się na jej częstotliwość, w następujący sposób:

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

Aby zapisać bajtów poprzez unikanie zaimportować pakiet ze <<Musicużywam w pełni kwalifikowane nazwy: Music`Eflat3. Jednak, nadal mam do zastąpienia bz flati #ze sharpdopasować format wejściowy na pytanie, co zrobić z prostego StringReplace.

vasilescur
źródło