Player: implementation complete
This commit is contained in:
parent
ec2e8ebd31
commit
0703aabbf1
12 changed files with 121 additions and 21 deletions
|
@ -13,6 +13,7 @@ SOURCES += \
|
||||||
src/PitchDetection.cpp \
|
src/PitchDetection.cpp \
|
||||||
src/Tuner.cpp \
|
src/Tuner.cpp \
|
||||||
src/TunerWorker.cpp \
|
src/TunerWorker.cpp \
|
||||||
|
src/audio/FreqPlayer.cpp \
|
||||||
src/audio/LinearFilter.cpp \
|
src/audio/LinearFilter.cpp \
|
||||||
src/audio/ZeroCross.cpp \
|
src/audio/ZeroCross.cpp \
|
||||||
src/scale/Scale.cpp \
|
src/scale/Scale.cpp \
|
||||||
|
@ -23,6 +24,7 @@ HEADERS += \
|
||||||
src/ObjectSaver.hpp \
|
src/ObjectSaver.hpp \
|
||||||
src/Tuner.hpp \
|
src/Tuner.hpp \
|
||||||
src/TunerWorker.hpp \
|
src/TunerWorker.hpp \
|
||||||
|
src/audio/FreqPlayer.hpp \
|
||||||
src/audio/LinearFilter.hpp \
|
src/audio/LinearFilter.hpp \
|
||||||
src/audio/ZeroCross.hpp \
|
src/audio/ZeroCross.hpp \
|
||||||
src/scale/Scale.hpp \
|
src/scale/Scale.hpp \
|
||||||
|
|
|
@ -17,6 +17,7 @@ SOURCES += \
|
||||||
src/ObjectSaver.cpp \
|
src/ObjectSaver.cpp \
|
||||||
src/Tuner.cpp \
|
src/Tuner.cpp \
|
||||||
src/TunerWorker.cpp \
|
src/TunerWorker.cpp \
|
||||||
|
src/audio/FreqPlayer.cpp \
|
||||||
src/audio/LinearFilter.cpp \
|
src/audio/LinearFilter.cpp \
|
||||||
src/audio/ZeroCross.cpp \
|
src/audio/ZeroCross.cpp \
|
||||||
src/scale/Scale.cpp \
|
src/scale/Scale.cpp \
|
||||||
|
@ -28,6 +29,7 @@ HEADERS += \
|
||||||
src/Tuner.cpp \
|
src/Tuner.cpp \
|
||||||
src/Tuner.hpp \
|
src/Tuner.hpp \
|
||||||
src/TunerWorker.hpp \
|
src/TunerWorker.hpp \
|
||||||
|
src/audio/FreqPlayer.hpp \
|
||||||
src/audio/LinearFilter.hpp \
|
src/audio/LinearFilter.hpp \
|
||||||
src/audio/ZeroCross.hpp \
|
src/audio/ZeroCross.hpp \
|
||||||
src/scale/Scale.hpp \
|
src/scale/Scale.hpp \
|
||||||
|
|
|
@ -198,6 +198,11 @@ QStringList PitchDetection::GetTemperamentList() const
|
||||||
return temperaments->GetNames();
|
return temperaments->GetNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double PitchDetection::GetNoteFreq(int note, int octave) const
|
||||||
|
{
|
||||||
|
return scale->GetNoteFreq(note, octave);
|
||||||
|
}
|
||||||
|
|
||||||
/// for analyse_file console logs
|
/// for analyse_file console logs
|
||||||
static void display_results(const PitchDetection::PitchResult &res)
|
static void display_results(const PitchDetection::PitchResult &res)
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,6 +92,8 @@ class PitchDetection {
|
||||||
void SetTemperament(int idx);
|
void SetTemperament(int idx);
|
||||||
/// Get temperament list
|
/// Get temperament list
|
||||||
QStringList GetTemperamentList() const;
|
QStringList GetTemperamentList() const;
|
||||||
|
/// Get the note frequency from Scale
|
||||||
|
double GetNoteFreq(int note, int octave) 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);
|
||||||
|
|
|
@ -66,6 +66,7 @@ void Tuner::SetPlaying(bool p)
|
||||||
{
|
{
|
||||||
if (p == playing) return;
|
if (p == playing) return;
|
||||||
playing = p;
|
playing = p;
|
||||||
|
worker->SetPlaying(p);
|
||||||
emit playingChanged();
|
emit playingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +96,14 @@ int Tuner::GetNote()
|
||||||
return result.note;
|
return result.note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tuner::SetNote(int note)
|
||||||
|
{
|
||||||
|
if (result.note == note) return;
|
||||||
|
result.note = note;
|
||||||
|
worker->SetNote(note);
|
||||||
|
emit resultChanged();
|
||||||
|
}
|
||||||
|
|
||||||
double Tuner::GetDeviation()
|
double Tuner::GetDeviation()
|
||||||
{
|
{
|
||||||
return result.deviation;
|
return result.deviation;
|
||||||
|
@ -105,6 +114,14 @@ int Tuner::GetOctave()
|
||||||
return result.octave;
|
return result.octave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tuner::SetOctave(int octave)
|
||||||
|
{
|
||||||
|
if (result.octave == octave) return;
|
||||||
|
result.octave = octave;
|
||||||
|
worker->SetOctave(octave);
|
||||||
|
emit resultChanged();
|
||||||
|
}
|
||||||
|
|
||||||
bool Tuner::GetFound()
|
bool Tuner::GetFound()
|
||||||
{
|
{
|
||||||
return result.found;
|
return result.found;
|
||||||
|
|
|
@ -29,8 +29,8 @@ class Tuner : public QObject {
|
||||||
Q_PROPERTY(bool running READ GetRunning WRITE SetRunning NOTIFY runningChanged)
|
Q_PROPERTY(bool running READ GetRunning WRITE SetRunning NOTIFY runningChanged)
|
||||||
Q_PROPERTY(double freq READ GetFreq NOTIFY resultChanged)
|
Q_PROPERTY(double freq READ GetFreq NOTIFY resultChanged)
|
||||||
Q_PROPERTY(double deviation READ GetDeviation NOTIFY resultChanged)
|
Q_PROPERTY(double deviation READ GetDeviation NOTIFY resultChanged)
|
||||||
Q_PROPERTY(int note READ GetNote NOTIFY resultChanged)
|
Q_PROPERTY(int note READ GetNote WRITE SetNote NOTIFY resultChanged)
|
||||||
Q_PROPERTY(int octave READ GetOctave NOTIFY resultChanged)
|
Q_PROPERTY(int octave READ GetOctave WRITE SetOctave NOTIFY resultChanged)
|
||||||
Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged)
|
Q_PROPERTY(bool found READ GetFound NOTIFY foundChanged)
|
||||||
Q_PROPERTY(int temperament_idx READ GetTemperamentIndex WRITE SetTemperamentIndex NOTIFY temperamentChanged)
|
Q_PROPERTY(int temperament_idx READ GetTemperamentIndex WRITE SetTemperamentIndex NOTIFY temperamentChanged)
|
||||||
Q_PROPERTY(QStringList temperament_list READ GetTemperamentList NOTIFY temperamentListChanged)
|
Q_PROPERTY(QStringList temperament_list READ GetTemperamentList NOTIFY temperamentListChanged)
|
||||||
|
@ -56,7 +56,9 @@ class Tuner : public QObject {
|
||||||
void SetRunning(bool r);
|
void SetRunning(bool r);
|
||||||
double GetFreq();
|
double GetFreq();
|
||||||
int GetNote();
|
int GetNote();
|
||||||
|
void SetNote(int note);
|
||||||
int GetOctave();
|
int GetOctave();
|
||||||
|
void SetOctave(int octave);
|
||||||
double GetDeviation();
|
double GetDeviation();
|
||||||
bool GetFound();
|
bool GetFound();
|
||||||
unsigned int GetTemperamentIndex();
|
unsigned int GetTemperamentIndex();
|
||||||
|
|
|
@ -26,6 +26,7 @@ extern "C" {
|
||||||
#include <pulse/simple.h>
|
#include <pulse/simple.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "audio/FreqPlayer.hpp"
|
||||||
#include "TunerWorker.hpp"
|
#include "TunerWorker.hpp"
|
||||||
|
|
||||||
#define name_(x) #x
|
#define name_(x) #x
|
||||||
|
@ -57,7 +58,9 @@ TunerWorker::TunerWorker() :
|
||||||
running(false),
|
running(false),
|
||||||
quit(false),
|
quit(false),
|
||||||
la_to_update(0),
|
la_to_update(0),
|
||||||
temperament_to_update(0) // update the first time in every cases
|
temperament_to_update(0), // update the first time in every cases
|
||||||
|
note_to_update(-1),
|
||||||
|
octave_to_update(-1)
|
||||||
{
|
{
|
||||||
//qRegisterMetaType<PitchDetection::PitchResult>("PitchDetection::PitchResult");
|
//qRegisterMetaType<PitchDetection::PitchResult>("PitchDetection::PitchResult");
|
||||||
}
|
}
|
||||||
|
@ -115,6 +118,21 @@ void TunerWorker::SetTemperamentIndex(int idx)
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TunerWorker::SetNote(int note)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
note_to_update = note;
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TunerWorker::SetOctave(int octave)
|
||||||
|
{
|
||||||
|
mutex.lock();
|
||||||
|
octave_to_update = octave;
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void TunerWorker::Entry()
|
void TunerWorker::Entry()
|
||||||
{
|
{
|
||||||
cerr << __func__ << endl;
|
cerr << __func__ << endl;
|
||||||
|
@ -132,6 +150,8 @@ void TunerWorker::Entry()
|
||||||
PitchDetection *pitchDetection = new PitchDetection();
|
PitchDetection *pitchDetection = new PitchDetection();
|
||||||
emit temperamentListUpdated(pitchDetection->GetTemperamentList());
|
emit temperamentListUpdated(pitchDetection->GetTemperamentList());
|
||||||
|
|
||||||
|
FreqPlayer<int16_t> *player = new FreqPlayer<int16_t>(PitchDetection::rate);
|
||||||
|
|
||||||
// pulseaudio
|
// pulseaudio
|
||||||
pa_simple *p_record = NULL, *p_play = NULL;
|
pa_simple *p_record = NULL, *p_play = NULL;
|
||||||
pa_sample_spec p_spec;
|
pa_sample_spec p_spec;
|
||||||
|
@ -179,6 +199,16 @@ void TunerWorker::Entry()
|
||||||
pitchDetection->SetTemperament(temperament_to_update);
|
pitchDetection->SetTemperament(temperament_to_update);
|
||||||
temperament_to_update = -1;
|
temperament_to_update = -1;
|
||||||
}
|
}
|
||||||
|
if (note_to_update != -1) {
|
||||||
|
result.note = note_to_update;
|
||||||
|
note_to_update = -1;
|
||||||
|
player->SetFreq(pitchDetection->GetNoteFreq(result.note, result.octave));
|
||||||
|
}
|
||||||
|
if (octave_to_update != -1) {
|
||||||
|
result.octave = octave_to_update;
|
||||||
|
octave_to_update = -1;
|
||||||
|
player->SetFreq(pitchDetection->GetNoteFreq(result.note, result.octave));
|
||||||
|
}
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
|
||||||
if (running ) {
|
if (running ) {
|
||||||
|
@ -220,14 +250,13 @@ void TunerWorker::Entry()
|
||||||
if (result.found) cout << Scale::NoteName(result.note) << " " << result.frequency << endl;
|
if (result.found) cout << Scale::NoteName(result.note) << " " << result.frequency << endl;
|
||||||
emit resultUpdated(result);
|
emit resultUpdated(result);
|
||||||
}
|
}
|
||||||
|
} // running
|
||||||
}
|
|
||||||
|
|
||||||
if (playing) {
|
if (playing) {
|
||||||
// play
|
// play
|
||||||
if (!p_play) {
|
if (!p_play) {
|
||||||
// start pulseaudio if stopped
|
// start pulseaudio if stopped
|
||||||
p_record = pa_simple_new(
|
p_play = pa_simple_new(
|
||||||
NULL,
|
NULL,
|
||||||
NAME,
|
NAME,
|
||||||
PA_STREAM_PLAYBACK,
|
PA_STREAM_PLAYBACK,
|
||||||
|
@ -238,8 +267,16 @@ void TunerWorker::Entry()
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// update frequency to update from previous tuner results
|
||||||
|
player->SetFreq(pitchDetection->GetNoteFreq(result.note, result.octave));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
player->WriteAudio(buffer, nbSampleBuffer);
|
||||||
|
if (pa_simple_write(p_play, buffer, nbSampleBuffer << 1, nullptr) < 0) {
|
||||||
|
cerr << "audio write failed" << endl;
|
||||||
|
}
|
||||||
|
} // playing
|
||||||
|
|
||||||
// prevent screen blanking
|
// prevent screen blanking
|
||||||
nb_sample_running += nbSampleBuffer;
|
nb_sample_running += nbSampleBuffer;
|
||||||
|
@ -252,6 +289,7 @@ void TunerWorker::Entry()
|
||||||
if (p_record) pa_simple_free(p_record);
|
if (p_record) pa_simple_free(p_record);
|
||||||
if (p_play) pa_simple_free(p_play);
|
if (p_play) pa_simple_free(p_play);
|
||||||
|
|
||||||
|
delete player;
|
||||||
delete pitchDetection;
|
delete pitchDetection;
|
||||||
delete buffer;
|
delete buffer;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class TunerWorker : public QObject {
|
||||||
|
|
||||||
// to update vars
|
// to update vars
|
||||||
double la_to_update;
|
double la_to_update;
|
||||||
int temperament_to_update;
|
int temperament_to_update, note_to_update, octave_to_update;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// constructor
|
/// constructor
|
||||||
|
@ -62,6 +62,8 @@ class TunerWorker : public QObject {
|
||||||
void SetPlaying(bool p);
|
void SetPlaying(bool p);
|
||||||
void SetTemperamentIndex(int idx);
|
void SetTemperamentIndex(int idx);
|
||||||
void SetLa(double la);
|
void SetLa(double la);
|
||||||
|
void SetNote(int note);
|
||||||
|
void SetOctave(int octave);
|
||||||
void Entry();
|
void Entry();
|
||||||
void Quit();
|
void Quit();
|
||||||
|
|
||||||
|
|
|
@ -20,42 +20,53 @@
|
||||||
|
|
||||||
#include "FreqPlayer.hpp"
|
#include "FreqPlayer.hpp"
|
||||||
|
|
||||||
template typename<sample_t> FreqPlayer<sample_t>::FreqPlayer(int _rate):
|
template<typename sample_t> FreqPlayer<sample_t>::FreqPlayer(int _rate):
|
||||||
rate(_rate),
|
|
||||||
freq(440),
|
freq(440),
|
||||||
volume(0.2),
|
volume(0.2),
|
||||||
|
rate(_rate),
|
||||||
n_frame(0),
|
n_frame(0),
|
||||||
waveform(W_SINUS)
|
waveform(W_SINUS)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template typename<sample_t> void FreqPlayer<sample_t>::Reset()
|
template<typename sample_t> void FreqPlayer<sample_t>::Reset()
|
||||||
{
|
{
|
||||||
n_frame = 0;
|
n_frame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template typename<sample_s> void FreqPlayer<sample_t>::SetFreq(double freq)
|
template<typename sample_t> void FreqPlayer<sample_t>::SetFreq(double freq)
|
||||||
{
|
{
|
||||||
this->freq = freq;
|
this->freq = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
template typename<sample_s> void FreqPlayer<sample_t>::SetVolume(double volume)
|
template<typename sample_t> void FreqPlayer<sample_t>::SetVolume(double volume)
|
||||||
{
|
{
|
||||||
this->volume = volume;
|
this->volume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t FreqPlayer<int16_t>::max() { return INT16_MAX; }
|
template<> int16_t FreqPlayer<int16_t>::max() { return INT16_MAX; }
|
||||||
double FreqPlayer<double>::max() { return 1; }
|
template<> double FreqPlayer<double>::max() { return 1; }
|
||||||
|
|
||||||
template typename<sample_t> double FreqPlayer<sample_t>::radius()
|
template<typename sample_t> double FreqPlayer<sample_t>::radius()
|
||||||
{
|
{
|
||||||
return (double) (n_sample++) * freq / rate * M_PI * 2;
|
return (double) (n_frame++) * freq / rate * M_PI * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template typename<sample_t> sample_t FreqPlayer<sample_t>::AudioFrame()
|
template<typename sample_t> sample_t FreqPlayer<sample_t>::AudioFrame()
|
||||||
{
|
{
|
||||||
// return (n_sample++)
|
switch (waveform) {
|
||||||
|
case W_SINUS:
|
||||||
|
return (double) sin(radius()) * max();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename sample_t> void FreqPlayer<sample_t>::WriteAudio(sample_t *out, int nb_frame)
|
||||||
|
{
|
||||||
|
while (nb_frame--) *out++ = AudioFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
// instanciation for int16
|
// instanciation for int16
|
||||||
template class LinearFilter<int16_t>;
|
template class FreqPlayer<int16_t>;
|
||||||
|
|
|
@ -53,7 +53,9 @@ template<typename sample_t> class FreqPlayer {
|
||||||
/// reset current sound
|
/// reset current sound
|
||||||
void Reset();
|
void Reset();
|
||||||
/// get next audio frame
|
/// get next audio frame
|
||||||
sample_t AudioFrame();
|
inline sample_t AudioFrame();
|
||||||
|
/// write audio buffer
|
||||||
|
void WriteAudio(sample_t *out, int nb_frame);
|
||||||
/// set current frequency
|
/// set current frequency
|
||||||
void SetFreq(double freq);
|
void SetFreq(double freq);
|
||||||
/// set current volume
|
/// set current volume
|
||||||
|
|
|
@ -139,3 +139,14 @@ void Scale::SetLa(double la)
|
||||||
actualLa = la;
|
actualLa = la;
|
||||||
if (freq_setted) updateScale();
|
if (freq_setted) updateScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Scale::GetNoteFreq(int note, int octave)
|
||||||
|
{
|
||||||
|
assert(note >= 0 && note < nbNote);
|
||||||
|
double f = actualNoteFreq[note];
|
||||||
|
octave -= 4;
|
||||||
|
if (octave < 0) f /= 1 << octave;
|
||||||
|
else if (octave > 0) f *= 1 << octave;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
|
@ -56,9 +56,15 @@ class Scale {
|
||||||
/// Set notes frequencies from a temperament
|
/// Set notes frequencies from a temperament
|
||||||
void SetNotesFrequencies(const double freq[nbNote]);
|
void SetNotesFrequencies(const double freq[nbNote]);
|
||||||
|
|
||||||
|
/// Get ref freq for la4
|
||||||
double GetLa();
|
double GetLa();
|
||||||
|
|
||||||
|
/// Set ref freq for la4
|
||||||
void SetLa(double la);
|
void SetLa(double la);
|
||||||
|
|
||||||
|
/// get note frequency
|
||||||
|
double GetNoteFreq(int note, int octave);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find nearest note, octave, and deviation
|
* Find nearest note, octave, and deviation
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue