Thiết kế OO, làm thế nào để mô hình Tonal Harmony?


12

Tôi đã bắt đầu viết một chương trình trong C ++ 11 để phân tích hợp âm, thang âm và hòa âm. Vấn đề lớn nhất tôi gặp phải trong giai đoạn thiết kế của mình, đó là nốt 'C' là một nốt, một loại hợp âm (Cmaj, Cmin, C7, v.v.) và một loại phím (phím của Cmajor, Cminor). Vấn đề tương tự phát sinh với các khoảng (thứ 3 nhỏ, thứ 3 lớn).

Tôi đang sử dụng một lớp cơ sở, Token, đó là lớp cơ sở cho tất cả các 'biểu tượng' trong chương trình. ví dụ:

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;

Như bạn có thể thấy, để tạo tất cả các lớp dẫn xuất (CMajorTriad, C, CMajorScale, CMajorKey, v.v.) sẽ nhanh chóng trở nên phức tạp một cách lố bịch bao gồm tất cả các ghi chú khác, cũng như tăng cường. nhiều kế thừa sẽ không hoạt động, tức là:

class C : public Note, Triad, Key, Scale

lớp C, không thể là tất cả những điều này cùng một lúc. Đó là ngữ cảnh, cũng là đa hình với điều này sẽ không hoạt động (làm thế nào để xác định siêu phương thức nào để thực hiện? Gọi mọi nhà xây dựng siêu hạng không nên xảy ra ở đây)

Có bất kỳ ý tưởng thiết kế hoặc đề xuất mà mọi người phải cung cấp? Tôi đã không thể tìm thấy bất cứ điều gì trên google liên quan đến việc mô hình hóa sự hài hòa âm sắc từ góc độ OO. Có quá nhiều mối quan hệ giữa tất cả các khái niệm ở đây.


8
Tại sao 'C' sẽ là một lớp học? Tôi sẽ tưởng tượng 'Ghi chú', 'Hợp âm', v.v. sẽ là các lớp, có thể có một bảng liệt kê giá trị trong đó enum 'C' có thể đóng một phần.
Rotem

Nếu người dùng nhập-> hợp âm CEG, thì cần phải suy ra những nốt nào để tạo thành hợp âm phù hợp. Tôi đã nghĩ đến việc chuyển vào một vectơ <Notes> dưới dạng params cho phương thức exec (), tất cả sẽ được xử lý đa hình. Tuy nhiên, sử dụng một điều tra viên sẽ có ý nghĩa, nhưng sau đó tôi sẽ cần phải khởi tạo mọi đối tượng với enum mà tôi muốn sử dụng.
Igneous01

Tôi với @Rotem về điều này: Đôi khi, bạn chỉ cần thích thành phần đối tượng hơn là kế thừa.
Spoike

Đối với tôi, có vẻ hữu ích khi nghĩ về những gì bạn muốn làm với các lớp ghi chú / hợp âm / thang âm này. Bạn sẽ sản xuất bản nhạc? Tập tin Midi? Các biến đổi về điểm số (hoán vị, nhân đôi tất cả độ dài ghi chú, thêm các trill cho tất cả các ghi chú trên một ghi chú nhất định, v.v.)? Một khi bạn có một cấu trúc lớp có thể, hãy nghĩ về cách bạn sẽ hoàn thành các nhiệm vụ đó. Nếu nó có vẻ khó xử, có thể bạn muốn một cấu trúc lớp khác.
MatrixFrog

Câu trả lời:


9

Tôi nghĩ cách tiếp cận tốt nhất là tái tạo các mối quan hệ thực sự giữa các thực thể này.

Ví dụ: bạn có thể có:

  • một Noteđối tượng, có thuộc tính

    • tên (C, D, E, F, G, A, B)

    • tình cờ (tự nhiên, bằng phẳng, sắc nét)

    • tần số hoặc một định danh cao độ duy nhất khác

  • một Chordđối tượng, có thuộc tính

    • một mảng các Noteđối tượng

    • Tên

    • tình cờ

    • chất lượng (chính, phụ, giảm dần, tăng cường, đình chỉ)

    • bổ sung (7, 7+, 6, 9, 9+, 4)

  • một Scaleđối tượng, có thuộc tính

    • một mảng các Noteđối tượng

    • Tên

    • loại (chính, nhỏ tự nhiên, nhỏ giai điệu, nhỏ hài hòa)

    • chế độ (ionia, dorian, phrygian, lydian, mixolidian, aeilian, locrian)

Sau đó, nếu đầu vào của bạn là văn bản, bạn có thể tạo ghi chú bằng một chuỗi bao gồm tên ghi chú, tình cờ và (nếu bạn cần nó) quãng tám.

Ví dụ: mã giả, tôi không biết C ++):

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

Sau đó, trong Notelớp bạn có thể phân tích chuỗi và đặt thuộc tính.

A Chordcó thể được xây dựng bởi các ghi chú của nó:

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

... hoặc bằng một chuỗi bao gồm tên, chất lượng và ghi chú bổ sung:

chord = new Chord('Cmaj7');

Tôi không biết chính xác ứng dụng của bạn sẽ làm gì, vì vậy đây chỉ là những ý tưởng.

Chúc may mắn với dự án hấp dẫn của bạn!


4

Một số lời khuyên chung chung.


Nếu có nhiều sự không chắc chắn được mong đợi trong thiết kế lớp (chẳng hạn như trong tình huống của bạn), tôi khuyên bạn nên thử nghiệm với các thiết kế lớp cạnh tranh khác nhau.

Sử dụng C ++ ở giai đoạn này có thể không hiệu quả như các ngôn ngữ khác. (Vấn đề này là rõ ràng trong các đoạn mã của bạn phải xử lý typedefvirtualphá hủy.) Ngay cả khi mục tiêu dự án là tạo mã C ++, việc thiết kế lớp ban đầu bằng ngôn ngữ khác có thể hữu ích. (Ví dụ Java, mặc dù có nhiều lựa chọn.)

Đừng chọn C ++ chỉ vì thừa kế nhiều lần. Đa kế thừa có công dụng của nó nhưng nó không phải là cách chính xác để mô hình hóa vấn đề này (lý thuyết âm nhạc).


Đặc biệt chú ý đến định hướng. Mặc dù sự mơ hồ có rất nhiều trong các mô tả bằng tiếng Anh (văn bản), những sự mơ hồ này phải được giải quyết khi thiết kế các lớp OOP.

Chúng tôi nói về GG sắc nét như ghi chú. Chúng tôi nói về G chínhG nhỏ như quy mô. Vì vậy, NoteScalekhông phải là khái niệm hoán đổi cho nhau. Không thể có bất kỳ đối tượng nào có thể đồng thời là một thể hiện của a Notevà a Scale.

Trang này chứa một vài sơ đồ minh họa mối quan hệ: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations

Đối với một ví dụ khác, "Bộ ba bắt đầu bằng G trên thang điểm C " không có cùng ý nghĩa với "Bộ ba bắt đầu bằng C trên thang điểm G ".

Ở giai đoạn đầu này, Tokenlớp học (siêu lớp của mọi thứ) là không có cơ sở, bởi vì nó ngăn chặn sự định hướng. Nó có thể được giới thiệu sau nếu cần (được hỗ trợ bởi một đoạn mã chứng minh làm thế nào điều này có thể hữu ích.)


Để bắt đầu, hãy bắt đầu với một Notelớp là trung tâm của sơ đồ lớp, sau đó thêm dần các mối quan hệ (các phần dữ liệu cần được liên kết với các bộ dữ liệu Note) vào sơ đồ quan hệ lớp.

Một ghi chú C là một thể hiện của Notelớp. Một C lưu ý sẽ trả lại thuộc tính có liên quan đến ghi chú này, chẳng hạn như hội Tam hoàng có liên quan, và vị trí tương đối của nó ( Interval) đối với một Scalebắt đầu với một C lưu ý.

Mối quan hệ giữa các thể hiện của cùng một lớp (ví dụ, giữa một ghi chú C và một ghi chú E ) nên được mô hình hóa như các thuộc tính, không phải là thừa kế.

Hơn nữa, nhiều mối quan hệ giữa các lớp trong các ví dụ của bạn cũng được mô hình hóa phù hợp hơn như các thuộc tính. Thí dụ:

(ví dụ mã đang chờ xử lý vì tôi cần học lại lý thuyết âm nhạc ...)


Suy nghĩ thú vị, nhưng làm thế nào một người sẽ xử lý xác định chất lượng hợp âm trong bối cảnh phân tích hài hòa? Ví dụ C Hợp âm sẽ cần phải có thuộc tính chất lượng, được đặt thành nhỏ (không sao) nhưng sau đó, một hợp âm chiếm ưu thế / giảm dần / tăng / nhỏ 7, 9, 11 thì sao? Có rất nhiều hợp âm mà một nốt nhạc có thể thuộc về. Làm thế nào tôi có thể xác định các loại hợp âm khác nhau và phẩm chất tương ứng của chúng trong phần phân tích của mã là gì?
Igneous01

Tôi biết rất ít lý thuyết âm nhạc, vì vậy tôi không thể trả lời câu hỏi của bạn. Một cách có thể giúp tôi hiểu là tìm một bảng liệt kê tất cả các ghi chú liên quan đến các khái niệm đó. Truy vấn cho hợp âm có thể có các tham số bổ sung.
rwong

2
Dưới đây là một danh sách rất hay về tất cả các hợp âm có thể: en.wikipedia.org/wiki/List_of_chords Tất cả các hợp âm có thể được áp dụng cho bất kỳ ghi chú nào, điều quan trọng với tình huống của tôi là các giai điệu tăng cường là chính xác: tức là. Cflat Major! = BMajor, Chúng là hợp âm trên piano, nhưng chức năng điều hòa của chúng rất khác nhau trên giấy. Tôi nghĩ rằng một điều tra viên để chia sẻ / vỗ một ghi chú sẽ có ý nghĩa nhất đối với một ví dụ của ghi chú. Đó là cách C.Sharpen () = C # và C.Flatten () = Cb, điều này có thể giúp tôi xác nhận hợp âm người dùng dễ dàng hơn.
Igneous01

2

Về cơ bản, nốt nhạc là tần số và khoảng âm nhạc là tỷ số tần số.

Mọi thứ khác có thể được xây dựng dựa trên điều đó.

Hợp âm là một danh sách các quãng. Một quy mô là một lưu ý cơ bản và một hệ thống điều chỉnh. Một hệ thống điều chỉnh cũng là một danh sách các khoảng.

Làm thế nào bạn đặt tên cho họ chỉ là một vật phẩm văn hóa.

Bài viết lý thuyết âm nhạc của Wikipedia là một điểm khởi đầu tốt đẹp.


Thật thú vị, mặc dù tôi không chắc chắn rằng nó thực sự hữu ích để mô hình hóa hệ thống theo thực tế vật lý cơ bản. Hãy nhớ rằng, mô hình được yêu cầu phải hữu ích trong việc nêu rõ một khía cạnh cụ thể, không nhất thiết phải toàn diện hoặc thậm chí chính xác. Mặc dù cách tiếp cận của bạn sẽ vừa chính xác vừa toàn diện, nhưng nó có thể ở mức quá thấp cho trường hợp sử dụng của OP.
Konrad Rudolph

@KonradRudolph - Với vị trí cực đoan của tôi, tôi chỉ muốn chỉ ra rằng người ta không nên trộn mô hình cơ bản với lớp trình bày, theo cách tương tự như thời gian tiết kiệm ánh sáng ban ngày: Bản thân việc tính toán dễ dàng hơn nhiều. Tôi đồng ý rằng mức độ trừu tượng hữu ích nhất không phải là những gì tôi đề xuất, nhưng tôi cảm thấy rằng mức độ trừu tượng được đề xuất bởi OP cũng không đủ.
mouviciel

Mục đích của chương trình này là không nhất thiết phải hiển thị thực tế vật lý của âm nhạc. Nhưng đối với những người nghiên cứu lý thuyết (như bản thân tôi) để có thể nhanh chóng phát âm trong một số hợp âm và có chương trình diễn giải khả năng tốt nhất của nó như thế nào các hợp âm này có liên quan với nhau theo nghĩa hài hòa. Tôi chỉ có thể phân tích nó theo cách cố gắng và thực sự để đọc thước đo bằng thước đo, nhưng đây là một công cụ khác để làm cho mọi thứ dễ dàng hơn và có thể tập trung vào các chi tiết tốt hơn khi phân tích.
Igneous01

1

Tôi đang tìm thấy dicussion này hấp dẫn.

Là các ghi chú được nhập thông qua midi (hoặc một số loại thiết bị ghi âm) hoặc chúng được nhập bằng cách nhập các chữ cái và ký hiệu?

Trong trường hợp khoảng từ C đến D-sharp / E-Flat:

Mặc dù D-sharp và E-Flat là cùng một âm (khoảng 311Hz nếu A = 440Hz), khoảng từ C -> D-sharp được viết là tăng thứ 2, trong khi khoảng từ C -> E-phẳng được viết là a thứ 3 nhỏ. Đủ dễ dàng nếu bạn biết làm thế nào các ghi chú đã được viết. Không thể xác định nếu bạn chỉ có hai âm báo để tiếp tục.

Trong trường hợp này, tôi tin rằng bạn cũng sẽ cần một cách để tăng / giảm âm cùng với các phương thức .Sharpen () và .latten () được đề cập, như .SemiToneUp (), .ullToneDown (), v.v. rằng bạn có thể tìm thấy các ghi chú không theo quy mô mà không "tô màu" chúng dưới dạng vật sắc nhọn / căn hộ.

Tôi phải đồng ý với @Rotem rằng "C" không phải là một lớp trong chính nó, mà là một sự khởi tạo của lớp Note.

Nếu bạn xác định các thuộc tính cho một ghi chú, bao gồm tất cả các khoảng là nửa cung, thì bất kể giá trị ghi chú ban đầu ("C", "F", "G #"), bạn sẽ có thể nói rằng một chuỗi ba ghi chú có gốc, thứ 3 chính (M3), sau đó thứ 3 (m3) sẽ là một bộ ba chính. Tương tự, m3 + M3 là một bộ ba nhỏ, m3 + m3 giảm dần, tăng thêm M3 + M3. Ngoài ra, điều này sẽ cung cấp cho bạn một cách để gói gọn việc tìm kiếm thứ 11, giảm thứ 13, v.v. mà không cần mã hóa rõ ràng cho tất cả 12 ghi chú cơ bản, và quãng tám của chúng lên xuống.

Khi đã xong, bạn vẫn còn một số vấn đề cần giải quyết.

Lấy bộ ba C, E, G. Là một nhạc sĩ, tôi thấy điều này rõ ràng như một hợp âm Cmaj. Tuy nhiên, nhà phát triển trong tôi có thể diễn giải phần bổ sung này là E nhỏ Augment 5 (Root E + m3 + a5) hoặc Gsus4 thứ 6 không 5 (RootG + 4 + 6).

Vì vậy, để trả lời câu hỏi của bạn về việc thực hiện phân tích, tôi nghĩ cách tốt nhất để xác định phương thức (chính, phụ, v.v.) là lấy tất cả các ghi chú đã nhập, sắp xếp chúng theo giá trị nửa cung tăng dần và kiểm tra chúng theo các hình thức hợp âm đã biết . Sau đó, sử dụng từng ghi chú được nhập làm ghi chú gốc và thực hiện cùng một bộ đánh giá.

Bạn có thể cân nhắc các hình thức hợp âm sao cho phổ biến hơn (chính, phụ) được ưu tiên hơn các hình thức hợp âm tăng, lơ lửng, elektra, v.v., nhưng một phân tích chính xác sẽ yêu cầu trình bày tất cả các hình thức hợp âm phù hợp như các giải pháp có thể.

Một lần nữa, bài viết trên wikipedia đã làm rất tốt việc liệt kê các lớp cao độ, do đó, thật đơn giản (mặc dù tẻ nhạt) để mã hóa các mô hình của các hợp âm, ghi chú đã nhập, gán chúng cho các lớp / khoảng cách, và sau đó so sánh chống lại các hình thức được biết cho các trận đấu.

Điều này đã được rất nhiều niềm vui. Cảm ơn!


Họ đang được nhập, thông qua văn bản cho đến nay. Tuy nhiên sau này tôi có thể sử dụng midi nếu chương trình được gói gọn. Em bé bước ngay bây giờ: D
Igneous01

0

Âm thanh như một trường hợp cho các mẫu. Bạn dường như có một template <?> class Major : public Chord;quá Major<C>là-một Chord, như là Major<B>. Tương tự, bạn cũng có một Note<?>mẫu với các thể hiện Note<C>Note<D>.

Điều duy nhất tôi đã bỏ đi là ?một phần. Có vẻ như bạn có một enum {A,B,C,D,E,F,G}nhưng tôi không biết làm thế nào bạn đặt tên cho enum đó.


0

Cảm ơn bạn cho tất cả các đề xuất, bằng cách nào đó tôi quản lý để bỏ lỡ các phản hồi thêm. Cho đến nay các lớp học của tôi đã được thiết kế như vậy:

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

Để giải quyết các vấn đề tính toán hợp âm và hợp âm của tôi, tôi quyết định sử dụng bộ đệm tròn, cho phép tôi đi qua bộ đệm từ bất kỳ điểm nào, đi tiếp, cho đến khi tôi tìm thấy ghi chú tiếp theo phù hợp.

Để tìm khoảng thời gian diễn giải qua bộ đệm ghi chú thực, hãy dừng khi các chữ cái khớp (chỉ chữ cái, không phải ghi chú thực tế hoặc vị trí) vì vậy c - g # = 5

Để tìm khoảng cách thực - đi qua một bộ đệm khác gồm 12 số nguyên, hãy dừng khi vị trí ghi chú trên cùng giống với giá trị của bộ đệm tại chỉ mục, một lần nữa điều này chỉ tiến về phía trước. Nhưng phần bù có thể ở bất cứ đâu (ví dụ: buffer.at (-10))

bây giờ tôi biết cả khoảng thời gian diễn giải và khoảng cách vật lý giữa hai khoảng thời gian. vì vậy tên khoảng đã hoàn thành một nửa.

bây giờ tôi có thể giải thích các khoảng, tức là. nếu khoảng là 5 và khoảng cách là 8, thì đó là khoảng 5 tăng.

Cho đến nay lưu ý và khoảng thời gian đang làm việc như mong đợi, bây giờ tôi chỉ phải giải quyết định danh hợp âm.

Cảm ơn một lần nữa, tôi sẽ đọc lại một số trong những phản hồi này và kết hợp một số ý tưởng ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.