spek

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

commit f81ce84826b48f48c655bcf70343d99eb88bac74
parent 4df42e8258e98431392d4feeb06cdb67457aa221
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date:   Wed, 15 Aug 2012 00:56:20 -0700

Run the pipeline

Diffstat:
Msrc/spek-pipeline.c | 12++++++++++--
Msrc/spek-pipeline.h | 8++++----
Msrc/spek-spectrogram.cc | 57++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/spek-spectrogram.hh | 9+++++++--
Msrc/spek-spectrogram.vala | 36------------------------------------
5 files changed, 77 insertions(+), 45 deletions(-)

diff --git a/src/spek-pipeline.c b/src/spek-pipeline.c @@ -47,6 +47,7 @@ struct spek_pipeline int samples; int threshold; spek_pipeline_cb cb; + void *cb_data; struct spek_fft_plan *fft; float *coss; // Pre-computed cos table. @@ -79,7 +80,7 @@ static void reader_sync(struct spek_pipeline *p, int pos); static float average_input(const struct spek_pipeline *p, void *buffer); struct spek_pipeline * spek_pipeline_open( - const char *path, int bands, int samples, int threshold, spek_pipeline_cb cb) + const char *path, int bands, int samples, int threshold, spek_pipeline_cb cb, void *cb_data) { struct spek_pipeline *p = malloc(sizeof(struct spek_pipeline)); p->cx = spek_audio_open(path); @@ -88,6 +89,7 @@ struct spek_pipeline * spek_pipeline_open( p->samples = samples; p->threshold = threshold; p->cb = cb; + p->cb_data = cb_data; p->coss = NULL; p->fft = NULL; @@ -115,6 +117,11 @@ struct spek_pipeline * spek_pipeline_open( } } +const struct spek_audio_properties * spek_pipeline_properties(struct spek_pipeline *pipeline) +{ + return pipeline->properties; +} + void spek_pipeline_start(struct spek_pipeline *p) { if (!p->properties->error) return; @@ -176,6 +183,7 @@ void spek_pipeline_close(struct spek_pipeline *p) { spek_audio_close(p->cx); p->cx = NULL; } + free(p); } static void * reader_func (void *pp) { @@ -310,7 +318,7 @@ static void * worker_func (void *pp) { } if (sample == p->samples) break; - p->cb(sample++, p->output); + p->cb(sample++, p->output, p->cb_data); memset(p->output, 0, sizeof(float) * p->bands); frames = 0; diff --git a/src/spek-pipeline.h b/src/spek-pipeline.h @@ -26,15 +26,15 @@ extern "C" { struct spek_pipeline; struct spek_audio_properties; -typedef void (*spek_pipeline_cb)(int sample, float *values); +typedef void (*spek_pipeline_cb)(int sample, float *values, void *cb_data); struct spek_pipeline * spek_pipeline_open( - const char *path, int bands, int samples, int threshold, spek_pipeline_cb cb); - -void spek_pipeline_start(struct spek_pipeline *pipeline); + const char *path, int bands, int samples, int threshold, spek_pipeline_cb cb, void *cb_data); const struct spek_audio_properties * spek_pipeline_properties(struct spek_pipeline *pipeline); +void spek_pipeline_start(struct spek_pipeline *pipeline); + void spek_pipeline_close(struct spek_pipeline *pipeline); #ifdef __cplusplus diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc @@ -16,8 +16,12 @@ * along with Spek. If not, see <http://www.gnu.org/licenses/>. */ +#include <cmath> #include <wx/dcbuffer.h> +#include "spek-audio-desc.hh" +#include "spek-pipeline.h" + #include "spek-spectrogram.hh" BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel) @@ -39,7 +43,9 @@ enum SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE), - palette(RULER, BANDS) + pipeline(NULL), + palette(RULER, BANDS), + image() { SetBackgroundStyle(wxBG_STYLE_CUSTOM); @@ -122,8 +128,57 @@ void SpekSpectrogram::render(wxDC& dc) dc.DrawBitmap(bmp, w - RPAD + GAP, TPAD); } +void SpekSpectrogram::pipeline_cb(int sample, float *values, void *cb_data) +{ + static double log10_threshold = log10(-THRESHOLD); + 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 = get_color(level); + s->image.SetRGB( + sample, + y, + color >> 16, + (color >> 8) & 0xFF, + color & 0xFF + ); + } + + s->Refresh(false); // TODO: refresh only one pixel column +} + + void SpekSpectrogram::start() { + if(this->pipeline) { + spek_pipeline_close(this->pipeline); + this->pipeline = NULL; + } + + // 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 + // different values but we need some consistency. + wxSize size = GetClientSize(); + int samples = size.GetWidth() - LPAD - RPAD; + if (samples > 0) { + this->image.Create(samples, BANDS); + this->pipeline = spek_pipeline_open( + this->path.utf8_str(), + BANDS, + samples, + THRESHOLD, + pipeline_cb, + this + ); + spek_pipeline_start(this->pipeline); + this->desc = spek_audio_desc(spek_pipeline_properties(this->pipeline)); + } else { + this->image.Create(1, 1); + } + + Refresh(false); } // Modified version of Dan Bruton's algorithm: diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh @@ -21,6 +21,8 @@ #include <wx/wx.h> +struct spek_pipeline; + class SpekSpectrogram : public wxPanel { public: @@ -33,11 +35,14 @@ private: void render(wxDC& dc); void start(); - uint32_t get_color(double level); + static void pipeline_cb(int sample, float *values, void *cb_data); + static uint32_t get_color(double level); + spek_pipeline *pipeline; wxString path; - wxString info; + wxString desc; wxImage palette; + wxImage image; DECLARE_EVENT_TABLE() }; diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala @@ -24,8 +24,6 @@ using Pango; namespace Spek { class Spectrogram : DrawingArea { - private Pipeline pipeline; - private ImageSurface image; public Spectrogram () { @@ -38,30 +36,6 @@ namespace Spek { surface.write_to_png (file_name); } - private void start () { - if (pipeline != null) { - pipeline.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 - // different values but we need some consistency. - Allocation allocation; - get_allocation (out allocation); - int samples = allocation.width - LPAD - RPAD; - if (samples > 0) { - image = new ImageSurface (Format.RGB24, samples, BANDS); - pipeline = new Pipeline (file_name, BANDS, samples, THRESHOLD, data_cb); - pipeline.start (); - info = pipeline.description; - } else { - image = null; - pipeline = null; - } - - queue_draw (); - } - private int prev_width = -1; protected override void size_allocate (Gdk.Rectangle allocation) { base.size_allocate (allocation); @@ -74,16 +48,6 @@ namespace Spek { } } - private double log10_threshold = Math.log10 (-THRESHOLD); - private void data_cb (int sample, float[] values) { - for (int y = 0; y < BANDS; y++) { - var level = double.min ( - 1.0, Math.log10 (1.0 - THRESHOLD + values[y]) / log10_threshold); - put_pixel (image, sample, y, get_color (level)); - } - Idle.add (() => { queue_draw (); return false; }); - } - protected override bool expose_event (EventExpose event) { var window = get_window (); var cr = cairo_create (window);