OO Tasarım, Tonal Uyum nasıl modellenir?


12

C ++ 11'de akorları, ölçekleri ve uyumu analiz edecek bir program yazmaya başladım. Tasarım aşamamda yaşadığım en büyük sorun, 'C' notunun bir not, bir tür akor (Cmaj, Cmin, C7, vb.) Ve bir tür anahtar (Cmajor, Cminor'un anahtarı) olmasıdır. Aynı sorun aralıklarla da ortaya çıkar (küçük 3., büyük 3.).

Programdaki tüm 'semboller' için temel sınıf olan bir temel sınıf olan Token kullanıyorum. Yani mesela:

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;

Gördüğünüz gibi, türetilmiş tüm sınıfları (CMajorTriad, C, CMajorScale, CMajorKey, vb.) Oluşturmak, diğer tüm notları ve enharmonikleri de dahil olmak üzere hızla gülünç bir şekilde karmaşık hale gelecektir. çoklu kalıtım çalışmaz, yani:

class C : public Note, Triad, Key, Scale

C sınıfı, bunların hepsi aynı anda olamaz. Bağlamsaldır, ayrıca bununla polimorflama işe yaramaz (hangi süper yöntemlerin gerçekleştirileceği nasıl belirlenir? Her süper sınıf kurucularını çağırmak burada olmamalı)

İnsanların sunması gereken tasarım fikirleri veya önerileri var mı? Google'da ton uyumunu bir OO perspektifinden modelleme konusunda hiçbir şey bulamadım. Buradaki tüm kavramlar arasında çok fazla ilişki var.


8
Neden 'C' bir sınıf olsun ki? 'Not', 'Akor' vb. 'C' numarasının bir rol oynayabileceği bir değer numaralandırması olan sınıflar olacağını hayal ederdim.
Rotem

Kullanıcı-> akor CEG girerse, uygun akoru oluşturmak için notaların ne olduğunu bulması gerekir. <Notes> 'un bir vektörüne, hepsi polimorfik olarak ele alınacak olan execute () yöntemine params olarak geçmeyi düşünüyordum. Ancak bir numaralandırıcı kullanmak mantıklı olurdu, ama sonra her nesneyi kullanmak istediğim numaralandırma ile başlatmam gerekirdi.
Igneous01

Bu konuda @Rotem ile beraberim: Bazen, nesne kompozisyonunu miras yerine tercih etmeniz gerekir.
Aralık'ta Spoike

Bana göre bu nota / akor / ölçek sınıflarıyla ne yapmak istediğinizi düşünmek faydalı olabilir . Notalar üretecek misiniz? Midi dosyaları? Skorlar üzerinde dönüşümler (transpozisyon, tüm nota uzunluklarını ikiye katlama, belirli bir notanın üzerindeki tüm notalara titreme ekleme, vb.)? Olası bir sınıf yapısına sahip olduğunuzda, bu görevleri nasıl başaracağınızı düşünün. Eğer garip görünüyorsa, belki farklı bir sınıf yapısı istersiniz.
MatrixFrog

Yanıtlar:


9

Bence en iyi yaklaşım, bu varlıklar arasındaki gerçek ilişkileri yeniden oluşturmaktır.

Örneğin, şunlara sahip olabilirsiniz:

  • Noteözellikleri olan bir nesne

    • isim (C, D, E, F, G, A, B)

    • kazara (doğal, düz, keskin)

    • frekans veya başka bir benzersiz adım tanımlayıcısı

  • Chordözellikleri olan bir nesne

    • bir dizi Notenesne

    • isim

    • tesadüfi

    • kalite (büyük, küçük, azaltılmış, artırılmış, askıya alınmış)

    • eklemeler (7, 7+, 6, 9, 9+, 4)

  • Scaleözellikleri olan bir nesne

    • bir dizi Notenesne

    • isim

    • tip (majör, doğal minör, melodik minör, harmonik minör)

    • mod (iyon, dorian, phrygian, lydian, mixolidian, aeolian, locrian)

Ardından, girdiniz metinselse, not adı, yanlışlıkla ve (gerekirse) oktav içeren bir dizeyle notlar oluşturabilirsiniz.

Örneğin (sözde kod, C ++ bilmiyorum):

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

Daha sonra, Notesınıfta dizeyi ayrıştırabilir ve özellikleri ayarlayabilirsiniz.

A Chordnotları ile inşa edilebilir:

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

... veya ad, kalite ve ek notlar içeren bir dize ile:

chord = new Chord('Cmaj7');

Başvurunuzun tam olarak ne yapacağını bilmiyorum, bu yüzden bunlar sadece fikir.

Büyüleyici projenizde bol şanslar!


4

Bazı genel öneriler.


Sınıf tasarımında çok fazla belirsizlik olması durumunda (durumunuzda olduğu gibi), farklı rakip sınıf tasarımlarıyla denemeler yapmanızı tavsiye ederim.

Bu aşamada C ++ kullanmak diğer diller kadar verimli olmayabilir. (Bu sorun, başa çıkmak zorunda olan kod parçalarınızda typedefve virtualyıkıcılarda açıktır .) Proje hedefi C ++ kodu üretmek olsa bile, ilk sınıf tasarımını başka bir dilde yapmak verimli olabilir. (Örneğin Java, birçok seçenek olsa da.)

Birden fazla kalıtım nedeniyle C ++ 'ı seçmeyin. Çoklu kalıtımın kullanımları vardır, ancak bu sorunu modellemek için doğru yol değildir (müzik teorisi).


Belirsizleştirmek için özel dikkat gösterin. İngilizce (metinsel) açıklamalarda belirsizlikler bol olsa da, OOP sınıfları tasarlanırken bu belirsizlikler giderilmelidir.

Not olarak G ve G'den bahsediyoruz . Ölçek olarak G majör ve G minörden bahsediyoruz . Böylece Noteve Scalebirbirinin yerine geçebilen kavramlar değildir. Aynı anda a ve a örneği olabilecek herhangi bir nesne olamaz .NoteScale

Bu sayfa, ilişkiyi gösteren birkaç şema içermektedir: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations

Başka bir örnek olarak, "Triad olduğu ile başlar G bir ilgili Cı büyük ölçekli" "bir Triad ile aynı anlama sahip değildir ile başlar C bir ilgili majör ölçekli".

Bu erken aşamada, Tokensınıf (her şeyin üst sınıfı) haksızdır, çünkü anlam ayrılmasını önler. Gerekirse daha sonra eklenebilir (bunun nasıl yararlı olabileceğini gösteren bir kod parçası tarafından desteklenir).


Başlamak için Note, sınıf diyagramının merkezi olan bir sınıfla başlayın , sonra Notesınıf ilişkileri diyagramına ilişkileri ( s tuples ile ilişkili olması gereken veri parçaları) yavaş yavaş ekleyin .

Bir Cı- not bir örneğidir Notesınıfı. Bir not gibi ilgili üçlü olarak, bu kayda ilgili özellikler, ve göreli konumunu (döner Intervalbir ile ilgili olarak) Scalebu başlar bir ile not.

Aynı sınıftaki örnekler arasındaki ilişkiler (örneğin, bir C notu ile E notu arasında) miras değil özellikler olarak modellenmelidir.

Dahası, örneklerinizdeki sınıflar arası ilişkilerin birçoğu özellik olarak daha uygun bir şekilde modellenmiştir. Misal:

(kod örnekleri beklemede çünkü müzik teorisini yeniden öğrenmem gerekiyor ...)


İlginç bir düşünce, ancak harmonik analiz bağlamında akor niteliklerinin belirlenmesinde nasıl başa çıkılır? C Akor örneğinin önemsiz olarak ayarlanmış kaliteli özelliğe sahip olması gerekir (tamamdır) ama sonra baskın / azalan / artırılmış / küçük 7s, 9, 11 akorları ne olacak? Tek bir notanın ait olabileceği birçok akor vardır. Kodun analiz bölümünde çeşitli akor tiplerinin ve ilgili niteliklerinin ne olduğunu nasıl belirleyebilirim?
Igneous01

Çok az müzik teorisi biliyorum, bu yüzden sorunuza cevap veremiyorum. Anlamama yardımcı olabilecek bir yol, bu kavramlarda yer alan tüm notları listeleyen bir tablo bulmak olacaktır. Akorlar için sorgular ek parametreler alabilir.
rwong

2
İşte tüm olası akorların çok güzel bir listesi: en.wikipedia.org/wiki/List_of_chords Tüm akorlar herhangi bir nota uygulanabilir, benim durumumda önemli olan şey, enharmoniklerin doğru olmasıdır: yani. Cflat major! = BMajor, Piyanoda fiziksel olarak aynı akor, ancak harmonik fonksiyonları kağıt üzerinde çok farklı. Bir notu keskinleştirmek / düzleştirmek için bir numaralandırıcının not örneği için en anlamlı olacağını düşünüyorum. Bu şekilde C.Sharpen () = C # ve C.Flatten () = Cb, bu kullanıcı akorlarını doğrulamamı kolaylaştırabilir.
Igneous01

2

Temel olarak müzik notaları frekans, müzik aralıkları frekans oranlarıdır.

Diğer her şey bunun üzerine inşa edilebilir.

Akor, aralıkların listesidir. Ölçek temel bir not ve ayarlama sistemidir. Bir ayar sistemi de aralıkların bir listesidir.

Onları nasıl adlandırdığınız sadece kültürel bir eserdir.

Wikipedia'nın Müzik teorisi makalesi güzel bir başlangıç ​​noktasıdır.


İlginç, ancak sistemi temeldeki fiziksel gerçeklik açısından modellemenin mutlaka yararlı olduğundan emin değilim. Unutmayın, modelin belirli bir yönü ifade etmede yardımcı olması, kapsamlı ve hatta doğru olması gerekmez. Yaklaşımınız hem doğru hem de kapsamlı olsa da, OP'nin kullanım durumu için çok düşük bir seviye olabilir.
Konrad Rudolph

@KonradRudolph - Aşırı konumumla, sadece temel modeli sunum katmanıyla, yaz saati uygulamalarına benzer bir şekilde karıştırmamaya dikkat etmek istedim: Hesaplamalar modelin kendisinde çok daha kolay. En yararlı soyutlama seviyesinin önerdiğim şey olmadığını kabul ediyorum, ancak OP tarafından önerilen soyutlama seviyesinin de yeterli olmadığını hissediyorum.
mouviciel

Bu programın amacı mutlaka müziğin fiziksel gerçekliğini göstermek değildir. Ancak teoriyi okuyan insanlar için (benim gibi) sadece bazı akorları hızlı bir şekilde çizebilmek ve programın bu akorların birbiriyle nasıl uyumlu olduğunu en iyi şekilde yorumlayabilmesi. Sadece puan ölçüsünü ölçerek okumanın denenmiş ve gerçek bir yolunu analiz edebilirim, ancak bu işleri kolaylaştırmak ve analiz ederken daha ince ayrıntılara odaklanabilmek için başka bir araçtır.
13:23

1

Bu tartışmayı büyüleyici buluyorum.

Notlar midi (veya bir tür ton yakalama aygıtı) aracılığıyla mı giriliyor yoksa harfler ve simgeler yazarak mı giriliyor?

C ile D-keskin / E-düz arasında bir aralık olması durumunda:

D-sharp ve E-flat aynı tonda olmasına rağmen (A = 440Hz ise 311Hz civarında), C -> D-sharp arasındaki aralık artırılmış 2 olarak yazılırken, C -> E-flat arasındaki aralık bir wittem olur minör 3.. Notun nasıl yazıldığını biliyorsanız yeterince kolay. Devam etmek için sadece iki tonunuz olup olmadığını belirlemek imkansız.

Bu durumda, aynı zamanda .SemiToneUp (), .FullToneDown () vb.Gibi bahsedilen .Sharpen () ve .Flatten () yöntemleriyle birlikte tonu artırmanın / azaltmanın bir yoluna ihtiyacınız olacağını düşünüyorum. sonraki notaları keskinleştirme / daire olarak "renklendirmeden" bir ölçekte bulabilirsiniz.

@Rotem ile "C" nin kendi içinde bir sınıf değil, daha çok Note sınıfının bir örneği olduğunu kabul etmeliyim.

Bir notun özelliklerini, aralıklar da dahil olmak üzere yarı tonlar olarak tanımlarsanız, ilk not değerine ("C", "F", "G #") bakılmaksızın, kök, ana 3. (M3), sonra küçük 3. (m3) büyük bir üçlü olur. Benzer şekilde, m3 + M3 küçük bir üçlüdür, m3 + m3 azalmıştır, M3 + M3 artırılmıştır. Buna ek olarak, bu, 12 temel notanın tümü ve oktavları yukarı ve aşağı için açıkça kodlamadan 11., azaltılmış 13. vb. Bulmayı kapsüllemek için bir yol verecektir.

Bir kez bitti, hala çözmek için bazı sorunlar kaldı.

Tri, C, E, G takımını al. Bir müzisyen olarak bunu açıkça bir Cmaj akoru olarak görüyorum. Bununla birlikte, içimdeki geliştirici bunu ek olarak E minör Augment 5 (Root E + m3 + a5) veya Gsus4 6. no. 5. (RootG + 4 + 6) olarak yorumlayabilir.

Bu nedenle, analiz yapma ile ilgili sorunuzu cevaplamak için, modaliteyi (maj, minör, vb.) Belirlemenin en iyi yolunun girilen tüm notları almak, artan yarı ton değerinde düzenlemek ve bilinen akor formlarına karşı test etmek olduğunu düşünüyorum. . Ardından, kök not olarak girilen her notu kullanın ve aynı değerlendirme kümesini gerçekleştirin.

Akor formlarını, artırılmış, askıya alınmış, elektra, vb. Akor formlarına göre daha yaygın (majör, minör) öncelikli olacak şekilde ağırlıklandırabilirsiniz, ancak doğru bir analiz, eşleşen tüm akor formlarının olası çözümler olarak sunulmasını gerektirecektir.

Yine atıfta bulunulan wikipedia makalesi, perde sınıflarını listelemek için iyi bir iş çıkarır, bu nedenle akorların modellerini kodlamak, girilen notları almak, bunları sınıflara / aralıklara atamak ve sonra karşılaştırmak basit olmalıdır (sıkıcı olsa da). maçlar için bilinen formlara karşı.

Bu çok eğlenceliydi. Teşekkürler!


Şimdilik metin aracılığıyla giriliyorlar. Ancak daha sonra program düzgün bir şekilde kapsüllenmişse midi kullanabilirim. Bebek şu anda adımlar: D
Igneous01

0

Şablonlar için bir vaka gibi geliyor. Bir var gibi template <?> class Major : public Chord;öylesine Major<C>is-a Chordgibidir, Major<B>. Benzer şekilde, aynı zamanda bir var Note<?>örnekleriyle şablonu Note<C>ve Note<D>.

Dışarıda kalan tek şey ?kısım. Görünüşe göre bir tane var enum {A,B,C,D,E,F,G}ama o numaraya nasıl isim vereceğini bilmiyorum.


0

Tüm önerileriniz için teşekkür ederim, bir şekilde ekstra yanıtları kaçırmayı başardım. Şu ana kadar derslerim şu şekilde tasarlandı:

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

Aralık ve akor hesaplama problemlerimi çözmek için, eşleşen bir sonraki notu bulana kadar herhangi bir noktadan arabelleği geçmeme izin veren dairesel tamponu kullanmaya karar verdim.

Yorumlanan aralığı bulmak için - gerçek notlar arabelleğini çaprazlayın, harfler eşleştiğinde durun (sadece harf, gerçek not veya konum değil), böylece c - g # = 5

Gerçek tam dönüşü bulmak için 12 tamsayı olan başka bir arabellek, üst nota konumu arabellek dizindeki değerle aynı olduğunda durun, yine bu yalnızca ileriye doğru hareket eder. Ancak ofset herhangi bir yerde olabilir (yani buffer.at (-10))

Şimdi hem yorumlanmış aralığı hem de ikisi arasındaki fiziksel mesafeyi biliyorum. bu nedenle aralık adı zaten yarıda.

şimdi aralığı yorumlayabiliyorum, yani. aralık 5 ve mesafe 8 ise, artırılmış bir 5. olur.

Şimdiye kadar not ve aralık beklendiği gibi çalışıyor, şimdi sadece akor tanımlayıcıyla uğraşmak zorundayım.

Tekrar teşekkürler, bu yanıtların bazılarını tekrar okuyacağım ve bazı fikirleri buraya dahil edeceğim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.