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/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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue