Ich habe begonnen, ein Programm in C ++ 11 zu schreiben, das Akkorde, Tonleitern und Harmonien analysiert. Das größte Problem, das ich in meiner Entwurfsphase habe, ist, dass die Note 'C' eine Note, eine Akkordart (Cmaj, Cmin, C7 usw.) und eine Tonart (die Tonart von Cmajor, Cminor) ist. Das gleiche Problem tritt mit Intervallen (Moll 3, Dur 3) auf.
Ich benutze eine Basisklasse, Token, das ist die Basisklasse für alle 'Symbole' im Programm. so zum Beispiel:
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;
Wie Sie sehen, würde das Erstellen aller abgeleiteten Klassen (CMajorTriad, C, CMajorScale, CMajorKey usw.) einschließlich aller anderen Noten und Enharmonics schnell lächerlich komplex werden. Mehrfachvererbung würde nicht funktionieren, dh:
class C : public Note, Triad, Key, Scale
Klasse C kann nicht alles gleichzeitig sein. Es ist kontextabhängig, auch Polymorphing wird damit nicht funktionieren (wie man bestimmt, welche Supermethoden auszuführen sind? Aufrufen aller Superklassenkonstruktoren sollte hier nicht passieren).
Gibt es irgendwelche Designideen oder Vorschläge, die die Leute zu bieten haben? In Bezug auf die Modellierung der tonalen Harmonie aus einer OO-Perspektive konnte ich bei Google nichts finden. Es gibt einfach viel zu viele Beziehungen zwischen allen Konzepten.
quelle
Antworten:
Ich denke, der beste Ansatz ist es, die realen Beziehungen zwischen diesen Einheiten zu reproduzieren.
Zum Beispiel könnten Sie haben:
ein
Note
Objekt, dessen Eigenschaften sindName (C, D, E, F, G, A, B)
zufällig (natürlich, flach, scharf)
Frequenz oder eine andere eindeutige Tonhöhenkennung
ein
Chord
Objekt, dessen Eigenschaften sindeine Reihe von
Note
ObjektenName
versehentlich
Qualität (Dur, Moll, vermindert, erweitert, ausgesetzt)
Ergänzungen (7, 7+, 6, 9, 9+, 4)
ein
Scale
Objekt, dessen Eigenschaften sindeine Reihe von
Note
ObjektenName
Typ (Dur, natürliches Moll, melodisches Moll, harmonisches Moll)
Modus (ionisch, dorisch, phrygisch, lydisch, mixolidisch, äolisch, locrisch)
Wenn Ihre Eingabe in Textform erfolgt, können Sie Notizen mit einer Zeichenfolge erstellen, die den Notennamen, die zufällige Oktave und (falls erforderlich) die Oktave enthält.
Zum Beispiel (Pseudocode, ich kenne C ++ nicht):
Dann in der
Note
Klasse die Zeichenfolge analysieren und die Eigenschaften festlegen.A
Chord
könnte durch seine Notizen konstruiert werden:... oder durch eine Zeichenfolge mit Name, Qualität und zusätzlichen Anmerkungen:
Ich weiß nicht genau, was Ihre Bewerbung bewirken wird. Das sind also nur Ideen.
Viel Glück mit Ihrem faszinierenden Projekt!
quelle
Einige allgemeine Ratschläge.
Wenn im Klassendesign viel Unsicherheit zu erwarten ist (wie in Ihrer Situation), würde ich empfehlen, mit verschiedenen konkurrierenden Klassendesigns zu experimentieren.
Die Verwendung von C ++ in dieser Phase ist möglicherweise nicht so produktiv wie in anderen Sprachen. (Dieses Problem tritt in Ihren Codefragmenten auf, die sich mit
typedef
und befassen müssenvirtual
Destruktoren .) Auch wenn das Projektziel darin besteht, C ++ - Code zu erstellen, kann es produktiv sein, das Design der ersten Klasse in einer anderen Sprache durchzuführen. (Zum Beispiel Java, obwohl es viele Möglichkeiten gibt.)Wählen Sie C ++ nicht nur wegen der Mehrfachvererbung. Mehrfachvererbung hat seine Verwendung, ist jedoch nicht der richtige Weg, um dieses Problem zu modellieren (Musiktheorie).
Achten Sie besonders auf die Disambiguierung. Obwohl in englischen (textuellen) Beschreibungen häufig Unklarheiten auftreten, müssen diese beim Entwerfen von OOP-Klassen behoben werden.
Wir sprechen von G und Gis als Noten. Wir sprechen von G-Dur und G-Moll als Tonleitern. Somit sind
Note
undScale
sind keine austauschbaren Begriffe. Es kann nicht sein irgendein Objekt , das gleichzeitig eine Instanz eines sein kann ,Note
und einScale
.Diese Seite enthält einige Diagramme, die die Beziehung veranschaulichen: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations
In einem anderen Beispiel hat "eine Triade, die mit G in C-Dur beginnt " nicht die gleiche Bedeutung wie "eine Triade, die mit C in G-Dur beginnt ".
Zu diesem frühen Zeitpunkt ist die
Token
Klasse (die Oberklasse von allem) nicht gerechtfertigt, da sie eine Disambiguierung verhindert. Sie kann bei Bedarf später eingeführt werden (unterstützt von einem Codefragment, das zeigt, wie nützlich dies sein kann.)Beginnen Sie zunächst mit einer
Note
Klasse, die das Zentrum des Klassendiagramms darstellt, und fügen Sie dann nach und nach die Beziehungen (Datenelemente, die Tupeln vonNote
s zugeordnet werden müssen) zum Klassenbeziehungsdiagramm hinzu.Eine C- Note ist eine Instanz der
Note
Klasse. Eine C- Note gibt Eigenschaften zurück, die sich auf diese Note beziehen, wie z. B. verwandte Triaden und ihre relative Position (Interval
) in Bezug auf eine NoteScale
, die mit einer C- Note beginnt .Beziehungen zwischen Instanzen derselben Klasse (z. B. zwischen einer C- Note und einer E- Note) sollten als Eigenschaften und nicht als Vererbung modelliert werden.
Darüber hinaus werden viele der klassenübergreifenden Beziehungen in Ihren Beispielen auch besser als Eigenschaften modelliert. Beispiel:
(Codebeispiele stehen noch aus, da ich die Musiktheorie neu lernen muss ...)
quelle
Grundsätzlich sind Noten Frequenzen und musikalische Intervalle Frequenzverhältnisse.
Alles andere kann darauf aufgebaut werden.
Ein Akkord ist eine Liste von Intervallen. Eine Skala ist eine Grundnote und ein Stimmsystem. Ein Stimmsystem ist auch eine Liste von Intervallen.
Wie Sie sie nennen, ist nur ein kulturelles Artefakt.
Der musiktheoretische Artikel von Wikipedia ist ein guter Ausgangspunkt.
quelle
Ich finde diese Diskussion faszinierend.
Werden die Noten über Midi (oder eine Art Tonaufnahmegerät) eingegeben oder werden sie durch Eingabe der Buchstaben und Symbole eingegeben?
Im Fall des Intervalls von C bis Dis / Es:
Obwohl Dis und Es der gleiche Ton sind (um 311 Hz, wenn A = 440 Hz), wird das Intervall von C -> Dis um eine erhöhte Sekunde erhöht, während das Intervall von C -> Es wie a geschrieben wird Moll 3.. Einfach genug, wenn Sie wissen, wie die Notiz geschrieben wurde. Es ist unmöglich zu bestimmen, ob Sie nur die zwei Töne haben, die weitergehen sollen.
In diesem Fall werden Sie meines Erachtens auch eine Möglichkeit benötigen, den Ton zusammen mit den genannten Methoden .Sharpen () und .Flatten () zu erhöhen / zu verringern, z. B. .SemiToneUp (), .FullToneDown () usw. dass Sie nachfolgende Noten in einer Skala finden können, ohne sie als Sharps / Flats "einzufärben".
Ich muss @Rotem zustimmen, dass "C" keine Klasse für sich ist, sondern eine Instanziierung der Note-Klasse.
Wenn Sie die Eigenschaften für eine Note definieren, einschließlich aller Intervalle als Halbtöne, können Sie unabhängig vom anfänglichen Notenwert ("C", "F", "G #") feststellen, dass eine Sequenz mit drei Noten die folgende hat root, major 3rd (M3), dann minor 3rd (m3) wäre eine Dur-Triade. In ähnlicher Weise ist m3 + M3 eine kleine Triade, m3 + m3 verringert, M3 + M3 erhöht. Außerdem können Sie auf diese Weise das Ermitteln der 11., der verminderten 13. usw. kapseln, ohne diese explizit für alle 12 Basisnoten und ihre Oktaven nach oben und unten zu codieren.
Sobald dies erledigt ist, haben Sie noch einige Probleme zu lösen.
Nehmen Sie die Triade C, E, G. Als Musiker sehe ich das deutlich als Cmaj-Akkord. Der Entwickler in mir kann dies jedoch zusätzlich als e-Moll-Augment 5 (Wurzel E + m3 + a5) oder als Gsus4 6.-5. (Wurzel G + 4 + 6) interpretieren.
Um Ihre Frage zur Durchführung der Analyse zu beantworten, ist es meiner Meinung nach die beste Methode, die Modalität (Maj, Moll usw.) zu bestimmen, alle eingegebenen Noten zu nehmen, in aufsteigenden Halbtonwerten anzuordnen und sie mit den bekannten Akkordformen zu testen . Verwenden Sie dann jede als Grundton eingegebene Note und führen Sie die gleichen Auswertungen durch.
Sie können die Akkordformen so gewichten, dass häufiger (Dur, Moll) Vorrang vor den Akkordformen Augmented, Suspended, Elektra usw. hat. Für eine genaue Analyse müssen jedoch alle übereinstimmenden Akkordformen als mögliche Lösungen angegeben werden.
Auch in dem Wikipedia-Artikel, auf den verwiesen wird, werden die Tonhöhenklassen gut aufgelistet. Daher sollte es einfach (wenn auch mühsam) sein, die Modelle der Akkorde zu codieren, die eingegebenen Noten zu nehmen, sie Tonhöhenklassen / Intervallen zuzuordnen und dann zu vergleichen gegen die bekannten Formen für Streichhölzer.
Das hat sehr viel Spaß gemacht. Vielen Dank!
quelle
Klingt wie ein Fall für Vorlagen. Sie scheinen ein zu haben ,
template <?> class Major : public Chord;
soMajor<C>
ist-einChord
, wieMajor<B>
. Ebenso haben Sie auch eineNote<?>
Vorlage mit InstanzenNote<C>
undNote<D>
.Das einzige, was ich ausgelassen habe, ist der
?
Teil. Es scheint, Sie haben eine,enum {A,B,C,D,E,F,G}
aber ich weiß nicht, wie Sie diese Aufzählung nennen würden.quelle
Vielen Dank für alle Vorschläge, irgendwie habe ich es geschafft, die zusätzlichen Antworten zu verpassen. Bisher sind meine Klassen so angelegt:
Um meine Probleme mit der Intervall- und Akkordberechnung zu lösen, habe ich mich für den Ringspeicher entschieden, mit dem ich den Puffer von einem beliebigen Punkt aus durchlaufen kann, bis ich die nächste passende Note finde.
Stoppen Sie, wenn die Buchstaben übereinstimmen (nur der Buchstabe, nicht die tatsächliche Note oder Position), um das interpretierte Intervall zu finden, das den Puffer für echte Noten durchläuft. C - g # = 5
Um die reale Distanz zu finden, die einen anderen Puffer mit 12 ganzen Zahlen durchläuft, stoppen Sie, wenn die obere Notenposition mit dem Wert des Puffers am Index übereinstimmt. Auch dies bewegt sich nur vorwärts. Der Offset kann aber überall sein (zB buffer.at (-10))
Jetzt kenne ich sowohl das interpretierte Intervall als auch die physische Entfernung zwischen den beiden. Der Intervallname ist also bereits zur Hälfte vollständig.
jetzt kann ich das Intervall interpretieren, dh. Wenn das Intervall 5 und der Abstand 8 ist, ist es ein erhöhter fünfter.
Bisher funktionieren Note und Intervall wie erwartet, jetzt muss ich nur noch die Akkordkennung in Angriff nehmen.
Nochmals vielen Dank, ich werde einige dieser Antworten noch einmal lesen und hier einige Ideen einfließen lassen.
quelle