Comecei a escrever um programa em C ++ 11 que analisaria acordes, escalas e harmonia. O maior problema que estou tendo na minha fase de design é que a nota 'C' é uma nota, um tipo de acorde (Cmaj, Cmin, C7, etc) e um tipo de chave (a chave de Cmajor, Cminor). O mesmo problema surge com intervalos (terceiro menor, terceiro maior).
Estou usando uma classe base, Token, que é a classe base para todos os 'símbolos' no programa. por exemplo:
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;
Como você pode ver, criar todas as classes derivadas (CMajorTriad, C, CMajorScale, CMajorKey etc.) rapidamente se tornaria ridiculamente complexa, incluindo todas as outras notas, além de enarmônicos. herança múltipla não funcionaria, ou seja:
class C : public Note, Triad, Key, Scale
classe C, não pode ser todas essas coisas ao mesmo tempo. É contextual, também polimorfismo com isso não funcionará (como determinar quais super métodos a serem executados? Chamar todos os construtores de superclasses não deve acontecer aqui)
Existem idéias ou sugestões de design que as pessoas têm a oferecer? Não consegui encontrar nada no google com relação à modelagem da harmonia tonal de uma perspectiva OO. Existem relações demais entre todos os conceitos aqui.
fonte
Respostas:
Eu acho que a melhor abordagem é reproduzir os relacionamentos reais entre essas entidades.
Por exemplo, você poderia ter:
um
Note
objeto cujas propriedades sãonome (C, D, E, F, G, A, B)
acidental (natural, plano, afiado)
frequência ou outro identificador exclusivo de afinação
um
Chord
objeto cujas propriedades sãouma matriz de
Note
objetosnome
acidental
qualidade (maior, menor, diminuída, aumentada, suspensa)
adições (7, 7+, 6, 9, 9+, 4)
um
Scale
objeto cujas propriedades sãouma matriz de
Note
objetosnome
tipo (maior, menor natural, menor melódico, menor harmônico)
modo (ioniano, dórico, frígio, lídio, mixolidiano, eólico, locriano)
Então, se sua entrada for textual, você poderá criar notas com uma string, incluindo o nome da nota, acidental e (se necessário) oitava.
Por exemplo (pseudocódigo, não sei C ++):
Em seguida, na
Note
classe você pode analisar a sequência e definir as propriedades.A
Chord
poderia ser construído por suas notas:... ou por uma string, incluindo nome, qualidade e notas adicionais:
Não sei exatamente o que seu aplicativo fará, então são apenas ideias.
Boa sorte com seu projeto fascinante!
fonte
Alguns conselhos genéricos.
Se houver muita incerteza esperada no design da classe (como na sua situação), eu recomendaria experimentar diferentes designs de classe concorrentes.
O uso do C ++ nesse estágio pode não ser tão produtivo quanto outras linguagens. (Esse problema é aparente nos fragmentos de código que precisam ser tratados
typedef
evirtual
destruidores.) Mesmo que o objetivo do projeto seja produzir código C ++, pode ser produtivo criar o design de classe inicial em outro idioma. (Por exemplo, Java, embora haja muitas opções.)Não escolha C ++ apenas por causa da herança múltipla. A herança múltipla tem seus usos, mas não é a maneira correta de modelar esse problema (teoria musical).
Tome especial atenção para desambiguar. Embora as ambigüidades sejam abundantes nas descrições em inglês (textuais), essas ambigüidades devem ser resolvidas ao projetar classes OOP.
Falamos de G e G afiados como notas. Falamos de Sol maior e Sol menor como escalas. Assim,
Note
eScale
não são conceitos intercambiáveis. Não pode haver nenhum objeto que possa ser simultaneamente uma instância de aNote
e aScale
.Esta página contém alguns diagramas que ilustram o relacionamento: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations
Para outro exemplo, "uma tríade que começa com G em uma escala maior C " não tem o mesmo significado que "uma tríade que começa com C em uma escala maior G ".
Nesta fase inicial, a
Token
classe (a superclasse de tudo) é injustificada, porque impede a desambiguação. Pode ser introduzido posteriormente, se necessário (suportado por um fragmento de código que demonstra como isso pode ser útil).Para começar, comece com uma
Note
classe que é o centro do diagrama de classes e adicione gradualmente os relacionamentos (dados que precisam ser associados às tuplas deNote
s) ao diagrama de relacionamentos de classe.Uma nota C é uma instância da
Note
classe. Uma nota C retornará propriedades relacionadas a esta nota, como tríades relacionadas, e sua posição relativa (Interval
) em relação a umaScale
que comece com uma nota C.Os relacionamentos entre instâncias da mesma classe (por exemplo, entre uma nota C e uma nota E ) devem ser modelados como propriedades, não como herança.
Além disso, muitos dos relacionamentos entre classes nos seus exemplos também são modelados de maneira mais apropriada como propriedades. Exemplo:
(exemplos de código estão pendentes porque preciso reaprender teoria musical ...)
fonte
Basicamente, as notas musicais são frequências e intervalos musicais são proporções de frequência.
Tudo o resto pode ser construído sobre isso.
Um acorde é uma lista de intervalos. Uma escala é uma nota fundamental e um sistema de afinação. Um sistema de ajuste também é uma lista de intervalos.
Como você os nomeia é apenas um artefato cultural.
O artigo de teoria musical da Wikipedia é um bom ponto de partida.
fonte
Estou achando essa discussão fascinante.
As notas estão sendo inseridas via midi (ou algum tipo de dispositivo de captura de tom) ou estão sendo digitadas digitando as letras e os símbolos?
No caso do intervalo de C a D-sharp / E-flat:
Embora D-sharp e E-flat sejam o mesmo tom (em torno de 311Hz se A = 440Hz), o intervalo de C -> D-sharp é gravado em um segundo aumentado, enquanto o intervalo de C -> E-flat é gravado como um menor 3º. Fácil, se você souber como a nota foi escrita. Impossível determinar se você tem apenas os dois tons para continuar.
Nesse caso, acredito que você também precisará de uma maneira de aumentar / diminuir o tom, juntamente com os métodos .Sharpen () e .Flatten () mencionados, como .SemiToneUp (), .FullToneDown () etc.) que você pode encontrar notas subesquentes em uma escala sem "colori-las" como objetos cortantes / planos.
Eu tenho que concordar com o @Rotem que "C" não é uma classe em si, mas sim uma instanciação da classe Note.
Se você definir as propriedades de uma nota, incluindo todos os intervalos como semitons, independentemente do valor inicial da nota ("C", "F", "G #"), poderá dizer que uma sequência de três notas possui o raiz, terceiro maior (M3) e terceiro menor (m3) seria uma tríade maior. Da mesma forma, m3 + M3 é uma tríade menor, m3 + m3 diminuído, M3 + M3 aumentado. Além disso, isso permitiria encapsular a localização da 11ª, da 13ª diminuída, etc., sem codificá-las explicitamente para todas as 12 notas de base e suas oitavas para cima e para baixo.
Feito isso, você ainda terá alguns problemas a resolver.
Tome a tríade C, E, G. Como músico, vejo isso claramente como um acorde de Cmaj. No entanto, o desenvolvedor em mim pode interpretar isso adicionalmente como E menor Augment 5 (Root E + m3 + a5) ou Gsus4 6th no 5th (RootG + 4 + 6).
Portanto, para responder à sua pergunta sobre a análise, acho que a melhor maneira de determinar a modalidade (maior, menor, etc.) seria pegar todas as notas inseridas, organizá-las em um valor de semitom crescente e testá-las nas formas de acordes conhecidas . Em seguida, use cada nota inserida como nota raiz e execute o mesmo conjunto de avaliações.
Você pode ponderar as formas de acordes para que mais comuns (maior, menor) tenham precedência sobre as formas de acordes aumentadas, suspensas, elektra etc., mas uma análise precisa exigiria apresentar todas as formas de acordes correspondentes como possíveis soluções.
Novamente, o artigo da wikipedia mencionado faz um bom trabalho ao listar as classes de afinação, por isso deve ser simples (embora tedioso) codificar os modelos dos acordes, fazer as anotações inseridas, atribuí-las às classes / intervalos de afinação e comparar contra as formas conhecidas de correspondências.
Isso tem sido muito divertido. Obrigado!
fonte
Parece um caso para modelos. Você parece ter um
template <?> class Major : public Chord;
modoMajor<C>
é-umChord
, como éMajor<B>
. Da mesma forma, você também tem umNote<?>
modelo com instânciasNote<C>
eNote<D>
.A única coisa que deixei de fora é a
?
parte. Parece que você tem um,enum {A,B,C,D,E,F,G}
mas eu não sei como você nomearia esse enum.fonte
Obrigado por todas as sugestões, de alguma forma eu consegui perder as respostas extras. Até agora, minhas aulas foram projetadas da seguinte forma:
Para resolver meus problemas de cálculo de intervalo e acordes, decidi usar o buffer circular, o que me permite atravessá-lo a partir de qualquer ponto, seguindo em frente até encontrar a próxima nota que corresponda.
Para encontrar o intervalo interpretado - atravesse o buffer de notas reais, pare quando as letras corresponderem (apenas a letra, não a nota ou a posição real), então c - g # = 5
Para encontrar a distância real - atravessar outro buffer de 12 números inteiros, pare quando a posição da nota superior for igual ao valor do buffer no índice, novamente isso está avançando apenas. Mas o deslocamento pode estar em qualquer lugar (ou seja, buffer.at (-10))
agora conheço o intervalo interpretado e a distância física entre os dois. então o nome do intervalo já está meio completo.
agora eu sou capaz de interpretar o intervalo, ou seja. se o intervalo for 5 e a distância for 8, será um quinto aumentado.
Até agora, a nota e o intervalo estão funcionando conforme o esperado, agora só tenho que resolver o identificador de acordes.
Mais uma vez obrigado, releremos algumas dessas respostas e incorporarei algumas idéias aqui.
fonte