OO Design, วิธีสร้างแบบจำลอง Tonal Harmony?


12

ฉันเริ่มเขียนโปรแกรมใน C ++ 11 ที่จะวิเคราะห์คอร์ดเครื่องชั่งและความสามัคคี ปัญหาที่ใหญ่ที่สุดที่ฉันมีในขั้นตอนการออกแบบของฉันคือโน้ต 'C' คือโน้ตประเภทของคอร์ด (Cmaj, Cmin, C7, ฯลฯ ) และประเภทของคีย์ (คีย์ของ Cmajor, Cminor) ปัญหาเดียวกันเกิดขึ้นกับช่วงเวลา (เล็กน้อย 3, ใหญ่ 3)

ฉันใช้คลาสพื้นฐานโทเค็นซึ่งเป็นคลาสพื้นฐานสำหรับ 'สัญลักษณ์' ทั้งหมดในโปรแกรม ตัวอย่างเช่น:

class Token {
public:
    typedef shared_ptr<Token> pointer_type;
    Token() {}
    virtual ~Token() {}
};

class Command : public Token {
public:
    Command() {}
    pointer_type execute();
}

class Note : public Token;

class Triad : public Token; class MajorTriad : public Triad; // CMajorTriad, etc

class Key : public Token; class MinorKey : public Key; // Natural Minor, Harmonic minor,etc

class Scale : public Token;

ดังที่คุณเห็นการสร้างคลาสที่ได้รับทั้งหมด (CMajorTriad, C, CMajorScale, CMajorKey ฯลฯ ) จะกลายเป็นความซับซ้อนที่ซับซ้อนอย่างรวดเร็วอย่างน่าขันรวมถึงโน้ตอื่น ๆ รวมถึงการเพิ่มประสิทธิภาพ การสืบทอดหลายอย่างจะไม่ทำงานเช่น:

class C : public Note, Triad, Key, Scale

คลาส C ไม่สามารถเป็นสิ่งเหล่านี้ทั้งหมดในเวลาเดียวกัน มันเป็นบริบทยัง polymorphing ด้วยนี้จะไม่ทำงาน (วิธีการกำหนดวิธีการที่ซุปเปอร์ที่จะดำเนินการหรือไม่เรียกตัวสร้างซุปเปอร์คลาสทุกคนไม่ควรเกิดขึ้นที่นี่)

มีแนวคิดหรือข้อเสนอแนะการออกแบบที่ผู้คนเสนอให้หรือไม่? ฉันไม่สามารถพบสิ่งใดใน google ที่เกี่ยวข้องกับการสร้างแบบจำลองความสามัคคีของวรรณยุกต์จากมุมมองของ OO มีความสัมพันธ์มากเกินไประหว่างแนวคิดทั้งหมดที่นี่


8
ทำไม 'C' ถึงจะเป็นคลาส ฉันคิดว่า 'Note', 'Chord' ฯลฯ จะเป็นคลาสซึ่งอาจมีการแจกแจงค่าที่ enum 'C' อาจมีส่วนร่วม
Rotem

หากผู้ใช้ป้อน -> คอร์ด CEG ก็จะต้องสรุปสิ่งที่บันทึกเป็นรูปแบบคอร์ดที่เหมาะสม ฉันกำลังคิดถึงการผ่านเวกเตอร์ของ <Notes> เป็น params ไปยังเมธอด execute () ซึ่งทั้งหมดจะถูกจัดการแบบ polymorphically อย่างไรก็ตามการใช้ตัวแจงนับทำให้เข้าใจได้ แต่จากนั้นฉันจะต้องยกตัวอย่างวัตถุทุกชิ้นด้วย enum ที่ฉันต้องการใช้
Igneous01

ฉันใช้ @Remem ในรายการนี้: บางครั้งคุณต้องชอบการจัดวางวัตถุมากกว่ามรดก
Spoike

สำหรับฉันแล้วมันอาจเป็นประโยชน์ถ้าคุณคิดเกี่ยวกับสิ่งที่คุณต้องการจะทำกับคลาส note / chord / scale คุณจะผลิตแผ่นเพลง? ไฟล์ Midi? การแปลงคะแนน (การเปลี่ยนรูป, เพิ่มความยาวโน้ตทั้งหมดเป็นสองเท่า, เพิ่มทริลล์ไปยังโน้ตทั้งหมดทั้งหมดด้านบนโน้ตย่อ ฯลฯ ) หรือไม่? เมื่อคุณมีโครงสร้างชั้นเรียนที่เป็นไปได้คิดว่าคุณจะทำงานเหล่านั้นสำเร็จได้อย่างไร ถ้ามันดูน่าอึดอัดใจบางทีคุณอาจต้องการโครงสร้างชั้นเรียนที่แตกต่างกัน
MatrixFrog

คำตอบ:


9

ฉันคิดว่าวิธีที่ดีที่สุดคือการสร้างความสัมพันธ์ที่แท้จริงระหว่างหน่วยงานเหล่านี้

ตัวอย่างเช่นคุณอาจมี:

  • Noteวัตถุที่มีคุณสมบัติเป็น

    • ชื่อ (C, D, E, F, G, A, B)

    • อุบัติเหตุ (โดยธรรมชาติ, แบน, คมชัด)

    • ความถี่หรือตัวระบุระยะพิทซ์อื่น

  • Chordวัตถุที่มีคุณสมบัติเป็น

    • อาร์เรย์ของNoteวัตถุ

    • ชื่อ

    • โดยบังเอิญ

    • คุณภาพ (หลัก, เล็กน้อย, ลดลง, เติม, ถูกระงับ)

    • ข้อมูลเพิ่มเติม (7, 7+, 6, 9, 9+, 4)

  • Scaleวัตถุที่มีคุณสมบัติเป็น

    • อาร์เรย์ของNoteวัตถุ

    • ชื่อ

    • ประเภท (ที่สำคัญรองลงมาเป็นธรรมชาติเล็กน้อยไพเราะเล็กน้อยประสานกัน)

    • โหมด (ionian, dorian, phrygian, lydian, mixolidian, aeolian, locrian)

จากนั้นหากอินพุตของคุณเป็นข้อความคุณสามารถสร้างบันทึกย่อด้วยสตริงซึ่งรวมถึงชื่อโน้ตโดยไม่ได้ตั้งใจและ (หากคุณต้องการ) อ็อกเทฟ

ตัวอย่างเช่น (pseudocode ฉันไม่รู้ C ++):

note = new Note('F#2');

จากนั้นในNoteชั้นเรียนคุณสามารถแยกสตริงและตั้งค่าคุณสมบัติ

Chordอาจจะสร้างขึ้นโดยโน้ต:

chord = new Chord(['C2', 'E2', 'G2']);

... หรือสตริงรวมถึงชื่อคุณภาพและหมายเหตุเพิ่มเติม:

chord = new Chord('Cmaj7');

ฉันไม่ทราบว่าแอปพลิเคชันของคุณจะทำสิ่งใดดังนั้นสิ่งเหล่านี้จึงเป็นเพียงแนวคิด

ขอให้โชคดีกับโครงการที่น่าสนใจของคุณ!


4

คำแนะนำทั่วไปบางอย่าง


หากมีความไม่แน่นอนจำนวนมากที่คาดว่าจะเกิดขึ้นในการออกแบบชั้นเรียน (เช่นในสถานการณ์ของคุณ) ฉันขอแนะนำให้ทดสอบการออกแบบชั้นเรียนที่แตกต่างกัน

การใช้ C ++ ในขั้นตอนนี้อาจไม่ได้ผลเหมือนภาษาอื่น ๆ (ปัญหานี้เห็นได้ชัดในส่วนของรหัสของคุณต้องจัดการtypedefและvirtualdestructors) แม้ว่าเป้าหมายของโครงการคือการผลิตรหัส C ++ มันอาจจะเป็นประโยชน์ในการออกแบบชั้นเรียนเริ่มต้นในภาษาอื่น (ตัวอย่างเช่น Java แม้ว่าจะมีตัวเลือกมากมาย)

อย่าเลือก C ++ เพียงเพราะมีหลายมรดก การสืบทอดหลายอย่างมีการใช้งาน แต่ไม่ได้เป็นวิธีที่ถูกต้องในการสร้างแบบจำลองปัญหานี้ (ทฤษฎีดนตรี)


ให้ความสนใจเป็นพิเศษในการแก้ความกำกวม แม้ว่าความกำกวมนั้นมีมากมายในภาษาอังกฤษ (ต้นฉบับ) คำอธิบายความคลุมเครือเหล่านี้จะต้องแก้ไขเมื่อออกแบบคลาส OOP

เราพูดถึงGและG ที่คมชัดเป็นโน้ต เราพูดถึงG MajorและG minorเป็นเกล็ด ดังนั้นNoteและScaleไม่ได้เป็นแนวคิดที่ใช้แทนกันได้ ก็จะไม่มีใด ๆวัตถุที่สามารถพร้อมกันอินสแตนซ์ของและNoteScale

หน้านี้มีไดอะแกรมสองสามตัวที่แสดงถึงความสัมพันธ์: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations

สำหรับตัวอย่างอื่น "กลุ่มที่เริ่มต้นด้วย Gในระดับเมเจอร์ C " ไม่มีความหมายเช่นเดียวกับ "กลุ่มที่เริ่มต้นด้วย Cในระดับเมเจอร์เมเจอร์ "

ในช่วงแรกนี้Tokenคลาส (ซุปเปอร์คลาสของทุกสิ่ง) ไม่ได้รับการรับรองเพราะมันช่วยป้องกันความไม่ชัดเจน สามารถนำมาใช้ได้ในภายหลังหากจำเป็น (รองรับโดยส่วนของรหัสที่แสดงให้เห็นว่าสิ่งนี้มีประโยชน์อย่างไร)


ในการเริ่มต้นให้เริ่มด้วยNoteคลาสที่เป็นศูนย์กลางของคลาสไดอะแกรมจากนั้นค่อยเพิ่มความสัมพันธ์ (ชิ้นส่วนของข้อมูลที่จำเป็นต้องเชื่อมโยงกับ tuples ของNotes) ในไดอะแกรมความสัมพันธ์ของคลาส

Cโน้ตเป็นตัวอย่างของNoteระดับ Cโน้ตจะกลับคุณสมบัติที่เกี่ยวข้องกับการบันทึกนี้เช่น triads ที่เกี่ยวข้องและตำแหน่งของญาติ ( Interval) ด้วยความเคารพกับScaleที่เริ่มต้นด้วยCทราบ

ความสัมพันธ์ระหว่างอินสแตนซ์ของคลาสเดียวกัน (ตัวอย่างเช่นระหว่างบันทึกCและบันทึกย่อE ) ควรเป็นแบบจำลองเป็นคุณสมบัติไม่ใช่มรดก

ยิ่งกว่านั้นความสัมพันธ์ระหว่างคลาสในตัวอย่างของคุณหลายรูปแบบก็มีความเหมาะสมมากกว่าเช่นกัน ตัวอย่าง:

(ตัวอย่างโค้ดกำลังรอเพราะฉันจำเป็นต้องเรียนรู้ทฤษฎีดนตรีอีกครั้ง ... )


ความคิดที่น่าสนใจ แต่จะมีวิธีจัดการกับคุณภาพของเสียงประสานในบริบทของการวิเคราะห์ฮาร์มอนิกได้อย่างไร? อินสแตนซ์ C Chord จะต้องมีคุณสมบัติที่มีคุณภาพตั้งค่าเป็นรอง (ซึ่งก็โอเค) แต่แล้วสิ่งที่เกี่ยวกับคอร์ดเด่น / ลดลง / เพิ่ม / รอง 7s, 9, 11 คอร์ด? มีหลายคอร์ดที่โน้ตเดี่ยวสามารถเป็นได้ ฉันจะกำหนดได้อย่างไรว่าคอร์ดประเภทต่าง ๆ และคุณสมบัติที่เกี่ยวข้องนั้นอยู่ในส่วนการวิเคราะห์ของโค้ดอย่างไร
Igneous01

ฉันรู้ทฤษฎีดนตรีน้อยมากดังนั้นฉันจึงไม่สามารถตอบคำถามของคุณได้ วิธีหนึ่งที่จะช่วยให้ฉันเข้าใจได้คือการหาตารางที่แสดงรายการโน้ตทั้งหมดที่เกี่ยวข้องกับแนวคิดเหล่านั้น แบบสอบถามสำหรับคอร์ดสามารถใช้พารามิเตอร์เพิ่มเติม
ร. ว.

2
นี่คือรายการที่ดีมากของคอร์ดที่เป็นไปได้ทั้งหมด: en.wikipedia.org/wiki/List_of_chordsคอร์ด ทั้งหมดสามารถนำไปใช้กับบันทึกใด ๆ สิ่งที่สำคัญกับสถานการณ์ของฉันคือการปรับปรุงที่ถูกต้อง: เช่น Cflat major! = BMajor พวกมันมีคอร์ดเหมือนกันบนเปียโน แต่ฟังก์ชั่นฮาร์โมนิกนั้นแตกต่างกันมากบนกระดาษ ฉันคิดว่าตัวแจงนับสำหรับการทำให้คมชัด / การแบนโน้ตจะเหมาะสมที่สุดสำหรับตัวอย่างของการบันทึก วิธีที่ C.Sharpen () = C # และ C.Flatten () = Cb นี่อาจทำให้ฉันตรวจสอบคอร์ดผู้ใช้ได้ง่ายขึ้น
Igneous01

2

โดยทั่วไปโน้ตดนตรีเป็นความถี่และช่วงเวลาดนตรีเป็นอัตราส่วนความถี่

ทุกสิ่งสามารถสร้างได้จากสิ่งนั้น

คอร์ดคือรายการของช่วงเวลา สเกลเป็นโน้ตพื้นฐานและระบบปรับแต่ง ระบบจูนก็เป็นรายการของช่วงเวลา

วิธีที่คุณตั้งชื่อพวกเขาเป็นเพียงสิ่งประดิษฐ์ทางวัฒนธรรม

บทความทฤษฎีดนตรีของ Wikipedia เป็นจุดเริ่มต้นที่ดี


ที่น่าสนใจแม้ว่าฉันไม่แน่ใจว่ามันจำเป็นต้องเป็นประโยชน์ในการสร้างแบบจำลองระบบในแง่ของความเป็นจริงทางกายภาพพื้นฐาน โปรดจำไว้ว่าตัวแบบจำเป็นต้องมีประโยชน์ในการสื่อสารด้านใดด้านหนึ่งโดยเฉพาะไม่จำเป็นต้องครอบคลุมหรือแม่นยำ แม้ว่าวิธีการของคุณจะแม่นยำและครอบคลุม แต่อาจมีระดับต่ำเกินไปสำหรับกรณีการใช้งานของ OP
Konrad Rudolph

@ KonradRudolph - ด้วยตำแหน่งที่สูงที่สุดของฉันฉันแค่ต้องการชี้ให้เห็นว่าไม่ควรผสมโมเดลพื้นฐานกับเลเยอร์การนำเสนอในลักษณะที่คล้ายกับเวลาในการปรับเวลาตามฤดูกาล: การคำนวณนั้นง่ายกว่ามากในตัวแบบเอง ฉันยอมรับว่าระดับนามธรรมที่เป็นประโยชน์ไม่ใช่สิ่งที่ฉันแนะนำ แต่ฉันรู้สึกว่าระดับนามธรรมที่ OP แนะนำนั้นไม่เพียงพอเช่นกัน
mouviciel

วัตถุประสงค์ของโปรแกรมนี้ไม่จำเป็นต้องแสดงความเป็นจริงทางกายภาพของดนตรี แต่สำหรับคนที่เรียนทฤษฎี (เช่นตัวฉันเอง) สามารถที่จะพล็อตได้อย่างรวดเร็วในบางคอร์ดและให้โปรแกรมตีความความสามารถที่ดีที่สุดว่าคอร์ดเหล่านี้เกี่ยวข้องกันอย่างไรในลักษณะที่ประสานกัน ฉันสามารถวิเคราะห์มันเป็นวิธีที่พยายามและเป็นจริงในการอ่านการวัดคะแนนโดยการวัด แต่นี่เป็นอีกเครื่องมือหนึ่งที่ทำให้สิ่งต่าง ๆ ง่ายขึ้นและเพื่อให้สามารถมุ่งเน้นไปที่รายละเอียดปลีกย่อยมากขึ้นเมื่อทำการวิเคราะห์
Igneous01

1

ฉันพบว่ามีความแตกต่างที่น่าสนใจ

บันทึกย่อกำลังถูกป้อนผ่าน midi (หรืออุปกรณ์จับสัญญาณเสียงบางประเภท) หรือมีการป้อนด้วยการพิมพ์ตัวอักษรและสัญลักษณ์?

ในกรณีของช่วงจาก C ถึง D-sharp / E-flat:

แม้ว่า D-sharp และ E-flat จะเป็นโทนเสียงเดียวกัน (ประมาณ 311Hz ถ้า A = 440Hz) ช่วงจาก C -> D-sharp เขียนขึ้นเป็นครั้งที่ 2 ในขณะที่ช่วงจาก C -> E-flat จะถูกเขียนเป็น รองลงมา ง่ายพอถ้าคุณรู้วิธีเขียนโน้ต เป็นไปไม่ได้ที่จะตรวจสอบว่าคุณมีเพียงสองเสียงต่อไป

ในกรณีนี้ฉันเชื่อว่าคุณจะต้องมีวิธีการเพิ่ม / ลดเสียงพร้อมด้วย. Sharpen () และ. Flatten () วิธีการที่กล่าวถึงเช่น. SemToneUp (), .FullToneDown () ฯลฯ ดังนั้น คุณสามารถค้นหาโน้ตย่อยได้ในระดับที่ไม่มี "การระบายสี" เป็นเซียน / แฟลต

ฉันต้องเห็นด้วยกับ @Remem ว่า "C" ไม่ใช่คลาสในตัวของมันเอง แต่เป็นการยกตัวอย่างของคลาส Note

หากคุณกำหนดคุณสมบัติของบันทึกย่อรวมถึงช่วงเวลาทั้งหมดเป็น semitones โดยไม่คำนึงถึงค่าบันทึกเริ่มต้น ("C", "F", "G #") คุณจะสามารถบอกได้ว่าลำดับโน้ตสามตัวที่มี รูท, เมเจอร์ 3 (M3), และ 3 รอง (m3) จะเป็นเมเจอร์สาม ในทำนองเดียวกัน m3 + M3 เป็นสามรองลดลง m3 + m3, M3 + M3 เพิ่ม นอกจากนี้สิ่งนี้จะช่วยให้คุณสามารถแค็ปซูลหาวันที่ 11 ลดลง 13th ฯลฯ โดยไม่ต้องเข้ารหัสพวกเขาอย่างชัดเจนสำหรับโน้ตฐานทั้ง 12 ตัวและเลอะเลือนของพวกเขาขึ้นและลง

เมื่อเสร็จแล้วคุณยังคงมีปัญหาต้องแก้ไข

รับสาม C, E, G ในฐานะนักดนตรีฉันเห็นสิ่งนี้ชัดเจนเหมือนคอร์ดคมาจ อย่างไรก็ตามผู้พัฒนาในฉันสามารถตีความการเพิ่มนี้เป็น E เล็กน้อย Augment 5 (Root E + m3 + a5) หรือ Gsus4 6th no 5th (RootG + 4 + 6)

ดังนั้นเพื่อตอบคำถามของคุณเกี่ยวกับการวิเคราะห์ฉันคิดว่าวิธีที่ดีที่สุดในการกำหนดรูปแบบ (maj, รองลงมา ฯลฯ ) คือการจดบันทึกทั้งหมดที่ป้อนจัดเรียงไว้ในค่า semitone จากน้อยไปมากและทดสอบกับแบบฟอร์มคอร์ดที่รู้จัก . จากนั้นใช้แต่ละบันทึกย่อที่ป้อนเป็นรูทโน้ตและดำเนินการประเมินชุดเดียวกัน

คุณสามารถถ่วงน้ำหนักรูปแบบคอร์ดเพื่อให้ทั่วไป (ส่วนใหญ่รองลงมา) มีความสำคัญมากกว่ารูปแบบคอร์ดเติม, เติม, เลคตรา, ฯลฯ แต่การวิเคราะห์ที่แม่นยำจะต้องนำเสนอรูปแบบคอร์ดที่ตรงกันทั้งหมดเป็นวิธีแก้ปัญหาที่เป็นไปได้

บทความวิกิพีเดียที่อ้างอิงอีกครั้งนั้นเป็นงานที่ดีในการแสดงรายการคลาสพิทช์ดังนั้นมันควรจะง่าย (ถึงแม้ว่าจะน่าเบื่อ) ในการโค๊ดโมเดลของคอร์ด, จดโน้ตที่ป้อน, มอบหมายให้พวกเขาลงในคลาส / ช่วงเวลา กับรูปแบบที่รู้จักกันสำหรับการแข่งขัน

สนุกมากเลยนะ ขอบคุณ!


ตอนนี้พวกเขากำลังป้อนข้อความผ่านทางข้อความ อย่างไรก็ตามในภายหลังฉันอาจจะสามารถใช้ midi หากโปรแกรมถูกห่อหุ้มอย่างถูกต้อง ก้าว
ย่างของ

0

ฟังดูเหมือนเคสสำหรับแม่แบบ คุณดูเหมือนจะมีtemplate <?> class Major : public Chord;เพื่อให้Major<C>เป็นแบบที่เป็นอยู่Chord Major<B>ในทำนองเดียวกันคุณยังมีNote<?>เทมเพลตที่มีอินสแตนซ์และNote<C>Note<D>

สิ่งเดียวที่ฉันทิ้งไว้คือ?ส่วนหนึ่ง ดูเหมือนว่าคุณจะมีenum {A,B,C,D,E,F,G}แต่ฉันไม่รู้ว่าคุณจะตั้งชื่อนั้นได้อย่างไร


0

ขอบคุณสำหรับคำแนะนำทุกอย่างฉันจัดการเพื่อพลาดคำตอบพิเศษ จนถึงชั้นเรียนของฉันได้รับการออกแบบเช่นนั้น:

Note
enum Qualities - { DFLAT = -2, FLAT, NATURAL, SHARP, DSHARP }
char letter[1] // 1 char letter
string name // real name of note
int value // absolute value, the position on the keyboard for a real note (ie. c is always 0)
int position // relative position on keyboard, when adding sharp/flat, position is modified
Qualities quality // the quality of the note ie sharp flat

เพื่อแก้ปัญหาการคำนวณช่วงเวลาและคอร์ดของฉันฉันตัดสินใจใช้บัฟเฟอร์แบบวงกลมซึ่งทำให้ฉันสามารถข้ามบัฟเฟอร์จากจุดใด ๆ ไปข้างหน้าจนกว่าฉันจะพบบันทึกย่อถัดไปที่ตรงกัน

ในการค้นหาช่วงเวลาที่ตีความ - สำรวจบัฟเฟอร์บันทึกย่อจริงหยุดเมื่อตัวอักษรตรงกัน (แค่ตัวอักษรไม่ใช่โน้ตหรือตำแหน่งจริง) ดังนั้น c - g # = 5

ในการค้นหาระยะทางจริงข้ามบัฟเฟอร์อีกจำนวน 12 จำนวนเต็มให้หยุดเมื่อตำแหน่งโน้ตบนสุดนั้นเหมือนกับค่าบัฟเฟอร์ของดัชนีที่ดัชนีอีกครั้งนี่เป็นการเคลื่อนที่ไปข้างหน้าเท่านั้น แต่ออฟเซ็ตสามารถอยู่ที่ใดก็ได้ (เช่น. buffer.at (-10))

ตอนนี้ฉันรู้ทั้งช่วงตีความและระยะทางกายภาพระหว่างสอง ดังนั้นชื่อช่วงเวลาจึงเสร็จสมบูรณ์แล้วครึ่งหนึ่ง

ตอนนี้ฉันสามารถตีความช่วงเวลาได้เช่น ถ้าช่วงเวลาเป็น 5 และระยะทางคือ 8 จากนั้นก็จะเพิ่มที่ 5

จนถึงทราบและช่วงเวลาทำงานตามที่คาดไว้ตอนนี้ฉันเพียง แต่ต้องจัดการกับตัวระบุคอร์ด

ขอขอบคุณอีกครั้งฉันจะอ่านคำตอบเหล่านี้อีกครั้งและรวมแนวคิดบางอย่างไว้ที่นี่

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