Wie häufig ist diese Note?

21

Schnelle musikalische Auffrischung:

Die Klaviertastatur besteht aus 88 Noten. Zu jeder Oktave gibt es 12 Töne C, C♯/D♭, D, D♯/E♭, E, F, F♯/G♭, G, G♯/A♭, A, A♯/B♭und B. Jedes Mal, wenn Sie ein 'C' drücken, wird das Pattern eine Oktave höher wiederholt.

Bildbeschreibung hier eingeben

Eine Note wird eindeutig identifiziert durch 1) den Buchstaben, einschließlich aller scharfen oder flachen Stellen, und 2) die Oktave, die eine Zahl von 0 bis 8 ist. Die ersten drei Noten der Tastatur sind A0, A♯/B♭und B0. Danach folgt die volle chromatische Skala auf Oktave 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♭1und B1. Danach folgt eine volle chromatische Tonleiter auf den Oktaven 2, 3, 4, 5, 6 und 7. Dann ist die letzte Note a C8.

Jede Note entspricht einer Frequenz im Bereich von 20-4100 Hz. Mit A0genau 27.500 Hertz ist jede entsprechende Note die vorherige Note mal die zwölfte Wurzel von zwei oder ungefähr 1,059463. Eine allgemeinere Formel lautet:

Bildbeschreibung hier eingeben

Dabei ist n die Nummer der Note, wobei A0 1 ist. (Weitere Informationen hier )

Die Herausforderung

Schreiben Sie ein Programm oder eine Funktion, die eine Zeichenfolge für eine Note aufnimmt und die Häufigkeit dieser Note ausgibt oder zurückgibt. Wir verwenden ein #Pfundzeichen für das scharfe Symbol (oder ein Hashtag für Ihre Youngins) und ein Kleinbuchstaben bfür das flache Symbol. Alle Eingaben werden (uppercase letter) + (optional sharp or flat) + (number)ohne Leerzeichen aussehen . Wenn die Eingabe außerhalb des Tastaturbereichs liegt (niedriger als A0 oder höher als C8) oder ungültige, fehlende oder zusätzliche Zeichen vorhanden sind, handelt es sich um eine ungültige Eingabe, die Sie nicht verarbeiten müssen. Sie können auch davon ausgehen, dass Sie keine seltsamen Eingaben wie E # oder Cb erhalten.

Präzision

Da unendliche Präzision nicht wirklich möglich ist, werden wir sagen, dass alles innerhalb eines Cent des wahren Wertes akzeptabel ist. Ohne ins Detail zu gehen, ist ein Cent die 1200. Wurzel von zwei oder 1.0005777895. Lassen Sie uns ein konkretes Beispiel verwenden, um es klarer zu machen. Angenommen, Ihre Eingabe war A4. Der genaue Wert dieser Note beträgt 440 Hz. Einmal Cent Flat ist 440 / 1.0005777895 = 439.7459. Sobald Cent 440 * 1.0005777895 = 440.2542Sharp ist, ist jede Zahl größer als 439,7459, aber kleiner als 440,2542 genau genug, um zu zählen.

Testfälle

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.

Denken Sie daran, dass Sie nicht mit ungültigen Eingaben umgehen müssen. Wenn Ihr Programm vorgibt, echte Eingaben zu sein, und einen Wert ausgibt, ist dies akzeptabel. Wenn dein Programm abstürzt, ist das auch akzeptabel. Alles kann passieren, wenn du eins bekommst. Eine vollständige Liste der Ein- und Ausgänge finden Sie auf dieser Seite

Wie üblich ist dies Codegolf, so dass Standardlücken gelten und die kürzeste Antwort in Bytes gewinnt.

DJMcMayhem
quelle
9
"H # 4 -> H ist keine echte Note, ungültige Eingabe." Außer in Europa.
Lui
6
@Lui was ist das mit Europa, als ob es ganz Europa nutzt H? HBedeutung B ist AFAIK nur im deutschsprachigen Raum verwendet. (Wo Bübrigens Bb bedeutet.) Was die Briten und Iren B nennen, heißt in Spanien und Italien Si oder Ti, wie in Do Re Mi Fa Sol La Si.
Level River St
3
Ich habe schon einmal eine B♯2 auf einer Bratsche gespielt, es ist eine absolut vernünftige Note und überhaupt nicht komisch.
Neil
3
@steveverrill Hwird laut Wikipedia in Deutschland, Tschechien, der Slowakei, Polen, Ungarn, Serbien, Dänemark, Norwegen, Finnland, Estland und Österreich verwendet . (Ich kann es auch für Finnland selbst bestätigen.)
PurkkaKoodari
6
@Neil Es war wohl nur ein Zufall. ;)
Becher

Antworten:

21

Japt, 41 37 35 34 Bytes

Ich habe endlich die Chance, es ¾gut zu gebrauchen! :-)

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

Probieren Sie es online!

Wie es funktioniert

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

Testfälle

Alle gültigen Testfälle kommen gut durch. Es sind die Invaliden, bei denen es komisch wird ...

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
quelle
13
+ ¾ für die Verwendung von ¾ :)
Anatolyg
1
Sind das nicht tatsächlich 38 Bytes ?
Patrick Roberts
@PatrickRoberts Dies sind 38 Byte in UTF-8, aber Japt verwendet die ISO-8859-1-Codierung , bei der jedes Zeichen genau ein Byte enthält.
ETHproductions
8

Pyth, 46 44 43 42 39 35 Bytes

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

Probieren Sie es online aus. Testsuite.

Der Code verwendet jetzt einen ähnlichen Algorithmus wie die Japt-Antwort von ETHproductions .

Erläuterung

                                            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)

Alte Version (42 Bytes, 39 mit gepacktem String)

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

Erläuterung

PurkkaKoodari
quelle
Das ist interessant. Wie packt Pyth Strings?
Luis Mendo
@LuisMendo Informationen dazu finden Sie in den Dokumenten . Grundsätzlich findet es die kleinste Basis, in die die Daten konvertiert werden sollen, und codiert das Ergebnis dann in Basis 256.
PurkkaKoodari,
7

Mathematica, 77 Bytes

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

Erklärung :

Die Hauptidee dieser Funktion besteht darin, die Notenfolge in ihre relative Tonhöhe umzuwandeln und dann ihre Frequenz zu berechnen.

Die Methode, die ich benutze, ist das Exportieren des Sounds nach Midi und das Importieren der Rohdaten, aber ich vermute, dass es einen eleganteren Weg gibt.


Testfälle :

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
quelle
2
Normalerweise bin ich traurig, Mathematica-Buildins zu sehen, die Probleme trivial lösen, aber dies ist eigentlich eine ziemlich inspirierte Art und Weise, dies zu tun.
Robert Fraser
4

MATL , 56 53 50 49 48 Bytes

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

Verwendet die aktuelle Version (10.1.0) , die älter als diese Herausforderung ist.

Probieren Sie es online !

Erläuterung

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
quelle
3

JavaScript ES7, 73 70 69 Bytes

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

Verwendet die gleiche Technik wie meine Japt-Antwort .

ETHproductions
quelle
3

Ruby, 69 65

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

Ungolfed im Testprogramm

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

Ausgabe

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
quelle
2

ES7, 82 Bytes

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

Gibt bei Eingabe von "B # 2" wie erwartet 130.8127826502993 zurück.

Bearbeiten: 3 Bytes dank @ user81655 gespeichert.

Neil
quelle
@ user81655 2*3**3*2ist 108 in der Firefox-Browserkonsole, was dem entspricht 2*(3**3)*2. Beachten Sie auch, dass diese Seite auch besagt, dass sie ?:eine höhere Priorität hat als, =aber tatsächlich die gleiche Priorität haben (beachten Sie a=b?c=d:e=f).
Neil
Ach ja ok Mein Firefox hat es nicht, **daher konnte ich es noch nie testen. Ich denke, ?:hat eine höhere Priorität, als =wenn, weil in Ihrem Beispiel aauf das Ergebnis des Ternärs festgelegt ist, anstatt bdann das Ternär auszuführen. Die anderen beiden Aufgaben sind im Ternär enthalten, daher handelt es sich um einen Sonderfall.
user81655
@ user81655 Wie ist es e=fim Ternary ?
Neil
Überlegen Sie a=b?c=d:e=f?g:h. Wenn sie die gleiche Priorität und die erste ternären am Ende gegangene =nach ewäre es einen ungültigen linken Zuordnungsfehler verursachen.
user81655
@ user81655 Das wäre aber auch ein Problem, wenn ?:höher priorisiert wäre als =ohnehin. Der Ausdruck muss gruppiert werden, als ob es war a=(b?c=d:(e=(f?g:h))). Sie können das nicht tun, wenn sie nicht die gleiche Priorität haben.
Neil
2

C, 123 Bytes

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

Verwendung:

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

Der berechnete Wert liegt immer um ca. 0,8 Cent unter dem exakten Wert, da ich aus den Gleitkommazahlen so viele Ziffern wie möglich ausgeschnitten habe.

Übersicht über den Code:

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
quelle
1

R, 157 150 141 136 Bytes

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

Mit Einzug und Zeilenumbrüchen:

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

Verwendung:

> 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
quelle
1

Python, 97 bis 95 Bytes

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

Basierend auf dem alten Ansatz von Pietu1998 (und anderen), nach dem Index der Note in der Zeichenfolge 'C@D@EF@G@A@B'für ein Leerzeichen zu suchen . Ich benutze iterables Auspacken, um den Notenstring ohne Bedingungen zu analysieren. Am Ende habe ich ein bisschen Algebra gemacht, um den Konvertierungsausdruck zu vereinfachen. Ich weiß nicht, ob ich es kürzer machen kann, ohne meinen Ansatz zu ändern.

Ogaday
quelle
1
Ich denke , b==['#']verkürzt werden könnte '#'in b, und not bzu b>[].
Zgarb
Schöne Punkte! Funktioniert für meine Testsuite, danke. Ich denke, ich kann das Golfspielen in Python ein bisschen verbessern, danke.
Ogaday
1

Wolfram Language (Mathematica), 69 Bytes

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

Wenn Sie das Musikpaket verwenden , bei dem Sie einfach eine Note als Ausdruck eingeben, wird die Häufigkeit folgendermaßen bewertet:

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

So speichern Bytes durch die Vermeidung des Pakets mit importieren <<Music, ich bin die vollqualifizierten Namen verwenden: Music`Eflat3. Allerdings muss ich immer noch bmit flatund #mit ersetzen sharp, um dem Eingabeformat der Frage zu entsprechen, was ich mit einem einfachen mache StringReplace.

Vasilescur
quelle