Proper notification using custom events

This commit is contained in:
Alexander Kojevnikov 2012-08-19 12:05:57 -07:00
parent 4e71509218
commit 0b121ec1c5
5 changed files with 148 additions and 25 deletions

View File

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

45
src/spek-events.cc Normal file
View File

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

53
src/spek-events.hh Normal file
View File

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

View File

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

View File

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