29 #include "../system/eptexception.h"
30 #include "../adapters/filemanager.h"
31 #include "../system/log.h"
32 #include "../thirdparty/timesupport/timesupport.h"
49 std::locale oldLocale(std::locale::global(std::locale::classic()));
53 std::locale::global(oldLocale);
57 std::locale::global(oldLocale);
64 std::locale oldLocale(std::locale::global(std::locale::classic()));
74 std::locale::global(oldLocale);
78 std::locale::global(oldLocale);
84 auto startTime = std::chrono::high_resolution_clock::now();
86 tinyxml2::XMLDocument doc(
true, tinyxml2::COLLAPSE_WHITESPACE);
87 doc.LoadFile(absolutePath.c_str());
89 std::stringstream errormsg;
90 errormsg <<
"Error " << doc.ErrorID() <<
": " << doc.ErrorName() <<
" - File: " << absolutePath;
94 auto parsedTime = std::chrono::high_resolution_clock::now();
96 int parsedDuration =
static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(parsedTime - startTime).count());
97 LogI(
"Succesfully loaded Xml-File: %s. This took %i ms", absolutePath.c_str(), parsedDuration);
99 tinyxml2::XMLElement *root = doc.FirstChildElement();
101 LogW(
"Xml-document has no root node");
110 LogW(
"No file version specified. Trying to continue with minimum supported.");
116 std::stringstream errormsg;
122 for (tinyxml2::XMLElement *child = root->FirstChildElement(); child;
123 child = child->NextSiblingElement()) {
124 if (strcmp(child->Value(),
"piano") == 0) {
129 auto contentParseTime = std::chrono::high_resolution_clock::now();
131 int contentTime =
static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(contentParseTime - parsedTime).count());
132 int totalTime =
static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(contentParseTime - startTime).count());
134 LogI(
"Content parsed in %i ms. Complete file opening took %i ms.", contentTime, totalTime);
139 tinyxml2::XMLDocument doc;
142 doc.InsertEndChild(doc.NewDeclaration());
144 tinyxml2::XMLElement *root = doc.NewElement(
"entropyPianoTunerFile");
145 doc.InsertEndChild(root);
149 tinyxml2::XMLElement *pianoElement = doc.NewElement(
"piano");
150 root->InsertEndChild(pianoElement);
151 write(pianoElement, piano);
154 doc.SaveFile(absolutePath.c_str());
156 std::stringstream errormsg;
157 errormsg <<
"Error " << doc.ErrorID() <<
": " << doc.ErrorName() <<
" - File: " << absolutePath;
161 LogI(
"Succesfully saved Xml-File: %s", absolutePath.c_str());
165 if (!element->GetText()) {
166 return std::string();
168 return std::string(element->GetText());
173 tinyxml2::XMLElement *e = parent->GetDocument()->NewElement(label);
174 parent->InsertEndChild(e);
179 EptAssert(e,
"XMLElement has to exist.");
183 e->QueryIntAttribute(
"type", &type);
184 piano.
setType(static_cast<piano::PianoType>(type));
186 for (
const tinyxml2::XMLElement *data = e->FirstChildElement(); data;
187 data = data->NextSiblingElement()) {
188 if (strcmp(data->Value(),
"name") == 0) {
190 }
else if (strcmp(data->Value(),
"serialNumber") == 0) {
192 }
else if (strcmp(data->Value(),
"manufactionYear") == 0) {
194 }
else if (strcmp(data->Value(),
"manufactionLocation") == 0) {
196 }
else if (strcmp(data->Value(),
"tuningLocation") == 0) {
198 }
else if (strcmp(data->Value(),
"tuningTimestamp") == 0) {
199 if (data->GetText()) {
204 }
else if (strcmp(data->Value(),
"keyboard") == 0) {
222 tinyxml2::XMLElement *keyboardElem = e->GetDocument()->NewElement(
"keyboard");
223 e->InsertEndChild(keyboardElem);
231 e->QueryIntAttribute(
"numberOfKeys", &numberOfKeys);
232 e->QueryIntAttribute(
"keyNumberOfA", &keyNumberOfA);
235 for (
const tinyxml2::XMLElement *keyElement = e->FirstChildElement(); keyElement;
236 keyElement = keyElement->NextSiblingElement()) {
237 if (strcmp(keyElement->Value(),
"key") == 0) {
239 keyElement->QueryAttribute(
"key", &key);
241 LogE(
"Key attribute not provided.");
246 keyboard[key].getPeaks().clear();
249 std::fill(keyboard[key].getSpectrum().begin(), keyboard[key].getSpectrum().end(), 0);
252 keyElement->QueryAttribute(
"recordedFrequency", &keyboard[key].getRecordedFrequency());
253 keyElement->QueryAttribute(
"measuredInharmonicity", &keyboard[key].getMeasuredInharmonicity());
254 keyElement->QueryAttribute(
"computedFrequency", &keyboard[key].getComputedFrequency());
255 keyElement->QueryAttribute(
"tunedFrequency", &keyboard[key].getTunedFrequency());
256 keyElement->QueryAttribute(
"recorded", &keyboard[key].isRecorded());
257 keyElement->QueryAttribute(
"quality", &keyboard[key].getRecognitionQuality());
259 for (
const tinyxml2::XMLElement *child = keyElement->FirstChildElement(); child;
260 child = child->NextSiblingElement()) {
261 if (strcmp(child->Value(),
"spectrum") == 0) {
263 auto &spectrum = keyboard[key].getSpectrum();
265 const char *s = child->GetText();
269 double *spec = spectrum.data();
272 double val = strtod(s, &p);
286 }
else if (strcmp(child->Value(),
"peak") == 0) {
288 double frequency = -1;
289 double intensity = -1;
290 child->QueryDoubleAttribute(
"frequency", &frequency);
291 child->QueryDoubleAttribute(
"intensity", &intensity);
292 keyboard[key].getPeaks()[frequency] = intensity;
304 for (
size_t key = 0; key < keyboard.
size(); ++key) {
305 tinyxml2::XMLElement *keyElement = e->GetDocument()->NewElement(
"key");
306 e->InsertEndChild(keyElement);
308 keyElement->SetAttribute(
"key", static_cast<int>(key));
310 keyElement->SetAttribute(
"recordedFrequency", keyboard[key].getRecordedFrequency());
311 keyElement->SetAttribute(
"measuredInharmonicity", keyboard[key].getMeasuredInharmonicity());
312 keyElement->SetAttribute(
"computedFrequency", keyboard[key].getComputedFrequency());
313 keyElement->SetAttribute(
"tunedFrequency", keyboard[key].getTunedFrequency());
314 keyElement->SetAttribute(
"recorded", keyboard[key].isRecorded());
315 keyElement->SetAttribute(
"quality", keyboard[key].getRecognitionQuality());
319 std::stringstream oss;
320 for (
size_t spec = 0; spec < spectrum.size() - 1; ++spec) {
322 oss << spectrum[spec] <<
" ";
325 oss << spectrum[spectrum.size() - 1];
326 tinyxml2::XMLElement *specElement = e->GetDocument()->NewElement(
"spectrum");
327 keyElement->InsertEndChild(specElement);
328 specElement->SetText(oss.str().c_str());
331 for (
auto peak : keyboard[key].getPeaks()) {
332 tinyxml2::XMLElement *peakElement = e->GetDocument()->NewElement(
"peak");
333 keyElement->InsertEndChild(peakElement);
334 peakElement->SetAttribute(
"frequency", peak.first);
335 peakElement->SetAttribute(
"intensity", peak.second);
346 std::ofstream stream;
347 stream.open(absolutePath);
348 if (!stream.is_open()) {
356 stream <<
"\"Key index\",\"Inharmonicity\",\"Recorded frequency\",\"Recorded deviation\",\"Computed frequency\",\"Computed deviation\",\"Tuned frequency\",\"Tuned deviation\",\"Quality\"" << std::endl;
361 auto cents = [A4] (
int i,
double f,
double fA4)
363 double ET = pow(2.0,(i-A4)/12.0);
364 if (f == 0 or fA4 == 0)
return 0.0;
365 else return 1200.0 * std::log(f/fA4/ET)/std::log(2.0);
369 stream << std::setw(3) << std::left << i + 1 << std::fixed << std::right
FileVersionType mFileVersion
file version as integer
double getRecordedFrequency() const
Get recorded frequency.
static const FileVersionType UNSET_FILE_VERSION
std::string getText(const tinyxml2::XMLElement *element)
Class describing the piano keyboard, holding a collection of keys.
static const std::string FILE_TYPE_NAME
piano::PianoType getPianoType() const
void setName(const std::string &name)
FileType
supported piano file types
const std::string & getManufactionYear() const
void changeKeyboardConfiguration(int numberOfKeys, int keyNumberOfA)
Change keyboard configuration.
void readXmlFile(const std::string &absolutePath, Piano &piano)
Class describing a single piano key.
static const int NumberOfBins
Total number of slots: 9 octaves.
const std::string & getManufactionLocation() const
bool write(const std::string &absolutePath, const Piano &piano, piano::FileType fileType) const
void writeXmlFile(const std::string &absolutePath, const Piano &piano) const
const std::string & getSerialNumber() const
void setType(piano::PianoType type)
bool read(const std::string &absolutePath, Piano &piano)
void setSerialNumber(const std::string &number)
#define EPT_EXCEPT(num, desc)
const Keyboard & getKeyboard() const
void setTuningTimeToActualTime()
This function resets the tuning time to the actual time. This is used as default value.
void setManufactureYear(const std::string &year)
double getComputedFrequency() const
Get computed frequency.
double getMeasuredInharmonicity() const
Get estimated inharmonicity.
void createTextXMLElement(tinyxml2::XMLElement *parent, const char *label, const char *text) const
static const FileVersionType CURRENT_FILE_VERSION
static const FileVersionType MIN_SUPPORTED_FILE_VERSION
const std::string & getTuningTime() const
double getRecognitionQuality() const
Get quality of recognition.
std::vector< double > SpectrumType
Type of a log-binned spectrum.
const std::string & getTuningLocation() const
int getKeyNumberOfA4() const
const double & getConcertPitch() const
void setTuningLocation(const std::string &loc)
void setManufactureLocation(const std::string &loc)
void writeCsvFile(const std::string &absolutePath, const Piano &piano) const
int getNumberOfKeys() const
const std::string & getName() const
double getTunedFrequency() const
Get tuned frequency.
void setTuningTime(const std::string &time)
const Key & getKey(int i) const