Corde per accordatura


9

Compito

Scrivi un programma per determinare la nota suonata, insieme a quanti centesimi non accordati, di una corda accordata su una data frequenza e premuta in un determinato punto.

Per semplicità, supponiamo che la frequenza del suono prodotto e la lunghezza della corda alla destra del punto in cui viene premuto siano inversamente proporzionali.

Nota: questo compito si occupa esclusivamente del tono fondamentale e non di sfumature / altre armoniche.

Ingresso

Al tuo programma vengono forniti due dati:

  • Una stringa di lunghezza arbitraria, che rappresenta la stringa in questione. Questa stringa verrà contrassegnata con una X in cui la stringa deve essere tenuta premuta.

    [-----] 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)
    

    Supponiamo che la nota venga suonata usando la parte della stringa alla destra di X.

  • Un numero (non necessariamente un numero intero), che indica la frequenza con cui viene sintonizzata la stringa. La precisione di questo numero sarà al massimo di quattro cifre oltre il decimale.

Si può presumere che le frequenze passate si trovino tra 10 Hze 40000 Hz.

L'input può essere passato in un formato a scelta. Si prega di specificare come l'ingresso è accettato nel programma nella risposta.

Produzione

Il tuo programma deve emettere sia la nota più vicina * nel sistema di accordatura a temperamento uguale a dodici toni, sia il numero di centesimi di distanza dalla nota più vicina che il suono indicato dalla stringa sarebbe (arrotondato al centesimo più vicino).

+ncentesimi dovrebbero essere usati per indicare i ncentesimi nitidi / sopra la nota e -ncentesimi per piatto / sotto la nota.

La nota dovrebbe essere emessa in notazione scientifica. Supponiamo che A4 sia sintonizzato su 440Hz. Usare b e # per note piatte / acute. Nota: è possibile utilizzare taglienti o piatti. Per la nota a 466.16Hz, o A#o Bbpuò essere emesso per la nota.

Il formato dell'output dipende da te, purché l'output contenga solo le due informazioni precedentemente specificate (ovvero non è consentito stampare ogni singolo output possibile).

* la nota più vicina si riferisce alla nota più vicina al suono indicato dall'ingresso, misurata nel numero di centesimi (quindi, la nota che si trova all'interno 50 centsdel suono). Se il suono è 50 centslontano da due note diverse (dopo l'arrotondamento), è possibile che venga emessa una delle due note.

Esempi

Il tuo programma dovrebbe funzionare per tutti i casi, non solo per i seguenti esempi.

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

* È possibile che sia stata emessa nitidezza o distorsione.

Link potenzialmente utili

Questo è quindi vince la risposta più breve.


Penso che i tuoi esempi siano in qualche modo incoerenti: secondo il primo [--X--]la stringa viene premuta nel mezzo della divisione in cui xè collocato, mentre l'ultimo [-X--]sarebbe a 3/8 (non 2/5) seguendo questa logica. O capisco qualcosa di sbagliato?
Flawr,

@flawr per l'ultimo [-X--], la stringa viene divisa in 4 punti (e quindi in 5 parti), e premuta nella seconda di queste divisioni. Pertanto, viene premuto 2/5e la lunghezza utilizzata è 3/5.
es1024,

Ah ok ora vedo, quindi ognuno in -pratica rappresenta la posizione delle divisioni, grazie per aver spiegato!
Flawr,

Risposte:


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'

Il punteggio esclude i commenti. Non ancora giocato a golf.

Produzione

Funziona correttamente su tutti i casi di test tranne quelli lunghi. Perché Eb9sembra che manchi un trattino dal test case: ce ne sono 22 -e uno X, che divide la stringa in 24 pezzi uguali. Secondo i miei calcoli manuali, questo è 9600Hz, che è 37 centesimi sopra un D9. Questo è esattamente ciò che il mio programma produce. Se aggiungo un altro trattino ottengo Eb9 + 8 centesimi. Sfortunatamente BBC Basic non è in grado di gestire stringhe di oltre 255 caratteri, quindi il Eb11caso dà un errore.

inserisci qui la descrizione dell'immagine


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

Riceve l'immagine ascii su una linea da sola e la frequenza su una linea separata.

Alcuni personaggi possono essere eliminati riducendo la precisione dei numeri magici 17.3123e 57.376.

Senza il golf, il programma è simile al seguente:

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
}

2
+1 per la fantastica scanfstringa di formato. Non avevo idea che tu potessi farlo. Verificherò più avanti il ​​tuo codice di output (ho pensato di farlo in C e sebbene qualcosa di simile mi sia venuto in mente per l'output, non riuscivo a vedere un modo per fare tutto in modo competitivo.) Presumo d+9sia perché sei indicizzato nota A, quindi devi adattare il numero di ottava all'indice della nota C: mi chiedo se c'è un modo per aggirare questo.
Level River St

Sì, il +9 compensa il fatto che le ottave iniziano in C. O è quello o sta facendo una correzione simile al calcolo del nome della nota. Per i nomi delle note, lo spostamento circolare potrebbe essere implementato da un LUT, ma mi piace il modo più "matematico" di calcolarli.
Anatolyg,

1

JavaScript (199)

Chiamalo ad es. Come 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)}

Fisso. (Dato che vivo in Europa ho usato B invece di Bb e H invece di B =)


Flawr, sei tedesco? Ho sempre pensato a B e H come una notazione tedesca, non una notazione europea. Regno Unito e Irlanda usano Bb e B. Spagna e Italia usano SIb e SI (come in DO RE MI FA SOL LA SI.). Comunque è solo un salvataggio di un personaggio.
Level River St

Sì, sono un paese di lingua tedesca, non ero a conoscenza del fatto che altri paesi europei usano quel sistema Doremi (ho sentito solo persone che lo usano nell'educazione dei bambini). Ad ogni modo è stato principalmente uno scherzo poiché, come hai detto, salva solo 1 carattere e non soddisfa veramente i requisiti =)
flawr

Questo sembra arrotondare il numero di centesimi in modo errato se il numero di centesimi è negativo (ad esempio, t('[---X--]',11.7103)(ultimo esempio) fornisce -10invece di-11
es1024

L'utilizzo p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)consente di risparmiare altri 2 caratteri.
Sean Latham,

@ es1024 Oh avrei dovuto saperlo: è perché ho implementato la funzione round con la round(x) = x+.5|0quale è corretta solo per i numeri positivi, lo aggiusterò in seguito. @ipi grazie!
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)))

Ungolfed:

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.")
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.