commit 3ecdad345927a15e2c39cddab1bd843287cd0802
parent 063d0433c0dd2e92cd9e1f84b3006a29a105fe1e
Author: Alexander Kojevnikov <alexander@kojevnikov.com>
Date: Mon, 13 Aug 2012 21:38:48 -0700
Paint the palette
Diffstat:
8 files changed, 239 insertions(+), 144 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
@@ -10,6 +10,8 @@ spek_SOURCES = \
spek-platform.hh \
spek-preferences.cc \
spek-preferences.hh \
+ spek-spectrogram.cc \
+ spek-spectrogram.hh \
spek-window.cc \
spek-window.hh
diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc
@@ -0,0 +1,170 @@
+/* spek-spectrogram.cc
+ *
+ * Copyright (C) 2010-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 <wx/dcbuffer.h>
+
+#include "spek-spectrogram.hh"
+
+BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel)
+ EVT_PAINT(SpekSpectrogram::OnPaint)
+END_EVENT_TABLE()
+
+enum
+{
+ THRESHOLD = -92,
+ NFFT = 2048,
+ BANDS = NFFT / 2 + 1,
+ LPAD = 60,
+ TPAD = 60,
+ RPAD = 80,
+ BPAD = 40,
+ GAP = 10,
+ RULER = 10,
+};
+
+SpekSpectrogram::SpekSpectrogram(wxFrame *parent) :
+ wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE),
+ palette(RULER, BANDS)
+{
+ SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+
+ // Pre-draw the palette.
+ for (int y = 0; y < BANDS; y++) {
+ uint32_t color = GetColor(y / (double) BANDS);
+ this->palette.SetRGB(
+ wxRect(0, BANDS - y - 1, RULER, 1),
+ color >> 16,
+ (color >> 8) & 0xFF,
+ color & 0xFF
+ );
+ }
+}
+
+void SpekSpectrogram::Open(const wxString& path)
+{
+ this->path = path;
+ Start();
+}
+
+void SpekSpectrogram::Save(const wxString& path)
+{
+}
+
+void SpekSpectrogram::OnPaint(wxPaintEvent& evt)
+{
+ wxAutoBufferedPaintDC dc(this);
+ Render(dc);
+}
+
+void SpekSpectrogram::Render(wxDC& dc)
+{
+ wxSize size = GetClientSize();
+ int w = size.GetWidth();
+ int h = size.GetHeight();
+
+ // Initialise.
+ dc.SetBackground(*wxBLACK_BRUSH);
+ dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetPen(*wxWHITE_PEN);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+ dc.SetTextForeground(wxColour(255, 255, 255));
+ wxFont normal = wxFont(9, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+ wxFont large = wxFont(normal);
+ large.SetPointSize(10);
+ large.SetWeight(wxFONTWEIGHT_BOLD);
+ wxFont small = wxFont(normal);
+ small.SetPointSize(8);
+ dc.SetFont(normal);
+ int normal_height = dc.GetTextExtent(wxT("dummy")).GetHeight();
+ dc.SetFont(large);
+ int large_height = dc.GetTextExtent(wxT("dummy")).GetHeight();
+
+ // Clean the background.
+ dc.Clear();
+
+ // Spek version
+ dc.SetFont(large);
+ wxString package_name(wxT(PACKAGE_NAME));
+ dc.DrawText(
+ package_name,
+ w - RPAD + GAP,
+ TPAD - 2 * GAP - normal_height - large_height
+ );
+ int package_name_width = dc.GetTextExtent(package_name + wxT(" ")).GetWidth();
+ dc.SetFont(normal);
+ dc.DrawText(
+ wxT(PACKAGE_VERSION),
+ w - RPAD + GAP + package_name_width,
+ TPAD - 2 * GAP - 2 * normal_height
+ );
+
+ // Border around the spectrogram.
+ // TODO: check if this uses antialiasing
+ dc.DrawRectangle(LPAD, TPAD, w - LPAD - RPAD, h - TPAD - BPAD);
+
+ // The palette.
+ wxBitmap bmp(this->palette.Scale(RULER, h - TPAD - BPAD + 1 /*TODO:, wxIMAGE_QUALITY_HIGH*/));
+ dc.DrawBitmap(bmp, w - RPAD + GAP, TPAD);
+}
+
+void SpekSpectrogram::Start()
+{
+}
+
+// Modified version of Dan Bruton's algorithm:
+// http://www.physics.sfasu.edu/astro/color/spectra.html
+// TODO: Move out to a C function.
+uint32_t SpekSpectrogram::GetColor(double level)
+{
+ level *= 0.6625;
+ double r = 0.0, g = 0.0, b = 0.0;
+ if (level >= 0 && level < 0.15) {
+ r = (0.15 - level) / (0.15 + 0.075);
+ g = 0.0;
+ b = 1.0;
+ } else if (level >= 0.15 && level < 0.275) {
+ r = 0.0;
+ g = (level - 0.15) / (0.275 - 0.15);
+ b = 1.0;
+ } else if (level >= 0.275 && level < 0.325) {
+ r = 0.0;
+ g = 1.0;
+ b = (0.325 - level) / (0.325 - 0.275);
+ } else if (level >= 0.325 && level < 0.5) {
+ r = (level - 0.325) / (0.5 - 0.325);
+ g = 1.0;
+ b = 0.0;
+ } else if (level >= 0.5 && level < 0.6625) {
+ r = 1.0;
+ g = (0.6625 - level) / (0.6625 - 0.5f);
+ b = 0.0;
+ }
+
+ // Intensity correction.
+ double cf = 1.0;
+ if (level >= 0.0 && level < 0.1) {
+ cf = level / 0.1;
+ }
+ cf *= 255.0;
+
+ // Pack RGB values into a 32-bit uint.
+ uint32_t rr = (uint32_t) (r * cf + 0.5);
+ uint32_t gg = (uint32_t) (g * cf + 0.5);
+ uint32_t bb = (uint32_t) (b * cf + 0.5);
+ return (rr << 16) + (gg << 8) + bb;
+}
diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh
@@ -0,0 +1,45 @@
+/* spek-spectrogram.hh
+ *
+ * Copyright (C) 2010-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_SPECTROGRAM_HH_
+#define SPEK_SPECTROGRAM_HH_
+
+#include <wx/wx.h>
+
+class SpekSpectrogram : public wxPanel
+{
+public:
+ SpekSpectrogram(wxFrame *parent);
+ void Open(const wxString& path);
+ void Save(const wxString& path);
+
+private:
+ void OnPaint(wxPaintEvent& evt);
+ void Render(wxDC& dc);
+
+ void Start();
+ uint32_t GetColor(double level);
+
+ wxString path;
+ wxString info;
+ wxImage palette;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif
diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala
@@ -24,42 +24,11 @@ using Pango;
namespace Spek {
class Spectrogram : DrawingArea {
- public string file_name { get; private set; }
private Pipeline pipeline;
- private string info;
- private const int THRESHOLD = -92;
- private const int NFFT = 2048;
- private const int BANDS = NFFT / 2 + 1;
private ImageSurface image;
- private ImageSurface palette;
-
- private const int LPAD = 60;
- private const int TPAD = 60;
- private const int RPAD = 80;
- private const int BPAD = 40;
- private const int GAP = 10;
- private const int RULER = 10;
- private double FONT_SCALE = Platform.get_font_scale ();
public Spectrogram () {
- // Pre-draw the palette.
- palette = new ImageSurface (Format.RGB24, RULER, BANDS);
- for (int y = 0; y < BANDS; y++) {
- var color = get_color (y / (double) BANDS);
- for (int x = 0; x < RULER; x++) {
- put_pixel (palette, x, y, color);
- }
- }
- show_all ();
- }
-
- public void open (string file_name) {
- this.file_name = file_name;
- this.info = "";
-
- start ();
- }
public void save (string file_name) {
Allocation allocation;
@@ -128,37 +97,8 @@ namespace Spek {
}
private void draw (Cairo.Context cr) {
- Allocation allocation;
- get_allocation (out allocation);
- double w = allocation.width;
- double h = allocation.height;
int text_width, text_height;
- // Clean the background.
- cr.set_source_rgb (0, 0, 0);
- cr.paint ();
-
- // Spek version
- cr.set_source_rgb (1, 1, 1);
- var layout = cairo_create_layout (cr);
- layout.set_font_description (FontDescription.from_string (
- "Sans " + (9 * FONT_SCALE).to_string ()));
- layout.set_width (RPAD * Pango.SCALE);
- layout.set_text ("dummy", -1);
- layout.get_pixel_size (out text_width, out text_height);
- int line_height = text_height;
- layout.set_font_description (FontDescription.from_string (
- "Sans Bold " + (10 * FONT_SCALE).to_string ()));
- layout.set_text (Config.PACKAGE_NAME + " ", -1);
- layout.get_pixel_size (out text_width, out text_height);
- cr.move_to (w - RPAD + GAP, TPAD - 2 * GAP - line_height);
- cairo_show_layout_line (cr, layout.get_line (0));
- layout.set_font_description (FontDescription.from_string (
- "Sans " + (9 * FONT_SCALE).to_string ()));
- layout.set_text (Config.PACKAGE_VERSION, -1);
- cr.rel_move_to (text_width, 0);
- cairo_show_layout_line (cr, layout.get_line (0));
-
if (image != null) {
// Draw the spectrogram.
cr.translate (LPAD, h - BPAD);
@@ -228,20 +168,6 @@ namespace Spek {
cairo_show_layout_line (cr, layout.get_line (0));
}
- // Border around the spectrogram.
- cr.set_source_rgb (1, 1, 1);
- cr.set_line_width (1);
- cr.set_antialias (Antialias.NONE);
- cr.rectangle (LPAD, TPAD, w - LPAD - RPAD, h - TPAD - BPAD);
- cr.stroke ();
-
- // The palette.
- cr.translate (w - RPAD + GAP, h - BPAD);
- cr.scale (1, -(h - TPAD - BPAD + 1) / palette.get_height ());
- cr.set_source_surface (palette, 0, 0);
- cr.paint ();
- cr.identity_matrix ();
-
// Prepare to draw the ruler.
cr.set_source_rgb (1, 1, 1);
cr.set_line_width (1);
@@ -265,55 +191,5 @@ namespace Spek {
density_ruler.draw (cr, layout);
cr.identity_matrix ();
}
-
- private void put_pixel (ImageSurface surface, int x, int y, uint32 color) {
- var i = y * surface.get_stride () + x * 4;
- unowned uchar[] data = surface.get_data ();
-
- // Translate uchar* to uint32* to avoid dealing with endianness.
- uint32 *p = (uint32 *) (&data[i]);
- *p = color;
- }
-
- // Modified version of Dan Bruton's algorithm:
- // http://www.physics.sfasu.edu/astro/color/spectra.html
- private uint32 get_color (double level) {
- level *= 0.6625;
- double r = 0.0, g = 0.0, b = 0.0;
- if (level >= 0 && level < 0.15) {
- r = (0.15 - level) / (0.15 + 0.075);
- g = 0.0;
- b = 1.0;
- } else if (level >= 0.15 && level < 0.275) {
- r = 0.0;
- g = (level - 0.15) / (0.275 - 0.15);
- b = 1.0;
- } else if (level >= 0.275 && level < 0.325) {
- r = 0.0;
- g = 1.0;
- b = (0.325 - level) / (0.325 - 0.275);
- } else if (level >= 0.325 && level < 0.5) {
- r = (level - 0.325) / (0.5 - 0.325);
- g = 1.0;
- b = 0.0;
- } else if (level >= 0.5 && level < 0.6625) {
- r = 1.0;
- g = (0.6625 - level) / (0.6625 - 0.5f);
- b = 0.0;
- }
-
- // Intensity correction.
- double cf = 1.0;
- if (level >= 0.0 && level < 0.1) {
- cf = level / 0.1;
- }
- cf *= 255.0;
-
- // Pack RGB values into Cairo-happy format.
- uint32 rr = (uint32) (r * cf + 0.5);
- uint32 gg = (uint32) (g * cf + 0.5);
- uint32 bb = (uint32) (b * cf + 0.5);
- return (rr << 16) + (gg << 8) + bb;
- }
}
}
diff --git a/src/spek-window.cc b/src/spek-window.cc
@@ -19,6 +19,8 @@
#include <wx/artprov.h>
#include <wx/filename.h>
+#include "spek-spectrogram.hh"
+
#include "spek-window.hh"
BEGIN_EVENT_TABLE(SpekWindow, wxFrame)
@@ -29,7 +31,7 @@ BEGIN_EVENT_TABLE(SpekWindow, wxFrame)
EVT_MENU(wxID_ABOUT, SpekWindow::OnAbout)
END_EVENT_TABLE()
-SpekWindow::SpekWindow() : wxFrame(NULL, -1, wxEmptyString)
+SpekWindow::SpekWindow(const wxString& path) : wxFrame(NULL, -1, wxEmptyString)
{
SetTitle(_("Spek - Acoustic Spectrum Analyser"));
// TODO: test on all platforms
@@ -75,6 +77,12 @@ SpekWindow::SpekWindow() : wxFrame(NULL, -1, wxEmptyString)
wxArtProvider::GetBitmap(wxART_FILE_SAVE)
);
toolbar->Realize();
+
+ this->spectrogram = new SpekSpectrogram(this);
+
+ if (!path.IsEmpty()) {
+ Open(path);
+ }
}
// TODO: s/audio/media/
@@ -176,5 +184,7 @@ void SpekWindow::Open(const wxString& path)
wxString title = wxString::Format(_("Spek - %s"), full_name.c_str());
// TODO: make sure the above works on all platforms, both in x32 and x64.
SetTitle(title);
+
+ this->spectrogram->Open(path);
}
}
diff --git a/src/spek-window.hh b/src/spek-window.hh
@@ -21,10 +21,12 @@
#include <wx/wx.h>
+class SpekSpectrogram;
+
class SpekWindow : public wxFrame
{
public:
- SpekWindow();
+ SpekWindow(const wxString& path);
private:
void OnOpen(wxCommandEvent& event);
@@ -35,6 +37,8 @@ private:
void Open(const wxString& path);
+ SpekSpectrogram *spectrogram;
+
DECLARE_EVENT_TABLE()
};
diff --git a/src/spek-window.vala b/src/spek-window.vala
@@ -50,17 +50,13 @@ namespace Spek {
info_bar.message_type = MessageType.INFO;
info_bar.response.connect(() => info_bar.hide());
- spectrogram = new Spectrogram ();
-
filter_png = new FileFilter ();
filter_png.set_name (_("PNG images"));
filter_png.add_pattern ("*.png");
var vbox = new VBox (false, 0);
vbox.pack_start (info_bar, false, true, 0);
- vbox.pack_start (spectrogram, true, true, 0);
add (vbox);
- spectrogram.show_all ();
vbox.show ();
show ();
@@ -69,10 +65,6 @@ namespace Spek {
drag_dest_set (this, DestDefaults.ALL, DEST_TARGET_ENTRIES, DragAction.COPY);
drag_data_received.connect (on_dropped);
- if (file_name != null) {
- open_file (file_name);
- }
-
try {
Thread.create<void*> (check_version, false);
} catch (ThreadError e) {
@@ -93,10 +85,6 @@ namespace Spek {
drag_finish (cx, false, false, time);
}
- private void open_file (string file_name) {
- spectrogram.open (file_name);
- }
-
private void on_file_save () {
var chooser = new FileChooserDialog (
_("Save Spectrogram"), this, FileChooserAction.SAVE,
@@ -119,10 +107,6 @@ namespace Spek {
chooser.destroy ();
}
- private void on_file_quit () {
- destroy ();
- }
-
private void on_edit_preferences () {
var dlg = new PreferencesDialog ();
dlg.transient_for = this;
diff --git a/src/spek.cc b/src/spek.cc
@@ -26,10 +26,12 @@
class Spek: public wxApp
{
-protected:
+private:
virtual bool OnInit();
virtual void OnInitCmdLine(wxCmdLineParser& parser);
virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
+
+ wxString path;
};
IMPLEMENT_APP(Spek)
@@ -43,7 +45,7 @@ bool Spek::OnInit()
return false;
}
- SpekWindow *window = new SpekWindow();
+ SpekWindow *window = new SpekWindow(this->path);
window->Show(true);
SetTopWindow(window);
return true;
@@ -89,5 +91,7 @@ bool Spek::OnCmdLineParsed(wxCmdLineParser& parser)
return false;
}
+ this->path = parser.GetParam();
+
return true;
}