Zacząłem pisać program w C ++ 11, który analizowałby akordy, skale i harmonię. Największym problemem, jaki mam w fazie projektowania, jest to, że nuta „C” jest nutą, rodzajem akordu (Cmaj, Cmin, C7 itd.) I rodzajem klucza (klawisz Cmajor, Cminor). Ten sam problem pojawia się w przypadku interwałów (trzeci mniejszy, trzeci większy).
Używam klasy podstawowej, Token, która jest klasą podstawową dla wszystkich „symboli” w programie. na przykład:
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;
Jak widać, stworzenie wszystkich pochodnych klas (CMajorTriad, C, CMajorScale, CMajorKey itp.) Szybko stałoby się absurdalnie złożone, w tym wszystkie inne nuty, a także enharmoniki. wielokrotne dziedziczenie nie działałoby, tzn .:
class C : public Note, Triad, Key, Scale
klasa C nie może być jednocześnie tymi wszystkimi rzeczami. Jest kontekstowy, również polimorfizacja z tym nie zadziała (jak ustalić, które super metody wykonać? Wywołanie każdego konstruktora superklasy nie powinno się tutaj zdarzyć)
Czy są jakieś pomysły lub sugestie projektowe, które ludzie mają do zaoferowania? Nie byłem w stanie znaleźć niczego w Google w odniesieniu do modelowania harmonii tonalnej z perspektywy OO. Istnieje zbyt wiele relacji między wszystkimi koncepcjami tutaj.
źródło
Odpowiedzi:
Myślę, że najlepszym podejściem jest odtworzenie prawdziwych relacji między tymi podmiotami.
Na przykład możesz mieć:
Note
obiekt, którego właściwości sąnazwa (C, D, E, F, G, A, B)
przypadkowy (naturalny, płaski, ostry)
częstotliwość lub inny unikalny identyfikator wysokości tonu
Chord
obiekt, którego właściwości sątablica
Note
obiektówNazwa
przypadkowy
jakość (duża, niewielka, obniżona, rozszerzona, zawieszona)
dodatki (7, 7+, 6, 9, 9+, 4)
Scale
obiekt, którego właściwości sątablica
Note
obiektówNazwa
rodzaj (major, natural minor, melodic minor, harmonic minor)
tryb (joński, dorycki, frygijski, lidian, mixolidian, eolski, locrian)
Następnie, jeśli dane wejściowe są tekstowe, możesz tworzyć notatki zawierające ciąg znaków, w tym nazwę notatki, przypadkowe i (jeśli potrzebujesz) oktawę.
Na przykład (pseudokod, nie znam C ++):
Następnie w
Note
klasie możesz przeanalizować ciąg i ustawić właściwości.A
Chord
można zbudować na podstawie jego notatek:... lub według ciągu zawierającego nazwę, jakość i dodatkowe uwagi:
Nie wiem, co dokładnie zrobi Twoja aplikacja, więc to tylko pomysły.
Powodzenia w fascynującym projekcie!
źródło
Kilka ogólnych porad.
Jeśli oczekuje się dużej niepewności w projektowaniu klas (np. W twojej sytuacji), zaleciłbym eksperymentowanie z różnymi konkurencyjnymi projektami klas.
Używanie C ++ na tym etapie może nie być tak wydajne jak inne języki. (Kwestia ta jest widoczna w twoim fragmenty kodu konieczności zajmowania się
typedef
ivirtual
destruktorów.) Nawet jeśli celem projektu jest stworzenie kodu C ++, może to być produktywnym zrobić wstępny projekt klasy w innym języku. (Na przykład Java, choć istnieje wiele możliwości.)Nie wybieraj C ++ tylko z powodu wielokrotnego dziedziczenia. Dziedziczenie wielokrotne ma swoje zastosowanie, ale nie jest to właściwy sposób modelowania tego problemu (teoria muzyki).
Zwróć szczególną uwagę na jednoznaczność. Mimo że w opisach angielskich (tekstowych) występuje wiele niejasności, należy je rozwiązać przy projektowaniu klas OOP.
Mówimy o nutach G i G jako nutach. Mówimy o G-dur i G-moll jako skalach. Tak więc,
Note
iScale
nie są wymienne pojęcia. Nie może być żadnego obiektu, który może być jednocześnie instancjąNote
ai aScale
.Ta strona zawiera kilka diagramów ilustrujących związek: http://www.howmusicworks.org/600/ChordScale-Relations/Chord-and-Scale-Relations
Na przykład: „triada rozpoczynająca się od G w skali C-dur ” nie ma tego samego znaczenia co „triada rozpoczynająca się od C w skali G-dur ”.
Na tym wczesnym etapie
Token
klasa (nadklasa wszystkiego) jest nieuzasadniona, ponieważ zapobiega jednoznaczności. W razie potrzeby można go wprowadzić później (obsługiwany przez fragment kodu, który pokazuje, jak może to być przydatne).Na początek zacznij od
Note
klasy, która jest centrum diagramu klas, a następnie stopniowo dodawaj relacje (fragmenty danych, które muszą być powiązane z krotkamiNote
s) do diagramu relacji klas.C uwaga jest instancją
Note
klasy. C Uwaga powróci właściwości, które są związane z tym zauważyć, takich jak związane z triad i jej względnego położenia (Interval
), w odniesieniu doScale
że rozpoczyna z C Uwaga.Relacje między instancjami tej samej klasy (na przykład między notatką C i notatką E ) powinny być modelowane jako właściwości, a nie dziedziczenie.
Co więcej, wiele relacji międzyklasowych w twoich przykładach jest również bardziej odpowiednio modelowanych jako właściwości. Przykład:
(przykłady kodu są w toku, ponieważ muszę ponownie nauczyć się teorii muzyki ...)
źródło
Zasadniczo nuty to częstotliwości, a interwały muzyczne to stosunki częstotliwości.
Na tym można zbudować wszystko inne.
Akord to lista interwałów. Skala jest podstawową nutą i systemem strojenia. System strojenia to także lista interwałów.
Jak je nazwiesz, to tylko kulturowy artefakt.
Artykuł na temat teorii muzyki w Wikipedii jest dobrym punktem wyjścia.
źródło
Uważam tę dyskusję za fascynującą.
Czy nuty są wprowadzane za pomocą midi (lub innego rodzaju urządzenia do przechwytywania tonów), czy też wprowadza się je, wpisując litery i symbole?
W przypadku przedziału od C do D-ostre / E-płaskie:
Chociaż D-ostry i E-płaski mają ten sam ton (około 311 Hz, jeśli A = 440 Hz), interwał od C -> D-ostry zapisywany jest jako powiększony 2., zaś interwał od C -> E-płaski jest zapisywany jako drobne 3.. Łatwo, jeśli wiesz, jak napisano notatkę. Nie można ustalić, czy masz tylko dwa dźwięki.
W tym przypadku uważam, że będziesz potrzebować sposobu na zwiększenie / zmniejszenie tonu wraz z wymienionymi metodami .Sharpen () i .Flatten (), takimi jak .SemiToneUp (), .FullToneDown () itp., Więc że można znaleźć kolejne nuty w skali bez „kolorowania” ich jako ostrych / płaskich.
Muszę zgodzić się z @Rotem, że „C” nie jest klasą samą w sobie, ale raczej instancją klasy Note.
Jeśli zdefiniujesz właściwości nuty, w tym wszystkie interwały jako półtonów, to niezależnie od początkowej wartości nuty („C”, „F”, „G #”) będziesz w stanie powiedzieć, że sekwencja trzech nut, która ma root, major 3rd (M3), a następnie minor 3rd (m3) byłby główną triadą. Podobnie m3 + M3 jest niewielką triadą, m3 + m3 zmniejszony, M3 + M3 powiększony. Dodatkowo dałoby to sposób na enkapsulację znalezienia 11, zmniejszonego 13 itd. Bez wyraźnego kodowania ich dla wszystkich 12 nut bazowych i ich oktaw w górę i w dół.
Gdy to zrobisz, wciąż masz problemy do rozwiązania.
Weź triadę C, E, G. Jako muzyk widzę to wyraźnie jako akord Cmaj. Jednak deweloper we mnie może interpretować to dodatkowo jako e-moll Augment 5 (Root E + m3 + a5) lub Gsus4 6th no 5th (RootG + 4 + 6).
Tak więc, aby odpowiedzieć na twoje pytanie dotyczące wykonywania analizy, myślę, że najlepszym sposobem na określenie modalności (maj, minor, itp.) Byłoby pobranie wszystkich wprowadzonych nut, ułożenie ich według rosnącej wartości półtonu i przetestowanie ich pod kątem znanych form akordów . Następnie użyj każdej nuty wpisanej jako nuta główna i wykonaj ten sam zestaw ocen.
Można tak wyważyć formy akordów, aby bardziej popularne (większe, mniejsze) miały pierwszeństwo przed formami akordów rozszerzonymi, zawieszonymi, elektra itp., Ale dokładna analiza wymagałaby przedstawienia wszystkich pasujących form akordów jako możliwych rozwiązań.
Znów wspomniany artykuł na Wikipedii dobrze spisuje klasy boisk, więc powinno być proste (choć żmudne) kodowanie modeli akordów, zapisywanie wprowadzonych notatek, przypisywanie ich do klas / interwałów pitch, a następnie porównywanie przeciwko znanym formom meczów.
To była świetna zabawa. Dzięki!
źródło
Brzmi jak skrzynka na szablony. To wydaje się mieć
template <?> class Major : public Chord;
takMajor<C>
jest-aChord
, jak to jestMajor<B>
. Podobnie maszNote<?>
szablon z instancjamiNote<C>
iNote<D>
.Jedyne, co pominąłem, to
?
część. Wygląda na to, że masz,enum {A,B,C,D,E,F,G}
ale nie wiem, jak nazwałbyś to wyliczenie.źródło
Dziękuję za wszystkie sugestie, jakoś udało mi się przeoczyć dodatkowe odpowiedzi. Do tej pory moje klasy były tak zaprojektowane:
Aby rozwiązać problemy z obliczaniem interwałów i akordów, zdecydowałem się użyć bufora kołowego, który pozwala mi przechodzić przez bufor z dowolnego punktu, idąc do przodu, aż znajdę następną pasującą nutę.
Aby znaleźć interpretowany interwał, przejdź do bufora rzeczywistych nut, zatrzymaj się, gdy litery będą pasować (tylko litera, a nie faktyczna nuta lub pozycja), więc c - g # = 5
Aby znaleźć rzeczywiste przejście przez kolejny bufor 12 liczb całkowitych, zatrzymaj się, gdy pozycja górnej nuty jest taka sama, jak wartość bufora na indeksie, ponownie jest to tylko ruch do przodu. Ale offset może być w dowolnym miejscu (np. Buffer.at (-10))
teraz znam zarówno interpretowany przedział, jak i fizyczną odległość między nimi. więc nazwa interwału jest już w połowie ukończona.
teraz jestem w stanie zinterpretować interwał, tj. jeśli interwał wynosi 5, a odległość wynosi 8, oznacza to, że jest to 5-ty stopień.
Do tej pory nuta i interwał działały zgodnie z oczekiwaniami, teraz muszę tylko zmierzyć się z identyfikatorem akordu.
Jeszcze raz dziękuję, przeczytam ponownie niektóre z tych odpowiedzi i przedstawię tutaj kilka pomysłów.
źródło