J'ai commencé à écrire un programme en C ++ 11 qui analyserait les accords, les gammes et l'harmonie. Le plus gros problème que j'ai dans ma phase de conception, c'est que la note 'C' est une note, un type d'accord (Cmaj, Cmin, C7, etc.) et un type de clé (la clé de Cmajor, Cminor). Le même problème se pose avec les intervalles (3e mineur, 3e majeur).
J'utilise une classe de base, Token, qui est la classe de base pour tous les «symboles» du programme. donc par exemple:
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;
Comme vous pouvez le voir, créer toutes les classes dérivées (CMajorTriad, C, CMajorScale, CMajorKey, etc.) deviendrait rapidement ridiculement complexe, y compris toutes les autres notes, ainsi que les harmoniques. l'héritage multiple ne fonctionnerait pas, c'est-à-dire:
class C : public Note, Triad, Key, Scale
classe C, ne peut pas être toutes ces choses en même temps. Il est contextuel, polymorphiser avec cela ne fonctionnera pas (comment déterminer les super méthodes à exécuter? Appeler tous les constructeurs de super classes ne devrait pas se produire ici)
Y a-t-il des idées ou des suggestions de design que les gens ont à offrir? Je n'ai rien trouvé sur google en ce qui concerne la modélisation de l'harmonie tonale du point de vue OO. Il y a juste trop de relations entre tous les concepts ici.
la source
Réponses:
Je pense que la meilleure approche est de reproduire les relations réelles entre ces entités.
Par exemple, vous pourriez avoir:
un
Note
objet, dont les propriétés sontnom (C, D, E, F, G, A, B)
accidentel (naturel, plat, tranchant)
fréquence ou un autre identifiant de hauteur unique
un
Chord
objet, dont les propriétés sontun tableau d'
Note
objetsNom
accidentel
qualité (majeure, mineure, diminuée, augmentée, suspendue)
ajouts (7, 7+, 6, 9, 9+, 4)
un
Scale
objet, dont les propriétés sontun tableau d'
Note
objetsNom
type (majeur, mineur naturel, mineur mélodique, mineur harmonique)
mode (ionien, dorien, phrygien, lydien, mixolidien, éolien, locrien)
Ensuite, si votre entrée est textuelle, vous pouvez créer des notes avec une chaîne comprenant le nom de la note, accidentelle et (si vous en avez besoin) l'octave.
Par exemple (pseudocode, je ne connais pas C ++):
Ensuite, dans la
Note
classe, vous pouvez analyser la chaîne et définir les propriétés.Un
Chord
pourrait être construit par ses notes:... ou par une chaîne comprenant le nom, la qualité et des notes supplémentaires:
Je ne sais pas exactement ce que fera votre application, ce ne sont donc que des idées.
Bonne chance avec votre projet fascinant!
la source
Quelques conseils génériques.
S'il y a beaucoup d'incertitude dans la conception de la classe (comme dans votre situation), je recommanderais d'expérimenter avec différentes conceptions de classes concurrentes.
L'utilisation de C ++ à ce stade peut ne pas être aussi productive que d'autres langages. (Ce problème est apparent dans vos fragments de code devant être traités
typedef
etvirtual
destructeurs.) Même si l'objectif du projet est de produire du code C ++, il peut être productif de faire la conception de classe initiale dans un autre langage. (Par exemple, Java, bien qu'il existe de nombreux choix.)Ne choisissez pas C ++ simplement en raison de l'héritage multiple. L'héritage multiple a ses utilités mais ce n'est pas la bonne façon de modéliser ce problème (théorie de la musique).
Faites particulièrement attention à lever l'ambiguïté. Même si les ambiguïtés sont abondantes dans les descriptions anglaises (textuelles), ces ambiguïtés doivent être résolues lors de la conception des classes OOP.
On parle de G et de G sharp comme notes. Nous parlons de sol majeur et de sol mineur comme des gammes. Ainsi,
Note
etScale
ne sont pas des concepts interchangeables. Il ne pouvait pas être tout objet qui peut être simultanément une instance d'unNote
et unScale
.Cette page contient quelques diagrammes qui illustrent la relation: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations
Pour un autre exemple, "une Triade qui commence par G sur une échelle majeure de C " n'a pas la même signification que "une Triade qui commence par C sur une échelle majeure de G ".
À ce stade précoce, la
Token
classe (la superclasse de tout) est injustifiée, car elle empêche toute ambiguïté. Il pourrait être introduit plus tard si nécessaire (soutenu par un fragment de code qui montre comment cela pourrait être utile.)Pour commencer, commencez par une
Note
classe qui est le centre du diagramme de classe, puis ajoutez progressivement les relations (éléments de données qui doivent être associés à des tuples deNote
s) au diagramme de relations de classe.Une note C est une instance de la
Note
classe. Une note C renverra des propriétés liées à cette note, telles que des triades liées, et sa position relative (Interval
) par rapport à uneScale
qui commence par une note C.Les relations entre les instances de la même classe (par exemple, entre une note C et une note E ) doivent être modélisées comme des propriétés et non comme un héritage.
De plus, la plupart des relations inter-classes dans vos exemples sont également mieux modélisées en tant que propriétés. Exemple:
(des exemples de code sont en attente car j'ai besoin de réapprendre la théorie musicale ...)
la source
Fondamentalement, les notes de musique sont des fréquences et les intervalles musicaux sont des rapports de fréquence.
Tout le reste peut être construit sur cela.
Un accord est une liste d'intervalles. Une gamme est une note fondamentale et un système d'accord. Un système de réglage est également une liste d'intervalles.
Comment vous les nommez n'est qu'un artefact culturel.
L' article sur la théorie musicale de Wikipédia est un bon point de départ.
la source
Je trouve cette discussion fascinante.
Les notes sont-elles entrées via midi (ou un type d'appareil de capture de tonalité) ou sont-elles entrées en tapant les lettres et les symboles?
Dans le cas de l'intervalle de C à D-sharp / E-flat:
Bien que D-sharp et E-flat aient le même ton (environ 311Hz si A = 440Hz), l'intervalle de C -> D-sharp est écrit un 2ème augmenté, tandis que l'intervalle de C -> E-flat est écrit comme un mineur 3e. Assez facile si vous savez comment la note a été écrite. Impossible de déterminer si vous n'avez que les deux tonalités pour continuer.
Dans ce cas, je pense que vous aurez également besoin d'un moyen d'incrémenter / décrémenter le ton avec les méthodes .Sharpen () et .Flatten () mentionnées, telles que .SemiToneUp (), .FullToneDown (), etc. que vous pouvez trouver des notes moins fréquentes dans une échelle sans les "colorer" comme des objets tranchants / plats.
Je suis d'accord avec @Rotem que "C" n'est pas une classe en soi, mais plutôt une instanciation de la classe Note.
Si vous définissez les propriétés d'une note, y compris tous les intervalles sous forme de demi-tons, alors quelle que soit la valeur de note initiale ("C", "F", "G #"), vous pourrez dire qu'une séquence de trois notes qui a le racine, 3e majeur (M3), puis 3e mineur (m3) serait une triade majeure. De même, m3 + M3 est une triade mineure, m3 + m3 diminué, M3 + M3 augmenté. De plus, cela vous donnerait un moyen d'encapsuler la recherche de la 11e, de la 13e diminuée, etc. sans les coder explicitement pour les 12 notes de base et leurs octaves de haut en bas.
Une fois cela fait, il vous reste encore des problèmes à résoudre.
Prenez la triade C, E, G. En tant que musicien, je vois cela clairement comme un accord Cmaj. Cependant, le développeur en moi peut interpréter cela en plus comme E mineur Augment 5 (Root E + m3 + a5) ou Gsus4 6th no 5th (RootG + 4 + 6).
Donc, pour répondre à votre question sur l'analyse, je pense que la meilleure façon de déterminer la modalité (maj, mineur, etc.) serait de prendre toutes les notes entrées, de les disposer en demi-tons ascendants et de les tester par rapport aux formes d'accord connues. . Ensuite, utilisez chaque note entrée comme note fondamentale et effectuez le même ensemble d'évaluations.
Vous pouvez pondérer les formes d'accords afin que les formes d'accords plus courantes (majeures, mineures) aient priorité sur les formes d'accords augmentées, suspendues, elektra, etc., mais une analyse précise nécessiterait de présenter toutes les formes d'accords correspondantes comme solutions possibles.
Encore une fois, l'article de Wikipédia référencé fait un bon travail de listage des classes de hauteur, donc il devrait être simple (quoique fastidieux) de coder les modèles des accords, de prendre les notes entrées, de les affecter à des classes / intervalles de hauteur, puis de comparer contre les formes connues pour les matchs.
Cela a été très amusant. Merci!
la source
Cela ressemble à un étui pour les modèles. Vous semblez avoir un
template <?> class Major : public Chord;
tel quiMajor<C>
estChord
, tel quelMajor<B>
. De même, vous avez également unNote<?>
modèle avec des instancesNote<C>
etNote<D>
.La seule chose que j'ai laissée de côté, c'est la
?
partie. Il semble que vous en ayez un,enum {A,B,C,D,E,F,G}
mais je ne sais pas comment vous nommeriez cette énumération.la source
Merci pour toutes les suggestions, j'ai réussi à manquer les réponses supplémentaires. Jusqu'à présent, mes cours ont été conçus comme suit:
Pour résoudre mes problèmes de calcul d'intervalle et d'accord, j'ai décidé d'utiliser le tampon circulaire, ce qui me permet de parcourir le tampon à partir de n'importe quel point, à l'avenir, jusqu'à ce que je trouve la prochaine note qui correspond.
Pour trouver l'intervalle interprété - parcourez le tampon de notes réelles, arrêtez-vous lorsque les lettres correspondent (juste la lettre, pas la note ou la position réelle) donc c - g # = 5
Pour trouver la distance réelle, parcourez un autre tampon de 12 entiers, arrêtez-vous lorsque la position de la note de tête est la même que la valeur du tampon à l'index, là encore, cela ne fait que progresser. Mais le décalage peut être n'importe où (c.-à-d. Buffer.at (-10))
maintenant je connais à la fois l'intervalle interprété et la distance physique entre les deux. le nom de l'intervalle est donc à moitié complet.
maintenant je suis capable d'interpréter l'intervalle, c'est à dire. si l'intervalle est de 5 et que la distance est de 8, alors c'est un 5e augmenté.
Jusqu'à présent, la note et l'intervalle fonctionnent comme prévu, maintenant je n'ai plus qu'à aborder l'identifiant de l'accord.
Merci encore, je vais relire certaines de ces réponses et y incorporer quelques idées.
la source