Тюнинг Струны

9

задача

Напишите программу, чтобы определить, звучит ли нота, а также сколько центов расстроено, строки, настроенной на заданную частоту и нажатой в данной точке.

Для простоты предположим, что частота создаваемого звука и длина струны справа от места, где она нажата, обратно пропорциональны.

Примечание: эта задача имеет дело только с основным тоном, а не с обертонами / другими гармониками.

вход

Ваша программа получает две части данных:

  • Строка произвольной длины, представляющая рассматриваемую строку. Эта строка будет помечена знаком X, где она должна удерживаться.

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

    Предположим, что нота звучит с использованием части строки справа от X.

  • Число (не обязательно целое число), обозначающее частоту настройки строки. Точность этого числа будет не более четырех цифр после запятой.

Можно предположить, что пройденные частоты будут лежать между 10 Hzи 40000 Hz.

Ввод может быть передан в формате по вашему выбору. Пожалуйста, укажите, как вход принят в вашу программу в вашем ответе.

Вывод

Ваша программа должна выводить как самую близкую ноту * в системе настройки равного темперамента из двенадцати тонов, так и количество центов от ближайшей ноты, которой будет обозначен звук, обозначенный строкой (округленный до ближайшего цента).

+nценты следует использовать для обозначения nцентов, острых / выше примечания, и -nцентов для плоских / ниже примечания.

Примечание должно быть выведено в примечании научной подачи. Предположим, А4 настроен на 440Hz. Используйте b и # для плоских / острых нот. Примечание: можно использовать либо острый, либо плоский. Для заметки в 466.16Hz, A#или Bbможет быть выведен для заметки.

Формат вывода зависит от вас, если вывод содержит только две ранее указанные части информации (то есть печать каждого возможного вывода не допускается).

* самая близкая нота относится к ноте, наиболее близкой к звуку, обозначаемому входом, измеренному в количестве центов (следовательно, ноте, которая находится внутри 50 centsзвука). Если звук отсутствует 50 centsв двух разных нотах (после округления), то может быть выведена любая из двух нот.

Примеры

Ваша программа должна работать для всех случаев, а не только для следующих примеров.

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

* Резкий или плоский может быть выведен.

Потенциально полезные ссылки

Это так самый короткий ответ выигрывает.

es1024
источник
Я думаю, что ваши примеры несколько противоречивы: согласно первому, [--X--]строка нажимается в середине деления, где xнаходится символ, в то время как последний [-X--]будет следовать 3/8 (не 2/5), если следовать этой логике. Или я что-то не так понимаю?
flawr
@flawr для последнего, [-X--]строка делится на 4 места (и, следовательно, на 5 частей), и нажимается во втором из этих делений. Таким образом, он нажимается на 2/5, а длина используется 3/5.
es1024
Ах, хорошо, теперь я вижу, так что каждый в -основном представляет позицию подразделений, спасибо за объяснение!
flawr

Ответы:

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'

Оценка исключает комментарии. Пока не играл в гольф.

Вывод

Выполняется правильно во всех тестовых случаях, кроме двух длинных. Для Eb9него , кажется , есть одна черта отсутствует из теста: Есть 22 -и один X, который делит строку на 24 равных частей. Согласно моим ручным расчетам, это 9600 Гц, что на 37 центов выше D9. Это именно то, что выводит моя программа. Если я добавлю еще одну черту, я получу Eb9 + 8 центов. К сожалению, BBC Basic не может обрабатывать строки длиной более 255 символов, поэтому Eb11регистр выдает ошибку.

введите описание изображения здесь

Уровень реки St
источник
3

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

Получает изображение ascii на отдельной строке, а частоту на отдельной строке.

Несколько персонажей можно сбросить, уменьшив точность магических чисел 17.3123и 57.376.

Без игры в гольф программа выглядит так:

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
источник
2
+1 за классную scanfстроку формата. Я понятия не имел, что ты можешь сделать это. Я проверю ваш выходной код позже (я думал о том, чтобы сделать это в C, и хотя что-то подобное произошло со мной для вывода, я не мог найти способ сделать все это конкурентно.) Я предполагаю d+9, потому что вы проиндексированы на примечание A, поэтому вы должны настроить октаву на индекс на примечании C: интересно, есть ли способ обойти это.
Уровень Река St
Да, +9 компенсирует тот факт, что октавы начинаются с C. Это либо так, либо исправление, аналогичное вычислению названия ноты. Для имен заметок круговое смещение может быть реализовано с помощью LUT, но мне нравится более «математический» способ их вычисления.
Анатолий
1

JavaScript (199)

Назовите это, например, как 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)}

Исправлена. (Так как я живу в Европе, я использовал B вместо Bb и H вместо B =)

flawr
источник
Flawr, ты немец? Я всегда думал о B и H как о немецкой нотации, а не европейской нотации. Великобритания и Ирландия используют Bb и B. Испания и Италия используют SIb и SI (как в DO RE MI FA SOL LA SI.). В любом случае это только сохранение одного персонажа.
Уровень Река St
Да, я из немецкоязычной страны, я не знал, что другие европейские страны используют эту систему Doremi (я только слышал, что люди используют ее в образовании детей). В любом случае, это была шутка, потому что, как вы сказали, она экономит только 1 символ и не соответствует требованиям =)
flawr
Кажется, что это неправильно t('[---X--]',11.7103)-10-11
округляет
Использование p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)экономит вам дополнительно 2 символа.
Шон Лэтэм
@ es1024 О, я должен был знать: это потому, что я реализовал функцию округления, round(x) = x+.5|0которая корректна только для положительных чисел, я исправлю это позже. @ipi спасибо!
flawr
1

Питон 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
источник