From 1d857fd25daa6de0d4fdb96ec5eb6745cd801f2c Mon Sep 17 00:00:00 2001 From: Louis-Joseph Fournier Date: Tue, 5 Jan 2016 10:34:22 +0100 Subject: [PATCH] PitchDetection and TunerWorker different objects --- Tuner.pro | 2 + harbour-sailtuner.pro | 3 + src/PitchDetection.cpp | 242 ++++++++++++++++++++++++++++++++++++++++ src/PitchDetection.hpp | 107 ++++++++++++++++++ src/Tuner.cpp | 75 +++++-------- src/Tuner.hpp | 28 +++-- src/TunerWorker.cpp | 205 ++++------------------------------ src/TunerWorker.hpp | 60 ++-------- src/audio/ZeroCross.cpp | 1 + src/desktop.cpp | 3 +- 10 files changed, 436 insertions(+), 290 deletions(-) create mode 100644 src/PitchDetection.cpp create mode 100644 src/PitchDetection.hpp diff --git a/Tuner.pro b/Tuner.pro index cfbec22..ff35621 100644 --- a/Tuner.pro +++ b/Tuner.pro @@ -7,6 +7,7 @@ CONFIG += c++11 debug SOURCES += \ src/desktop.cpp \ + src/PitchDetection.cpp \ src/Tuner.cpp \ src/TunerWorker.cpp \ src/audio/LinearFilter.cpp \ @@ -15,6 +16,7 @@ SOURCES += \ src/scale/Temperaments.cpp HEADERS += \ + src/PitchDetection.hpp \ src/Tuner.hpp \ src/TunerWorker.hpp \ src/audio/LinearFilter.hpp \ diff --git a/harbour-sailtuner.pro b/harbour-sailtuner.pro index 457ada4..a756127 100644 --- a/harbour-sailtuner.pro +++ b/harbour-sailtuner.pro @@ -12,6 +12,7 @@ RESOURCES += \ SOURCES += \ src/sailfish.cpp \ + src/PitchDetection.cpp \ src/Tuner.cpp \ src/TunerWorker.cpp \ src/audio/LinearFilter.cpp \ @@ -20,6 +21,8 @@ SOURCES += \ src/scale/Temperaments.cpp HEADERS += \ + src/PitchDetection.hpp \ + src/Tuner.cpp \ src/Tuner.hpp \ src/TunerWorker.hpp \ src/audio/LinearFilter.hpp \ diff --git a/src/PitchDetection.cpp b/src/PitchDetection.cpp new file mode 100644 index 0000000..ce1e5c8 --- /dev/null +++ b/src/PitchDetection.cpp @@ -0,0 +1,242 @@ +/* Copyright 2016 (C) Louis-Joseph Fournier + * louisjoseph.fournier@gmail.com + * + * This file is part of SailTuner. + * + * SailTuner is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SailTuner is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "PitchDetection.hpp" + +using namespace std; + +// high 10hz / 16k +static double a10[] = { 1 , -2.99214602, 2.98432286, -0.99217678 }; +static double b10[] = { 0.99608071, -2.98824212, 2.98824212, -0.99608071 }; + +const char * PitchDetection::filename_record = NULL; + +/// Pitch detection result methods + +PitchDetection::PitchResult::PitchResult() : + found(false), + deviation(0), + frequency(0), + note(0), + octave(0) +{ +} + +void PitchDetection::PitchResult::Set(int n, int o, double d, double f) +{ + note = n; + octave = o; + deviation = d; + frequency = f; + found = true; +} + +/// Pitch detection methods + +PitchDetection::PitchDetection() +{ + if (filename_record) file_record.open(filename_record); + + high_filter = new LinearFilter(3, a10, b10); + + ZeroCross::Config cross_config({rate, defaultNbFrame, defaultFreqMin, defaultFreqMax}); + cross = new ZeroCross(cross_config); + + scale = new Scale(); + temperaments = new Temperaments(":/data"); + + if (temperaments->SetTemperament(0)) { + scale->SetNotesFrequencies(temperaments->NotesFrequencies()); + } + else { + scale->ConstructEqualTemperament(); + } + + Reset(); +} + +PitchDetection::~PitchDetection() +{ + if (filename_record && file_record.is_open()) file_record.close(); + delete high_filter; + delete cross; + delete scale; + delete temperaments; +} + +/// reset analyse values +void PitchDetection::Reset() +{ + result.found = false; + updated = false; + count_found = count_not_found = 0; + note_found = octave_found = -1; + ResetDeviation(); + high_filter->Clear(); + cross->Clear(); +} + +void PitchDetection::ComputeFrame(int16_t v) +{ + v = (*high_filter)(v); + (*cross)(v); +} + +void PitchDetection::ResetDeviation() +{ + // reset deviation values + nb_deviation = 0; + deviation_start = 0; + deviation_sum = 0; +} + +void PitchDetection::UpdateDeviation(double d) +{ + if (nb_deviation == nbDeviationValues) { + deviation_sum -= deviation_values[deviation_start]; + deviation_start = (deviation_start + 1) % nbDeviationValues; + nb_deviation--; + } + deviation_values[(deviation_start + nb_deviation) % nbDeviationValues] = d; + nb_deviation++; + deviation_sum += d; +} + +void PitchDetection::SetFound(int n, int o, double d) +{ + if (n != note_found || o != octave_found) { + note_found = n; + octave_found = o; + count_found = 0; + SetNotFound(); + + ResetDeviation(); + UpdateDeviation(d); + } + else if (count_found++ >= nbConfirm) { + count_not_found = 0; + UpdateDeviation(d); + + result.Set(n, o, deviation_sum / nb_deviation, cross->Freq()); + updated = true; + } + else { + UpdateDeviation(d); + } +} + +void PitchDetection::SetNotFound() +{ + if (count_not_found++ >= nbDefect) { + count_found = 0; + if (result.found) { + result.found = false; + ResetDeviation(); + updated = true; + } + } +} + +void PitchDetection::SetLa(double la) +{ + scale->SetLa(la); +} + +void PitchDetection::SetTemperament(int idx) +{ + if (idx < 0) return; + if (temperaments->SetTemperament(idx)) { + scale->SetNotesFrequencies(temperaments->NotesFrequencies()); + } +} + +void PitchDetection::AudioAnalyse(const int16_t *ptr, int nb_frame) +{ + // record in file is needed + if (filename_record && file_record.is_open()) file_record.write((char*) ptr, nb_frame * sizeof(int16_t)); + + // compute every audio frame + while (nb_frame--) ComputeFrame(*ptr++); + + // find note, octave, deviation + if (cross->Freq()) { + int n, o = 0; + double d = 0; + n = scale->FindNote(cross->Freq(), o, d); + SetFound(n, o, d); + } + else { // no freq + SetNotFound(); + } +} + +bool PitchDetection::GetResultUpdated(PitchResult &res) +{ + if (!updated) return false; + res = this->result; + updated = false; + return true; +} + +QStringList PitchDetection::GetTemperamentList() const +{ + return temperaments->GetNames(); +} + +/// Set a filename to record raw audio stream + +void PitchDetection::set_record(const char *f) +{ + filename_record = f; +} + +/// for analyse_file console logs +static void display_results(const PitchDetection::PitchResult &res) +{ + if (res.found) + cout << res.frequency << " " << Scale::NoteName(res.note) << " " << res.octave << " " << res.deviation << endl; + else + cout << res.frequency << endl; +} + +/// analyse a file (static function) +void PitchDetection::analyse_file(const char *filename) +{ + cout << "analyse file " << filename << endl; + ifstream fin; + fin.open(filename); + + const int nb_frame = 1024; + PitchDetection *pitch = new PitchDetection(); + int16_t buffer[nb_frame]; + PitchResult result; + + while (1) { + fin.read((char*) buffer, sizeof(buffer)); + pitch->AudioAnalyse(buffer, sizeof(buffer) >> 1); + + if (pitch->GetResultUpdated(result)) display_results(result); + else cout << "." << endl; + + if (fin.eof()) break; + } + fin.close(); + delete pitch; +} diff --git a/src/PitchDetection.hpp b/src/PitchDetection.hpp new file mode 100644 index 0000000..21568b4 --- /dev/null +++ b/src/PitchDetection.hpp @@ -0,0 +1,107 @@ +/* Copyright 2016 (C) Louis-Joseph Fournier + * louisjoseph.fournier@gmail.com + * + * This file is part of SailTuner. + * + * SailTuner is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SailTuner is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _PITCH_DETECTION_HPP +#define _PITCH_DETECTION_HPP + +#include + +#include "audio/LinearFilter.hpp" +#include "audio/ZeroCross.hpp" +#include "scale/Scale.hpp" +#include "scale/Temperaments.hpp" + +/** + * Pitch detection algorithm + * + * Implements the pitch algorithm + * and note finding, using audio and scale objects + */ +class PitchDetection { + public: + /** + * Structure for pitch detection result + */ + struct PitchResult { + bool found; + double deviation, frequency; + int note, octave; + + PitchResult(); + void Set(int n, int o, double d, double f); + }; + + private: + static const int rate = 16000; + static const int defaultNbFrame = 1024; + static const int defaultFreqMin = 50; + static const int defaultFreqMax = 2000; + static const int nbSamplePreventRunning = rate * 40; // 40 seconds + /// number of analyses to confirm a note + static const int nbConfirm = 3; + /// number of analyses to drop a note + static const int nbDefect = 20; + /// number of deviation values for average + static const int nbDeviationValues = 8; + + static const char *filename_record; + + LinearFilter *high_filter; + ZeroCross *cross; + Scale *scale; + Temperaments *temperaments; + std::ofstream file_record; + + PitchResult result; + bool updated; + int note_found, octave_found, count_found, count_not_found; + int nb_deviation, deviation_start; + double deviation_sum; + double deviation_values[nbDeviationValues]; + + void SetFound(int note, int octave, double deviation); + void SetNotFound(); + void ResetDeviation(); + void UpdateDeviation(double d); + + /// Compute an audio sample + inline void ComputeFrame(int16_t v); + + public: + PitchDetection(); + ~PitchDetection(); + + /// compute an audio buffer + void AudioAnalyse(const int16_t *buffer, int size); + /// Get results if updated + bool GetResultUpdated(PitchResult &result); + /// reset computing + void Reset(); + /// Set la4 freq reference + void SetLa(double freq); + /// Set temperament + void SetTemperament(int idx); + /// Get temperament list + QStringList GetTemperamentList() const; + + /// analyse a file for debug + static void analyse_file(const char *filename); + /// write a file with raw audio + static void set_record(const char *filename_record); +}; + +#endif diff --git a/src/Tuner.cpp b/src/Tuner.cpp index 440f0c1..64e05aa 100644 --- a/src/Tuner.cpp +++ b/src/Tuner.cpp @@ -32,32 +32,24 @@ using namespace std; Tuner::Tuner() { running = false; - freq = deviation = 0; - note = octave = 0; - found = false; + temperament_idx = 0; la = Scale::defaultLa; worker = new TunerWorker(); - temperaments = new Temperaments(":/data"); - - if (temperaments->SetTemperament(0)) { - worker->SetNotesFrequencies(temperaments->NotesFrequencies()); - } - worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(&workerThread, &QThread::started, worker, &TunerWorker::Entry); - connect(this, &Tuner::quit, worker, &TunerWorker::Quit, Qt::DirectConnection); + connect(this, &Tuner::quit, worker, &TunerWorker::Quit, Qt::DirectConnection); connect(this, &Tuner::start, worker, &TunerWorker::Start); connect(this, &Tuner::stop, worker, &TunerWorker::Stop); - connect(this, &Tuner::setNotesFrequencies, worker, &TunerWorker::SetNotesFrequencies); + connect(this, &Tuner::setTemperamentIndex, worker, &TunerWorker::SetTemperament); connect(this, &Tuner::setLa, worker, &TunerWorker::SetLa); - connect(worker, &TunerWorker::resultFound, this, &Tuner::ResultFound); - connect(worker, &TunerWorker::resultNotFound, this, &Tuner::ResultNotFound); + connect(worker, &TunerWorker::resultUpdated, this, &Tuner::ResultUpdated); + connect(worker, &TunerWorker::temperamentListUpdated, this, &Tuner::TemperamentListUpdated); workerThread.start(); } @@ -67,7 +59,6 @@ Tuner::~Tuner() quit(); // workerThread.quit(); workerThread.wait(10); - delete temperaments; } bool Tuner::GetRunning() @@ -80,42 +71,42 @@ void Tuner::SetRunning(bool r) if (running == r) return; running = r; - if (r) start(); - else stop(); + if (r) emit start(); + else emit stop(); - runningChanged(); + emit runningChanged(); } double Tuner::GetFreq() { - return freq; + return result.frequency; } int Tuner::GetNote() { - return note; + return result.note; } double Tuner::GetDeviation() { - return deviation; + return result.deviation; } int Tuner::GetOctave() { - return octave; + return result.octave; } bool Tuner::GetFound() { - return found; + return result.found; } void Tuner::SetLa(double la) { this->la = la; - setLa(la); - laChanged(); + emit setLa(la); + emit laChanged(); } double Tuner::GetLa() @@ -125,39 +116,33 @@ double Tuner::GetLa() unsigned int Tuner::GetTemperamentIndex() { - return temperaments->GetCurrentIndex(); + return temperament_idx; } -void Tuner::SetTemperamentIndex(unsigned int idx) +void Tuner::SetTemperamentIndex(int idx) { - if (temperaments->SetTemperament(idx)) { - setNotesFrequencies(temperaments->NotesFrequencies()); - temperamentChanged(); - } + temperament_idx = idx; + emit setTemperamentIndex(idx); + emit temperamentChanged(); } QStringList Tuner::GetTemperamentList() const { - return temperaments->GetNames(); + return temperament_list; } -void Tuner::ResultFound(int note, int octave, double deviation, double freq) +void Tuner::ResultUpdated(const PitchDetection::PitchResult &result) { - this->note = note; - this->octave = octave; - this->deviation = deviation; - this->freq = freq; - resultChanged(); + const bool changed = (this->result.found ^ result.found); - if (!found) { - foundChanged(); - found = true; - } + this->result = result; + + if (result.found) emit resultChanged(); + if (changed) emit foundChanged(); } -void Tuner::ResultNotFound(double freq) +void Tuner::TemperamentListUpdated(const QStringList &list) { - this->freq = freq; - found = false; - foundChanged(); + temperament_list = list; + emit temperamentListChanged(); } diff --git a/src/Tuner.hpp b/src/Tuner.hpp index 0df2fce..1d40593 100644 --- a/src/Tuner.hpp +++ b/src/Tuner.hpp @@ -18,8 +18,10 @@ #ifndef _TUNER_HPP #define _TUNER_HPP +#include + +#include "PitchDetection.hpp" #include "TunerWorker.hpp" -#include "scale/Temperaments.hpp" class Tuner : public QObject { Q_OBJECT @@ -30,17 +32,18 @@ class Tuner : public QObject { Q_PROPERTY(int octave READ GetOctave NOTIFY resultChanged) Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged) Q_PROPERTY(int temperament_idx READ GetTemperamentIndex WRITE SetTemperamentIndex NOTIFY temperamentChanged) - Q_PROPERTY(QStringList temperament_list READ GetTemperamentList) + Q_PROPERTY(QStringList temperament_list READ GetTemperamentList NOTIFY temperamentListChanged) Q_PROPERTY(double la READ GetLa WRITE SetLa NOTIFY laChanged) private: - Temperaments *temperaments; TunerWorker *worker; QThread workerThread; - bool running, found; - double freq, deviation, la; - int note, octave; + PitchDetection::PitchResult result; + QStringList temperament_list; + bool running; + double la; + int temperament_idx; public: Tuner(); @@ -54,27 +57,30 @@ class Tuner : public QObject { double GetDeviation(); bool GetFound(); unsigned int GetTemperamentIndex(); - void SetTemperamentIndex(unsigned int idx); + void SetTemperamentIndex(int idx); QStringList GetTemperamentList() const; double GetLa(); void SetLa(double la); public slots: - void ResultFound(int note, int octave, double deviation, double frequency); - void ResultNotFound(double freq); + // slots from worker + void ResultUpdated(const PitchDetection::PitchResult &result); + void TemperamentListUpdated(const QStringList &list); signals: + // signals to UI void runningChanged(); void foundChanged(); - void temperamentChanged(); void laChanged(); void resultChanged(); + void temperamentChanged(); + void temperamentListChanged(); // signals to worker void quit(); void start(); void stop(); - void setNotesFrequencies(const double *freq); + void setTemperamentIndex(int idx); void setLa(double la_freq); }; diff --git a/src/TunerWorker.cpp b/src/TunerWorker.cpp index 330d6dc..1e1b3ab 100644 --- a/src/TunerWorker.cpp +++ b/src/TunerWorker.cpp @@ -19,18 +19,11 @@ #include #include -#include #include "TunerWorker.hpp" using namespace std; -// high 10hz / 16k -static double a10[] = { 1 , -2.99214602, 2.98432286, -0.99217678 }; -static double b10[] = { 0.99608071, -2.98824212, 2.98824212, -0.99608071 }; - -const char * TunerWorker::filename_record = NULL; - /// function to prevent screen blank on Sailfish OS static void blank_prevent(bool prevent) @@ -47,41 +40,16 @@ static void blank_prevent(bool prevent) } TunerWorker::TunerWorker() : - high_filter(NULL), - cross(NULL), - scale(NULL), running(false), quit(false), la_to_update(0), - freq_to_update(NULL) + temperament_to_update(-1) { - // part of reset - found = false; - count_found = count_not_found = 0; - nb_sample_running = 0; - note_found = octave_found = -1; - ResetDeviation(); } TunerWorker::~TunerWorker() { - if (filename_record && file_record.is_open()) file_record.close(); - if (high_filter) delete high_filter; - if (cross) delete cross; - if (scale) delete scale; -} - -/// reset analyse values -void TunerWorker::Reset() -{ - found = false; - count_found = count_not_found = 0; - nb_sample_running = 0; - note_found = octave_found = -1; - ResetDeviation(); - blank_prevent(true); - high_filter->Clear(); - cross->Clear(); + if (pitchDetection) delete pitchDetection; } void TunerWorker::Start() @@ -109,13 +77,6 @@ void TunerWorker::Quit() mutex.unlock(); } -void TunerWorker::SetNotesFrequencies(const double *notes_freq) -{ - mutex.lock(); - freq_to_update = notes_freq; - mutex.unlock(); -} - void TunerWorker::SetLa(double la) { mutex.lock(); @@ -123,107 +84,18 @@ void TunerWorker::SetLa(double la) mutex.unlock(); } -void TunerWorker::ComputeFrame(int16_t v) +void TunerWorker::SetTemperament(int idx) { - v = (*high_filter)(v); - (*cross)(v); + mutex.lock(); + temperament_to_update = idx; + mutex.unlock(); } -void TunerWorker::ResetDeviation() -{ - // reset deviation values - nb_deviation = 0; - deviation_start = 0; - deviation_sum = 0; -} - -void TunerWorker::UpdateDeviation(double d) -{ - if (nb_deviation == nbDeviationValues) { - deviation_sum -= deviation_values[deviation_start]; - deviation_start = (deviation_start + 1) % nbDeviationValues; - nb_deviation--; - } - deviation_values[(deviation_start + nb_deviation) % nbDeviationValues] = d; - nb_deviation++; - deviation_sum += d; -} - -void TunerWorker::SetFound(int n, int o, double d) -{ - if (n != note_found || o != octave_found) { - note_found = n; - octave_found = o; - count_found = 0; - SetNotFound(); - - ResetDeviation(); - UpdateDeviation(d); - } - else if (count_found++ >= nbConfirm) { - found = true; - count_not_found = 0; - UpdateDeviation(d); - - resultFound(n, o, deviation_sum / nb_deviation, cross->Freq()); - } - else { - UpdateDeviation(d); - } -} - -void TunerWorker::SetNotFound() -{ - if (count_not_found++ >= nbDefect) { - count_found = 0; - if (found) { - found = false; - ResetDeviation(); - resultNotFound(cross->Freq()); - } - } -} - -void TunerWorker::AudioAnalyse(const int16_t *ptr, int nb_frame) -{ - nb_sample_running += nb_frame; - - // record in file is needed - if (filename_record && file_record.is_open()) file_record.write((char*) ptr, nb_frame * sizeof(int16_t)); - - // compute every audio frame - while (nb_frame--) ComputeFrame(*ptr++); - - // find note, octave, deviation - if (cross->Freq()) { - int n, o = 0; - double d = 0; - n = scale->FindNote(cross->Freq(), o, d); - SetFound(n, o, d); - } - else { // no freq - SetNotFound(); - } - - // prevent screen blanking - if (nb_sample_running >= nbSamplePreventRunning && running) { - nb_sample_running = 0; - blank_prevent(true); - } -} - - void TunerWorker::Entry() { - // initialisations - if (filename_record) file_record.open(filename_record); - - high_filter = new LinearFilter(3, a10, b10); - - ZeroCross::Config cross_config({rate, defaultNbFrame, defaultFreqMin, defaultFreqMax}); - cross = new ZeroCross(cross_config); - - scale = new Scale(); + cerr << __func__ << endl; + pitchDetection = new PitchDetection(); + emit temperamentListUpdated(pitchDetection->GetTemperamentList()); while (1) { // wait for running @@ -231,8 +103,9 @@ void TunerWorker::Entry() if (!running) { blank_prevent(false); while (!running && !quit) condition.wait(&mutex); + cerr << "wake-up" << endl; // reset operations on start - if (!quit) Reset(); + if (!quit) pitchDetection->Reset(); } if (quit) { mutex.unlock(); @@ -240,58 +113,22 @@ void TunerWorker::Entry() } // update config if (la_to_update) { - scale->SetLa(la_to_update); + pitchDetection->SetLa(la_to_update); la_to_update = 0; } - if (freq_to_update) { - scale->SetNotesFrequencies(freq_to_update); - freq_to_update = NULL; + if (temperament_to_update != -1) { + pitchDetection->SetTemperament(temperament_to_update); + temperament_to_update = -1; } mutex.unlock(); std::cout << __func__ << " do job" << std::endl; } +/* + // prevent screen blanking + if (nb_sample_running >= nbSamplePreventRunning && running) { + nb_sample_running = 0; + blank_prevent(true); + }*/ } -/// Set a filename to record raw audio stream - -void TunerWorker::set_record(const char *f) -{ - filename_record = f; -} - -/// for analyse_file console logs -static void display_results(int note, int octave, double deviation, double frequency) -{ - cout << frequency << " " << Scale::NoteName(note) << " " << octave << " " << deviation << endl; -} - -static void display_no_results(double freq) -{ - cout << freq << endl; -} - -/// analyse a file (static function) -void TunerWorker::analyse_file(const char *filename) -{ - cout << "analyse file " << filename << endl; - ifstream fin; - fin.open(filename); - - const int nb_frame = 1024; - TunerWorker *tuner = new TunerWorker(); - int16_t buffer[nb_frame]; - - connect(tuner, &TunerWorker::resultFound, NULL, display_results); - connect(tuner, &TunerWorker::resultNotFound, NULL, display_no_results); - - while (1) { - fin.read((char*) buffer, sizeof(buffer)); - tuner->AudioAnalyse(buffer, sizeof(buffer) >> 1); -// cout << "." << endl; - - if (fin.eof()) break; - } - fin.close(); - delete tuner; -} diff --git a/src/TunerWorker.hpp b/src/TunerWorker.hpp index 384a054..b6acfc1 100644 --- a/src/TunerWorker.hpp +++ b/src/TunerWorker.hpp @@ -22,70 +22,32 @@ #include #include #include +#include -#include - -#include "audio/LinearFilter.hpp" -#include "audio/ZeroCross.hpp" -#include "scale/Scale.hpp" +#include "PitchDetection.hpp" /** - * Worker class to work with audio datas + * Worker class to receive audio and + * do pitch detection in a thread * - * Implements the pitch algorithm - * and note finding */ class TunerWorker : public QObject { Q_OBJECT private: - static const int rate = 16000; - static const int defaultNbFrame = 1024; - static const int defaultFreqMin = 50; - static const int defaultFreqMax = 2000; - static const int nbSamplePreventRunning = rate * 40; // 40 seconds - /// number of analyses to confirm a note - static const int nbConfirm = 3; - /// number of analyses to drop a note - static const int nbDefect = 20; - /// number of deviation values for average - static const int nbDeviationValues = 8; - - static const char *filename_record; - - LinearFilter *high_filter; - ZeroCross *cross; - Scale *scale; - std::ofstream file_record; - QMutex mutex; QWaitCondition condition; - bool running, found, quit; + PitchDetection *pitchDetection; + + bool running, quit; int nb_sample_running; - int note_found, octave_found, count_found, count_not_found; - int nb_deviation, deviation_start; - double deviation_sum; - double deviation_values[nbDeviationValues]; // to update vars double la_to_update; - const double *freq_to_update; - - inline void ComputeFrame(int16_t v); - void SetFound(int note, int octave, double deviation); - void SetNotFound(); - void Reset(); - void ResetDeviation(); - void UpdateDeviation(double d); - void AudioAnalyse(const int16_t *buffer, int size); + int temperament_to_update; public: - /// analyse a file for debug - static void analyse_file(const char *filename); - /// write a file with raw audio - static void set_record(const char *filename_record); - /// constructor TunerWorker(); ~TunerWorker(); @@ -93,14 +55,14 @@ class TunerWorker : public QObject { public slots: void Start(); void Stop(); - void SetNotesFrequencies(const double *notes_freq); + void SetTemperament(int idx); void SetLa(double la); void Entry(); void Quit(); signals: - void resultFound(int note, int octave, double deviation, double frequency); - void resultNotFound(double freq); + void resultUpdated(const PitchDetection::PitchResult &result); + void temperamentListUpdated(const QStringList &list); }; #endif diff --git a/src/audio/ZeroCross.cpp b/src/audio/ZeroCross.cpp index 6c25848..b196a79 100644 --- a/src/audio/ZeroCross.cpp +++ b/src/audio/ZeroCross.cpp @@ -120,6 +120,7 @@ template ZeroCross::ZeroCross(const Config &config) template void ZeroCross::Clear() { + last_sample = 0; pattern_current.time = -1; nb_frame_analysed = 0; freq = 0; diff --git a/src/desktop.cpp b/src/desktop.cpp index 1ce5ff4..35b041b 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -22,12 +22,13 @@ #include #include +#include "PitchDetection.hpp" #include "Tuner.hpp" Q_DECL_EXPORT int main(int argc, char* argv[]) { if (argc == 2) { - TunerWorker::analyse_file(argv[1]); + PitchDetection::analyse_file(argv[1]); return 0; }