Cuerdas de afinación

9

Tarea

Escriba un programa para determinar la nota que suena, junto con cuántos centavos fuera de tono, de una cuerda sintonizada a una frecuencia dada y presionada hacia abajo en un punto dado.

En aras de la simplicidad, suponga que la frecuencia del sonido producido y la longitud de la cuerda a la derecha de donde se presiona son inversamente proporcionales.

Nota: esta tarea se ocupa únicamente del tono fundamental, y no con armónicos u otros armónicos.

Entrada

Su programa recibe dos datos:

  • Una cadena de longitud arbitraria, que representa la cadena en cuestión. Esta cadena se marcará con una X donde la cadena se mantendrá presionada.

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

    Suponga que la nota suena usando la parte de la cadena a la derecha de X.

  • Un número (no necesariamente un número entero), que significa la frecuencia con la que se afina la cadena. La precisión de este número será como máximo cuatro dígitos más allá del decimal.

Se puede suponer que las frecuencias pasadas se ubicarán entre 10 Hzy 40000 Hz.

La entrada se puede pasar en un formato de su elección. Especifique cómo se acepta la entrada en su programa en su respuesta.

Salida

Su programa debe emitir tanto la nota más cercana * en el sistema de afinación de temperamento igual de doce tonos como el número de centavos de distancia de la nota más cercana que el sonido denotado por la cuerda sería (redondeado al centavo más cercano).

+nlos centavos se deben usar para denotar ncentavos agudos / por encima de la nota, y -ncentavos para los planos / debajo de la nota.

La nota debe salir en notación científica de tono. Suponga que A4 está sintonizado 440Hz. Use by # para notas planas / agudas. Nota: Se puede usar bien filoso o plano. Para la nota al 466.16Hz, ya sea A#o Bbpuede ser emitida por la nota.

El formato de salida depende de usted, siempre que la salida contenga solo las dos piezas de información previamente especificadas (es decir, no se permite imprimir todas las salidas posibles).

* la nota más cercana se refiere a la nota más cercana al sonido denotado por la entrada, medida en el número de centavos (por lo tanto, la nota que está dentro 50 centsdel sonido). Si el sonido está 50 centsalejado de dos notas diferentes (después del redondeo), se puede emitir cualquiera de las dos notas.

Ejemplos

Su programa debería funcionar para todos los casos, no solo para los siguientes ejemplos.

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

* Ya sea afilado o plano podría haber salido.

Enlaces potencialmente útiles

Este es el por lo que gana la respuesta más corta.

es1024
fuente
Creo que sus ejemplos son algo inconsistentes: según el primero, [--X--]la cadena se presiona en el medio de la división donde xse coloca, mientras que el último [-X--]estaría en 3/8 (no 2/5) cuando se sigue esta lógica. ¿O entiendo algo mal?
flawr
@flawr para el último [-X--], la cadena se divide en 4 lugares (y, por lo tanto, en 5 partes), y se presiona en la segunda de estas divisiones. Por lo tanto, se presiona en 2/5, y la longitud utilizada es 3/5.
es1024
Ah, ok, ya veo, así que cada uno -básicamente representa la posición de las divisiones, ¡gracias por explicarlo!
flawr

Respuestas:

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'

La puntuación excluye los comentarios. No golf todavía.

Salida

Funciona correctamente en todos los casos de prueba, excepto los dos largos. Por Eb9lo que parece hay un guión que falta en el caso de prueba: Hay 22 -y uno X, que divide la cadena en 24 partes iguales. Según mis cálculos manuales, esto es 9600Hz, que es 37 centavos por encima de un D9. Esto es exactamente lo que produce mi programa. Si agrego otro guión obtengo Eb9 + 8 centavos. Desafortunadamente, BBC Basic no puede manejar cadenas de más de 255 caracteres, por lo que el Eb11caso da un error.

ingrese la descripción de la imagen aquí

Level River St
fuente
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);}

Recibe la imagen ascii en una línea por sí misma y la frecuencia en una línea separada.

Se pueden soltar algunos caracteres reduciendo la precisión de los números mágicos 17.3123y 57.376.

Sin el golf, el programa se ve así:

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
}
anatolyg
fuente
2
+1 para la scanfcadena de formato impresionante . No tenía idea de que pudieras hacer eso. Veré su código de salida más tarde (pensé en hacer esto en C y aunque se me ocurrió algo similar para la salida, no pude ver una manera de hacer todo de manera competitiva). Supongo que d+9es porque está indexado en nota A, por lo que debe ajustar el número de octava al índice en la nota C: Me pregunto si hay alguna forma de evitarlo.
Level River St
Sí, el +9 compensa el hecho de que las octavas comienzan en C. Es eso o hacer una solución similar al cálculo del nombre de la nota. Para los nombres de las notas, el LUT podría implementar el desplazamiento circular, pero me gusta la forma más "matemática" de calcularlos.
anatolyg
1

JavaScript (199)

Llámalo, por ejemplo, como 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)}

Fijo. (Como vivo en Europa, usé B en lugar de Bb y H en lugar de B =)

falla
fuente
Flawr, ¿eres alemán? Siempre pensé en B y H como una notación alemana, no una notación europea. El Reino Unido e Irlanda usan Bb y B. España e Italia usan SIb y SI (como en DO RE MI FA SOL LA SI.). De todos modos, solo se trata de salvar a un personaje.
Level River St
Sí, soy un país de habla alemana, no sabía que otros países europeos usan ese sistema Doremi (solo escuché que la gente lo usa en la educación infantil). De todos modos, fue principalmente una broma, ya que, como dijiste, solo ahorra 1 personaje y realmente no cumple los requisitos =)
error
Esto parece redondear incorrectamente el número de centavos si el número de centavos es negativo (por ejemplo, t('[---X--]',11.7103)(último ejemplo) da en -10lugar de-11
es1024
El uso le p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)ahorra 2 caracteres adicionales.
Sean Latham
@ es1024 Oh, debería haberlo sabido: es porque implementé la función redonda por la round(x) = x+.5|0cual solo es correcta para números positivos, lo arreglaré más tarde. @ipi gracias!
flawr
1

Pitón 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)))

Sin golf:

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.")
competitivo
fuente