spek

Acoustic spectrum analyser
git clone http://git.hanabi.in/repos/spek.git
Log | Files | Refs | README

commit 70ecaae62eb908f0784cce406138fcc6787f718e
parent df59b4d1e2a45a1b6351889fb713a411d494729f
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date:   Sun,  3 Apr 2016 12:47:01 -0700

Change the window function

And add Blackman-Harris in addition to Hann and Hamming.

References #94.

Diffstat:
MMANUAL.md | 3+++
Msrc/spek-pipeline.cc | 22+++++++++++++++++-----
Msrc/spek-pipeline.h | 9+++++++++
Msrc/spek-spectrogram.cc | 8+++++++-
Msrc/spek-spectrogram.h | 2++
5 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/MANUAL.md b/MANUAL.md @@ -53,6 +53,9 @@ On OS X use the Command key instead of Ctrl. `Ctrl-Shift-up`, `Ctrl-Shift-down` : Change the upper limit of the dynamic range in dBFS. +`f`, `F` +: Change the DFT window function. + `s`, `S` : Change the DFT window size. diff --git a/src/spek-pipeline.cc b/src/spek-pipeline.cc @@ -25,6 +25,7 @@ struct spek_pipeline { std::unique_ptr<AudioFile> file; std::unique_ptr<FFTPlan> fft; + enum window_function window_function; int samples; spek_pipeline_cb cb; void *cb_data; @@ -60,6 +61,7 @@ static void reader_sync(struct spek_pipeline *p, int pos); struct spek_pipeline * spek_pipeline_open( std::unique_ptr<AudioFile> file, std::unique_ptr<FFTPlan> fft, + enum window_function window_function, int samples, spek_pipeline_cb cb, void *cb_data @@ -68,6 +70,7 @@ struct spek_pipeline * spek_pipeline_open( spek_pipeline *p = new spek_pipeline(); p->file = std::move(file); p->fft = std::move(fft); + p->window_function = window_function; p->samples = samples; p->cb = cb; p->cb_data = cb_data; @@ -319,6 +322,19 @@ static void reader_sync(struct spek_pipeline *p, int pos) pthread_mutex_unlock(&p->worker_mutex); } +static float get_window(enum window_function f, int i, float *coss, int n) { + switch (f) { + case WINDOW_HANN: + return 0.5f * (1.0f - coss[i]); + case WINDOW_HAMMING: + return 0.53836f - 0.46164f * coss[i]; + case WINDOW_BLACKMAN_HARRIS: + return 0.35875f - 0.48829f * coss[i] + 0.14128f * coss[2*i % n] - 0.01168f * coss[3*i % n]; + default: + assert(false); + } +} + static void * worker_func(void *pp) { struct spek_pipeline *p = (spek_pipeline*)pp; @@ -370,11 +386,7 @@ static void * worker_func(void *pp) prev_head = head; for (int i = 0; i < p->nfft; i++) { float val = p->input[(p->input_size + head - p->nfft + i) % p->input_size]; - // TODO: allow the user to chose the window function - // Hamming window. - // val *= 0.53836f - 0.46164f * coss[i]; - // Hann window. - val *= 0.5f * (1.0f - p->coss[i]); + val *= get_window(p->window_function, i, p->coss, p->nfft); p->fft->set_input(i, val); } p->fft->execute(); diff --git a/src/spek-pipeline.h b/src/spek-pipeline.h @@ -7,11 +7,20 @@ class AudioFile; class FFTPlan; struct spek_pipeline; +enum window_function { + WINDOW_HANN, + WINDOW_HAMMING, + WINDOW_BLACKMAN_HARRIS, + WINDOW_COUNT, + WINDOW_DEFAULT = WINDOW_HANN, +}; + typedef void (*spek_pipeline_cb)(int bands, int sample, float *values, void *cb_data); struct spek_pipeline * spek_pipeline_open( std::unique_ptr<AudioFile> file, std::unique_ptr<FFTPlan> fft, + enum window_function window_function, int samples, spek_pipeline_cb cb, void *cb_data diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc @@ -5,7 +5,6 @@ #include "spek-audio.h" #include "spek-events.h" #include "spek-fft.h" -#include "spek-pipeline.h" #include "spek-platform.h" #include "spek-ruler.h" #include "spek-utils.h" @@ -48,6 +47,7 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : audio(new Audio()), // TODO: refactor fft(new FFT()), pipeline(NULL), + window_function(WINDOW_DEFAULT), duration(0.0), sample_rate(0), palette(PALETTE_DEFAULT), @@ -102,6 +102,11 @@ void SpekSpectrogram::on_char(wxKeyEvent& evt) this->urange = spek_min(this->urange + 1, MAX_RANGE); } else if (CS && D) { this->urange = spek_max(this->urange - 1, this->lrange + 1); + } else if (S && evt.GetKeyCode() == 'F') { + this->window_function = (enum window_function) ((this->window_function + 1) % WINDOW_COUNT); + } else if (N && evt.GetKeyCode() == 'f') { + this->window_function = + (enum window_function) ((this->window_function - 1 + WINDOW_COUNT) % WINDOW_COUNT); } else if (S && evt.GetKeyCode() == 'S') { this->fft_bits = spek_min(this->fft_bits + 1, MAX_FFT_BITS); this->create_palette(); @@ -358,6 +363,7 @@ void SpekSpectrogram::start() this->pipeline = spek_pipeline_open( this->audio->open(std::string(this->path.utf8_str())), this->fft->create(this->fft_bits), + this->window_function, samples, pipeline_cb, this diff --git a/src/spek-spectrogram.h b/src/spek-spectrogram.h @@ -5,6 +5,7 @@ #include <wx/wx.h> #include "spek-palette.h" +#include "spek-pipeline.h" class Audio; class FFT; @@ -34,6 +35,7 @@ private: std::unique_ptr<Audio> audio; std::unique_ptr<FFT> fft; spek_pipeline *pipeline; + enum window_function window_function; wxString path; wxString desc; double duration;