Tuning Strings

9

Tarefa

Escreva um programa para determinar a nota tocada, além de quantos centavos desafinados, de uma corda afinada para uma determinada frequência e pressionada em um determinado ponto.

Por uma questão de simplicidade, suponha que a frequência do som produzido e o comprimento da corda à direita de onde ele é pressionado sejam inversamente proporcionais.

Nota: esta tarefa lida apenas com o tom fundamental, e não com sobretons / outros harmônicos.

Entrada

Seu programa recebe dois dados:

  • Uma sequência de comprimento arbitrário, representando a sequência em questão. Essa sequência será marcada com um X onde a sequência deve ser mantida pressionada.

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

    Suponha que a nota seja tocada usando a parte da corda à direita da X.

  • Um número (não necessariamente um número inteiro), significando a frequência na qual a sequência é sintonizada. A precisão desse número terá no máximo quatro dígitos após o decimal.

Pode-se supor que as frequências passadas estarão entre 10 Hze 40000 Hz.

A entrada pode ser transmitida no formato de sua escolha. Especifique como a entrada é aceita em seu programa em sua resposta.

Resultado

Seu programa deve emitir a nota mais próxima * no sistema de ajuste de temperamento com doze tons e o número de centavos da nota mais próxima que o som indicado pela corda seria (arredondado para o centavo mais próximo).

+ncentavos devem ser usados ​​para indicar ncentavos afiados / acima da nota e -ncentavos para flat / abaixo da nota.

A nota deve ser impressa em notação científica. Suponha que A4 esteja sintonizado 440Hz. Use be # para obter notas agudas / nítidas. Nota: Pode ser afiada ou plana. Para a nota em 466.16Hz, uma A#ou Bbpode ser emitida para a nota.

O formato da saída depende de você, desde que a saída contenha apenas as duas informações especificadas anteriormente (por exemplo, imprimir todas as saídas possíveis não é permitido).

* nota mais próxima refere-se à nota mais próxima do som indicado pela entrada, medido no número de centavos (portanto, a nota que está dentro 50 centsdo som). Se o som estiver 50 centslonge de duas notas diferentes (após o arredondamento), qualquer uma das duas notas poderá ser emitida.

Exemplos

Seu programa deve funcionar para todos os casos, não apenas para os seguintes exemplos.

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

* Afiado ou achatado, poderia ter sido produzido.

Links potencialmente úteis

Este é o isso a resposta mais curta vence.

es1024
fonte
Eu acho que seus exemplos são um tanto inconsistentes: de acordo com o primeiro, [--X--]a corda é pressionada no meio da divisão em que o local xé colocado, enquanto a última [-X--]seria em 3/8 (não em 2/5) ao seguir essa lógica. Ou entendo algo errado?
flawr
@flawr para o último [-X--], a sequência é dividida em 4 lugares (e, portanto, em 5 partes) e pressionada na segunda dessas divisões. Assim, é pressionado em 2/5e o comprimento usado é 3/5.
es1024
Ah, ok agora eu entendo, então cada uma -representa basicamente a posição das divisões, obrigado por explicar!
flawr

Respostas:

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'

A pontuação exclui comentários. Ainda não jogou golfe.

Resultado

Executa corretamente em todos os casos de teste, exceto os dois longos. Para Eb9parece que há um traço ausente do caso de teste: Existem 22 -e um X, que divide a string em 24 partes iguais. De acordo com meus cálculos manuais, isso é 9600Hz, que é 37 centavos acima de um D9. É exatamente isso que meu programa gera. Se eu adicionar outro traço, recebo Eb9 + 8 centavos. Infelizmente, o BBC Basic não pode manipular cadeias com mais de 255 caracteres; portanto, o Eb11caso apresenta um erro.

insira a descrição da imagem aqui

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

Recebe a imagem ascii em uma linha por si só, e a frequência em uma linha separada.

Alguns caracteres podem ser eliminados, reduzindo a precisão dos números mágicos 17.3123e 57.376.

Sem o golfe, o programa fica assim:

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
fonte
2
+1 para a scanfsequência de formato impressionante . Eu não tinha ideia de que você poderia fazer isso. Verificarei o código de saída mais tarde (pensei em fazer isso em C e, embora algo semelhante tenha me ocorrido para a saída, não consegui encontrar uma maneira de fazer tudo de forma competitiva.) Presumo que d+9seja porque você está indexado em note A, então você precisa ajustar o número da oitava no índice da nota C: Gostaria de saber se existe uma maneira de contornar isso.
Level River St
Sim, o +9 compensa o fato de as oitavas começarem em C. É isso ou fazer uma correção semelhante ao cálculo do nome da nota. Para nomes de notas, o deslocamento circular pode ser implementado por uma LUT, mas eu gosto da maneira mais "matemática" de calculá-las.
Anatolyg 17/08/14
1

JavaScript (199)

Chame, por exemplo, 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)}

Fixo. (Como moro na Europa, usei B em vez de Bb e H em vez de B =)

flawr
fonte
Flawr, você é alemão? Eu sempre pensei em B e H como uma notação alemã, não uma notação européia. O Reino Unido e a Irlanda usam Bb e B. Espanha e Itália usam SIb e SI (como em DO RE MI FA SOL LA SI.). Enfim, é apenas uma economia de um personagem.
Level River St
Sim, sou um país de língua alemã, não sabia que outros países europeus usam esse sistema Doremi (só ouvi pessoas usando-o na educação infantil). De qualquer maneira era primarly uma piada desde que você disse que só economiza 1 caractere e realmente não cumprir as exigências =)
flawr
Este parece arredondar o número de centavos incorretamente se o número de centavos é negativo (por exemplo, t('[---X--]',11.7103)(último exemplo) dá -10ao invés de-11
es1024
Usar p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)economiza 2 caracteres adicionais.
Sean Latham
@ es1024 Oh, eu deveria saber: é porque eu implementei a função round pela round(x) = x+.5|0qual só é correto para números positivos, eu vou corrigir isso mais tarde. @ipi thanks!
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.")
comperendinous
fonte