spek

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

commit 0b121ec1c5ce99535d35a6a54c9252bd9f552a7d
parent 4e71509218bbaad75a9106505129e1976d251b82
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date:   Sun, 19 Aug 2012 12:05:57 -0700

Proper notification using custom events

Diffstat:
Msrc/Makefile.am | 2++
Asrc/spek-events.cc | 45+++++++++++++++++++++++++++++++++++++++++++++
Asrc/spek-events.hh | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/spek-spectrogram.cc | 68++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/spek-spectrogram.hh | 5++++-
5 files changed, 148 insertions(+), 25 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am @@ -5,6 +5,8 @@ spek_SOURCES = \ spek-audio-desc.hh \ spek-audio.c \ spek-audio.h \ + spek-events.cc \ + spek-events.hh \ spek-fft.c \ spek-fft.h \ spek-palette.c \ diff --git a/src/spek-events.cc b/src/spek-events.cc @@ -0,0 +1,45 @@ +/* spek-events.cc + * + * Copyright (C) 2012 Alexander Kojevnikov <alexander@kojevnikov.com> + * + * Spek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Spek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Spek. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "spek-events.hh" + +//IMPLEMENT_DYNAMIC_CLASS(SpekHaveSampleEvent, wxEvent) +DEFINE_EVENT_TYPE(SPEK_HAVE_SAMPLE) + +SpekHaveSampleEvent::SpekHaveSampleEvent(int bands, int sample, float *values, bool free_values) + : wxEvent(), bands(bands), sample(sample), values(values), free_values(free_values) +{ + SetEventType(SPEK_HAVE_SAMPLE); +} + +SpekHaveSampleEvent::SpekHaveSampleEvent(const SpekHaveSampleEvent& other) +{ + SetEventType(SPEK_HAVE_SAMPLE); + this->bands = other.bands; + this->sample = other.sample; + this->values = (float *)malloc(this->bands * sizeof(float)); + memcpy(this->values, other.values, this->bands * sizeof(float)); + this->free_values = true; +} + +SpekHaveSampleEvent::~SpekHaveSampleEvent() +{ + if (this->free_values) { + free(this->values); + } +} diff --git a/src/spek-events.hh b/src/spek-events.hh @@ -0,0 +1,53 @@ +/* spek-events.hh + * + * Copyright (C) 2012 Alexander Kojevnikov <alexander@kojevnikov.com> + * + * Spek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Spek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Spek. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SPEK_EVENTS_HH_ +#define SPEK_EVENTS_HH_ + +#include <wx/wx.h> + +class SpekHaveSampleEvent: public wxEvent +{ +public: + SpekHaveSampleEvent(int bands, int sample, float *values, bool free_values); + SpekHaveSampleEvent(const SpekHaveSampleEvent& other); + ~SpekHaveSampleEvent(); + + int get_bands() const { return this->bands; } + int get_sample() const { return this->sample; } + const float *get_values() const { return this->values; } + + wxEvent *Clone() const { return new SpekHaveSampleEvent(*this); } +// DECLARE_DYNAMIC_CLASS(SpekHaveSampleEvent); + +private: + int bands; + int sample; + float *values; + bool free_values; +}; + +typedef void (wxEvtHandler::*SpekHaveSampleEventFunction)(SpekHaveSampleEvent&); + +DECLARE_EVENT_TYPE(SPEK_HAVE_SAMPLE, wxID_ANY) + +#define SPEK_EVT_HAVE_SAMPLE(fn) \ + DECLARE_EVENT_TABLE_ENTRY(SPEK_HAVE_SAMPLE, -1, -1, \ + (wxObjectEventFunction) (SpekHaveSampleEventFunction) &fn, (wxObject *) NULL ), + +#endif diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc @@ -21,6 +21,7 @@ #include "spek-audio.h" #include "spek-audio-desc.hh" +#include "spek-events.hh" #include "spek-palette.h" #include "spek-pipeline.h" #include "spek-platform.hh" @@ -32,6 +33,7 @@ BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel) EVT_IDLE(SpekSpectrogram::on_idle) EVT_PAINT(SpekSpectrogram::on_paint) EVT_SIZE(SpekSpectrogram::on_size) + SPEK_EVT_HAVE_SAMPLE(SpekSpectrogram::on_have_sample) END_EVENT_TABLE() enum @@ -72,6 +74,11 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : } } +SpekSpectrogram::~SpekSpectrogram() +{ + this->stop(); +} + void SpekSpectrogram::open(const wxString& path) { this->path = path; @@ -109,6 +116,30 @@ void SpekSpectrogram::on_size(wxSizeEvent& evt) } } +void SpekSpectrogram::on_have_sample(SpekHaveSampleEvent& event) +{ + static double log10_threshold = log10(-THRESHOLD); + int bands = event.get_bands(); + int sample = event.get_sample(); + const float *values = event.get_values(); + + for (int y = 0; y < bands; y++) { + double level = log10(1.0 - THRESHOLD + values[y]) / log10_threshold; + if (level > 1.0) level = 1.0; + uint32_t color = spek_palette_spectrum(level); + this->image.SetRGB( + sample, + bands - y - 1, + color >> 16, + (color >> 8) & 0xFF, + color & 0xFF + ); + } + + // TODO: refresh only one pixel column + this->Refresh(); +} + static wxString time_formatter(int unit) { // TODO: i18n @@ -261,36 +292,16 @@ void SpekSpectrogram::render(wxDC& dc) density_ruler.draw(dc); } -void SpekSpectrogram::pipeline_cb(int sample, float *values, void *cb_data) +static void pipeline_cb(int sample, float *values, void *cb_data) { - static double log10_threshold = log10(-THRESHOLD); + SpekHaveSampleEvent event(BANDS, sample, values, false); SpekSpectrogram *s = (SpekSpectrogram *)cb_data; - - for (int y = 0; y < BANDS; y++) { - double level = log10(1.0 - THRESHOLD + values[y]) / log10_threshold; - if (level > 1.0) level = 1.0; - uint32_t color = spek_palette_spectrum(level); - s->image.SetRGB( - sample, - BANDS - y - 1, - color >> 16, - (color >> 8) & 0xFF, - color & 0xFF - ); - } - - s->Refresh(); // TODO: refresh only one pixel column - wxWakeUpIdle(); + wxPostEvent(s, event); } - void SpekSpectrogram::start() { - if (this->pipeline) { - spek_pipeline_close(this->pipeline); - this->pipeline = NULL; - this->properties = NULL; - } + this->stop(); // The number of samples is the number of pixels available for the image. // The number of bands is fixed, FFT results are very different for @@ -317,6 +328,15 @@ void SpekSpectrogram::start() Refresh(); } +void SpekSpectrogram::stop() +{ + if (this->pipeline) { + spek_pipeline_close(this->pipeline); + this->pipeline = NULL; + this->properties = NULL; + } +} + // Trim `s` so that it fits into `length`. static wxString trim(wxDC& dc, const wxString& s, int length, bool trim_end) { diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh @@ -21,6 +21,7 @@ #include <wx/wx.h> +class SpekHaveSampleEvent; struct spek_audio_properties; struct spek_pipeline; @@ -28,6 +29,7 @@ class SpekSpectrogram : public wxPanel { public: SpekSpectrogram(wxFrame *parent); + ~SpekSpectrogram(); void open(const wxString& path); void save(const wxString& path); @@ -35,10 +37,11 @@ private: void on_idle(wxIdleEvent& evt); void on_paint(wxPaintEvent& evt); void on_size(wxSizeEvent& evt); + void on_have_sample(SpekHaveSampleEvent& evt); void render(wxDC& dc); void start(); - static void pipeline_cb(int sample, float *values, void *cb_data); + void stop(); spek_pipeline *pipeline; const spek_audio_properties *properties;