diff --git a/Tuner.pro b/Tuner.pro
index 3f30835..4a34d8d 100644
--- a/Tuner.pro
+++ b/Tuner.pro
@@ -21,4 +21,5 @@ HEADERS += \
src/scale/Temperaments.hpp
RESOURCES += \
- qml/desktop.qrc
+ qml/desktop.qrc \
+ data/temperaments.qrc
diff --git a/data/Temperaments.csv b/data/Temperaments.csv
index 5a4b6c0..df2caf3 100644
--- a/data/Temperaments.csv
+++ b/data/Temperaments.csv
@@ -1,3 +1,4 @@
+Equal;261.63;277.18;293.66;311.13;329.63;349.23;369.99;392.00;415.30;440.00;466.16;493.88
Werckmeister III;263.40;277.50;294.33;312.18;330.00;351.21;369.99;393.77;416.24;440.00;468.27;495.00
Kirnberger I;264.00;278.12;297.00;312.89;330.00;352.00;371.25;396.00;417.19;440.00;469.33;495.00
Kirnberger II;262.36;276.40;295.16;310.95;327.95;349.81;368.94;393.54;414.59;440.00;466.42;491.93
@@ -6,7 +7,6 @@ Kirnberger III unequal;263.10;277.18;294.50;311.82;328.88;350.80;369.98;393.80;4
Kelletat;262.82;276.97;294.33;311.49;328.65;350.43;369.29;393.81;415.32;440.00;467.24;492.39
Kellner;262.87;276.93;294.13;311.55;329.11;350.49;369.24;393.24;415.40;440.00;467.32;493.66
Billeter;262.40;276.71;294.50;311.29;328.70;350.20;368.95;393.10;415.07;440.00;466.93;492.50
-Equal temperature;261.63;277.18;293.66;311.13;329.63;349.23;369.99;392.00;415.30;440.00;466.16;493.88
Lehman 1/6 Pyth.;262.53;277.82;294.00;311.85;329.25;350.85;370.42;392.90;416.27;440.00;467.24;493.88
Lehman 1/6 Synt.;262.35;277.89;293.94;311.92;329.32;350.52;370.51;392.72;416.36;440.00;467.35;494.00
Fritz (1756 - Equal Beat);261.76;277.33;293.73;311.25;329.70;349.41;370.17;392.04;415.39;440.00;466.27;493.96
diff --git a/data/temperaments.qrc b/data/temperaments.qrc
new file mode 100644
index 0000000..ebbcafa
--- /dev/null
+++ b/data/temperaments.qrc
@@ -0,0 +1,5 @@
+
+
+Temperaments.csv
+
+
diff --git a/harbour-sailtuner.pro b/harbour-sailtuner.pro
index 88de359..41eadb2 100644
--- a/harbour-sailtuner.pro
+++ b/harbour-sailtuner.pro
@@ -7,7 +7,8 @@ DEFINES += TARGET=\""$(TARGET")\"
# PKGCONFIG += libpulse
RESOURCES += \
- qml/sailfish.qrc
+ qml/sailfish.qrc \
+ data/temperaments.qrc
SOURCES += \
src/sailfish.cpp \
diff --git a/src/Tuner.cpp b/src/Tuner.cpp
index 3de897c..1970487 100644
--- a/src/Tuner.cpp
+++ b/src/Tuner.cpp
@@ -67,7 +67,14 @@ Tuner::Tuner()
cross = new ZeroCross(cross_config);
scale = new Scale();
- scale->ConstructEqualTemperament();
+
+ temperaments = new Temperaments(":/data");
+ if (temperaments->SetTemperament(0)) {
+ scale->SetNotesFrequencies(temperaments->NotesFrequencies());
+ }
+ else {
+ scale->ConstructEqualTemperament();
+ }
settings.setCodec("audio/PCM");
settings.setChannelCount(1);
@@ -269,6 +276,24 @@ bool Tuner::GetFound()
return found;
}
+unsigned int Tuner::GetTemperamentIndex()
+{
+ return temperaments->GetCurrentIndex();
+}
+
+void Tuner::SetTemperamentIndex(unsigned int idx)
+{
+ if (temperaments->SetTemperament(idx)) {
+ scale->SetNotesFrequencies(temperaments->NotesFrequencies());
+ temperamentChanged();
+ }
+}
+
+QStringList Tuner::GetTemperamentList() const
+{
+ return temperaments->GetNames();
+}
+
/// Set a filename to record raw audio stream
void Tuner::set_record(const char *f)
diff --git a/src/Tuner.hpp b/src/Tuner.hpp
index 4434c6f..1d0e9da 100644
--- a/src/Tuner.hpp
+++ b/src/Tuner.hpp
@@ -23,6 +23,7 @@
#include "audio/LinearFilter.hpp"
#include "audio/ZeroCross.hpp"
#include "scale/Scale.hpp"
+#include "scale/Temperaments.hpp"
class Tuner : public QObject {
Q_OBJECT
@@ -33,6 +34,8 @@ class Tuner : public QObject {
Q_PROPERTY(int octave READ GetOctave NOTIFY octaveChanged)
Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged)
Q_PROPERTY(QString noteName READ GetNoteName NOTIFY noteNameChanged)
+ Q_PROPERTY(int temperament_idx READ GetTemperamentIndex WRITE SetTemperamentIndex NOTIFY temperamentChanged)
+ Q_PROPERTY(QStringList temperament_list READ GetTemperamentList)
private:
QAudioRecorder *recorder;
@@ -42,6 +45,7 @@ class Tuner : public QObject {
LinearFilter *high_filter;
ZeroCross *cross;
Scale *scale;
+ Temperaments *temperaments;
static const char *filename_record;
std::ofstream file_record;
@@ -92,6 +96,9 @@ class Tuner : public QObject {
double GetDeviation();
bool GetFound();
const char* GetNoteName();
+ unsigned int GetTemperamentIndex();
+ void SetTemperamentIndex(unsigned int idx);
+ QStringList GetTemperamentList() const;
/// analyse a file for debug
static void analyse_file(const char *filename);
@@ -106,4 +113,5 @@ class Tuner : public QObject {
void octaveChanged();
void deviationChanged();
void foundChanged();
+ void temperamentChanged();
};
diff --git a/src/scale/Scale.cpp b/src/scale/Scale.cpp
index 6c22d27..8f21389 100644
--- a/src/scale/Scale.cpp
+++ b/src/scale/Scale.cpp
@@ -41,7 +41,10 @@ Scale::Scale()
void Scale::updateScale()
{
actualFactor = actualLa / defaultLa;
- for (int i = 0; i < nbNote; i++) actualNoteFreq[i] = actualFactor * noteFreq[i];
+ for (int i = 0; i < nbNote; i++) {
+ actualNoteFreq[i] = actualFactor * noteFreq[i];
+// std::cerr << " " << noteFreq[i] << " " << actualNoteFreq[i] << std::endl;
+ }
actualRange[0] = actualNoteFreq[0] * pow(halfToneFactor(0, -1),0.5);
actualRange[1] = actualNoteFreq[nbNote - 1] * pow(halfToneFactor(nbNote - 1, 1), 0.5);
@@ -116,7 +119,7 @@ double Scale::GetLa()
return actualLa;
}
-void Scale::SetNotesFrequencies(double freq[nbNote])
+void Scale::SetNotesFrequencies(const double freq[nbNote])
{
memcpy(noteFreq, freq, sizeof(double) * nbNote);
updateScale();
diff --git a/src/scale/Scale.hpp b/src/scale/Scale.hpp
index 5847539..f97834e 100644
--- a/src/scale/Scale.hpp
+++ b/src/scale/Scale.hpp
@@ -52,7 +52,7 @@ class Scale {
void ConstructEqualTemperament();
/// Set notes frequencies from a temperament
- void SetNotesFrequencies(double freq[nbNote]);
+ void SetNotesFrequencies(const double freq[nbNote]);
double GetLa();
void SetLa(double la);
diff --git a/src/scale/Temperaments.cpp b/src/scale/Temperaments.cpp
index 38cc84a..ae0c989 100644
--- a/src/scale/Temperaments.cpp
+++ b/src/scale/Temperaments.cpp
@@ -15,59 +15,128 @@
*
*/
-#include
-#include
-#include
-#include
+#include
+#include
#include "Temperaments.hpp"
using namespace std;
-Temperaments::Temperaments(const char * dirname) : current(0)
+Temperaments::Temperaments(const QString & dirname) : current(0)
{
GetDir(dirname);
}
-void Temperaments::GetDir(const char * dirname)
+void Temperaments::GetDir(const QString & dirname)
{
- DIR *pdir = opendir(dirname);
- struct dirent *pent = NULL;
- struct stat filestat;
- string filepath;
-
- if (!pdir) {
- cerr << __func__ << ": impossible to open dir " << dirname << endl;
+ QDir dir(dirname);
+ if (!dir.exists()) {
+ qDebug() << __func__ << "dir doesn't exist: " << dirname;
return;
}
- while((pent = readdir(pdir))) {
- // get only files
- if (pent->d_name[0] == '.') continue;
- filepath = dirname;
- filepath += "/";
- filepath += pent->d_name;
- if (stat(filepath.c_str(), &filestat )) continue;
- if (S_ISDIR( filestat.st_mode )) continue;
+ dir.setFilter(QDir::Files);
+ QStringList files = dir.entryList();
+ for (auto &f : files) CheckFile(dirname + "/" + f);
- CheckFile(filepath);
+ qDebug() << list.size() << "temperaments";
+}
+
+void Temperaments::CheckFile(const QString & filename)
+{
+ qDebug() << __func__ << "check " << filename;
+ QFile file(filename);
+ if (!file.exists()) {
+ qDebug() << __func__ << "file doesn't exist: " << filename;
+ return;
+ }
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << __func__ << "cannot open file " << filename;
+ return;
+ }
+ QByteArray line;
+ QString name;
+ int offset, f_pos;
+ int n_line = 0;
+ while (1) {
+ f_pos = file.pos();
+ line = file.readLine();
+ if (line.count() == 0) break;
+ n_line++;
+ offset = line.indexOf(';');
+ if (offset < 1) {
+ qDebug() << __func__ << "cannot read line " << n_line;
+ continue;
+ }
+ // add temperament
+ name = line.left(offset);
+ qDebug() << " -> add temperament" << name;
+ list.push_back(temp_t{name, filename, f_pos});
}
}
-void Temperaments::CheckFile(string filename)
+bool Temperaments::CheckoutTemperament(const temp_t &temp)
{
- cout << __func__ << " " << filename << endl;
+ QFile file(temp.file);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << __func__ << "cannot open file " << temp.file;
+ return false;
+ }
+ file.seek(temp.seek);
+ QByteArray line = file.readLine();
+ if (line.count() == 0) {
+ qDebug() << __func__ << "empty line" << temp.file << "pos" << temp.seek;
+ return false;
+ }
+ auto tab = line.trimmed().split(';');
+ if (tab.count() != nb_notes + 1) {
+ qDebug() << __func__ << "nb element not match" << temp.file << "pos" << temp.seek << "count" << tab.count();
+ return false;
+ }
+ for (int i = 1; i < nb_notes + 1; i++) {
+ notes[i-1] = tab[i].toDouble();
+ }
+ qDebug() << "temperament" << temp.name << "loaded";
+ return true;
}
-string Temperaments::GetCurrentName() const
+bool Temperaments::SetTemperament(unsigned int index)
+{
+ if (index >= list.size()) {
+ qDebug() << __func__ << "index" << index << "out of range";
+ return false;
+ }
+ current = index;
+ return CheckoutTemperament(list[current]);
+}
+
+bool Temperaments::SetTemperament(const QString name)
+{
+ int idx = 0;
+ for (auto &t : list) {
+ if (t.name == name) {
+ return SetTemperament(idx);
+ }
+ idx++;
+ }
+ return false;
+}
+
+unsigned int Temperaments::GetCurrentIndex() const
+{
+ return current;
+}
+
+QString Temperaments::GetCurrentName() const
{
if (current >= list.size()) return "";
return list[current].name;
}
-string Temperaments::GetName(unsigned int n) const
+QStringList Temperaments::GetNames() const
{
- if (n < list.size()) return "";
- return list[n].name;
+ QStringList ret;
+ for (auto & t : list) ret << t.name;
+ return ret;
}
const double * Temperaments::NotesFrequencies() const
diff --git a/src/scale/Temperaments.hpp b/src/scale/Temperaments.hpp
index e0a9827..6214eb3 100644
--- a/src/scale/Temperaments.hpp
+++ b/src/scale/Temperaments.hpp
@@ -18,7 +18,7 @@
#ifndef __TEMPERAMENTS_HPP
#define __TEMPERAMENTS_HPP
-#include
+#include
#include
/**
@@ -31,8 +31,8 @@ class Temperaments {
private:
/// describe internal a temperament
struct temp_t {
- std::string name; ///< temperament name
- std::string file; ///< file name
+ QString name; ///< temperament name
+ QString file; ///< file name
int seek; ///< position in file
};
@@ -42,21 +42,24 @@ class Temperaments {
std::vector list;
double notes[nb_notes];
- void GetDir(const char *dirname);
- void CheckFile(std::string filename);
- void GetTemperament(const temp_t temperament);
+ void GetDir(const QString & dirname);
+ void CheckFile(const QString & filename);
+ bool CheckoutTemperament(const temp_t & temperament);
public:
/// constructor with dir name to find data files
- Temperaments(const char * dirname);
+ Temperaments(const QString & dirname);
~Temperaments();
/// set current temperament
- bool SetTemperament(std::string name);
+ bool SetTemperament(const QString name);
+ bool SetTemperament(unsigned int index);
+ /// get index of current temperament
+ unsigned int GetCurrentIndex() const;
/// get the name of current temperament
- std::string GetCurrentName() const;
+ QString GetCurrentName() const;
/// get the name of temperament number n
- std::string GetName(unsigned int n) const;
+ QStringList GetNames() const;
/// get notes frequencies as double[nb_notes]
const double * NotesFrequencies() const;
};