Last active
August 29, 2015 14:24
-
-
Save wbajzek/5be46cfa8ebc11f7cc69 to your computer and use it in GitHub Desktop.
Scala parser
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 <iostream> | |
#include <string> | |
#include <math.h> | |
#include <array> | |
class ScalaDigester | |
{ | |
public: | |
ScalaDigester(std::string input) | |
{ | |
scala_string = input; | |
current_pos = 0; | |
} | |
std::string getNextLine() | |
{ | |
bool is_comment = false; | |
std::string line; | |
if (current_pos < scala_string.length()) | |
do | |
{ | |
line = scala_string.substr(current_pos, | |
scala_string.find("\n", current_pos) - current_pos); | |
current_pos += line.length() + 1; | |
// lines in a scala file beginning with ! are comments | |
if (line.at(0) == '!') | |
is_comment = true; | |
else | |
is_comment = false; | |
} | |
while (is_comment == true); | |
return line; | |
} | |
private: | |
std::string scala_string; | |
int current_pos; | |
}; | |
class Scale | |
{ | |
public: | |
Scale(std::string input) | |
{ | |
ScalaDigester digester(input); | |
name = digester.getNextLine(); | |
degrees = std::stoi(digester.getNextLine()); | |
int count = 0; | |
while (count < degrees) | |
intervals[count++] = digester.getNextLine(); | |
} | |
std::string getName() | |
{ | |
return name; | |
} | |
int getDegrees() | |
{ | |
return degrees; | |
} | |
void getFrequencies(float frequencies[128], float root) | |
{ | |
frequencies[0] = root; | |
int key_note = 1; | |
while (key_note < 128) | |
{ | |
int current_degree = 0; | |
while (current_degree < degrees) | |
{ | |
float interval = parseInterval(intervals[current_degree]); | |
frequencies[key_note] = root * interval; | |
current_degree++; | |
if (current_degree == degrees) | |
root = frequencies[key_note]; | |
key_note++; | |
if (key_note > 128) | |
return; | |
} | |
} | |
} | |
private: | |
float parseInterval(std::string interval) | |
{ | |
if (interval.find(".") < interval.length()) | |
return pow(2.0, std::stof(interval) / 1200.0); | |
else | |
{ | |
int slash_pos = interval.find("/"); | |
float numerator; | |
float denominator; | |
if (slash_pos > -1) { | |
numerator = std::stof(interval.substr(0,slash_pos)); | |
denominator = std::stof(interval.substr(slash_pos + 1)); | |
} | |
else | |
{ | |
numerator = std::stof(interval); | |
denominator = 1.f; | |
} | |
return numerator / denominator; | |
} | |
} | |
std::string name; | |
int degrees; | |
std::string intervals[128]; | |
}; | |
int main() | |
{ | |
// taken from http://www.huygens-fokker.org/scala/scl_format.html | |
std::string sample_input = "! meanquar.scl\n!\n1/4-comma meantone scale. Pietro Aaron's temperament (1523)\n 12\n!\n 76.04900\n 193.15686\n 310.26471\n 5/4\n 503.42157\n 579.47057\n 696.57843\n 25/16\n 889.73529\n 1006.84314\n 1082.89214\n 2/1"; | |
// after you instantiate the object you can get the name and # scale degrees | |
Scale scale(sample_input); | |
std::cout << scale.getName() << "\n"; | |
std::cout << scale.getDegrees() << "\n"; | |
// given a root_frequency, it will populate a frequencies array with the scale | |
float root_frequency = 1.0; | |
float frequencies[128]; | |
scale.getFrequencies(frequencies, root_frequency); | |
// print them out for testing purposes | |
int i = 0; | |
while (i < 128) | |
std::cout << frequencies[i++] << "\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment