Cordes d'accordage

9

Tâche

Écrivez un programme pour déterminer la note émise, ainsi que le nombre de cents désaccordés, d'une corde accordée à une fréquence donnée et enfoncée à un moment donné.

Par souci de simplicité, supposons que la fréquence du son produit et la longueur de la corde à droite de l'endroit où elle est pressée sont inversement proportionnelles.

Remarque: cette tâche concerne uniquement le ton fondamental, et non les harmoniques / autres harmoniques.

Contribution

Votre programme reçoit deux données:

  • Une chaîne de longueur arbitraire, représentant la chaîne en question. Cette chaîne sera marquée d'un X où la chaîne doit être maintenue enfoncée.

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

    Supposons que la note soit jouée en utilisant la partie de la corde à droite de la X.

  • Un nombre (pas nécessairement un entier), indiquant la fréquence à laquelle la chaîne est accordée. La précision de ce nombre sera au plus de quatre chiffres après la décimale.

On peut supposer que les fréquences passées se situeront entre 10 Hzet 40000 Hz.

La saisie peut être transmise dans le format de votre choix. Veuillez spécifier comment la contribution est acceptée dans votre programme dans votre réponse.

Production

Votre programme doit produire à la fois la note la plus proche * dans le système d'accord de tempérament égal à douze tons et le nombre de centièmes de la note la plus proche que le son dénoté par la chaîne serait (arrondi au cent le plus proche).

+nles cents doivent être utilisés pour désigner les ncents nets / au-dessus de la note, et les -ncents pour plat / en dessous de la note.

La note doit être émise en notation de hauteur scientifique. Supposons que A4 est réglé 440Hz. Utilisez b et # pour des notes plates / nettes. Remarque: vous pouvez utiliser soit tranchant soit plat. Pour la note à 466.16Hz, soit A#ou Bbpeut être émis pour la note.

Le format de la sortie dépend de vous, tant que la sortie ne contient que les deux informations précédemment spécifiées (c'est-à-dire que l'impression de chaque sortie possible n'est pas autorisée).

* la note la plus proche fait référence à la note la plus proche du son dénoté par l'entrée, mesurée en nombre de cents (donc la note qui se trouve à l'intérieur 50 centsdu son). Si le son est 50 centséloigné de deux notes différentes (après l'arrondi), alors l'une ou l'autre des deux notes peut être émise.

Exemples

Votre programme devrait fonctionner pour tous les cas, pas seulement les exemples suivants.

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

* Des images nettes ou plates auraient pu être émises.

Liens potentiellement utiles

C'est le donc la réponse la plus courte l'emporte.

es1024
la source
Je pense que vos exemples sont quelque peu incohérents: selon le premier, [--X--]la chaîne est pressée au milieu de la division où le xest placé, tandis que le dernier [-X--]serait à 3/8 (pas 2/5) en suivant cette logique. Ou est-ce que je comprends quelque chose de mal?
flawr
@flawr pour la dernière [-X--], la chaîne est divisée à 4 endroits (et donc en 5 parties), et pressée à la seconde de ces divisions. Ainsi, il est pressé 2/5et la longueur utilisée est 3/5.
es1024
Ah ok maintenant je vois, donc chacun -représente fondamentalement la position des divisions, merci de m'expliquer!
flawr

Réponses:

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'

Le score exclut les commentaires. Pas encore joué au golf.

Production

Fonctionne correctement sur tous les cas de test sauf les deux longs. Car Eb9il semble qu'il manque un tiret dans le cas de test: il y en a 22 -et un X, qui divise la chaîne en 24 morceaux égaux. Selon mes calculs manuels, c'est 9600Hz, ce qui est 37 cents au-dessus d'un D9. C'est exactement ce que mon programme produit. Si j'ajoute un autre tiret, j'obtiens Eb9 + 8 cents. Malheureusement, BBC Basic ne peut pas gérer les chaînes de plus de 255 caractères, donc le Eb11cas donne une erreur.

entrez la description de l'image ici

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

Reçoit l'image ascii sur une ligne seule et la fréquence sur une ligne distincte.

Quelques caractères peuvent être supprimés en réduisant la précision des nombres magiques 17.3123et 57.376.

Sans le golf, le programme ressemble à ceci:

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
la source
2
+1 pour la scanfchaîne de format génial . Je ne savais pas que tu pouvais faire ça. Je vérifierai le code de sortie plus tard (j'ai pensé à faire cela en C et bien que quelque chose de similaire me soit arrivé pour la sortie, je ne pouvais pas voir un moyen de faire le tout de manière compétitive.) Je suppose que d+9c'est parce que vous êtes indexé sur note A donc vous devez ajuster le nombre d'octaves à l'index sur la note C: Je me demande s'il y a un moyen de contourner cela.
Level River St
Oui, le +9 compense le fait que les octaves commencent à C. C'est soit cela, soit un correctif similaire au calcul du nom de la note. Pour les noms de notes, le décalage circulaire pourrait être implémenté par une LUT, mais j'aime la façon plus "mathématique" de les calculer.
anatolyg
1

JavaScript (199)

Appelez-le par exemple comme 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)}

Fixé. (Puisque je vis en Europe, j'ai utilisé B au lieu de Bb et H au lieu de B =)

flawr
la source
Flawr, êtes-vous allemand? J'ai toujours pensé B et H comme une notation allemande, pas une notation européenne. Le Royaume-Uni et l'Irlande utilisent Bb et B. L'Espagne et l'Italie utilisent SIb et SI (comme dans DO RE MI FA SOL LA SI.). De toute façon, ce n'est qu'une sauvegarde d'un caractère.
Level River St
Oui, je suis un pays germanophone, je ne savais pas que d'autres pays européens utilisent ce système Doremi (je n'ai entendu que des gens l'utiliser dans l'éducation des enfants). Quoi qu'il en soit, c'était avant tout une blague, car comme vous l'avez dit, cela n'économise que 1 caractère et ne répond pas vraiment aux exigences =)
flawr
Cela semble arrondir le nombre de cents de manière incorrecte si le nombre de cents est négatif (par exemple, t('[---X--]',11.7103)(dernier exemple) donne -10au lieu de-11
es1024
L'utilisation p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)vous permet d'économiser 2 caractères supplémentaires.
Sean Latham
@ es1024 Oh, j'aurais dû savoir: c'est parce que j'ai implémenté la fonction ronde round(x) = x+.5|0qui n'est correcte que pour les nombres positifs, je corrigerai ça plus tard. @ipi merci!
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)))

Non 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.")
compérendineux
la source