Player: implementation complete

This commit is contained in:
Louis-Joseph Fournier 2016-01-11 12:37:25 +01:00
parent ec2e8ebd31
commit 0703aabbf1
12 changed files with 121 additions and 21 deletions

View file

@ -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 \

View file

@ -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 \

View file

@ -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)
{ {

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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>;

View file

@ -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

View file

@ -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;
}

View file

@ -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
*/ */