Настроювання рядків


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центів для квартири / нижче банкноти.

Примітка повинна виводитись у науковому позначенні тону. Припустимо, що A4 налаштований на 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--]

* Можуть бути виведені різкі або плоскі.

Потенційно корисні посилання

Це є тому виграє найкоротша відповідь.


Я думаю, що ваші приклади дещо суперечливі: згідно з першим, [--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випадок дає помилку.

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


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
}

2
+1 для дивовижного scanfрядка формату. Я не здогадувався, що ти можеш це зробити. Я перевірю вас вихідний код пізніше (я думав про те, щоб зробити це в C, і хоча щось подібне мені трапилося для виводу, я не міг побачити спосіб зробити все це конкурентоспроможним.) Я припускаю d+9, що ви індексуєте Примітка A, тож вам доведеться відрегулювати число октави до індексу на примітці C: Цікаво, чи є спосіб обійти це.
Рівень Рівер Сент

Так, +9 компенсує той факт, що октави починаються з C. Це або це, або внесення подібного виправлення до обчислення назви ноти. Для імен нот, круговий зсув може бути реалізований LUT, але мені подобається більш "математичний" спосіб їх обчислення.
anatolyg

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 =)


Флар, ти німець? Я завжди вважав B і H німецькою позначенням, а не європейською позначкою. Великобританія та Ірландія використовують Bb та B. Іспанія та Італія використовують SIb та SI (як у DO RE MI FA SOL LA SI.). У будь-якому випадку це лише збереження одного персонажа.
Рівень Рівер Сент

Так, я є німецькомовною країною, я не знав, що інші європейські країни використовують цю систему Doremi (я чув лише, що люди використовують її в навчанні дітей). У будь-якому випадку це був жарт, оскільки, як ви вже говорили, він економить лише 1 знак і не відповідає вимогам =)
недолік

Здається, це неправильно округлює кількість центів, якщо кількість центів негативна (наприклад, t('[---X--]',11.7103)(останній приклад) дає -10замість-11
es1024

Використання 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)))

Безголівки:

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.")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.