Last active
August 8, 2019 22:47
-
-
Save boblucas/1b0b6bf68528708d6be1a91dff1ef3d2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <set> | |
#include <array> | |
#include <numeric> | |
#include <algorithm> | |
#include <iostream> | |
#include <math.h> | |
// Because C++ mod is really remainder not mod | |
int mod(int a, int b) { return a % b + b * (a < 0); } | |
int diatonic_to_chromatic(int d, int a = 0) { return d * 2 - (d / 7) * 2 - (mod(d, 7) > 2) + a; } | |
struct Note | |
{ | |
int pitch = 0, acc = 0; | |
std::array<unsigned, 12> chromagram = {}; | |
int diatonic() { return (pitch - acc) / 2 + ((pitch - acc) / 12) + (mod((pitch - acc), 12) > 4); } | |
void set_acc_by_diatonic(int step) | |
{ | |
acc = mod(pitch, 12) - diatonic_to_chromatic(mod(step, 7)); | |
acc -= 12 * (acc > 6); | |
} | |
}; | |
void pitchSpell(std::vector<Note>& notes, int kPre = 10, int kPost = 42) | |
{ | |
for(int i = 0; i < notes.size(); i++) | |
for(int j = std::max(0, i - kPre); j < std::min((int)notes.size(), i + kPost); j++) | |
++notes[i].chromagram[notes[j].pitch % 12]; | |
std::array<int, 12> morphInt = {0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6}; | |
std::array<int, 12> initMorph = {0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6}; | |
int c0 = notes[0].pitch % 12; | |
int m0 = initMorph[c0]; | |
std::array<int, 12> tonicMorphForTonicChroma; | |
for(int ct = 0; ct < 12; ct++) | |
tonicMorphForTonicChroma[ct] = mod(m0 - morphInt[mod(c0-ct, 12)], 7); | |
for(auto& note : notes) | |
{ | |
std::vector<std::set<int>> chromas(7); | |
for(int ct = 0; ct < 12; ct++) | |
chromas[mod(morphInt[mod(note.pitch % 12 - ct, 12)] + tonicMorphForTonicChroma[ct], 7)].insert(ct); | |
int maxStrength = -1; | |
int maxM = 0; | |
for(int m = 0; m < 7; m++) | |
{ | |
int strength = 0; | |
for(int tonicChroma : chromas[m]) | |
strength += note.chromagram[tonicChroma]; | |
maxM = strength > maxStrength ? m : maxM; | |
maxStrength = std::max(strength, maxStrength); | |
} | |
note.set_acc_by_diatonic(maxM); | |
std::cout << note.pitch << " " << maxM << " " << note.acc << std::endl; | |
} | |
} | |
int main(int argc, char** argv) | |
{ | |
std::vector<int> pitches = {0, 0, 7, 7, 9, 9, 7, 7, 5, 5, 4 ,4 ,3, 3, 0, 0}; | |
std::vector<Note> notes; | |
for(auto p : pitches) notes.push_back({p, 0}); | |
pitchSpell(notes); | |
for(auto n : notes) | |
{ | |
std::cout << "CDEFGAB"[(n.diatonic() + 7*100) % 7] << "-b #+"[n.acc + 2] << ' '; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Sure you can do something like:
<Just added it above, because this view didn't work>
To just dump in some time ordered midi pitching and it will print back those pitches as note names + accidentals. I just did this and combined it with grep -Po "(?<=)\d+(?=)" to just get all pitches out of an imploded score, then you can do the same for the tpc values in the score and check the accuracy. It's all very hacky I apologize, just spend an hour or 2 on it to see the result.