Temperaments: load from csv file in qrc ressources
Module Temperaments is fully functionnal
This commit is contained in:
parent
8a43de5b5b
commit
986f736b68
10 changed files with 160 additions and 45 deletions
|
@ -21,4 +21,5 @@ HEADERS += \
|
||||||
src/scale/Temperaments.hpp
|
src/scale/Temperaments.hpp
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
qml/desktop.qrc
|
qml/desktop.qrc \
|
||||||
|
data/temperaments.qrc
|
||||||
|
|
|
@ -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
|
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 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
|
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
|
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
|
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
|
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 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
|
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
|
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
|
||||||
|
|
|
5
data/temperaments.qrc
Normal file
5
data/temperaments.qrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
|
<qresource prefix="/data/">
|
||||||
|
<file>Temperaments.csv</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -7,7 +7,8 @@ DEFINES += TARGET=\""$(TARGET")\"
|
||||||
# PKGCONFIG += libpulse
|
# PKGCONFIG += libpulse
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
qml/sailfish.qrc
|
qml/sailfish.qrc \
|
||||||
|
data/temperaments.qrc
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/sailfish.cpp \
|
src/sailfish.cpp \
|
||||||
|
|
|
@ -67,7 +67,14 @@ Tuner::Tuner()
|
||||||
cross = new ZeroCross<int16_t>(cross_config);
|
cross = new ZeroCross<int16_t>(cross_config);
|
||||||
|
|
||||||
scale = new Scale();
|
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.setCodec("audio/PCM");
|
||||||
settings.setChannelCount(1);
|
settings.setChannelCount(1);
|
||||||
|
@ -269,6 +276,24 @@ bool Tuner::GetFound()
|
||||||
return found;
|
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
|
/// Set a filename to record raw audio stream
|
||||||
|
|
||||||
void Tuner::set_record(const char *f)
|
void Tuner::set_record(const char *f)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "audio/LinearFilter.hpp"
|
#include "audio/LinearFilter.hpp"
|
||||||
#include "audio/ZeroCross.hpp"
|
#include "audio/ZeroCross.hpp"
|
||||||
#include "scale/Scale.hpp"
|
#include "scale/Scale.hpp"
|
||||||
|
#include "scale/Temperaments.hpp"
|
||||||
|
|
||||||
class Tuner : public QObject {
|
class Tuner : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -33,6 +34,8 @@ class Tuner : public QObject {
|
||||||
Q_PROPERTY(int octave READ GetOctave NOTIFY octaveChanged)
|
Q_PROPERTY(int octave READ GetOctave NOTIFY octaveChanged)
|
||||||
Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged)
|
Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged)
|
||||||
Q_PROPERTY(QString noteName READ GetNoteName NOTIFY noteNameChanged)
|
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:
|
private:
|
||||||
QAudioRecorder *recorder;
|
QAudioRecorder *recorder;
|
||||||
|
@ -42,6 +45,7 @@ class Tuner : public QObject {
|
||||||
LinearFilter<int16_t> *high_filter;
|
LinearFilter<int16_t> *high_filter;
|
||||||
ZeroCross<int16_t> *cross;
|
ZeroCross<int16_t> *cross;
|
||||||
Scale *scale;
|
Scale *scale;
|
||||||
|
Temperaments *temperaments;
|
||||||
static const char *filename_record;
|
static const char *filename_record;
|
||||||
std::ofstream file_record;
|
std::ofstream file_record;
|
||||||
|
|
||||||
|
@ -92,6 +96,9 @@ class Tuner : public QObject {
|
||||||
double GetDeviation();
|
double GetDeviation();
|
||||||
bool GetFound();
|
bool GetFound();
|
||||||
const char* GetNoteName();
|
const char* GetNoteName();
|
||||||
|
unsigned int GetTemperamentIndex();
|
||||||
|
void SetTemperamentIndex(unsigned int idx);
|
||||||
|
QStringList GetTemperamentList() const;
|
||||||
|
|
||||||
/// analyse a file for debug
|
/// analyse a file for debug
|
||||||
static void analyse_file(const char *filename);
|
static void analyse_file(const char *filename);
|
||||||
|
@ -106,4 +113,5 @@ class Tuner : public QObject {
|
||||||
void octaveChanged();
|
void octaveChanged();
|
||||||
void deviationChanged();
|
void deviationChanged();
|
||||||
void foundChanged();
|
void foundChanged();
|
||||||
|
void temperamentChanged();
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,10 @@ Scale::Scale()
|
||||||
void Scale::updateScale()
|
void Scale::updateScale()
|
||||||
{
|
{
|
||||||
actualFactor = actualLa / defaultLa;
|
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[0] = actualNoteFreq[0] * pow(halfToneFactor(0, -1),0.5);
|
||||||
actualRange[1] = actualNoteFreq[nbNote - 1] * pow(halfToneFactor(nbNote - 1, 1), 0.5);
|
actualRange[1] = actualNoteFreq[nbNote - 1] * pow(halfToneFactor(nbNote - 1, 1), 0.5);
|
||||||
|
|
||||||
|
@ -116,7 +119,7 @@ double Scale::GetLa()
|
||||||
return actualLa;
|
return actualLa;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scale::SetNotesFrequencies(double freq[nbNote])
|
void Scale::SetNotesFrequencies(const double freq[nbNote])
|
||||||
{
|
{
|
||||||
memcpy(noteFreq, freq, sizeof(double) * nbNote);
|
memcpy(noteFreq, freq, sizeof(double) * nbNote);
|
||||||
updateScale();
|
updateScale();
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Scale {
|
||||||
void ConstructEqualTemperament();
|
void ConstructEqualTemperament();
|
||||||
|
|
||||||
/// Set notes frequencies from a temperament
|
/// Set notes frequencies from a temperament
|
||||||
void SetNotesFrequencies(double freq[nbNote]);
|
void SetNotesFrequencies(const double freq[nbNote]);
|
||||||
|
|
||||||
double GetLa();
|
double GetLa();
|
||||||
void SetLa(double la);
|
void SetLa(double la);
|
||||||
|
|
|
@ -15,59 +15,128 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fstream>
|
#include <QDir>
|
||||||
#include <iostream>
|
#include <QDebug>
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "Temperaments.hpp"
|
#include "Temperaments.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Temperaments::Temperaments(const char * dirname) : current(0)
|
Temperaments::Temperaments(const QString & dirname) : current(0)
|
||||||
{
|
{
|
||||||
GetDir(dirname);
|
GetDir(dirname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Temperaments::GetDir(const char * dirname)
|
void Temperaments::GetDir(const QString & dirname)
|
||||||
{
|
{
|
||||||
DIR *pdir = opendir(dirname);
|
QDir dir(dirname);
|
||||||
struct dirent *pent = NULL;
|
if (!dir.exists()) {
|
||||||
struct stat filestat;
|
qDebug() << __func__ << "dir doesn't exist: " << dirname;
|
||||||
string filepath;
|
|
||||||
|
|
||||||
if (!pdir) {
|
|
||||||
cerr << __func__ << ": impossible to open dir " << dirname << endl;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while((pent = readdir(pdir))) {
|
dir.setFilter(QDir::Files);
|
||||||
// get only files
|
QStringList files = dir.entryList();
|
||||||
if (pent->d_name[0] == '.') continue;
|
for (auto &f : files) CheckFile(dirname + "/" + f);
|
||||||
filepath = dirname;
|
|
||||||
filepath += "/";
|
|
||||||
filepath += pent->d_name;
|
|
||||||
if (stat(filepath.c_str(), &filestat )) continue;
|
|
||||||
if (S_ISDIR( filestat.st_mode )) continue;
|
|
||||||
|
|
||||||
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 "";
|
if (current >= list.size()) return "";
|
||||||
return list[current].name;
|
return list[current].name;
|
||||||
}
|
}
|
||||||
|
|
||||||
string Temperaments::GetName(unsigned int n) const
|
QStringList Temperaments::GetNames() const
|
||||||
{
|
{
|
||||||
if (n < list.size()) return "";
|
QStringList ret;
|
||||||
return list[n].name;
|
for (auto & t : list) ret << t.name;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const double * Temperaments::NotesFrequencies() const
|
const double * Temperaments::NotesFrequencies() const
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#ifndef __TEMPERAMENTS_HPP
|
#ifndef __TEMPERAMENTS_HPP
|
||||||
#define __TEMPERAMENTS_HPP
|
#define __TEMPERAMENTS_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <QString>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,8 +31,8 @@ class Temperaments {
|
||||||
private:
|
private:
|
||||||
/// describe internal a temperament
|
/// describe internal a temperament
|
||||||
struct temp_t {
|
struct temp_t {
|
||||||
std::string name; ///< temperament name
|
QString name; ///< temperament name
|
||||||
std::string file; ///< file name
|
QString file; ///< file name
|
||||||
int seek; ///< position in file
|
int seek; ///< position in file
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,21 +42,24 @@ class Temperaments {
|
||||||
std::vector<temp_t> list;
|
std::vector<temp_t> list;
|
||||||
double notes[nb_notes];
|
double notes[nb_notes];
|
||||||
|
|
||||||
void GetDir(const char *dirname);
|
void GetDir(const QString & dirname);
|
||||||
void CheckFile(std::string filename);
|
void CheckFile(const QString & filename);
|
||||||
void GetTemperament(const temp_t temperament);
|
bool CheckoutTemperament(const temp_t & temperament);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// constructor with dir name to find data files
|
/// constructor with dir name to find data files
|
||||||
Temperaments(const char * dirname);
|
Temperaments(const QString & dirname);
|
||||||
~Temperaments();
|
~Temperaments();
|
||||||
|
|
||||||
/// set current temperament
|
/// 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
|
/// get the name of current temperament
|
||||||
std::string GetCurrentName() const;
|
QString GetCurrentName() const;
|
||||||
/// get the name of temperament number n
|
/// get the name of temperament number n
|
||||||
std::string GetName(unsigned int n) const;
|
QStringList GetNames() const;
|
||||||
/// get notes frequencies as double[nb_notes]
|
/// get notes frequencies as double[nb_notes]
|
||||||
const double * NotesFrequencies() const;
|
const double * NotesFrequencies() const;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue