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/Tuner.cpp \
src/TunerWorker.cpp \
src/audio/FreqPlayer.cpp \
src/audio/LinearFilter.cpp \
src/audio/ZeroCross.cpp \
src/scale/Scale.cpp \
@ -23,6 +24,7 @@ HEADERS += \
src/ObjectSaver.hpp \
src/Tuner.hpp \
src/TunerWorker.hpp \
src/audio/FreqPlayer.hpp \
src/audio/LinearFilter.hpp \
src/audio/ZeroCross.hpp \
src/scale/Scale.hpp \

View file

@ -17,6 +17,7 @@ SOURCES += \
src/ObjectSaver.cpp \
src/Tuner.cpp \
src/TunerWorker.cpp \
src/audio/FreqPlayer.cpp \
src/audio/LinearFilter.cpp \
src/audio/ZeroCross.cpp \
src/scale/Scale.cpp \
@ -28,6 +29,7 @@ HEADERS += \
src/Tuner.cpp \
src/Tuner.hpp \
src/TunerWorker.hpp \
src/audio/FreqPlayer.hpp \
src/audio/LinearFilter.hpp \
src/audio/ZeroCross.hpp \
src/scale/Scale.hpp \

View file

@ -198,6 +198,11 @@ QStringList PitchDetection::GetTemperamentList() const
return temperaments->GetNames();
}
double PitchDetection::GetNoteFreq(int note, int octave) const
{
return scale->GetNoteFreq(note, octave);
}
/// for analyse_file console logs
static void display_results(const PitchDetection::PitchResult &res)
{

View file

@ -92,6 +92,8 @@ class PitchDetection {
void SetTemperament(int idx);
/// Get temperament list
QStringList GetTemperamentList() const;
/// Get the note frequency from Scale
double GetNoteFreq(int note, int octave) const;
/// analyse a file for debug
static void analyse_file(const char *filename);

View file

@ -66,6 +66,7 @@ void Tuner::SetPlaying(bool p)
{
if (p == playing) return;
playing = p;
worker->SetPlaying(p);
emit playingChanged();
}
@ -95,6 +96,14 @@ int Tuner::GetNote()
return result.note;
}
void Tuner::SetNote(int note)
{
if (result.note == note) return;
result.note = note;
worker->SetNote(note);
emit resultChanged();
}
double Tuner::GetDeviation()
{
return result.deviation;
@ -105,6 +114,14 @@ int Tuner::GetOctave()
return result.octave;
}
void Tuner::SetOctave(int octave)
{
if (result.octave == octave) return;
result.octave = octave;
worker->SetOctave(octave);
emit resultChanged();
}
bool Tuner::GetFound()
{
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(double freq READ GetFreq NOTIFY resultChanged)
Q_PROPERTY(double deviation READ GetDeviation NOTIFY resultChanged)
Q_PROPERTY(int note READ GetNote NOTIFY resultChanged)
Q_PROPERTY(int octave READ GetOctave NOTIFY resultChanged)
Q_PROPERTY(int note READ GetNote WRITE SetNote NOTIFY resultChanged)
Q_PROPERTY(int octave READ GetOctave WRITE SetOctave 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 NOTIFY temperamentListChanged)
@ -56,7 +56,9 @@ class Tuner : public QObject {
void SetRunning(bool r);
double GetFreq();
int GetNote();
void SetNote(int note);
int GetOctave();
void SetOctave(int octave);
double GetDeviation();
bool GetFound();
unsigned int GetTemperamentIndex();

View file

@ -26,6 +26,7 @@ extern "C" {
#include <pulse/simple.h>
}
#include "audio/FreqPlayer.hpp"
#include "TunerWorker.hpp"
#define name_(x) #x
@ -57,7 +58,9 @@ TunerWorker::TunerWorker() :
running(false),
quit(false),
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");
}
@ -115,6 +118,21 @@ void TunerWorker::SetTemperamentIndex(int idx)
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()
{
cerr << __func__ << endl;
@ -132,6 +150,8 @@ void TunerWorker::Entry()
PitchDetection *pitchDetection = new PitchDetection();
emit temperamentListUpdated(pitchDetection->GetTemperamentList());
FreqPlayer<int16_t> *player = new FreqPlayer<int16_t>(PitchDetection::rate);
// pulseaudio
pa_simple *p_record = NULL, *p_play = NULL;
pa_sample_spec p_spec;
@ -179,6 +199,16 @@ void TunerWorker::Entry()
pitchDetection->SetTemperament(temperament_to_update);
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();
if (running ) {
@ -220,14 +250,13 @@ void TunerWorker::Entry()
if (result.found) cout << Scale::NoteName(result.note) << " " << result.frequency << endl;
emit resultUpdated(result);
}
}
} // running
if (playing) {
// play
if (!p_play) {
// start pulseaudio if stopped
p_record = pa_simple_new(
p_play = pa_simple_new(
NULL,
NAME,
PA_STREAM_PLAYBACK,
@ -238,8 +267,16 @@ void TunerWorker::Entry()
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
nb_sample_running += nbSampleBuffer;
@ -252,6 +289,7 @@ void TunerWorker::Entry()
if (p_record) pa_simple_free(p_record);
if (p_play) pa_simple_free(p_play);
delete player;
delete pitchDetection;
delete buffer;

View file

@ -49,7 +49,7 @@ class TunerWorker : public QObject {
// to update vars
double la_to_update;
int temperament_to_update;
int temperament_to_update, note_to_update, octave_to_update;
public:
/// constructor
@ -62,6 +62,8 @@ class TunerWorker : public QObject {
void SetPlaying(bool p);
void SetTemperamentIndex(int idx);
void SetLa(double la);
void SetNote(int note);
void SetOctave(int octave);
void Entry();
void Quit();

View file

@ -20,42 +20,53 @@
#include "FreqPlayer.hpp"
template typename<sample_t> FreqPlayer<sample_t>::FreqPlayer(int _rate):
rate(_rate),
template<typename sample_t> FreqPlayer<sample_t>::FreqPlayer(int _rate):
freq(440),
volume(0.2),
rate(_rate),
n_frame(0),
waveform(W_SINUS)
{
}
template typename<sample_t> void FreqPlayer<sample_t>::Reset()
template<typename sample_t> void FreqPlayer<sample_t>::Reset()
{
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;
}
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;
}
int16_t FreqPlayer<int16_t>::max() { return INT16_MAX; }
double FreqPlayer<double>::max() { return 1; }
template<> int16_t FreqPlayer<int16_t>::max() { return INT16_MAX; }
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
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
void Reset();
/// 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
void SetFreq(double freq);
/// set current volume

View file

@ -139,3 +139,14 @@ void Scale::SetLa(double la)
actualLa = la;
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
void SetNotesFrequencies(const double freq[nbNote]);
/// Get ref freq for la4
double GetLa();
/// Set ref freq for la4
void SetLa(double la);
/// get note frequency
double GetNoteFreq(int note, int octave);
/**
* Find nearest note, octave, and deviation
*/