การปรับแต่งสตริง


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 Hz40000 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 สำหรับอันสุดท้าย[-X--]สตริงถูกแบ่งที่ 4 แห่ง (และดังนั้นจึงมี 5 ส่วน) และกดที่ส่วนที่สองของแผนกเหล่านี้ ดังนั้นจึงมีการกดที่และระยะเวลาที่ใช้2/5 3/5
es1024

อ่าเข้าใจแล้วตอนนี้ฉันเห็นแล้วดังนั้นแต่ละคนจึง-เป็นตัวแทนของหน่วยงานขอบคุณที่อธิบาย!
ข้อผิดพลาด

คำตอบ:


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 ส่วนเท่ากัน ตามการคำนวณด้วยตนเองของฉันนี่คือ 9600Hz ซึ่งเป็น 37 เซนต์เหนือ D9 นี่คือสิ่งที่โปรแกรมของฉันส่งออก ถ้าฉันเพิ่มเส้นประอื่นฉันจะได้รับ Eb9 + 8 เซนต์ น่าเสียดายที่ BBC Basic ไม่สามารถจัดการกับสายอักขระได้มากกว่า 255 ตัวอักษรดังนั้นEb11เคสจึงมีข้อผิดพลาด

ป้อนคำอธิบายรูปภาพที่นี่


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

รับภาพ ASCII บนเส้นด้วยตัวเองและความถี่ในบรรทัดที่แยกต่างหาก

ไม่กี่ตัวอักษรสามารถลดลงโดยการลดความถูกต้องของหมายเลขมายากลและ17.312357.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

จาวาสคริปต์ (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 คุณเป็นคนเยอรมันหรือเปล่า ฉันมักจะคิดว่า B และ H เป็นสัญกรณ์เยอรมันไม่ใช่สัญกรณ์ยุโรป สหราชอาณาจักรและไอร์แลนด์ใช้ Bb และ B. สเปนและอิตาลีใช้ SIb และ SI (เช่นเดียวกับ DO RE MI FA SOL LA SI) อย่างไรก็ตามมันเป็นเพียงการบันทึกของตัวละครตัวหนึ่ง
เลเวลริเวอร์เซนต์

ใช่ฉันเป็นประเทศที่พูดภาษาเยอรมันฉันไม่ทราบว่าประเทศในยุโรปอื่นใช้ระบบ Doremi (ฉันได้ยินเพียงว่ามีคนใช้ในการศึกษาของเด็ก) อย่างไรก็ตามมันเป็นเรื่องตลก primarly ตั้งแต่ที่คุณบอกว่ามันเพียงช่วยประหยัด 1 ถ่านและไม่ได้จริงๆตอบสนองความต้องการ =)
flawr

สิ่งนี้ดูเหมือนจะปัดเศษจำนวนของ cents อย่างไม่ถูกต้องหากจำนวนของ cents เป็นลบ (ตัวอย่างเช่นt('[---X--]',11.7103)(ตัวอย่างสุดท้าย) ให้-10แทน-11
es1024

การใช้p="C0C#0D0D#0E0F0F#0G0G#0A0B0H".split(0)ช่วยให้คุณเพิ่มอีก 2 ตัวอักษร
Sean Latham

@ es1024 โอ้ฉันควรจะรู้: เป็นเพราะฉันใช้ฟังก์ชั่นรอบround(x) = x+.5|0ที่ถูกต้องเฉพาะสำหรับจำนวนบวกฉันจะแก้ไขได้ในภายหลัง @ipi ขอบคุณ!
ข้อบกพร่อง

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.")
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.