Strojenie strun

9

Zadanie

Napisz program, który określi, że zabrzmiała nuta, a także ile centów nie zostało dostrojone, struny dostrojonej do określonej częstotliwości i wciśniętej w danym punkcie.

Dla uproszczenia załóżmy, że częstotliwość wytwarzanego dźwięku i długość struny po prawej stronie od miejsca jej wciśnięcia są odwrotnie proporcjonalne.

Uwaga: to zadanie dotyczy wyłącznie tonu podstawowego, a nie podtonów / innych harmonicznych.

Wejście

Twój program otrzymuje dwie części danych:

  • Ciąg o dowolnej długości, reprezentujący dany ciąg. Łańcuch zostanie oznaczony znakiem X, w którym łańcuch będzie przytrzymywany.

    [-----] is a string divided in six sections (five divisions).
    [--X--] is a string pressed at the exact center of the string.
    [X----] is a string pressed at 1/6 the length of the string. (Length used is 5/6)
    [-X--] is a string pressed at 2/5 of the length of the string. (Length used is 3/5)
    

    Załóżmy, że nuta brzmi przy użyciu części struny po prawej stronie X.

  • Liczba (niekoniecznie liczba całkowita), oznaczająca częstotliwość, z jaką strojony jest ciąg. Dokładność tej liczby będzie wynosić co najwyżej cztery cyfry po przecinku.

Można założyć, że przekazywane częstotliwości będą znajdować się pomiędzy 10 Hzi 40000 Hz.

Dane wejściowe mogą być przekazywane w wybranym formacie. W odpowiedzi proszę określić, w jaki sposób dane wejściowe są akceptowane w twoim programie.

Wynik

Twój program musi wyprowadzać zarówno najbliższą nutę * w dwunastotonowym systemie strojenia o równym temperamencie, jak i liczbę centów od najbliższej nuty, jaką byłby dźwięk oznaczony przez strunę (zaokrąglony do najbliższego centa).

+ncentów należy używać do oznaczania ncentów ostrych / powyżej nuty, a -ncentów płaskich / poniżej nuty.

Notatka powinna być wyprowadzona w naukowym zapisie wysokości tonu. Załóżmy, że A4 jest dostrojony 440Hz. Użyj b i # dla płaskich / ostrych nut. Uwaga: Można użyć ostre lub płaskie. W przypadku nuty o 466.16Hzalbo A#albo Bbmoże być wyprowadzany dla nuty.

Format wydruku zależy od Ciebie, o ile wydruk zawiera tylko dwa uprzednio określone informacje (tzn. Drukowanie każdego możliwego wydruku jest niedozwolone).

* najbliższa nuta oznacza nutę najbliższą dźwiękowi oznaczonemu przez wejście, mierzoną liczbą centów (a więc nutą, która znajduje się w 50 centsdźwięku). Jeśli dźwięk jest 50 centsoddalony od dwóch różnych nut (po zaokrągleniu), może zostać wyprowadzona jedna z dwóch nut.

Przykłady

Twój program powinien działać we wszystkich przypadkach, a nie tylko w poniższych przykładach.

Output             Input Frequency   Input String
A4,  +0  cents     220               [-----X-----]
A5,  +0  cents     220               [--------X--]
D5,  -2  cents     440               [--X--------]
B4,  -49 cents     440               [X----------]
A#4, +19 cents*    314.1592          [X-]
Eb9, +8  cents*    400               [-----------------------X]
Eb11,+8  cents*    100               [--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------X]
D#1, +49 cents*    10                [--X]
A0,  -11 cents     11.7103           [---X--]

* Można było wyprowadzić ostry lub płaski.

Potencjalnie pomocne linki

To jest tak najkrótsza odpowiedź wygrywa.

es1024
źródło
Myślę, że twoje przykłady są nieco niespójne: zgodnie z pierwszym [--X--]sznurek jest wciśnięty w środku podziału, w którym xjest umieszczony, podczas gdy ostatni [-X--]byłby na 3/8 (nie 2/5), jeśli podążałby za tą logiką. Czy rozumiem coś złego?
flawr
@ flawr dla ostatniego, [-X--]ciąg jest podzielony w 4 miejscach (a zatem na 5 części) i wciśnięty w drugim z tych podziałów. W ten sposób jest wciśnięty 2/5, a zastosowana długość to 3/5.
es1024
Ach, ok, teraz rozumiem, więc każdy -zasadniczo przedstawia pozycję dywizji, dziękuję za wyjaśnienie!
flawr

Odpowiedzi:

1

BBC Basic, 161 #

  REM get frequency and string. Store length of string in n for later.
  INPUT f,s$
  n=LEN(s$)

  REM store floating-point value of note in semitones above (C0-0.5). Store integer value in n% (offset effectively means it will be rounded not truncated.)
  n=LN(f*(n-1)/(n-INSTR(s$,"X"))/15.8861)/LN(2)*12
  n%=n

  REM format printing to whole numbers only
  @%=2^17

  REM Output note name and octave. Output cents (discrepancy between n and n%, minus the offset of 0.5)
  PRINT MID$("C C#D D#E F F#G G#A A#B ",n%MOD12*2+1,2);INT(n/12)'(n-0.5-n%)*100'

Wynik nie uwzględnia komentarzy. Jeszcze nie grałem w golfa.

Wynik

Działa poprawnie na wszystkich przypadkach testowych z wyjątkiem dwóch długich. Dla Eb9Wydaje się, że jest jedna kreska brakuje z testu: Istnieje 22 -i jedną X, która dzieli ciąg na 24 równych części. Według moich ręcznych obliczeń jest to 9600 Hz, czyli 37 centów powyżej D9. Dokładnie to wyprowadza mój program. Jeśli dodam kolejną kreskę, dostanę Eb9 + 8 centów. Niestety BBC Basic nie może obsługiwać ciągów o długości przekraczającej 255 znaków, więc Eb11sprawa wyświetla błąd.

wprowadź opis zdjęcia tutaj

Level River St
źródło
3

C 179

main(n,d){float f;scanf("%*[^X]%nX%*[-]%n]%f",&n,&d,&f);f=log(f*d/(d-n))*17.3123-57.376;n=d=f+.5;n=n%12*7+784;printf("%c%d%c,%+2.0f cents\n",n/12,(d+9)/12,n%12/7*3+32,(f-d)*100);}

Odbiera sam obraz ascii na linii, a częstotliwość na osobnej linii.

Kilka postaci można upuścić, zmniejszając dokładność magicznych liczb 17.3123i 57.376.

Program bez gry w golfa wygląda następująco:

main(n,d)
{
    float f; // 'float' and '%f' better than 'double' and '%lf'

    scanf("%*[^X]%nX%*[-]%n]%f", &n, &d, &f);
    // n is the number of chars before 'X'
    // d is the number of chars before ']'
    // f is the frequency

    // Calculate the tuned frequency
    f = f * d / (d - n);

    // Convert the frequency to logarithmic scale, relative to pitch A0
    f=log(f)*17.3123-57.376;
    // alternatively: f = log2(f / (440 / 16)) * 12;

    // Round to nearest integer
    n=d=f+.5;

    // Calculate the note name ('A', 'B', etc), multipled by 12 for convenience
    n=n%12*7+784;

    printf("%c%d%c,%+2.0f cents\n", // output example: B4 ,-49 cents
        n/12,        // note name
        (d+9)/12,    // octave number
        n%12/7*3+32, // if n%12 is large enough, it's '#' else ' ' (natural)
        (f-d)*100);  // number of cents; stdio rounds it to integer
}
anatolig
źródło
2
+1 za niesamowity scanfciąg formatu. Nie miałem pojęcia, że ​​możesz to zrobić. Sprawdzę kod wyjściowy później (myślałem o zrobieniu tego w C i chociaż coś podobnego przyszło mi do głowy, nie mogłem znaleźć sposobu, aby zrobić to wszystko konkurencyjnie.) Zakładam, że d+9to dlatego, że jesteś zaindeksowany uwaga A, więc trzeba dostosować liczbę oktaw do indeksu w uwadze C: Zastanawiam się, czy jest na to jakiś sposób.
Level River St
Tak, +9 rekompensuje fakt, że oktawy zaczynają się od C. To albo to, albo wprowadzanie podobnej poprawki do obliczania nazwy nuty. W przypadku nazw nut przesunięcie kołowe może być realizowane przez LUT, ale podoba mi się bardziej „matematyczny” sposób ich obliczania.
anatolyg
1

JavaScript (199)

Nazwij to np. Jako t('[X-]',314.1592)

t=(s,f)=>{l=s.length-1;p='C C# D D# E F F# G G# A B H'.split(' ');n=12*Math.log2(f*l/(l-s.indexOf('X'))/16.3515978);m=n+.5|0;return p[m%12]+(n/12|0)+' '+((n-m)*100+.5|0)}

Naprawiony. (Ponieważ mieszkam w Europie, użyłem B zamiast Bb i H zamiast B =)

wada
źródło
Flawr, jesteś Niemcem? Zawsze uważałem B i H za notację niemiecką, a nie notację europejską. Wielka Brytania i Irlandia używają Bb i B. Hiszpania i Włochy używają SIb i SI (jak w DO RE MI FA SOL LA SI.). W każdym razie to tylko oszczędność jednej postaci.
Level River St
Tak, jestem z kraju niemieckojęzycznego, nie wiedziałem, że inne kraje europejskie używają tego systemu Doremi (słyszałem tylko, że ludzie używają go w edukacji dzieci). W każdym razie był to przede wszystkim żart, ponieważ, jak powiedziałeś, oszczędza tylko 1 znak i tak naprawdę nie spełnia wymagań =)
flawr
Wydaje się, że zaokrągla to liczbę centów niepoprawnie, jeśli liczba centów jest ujemna (na przykład t('[---X--]',11.7103)(ostatni przykład) daje -10zamiast-11
es1024,
Użycie p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)oszczędza dodatkowe 2 znaki.
Sean Latham
@ es1024 Och, powinienem był wiedzieć: ponieważ zaimplementowałem funkcję zaokrąglania, dzięki round(x) = x+.5|0której poprawne są tylko liczby dodatnie, naprawię to później. @ipi dzięki!
flawr
1

Python 3: 175

import math
def t(b,s):l=len(s)-1;n=12*math.log2(b*l/(l-s.index("X"))/16.35);m=round(n);return"%s%s%+d"%(("C C# D D# E F F# G G# A A# B".split()*99)[m],m//12,round(100*(n-m)))

Nie golfowany:

import math

c0 = 16.35

def tuning (base_frequency, string):
    return formatted (note_number (frequency (base_frequency, string)))

def formatted (note_number):
    return "{name}{octave:d}{cents:+d}".format (name=note_name (note_number),
                             octave=octave (note_number),
                             cents=cents_out (note_number))

def note_name (note_number):
    return ("C C# D D# E F F# G G# A A# B".split() * 99)[round (note_number)]

def note_number (frequency):
    return 12 * math.log2 (frequency / c0)

def octave (note_number):
    return round (note_number) // 12

def cents_out (note_number):
    return round (100 * (note_number - round (note_number)))

def frequency (base_frequency, string):
    string_length = len (string) - 1
    held_length = string_length - string.index ("X")
    return base_frequency * string_length / held_length

if "__main__" == __name__:

    print ("Testing functions against known values...")
    assert "A4+0"     == tuning (220,      "[-----X-----]")
    assert "A5+0"     == tuning (220,      "[--------X--]")
    assert "D5-2"     == tuning (440,      "[--X--------]")
    assert "B4-49"    == tuning (440,      "[X----------]")
    assert "A#4+19"   == tuning (314.1592, "[X-]")
    assert "D#9+8"    == tuning (400,      "[-----------------------X]")
    assert "D#11+8"   == tuning (100,      "[--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------X]")
    assert "D#1+49"   == tuning (10,       "[--X]")
    assert "A0-11"    == tuning (11.7103,  "[---X--]")
    print ("Tests passed.")
wszechstronny
źródło