From d4a5f322f0f9911ab64b13d147d3e2cc3681c9f2 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 15:13:03 -0700 Subject: [PATCH 01/60] Remove all references to Vala --- Makefile.am | 5 +---- configure.ac | 35 +++++++---------------------------- src/Makefile.am | 29 ++--------------------------- src/spek.cc | 6 ++++++ vapi/Makefile.am | 8 -------- vapi/config.vapi | 16 ---------------- vapi/spek-audio.vapi | 29 ----------------------------- vapi/spek-fft.vapi | 16 ---------------- vapi/spek-platform.vapi | 10 ---------- 9 files changed, 16 insertions(+), 138 deletions(-) create mode 100644 src/spek.cc delete mode 100644 vapi/Makefile.am delete mode 100644 vapi/config.vapi delete mode 100644 vapi/spek-audio.vapi delete mode 100644 vapi/spek-fft.vapi delete mode 100644 vapi/spek-platform.vapi diff --git a/Makefile.am b/Makefile.am index fc960b9..9522275 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,11 +1,8 @@ -# Makefile.am - SUBDIRS = \ data \ man \ po \ - src \ - vapi + src EXTRA_DIST = \ intltool-extract.in \ diff --git a/configure.ac b/configure.ac index b3ad561..597583a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,42 +1,22 @@ -# configure.ac - AC_INIT([spek],[0.7]) -AC_CONFIG_SRCDIR([src/spek.vala]) +AC_CONFIG_SRCDIR([src/spek.cc]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign no-dist-gzip dist-xz]) - -# Enable silent rules is available -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) +AM_SILENT_RULES AM_MAINTAINER_MODE -AC_PROG_CC -AC_PROG_CC_STDC -AM_PROG_VALAC([0.12.0]) +AC_PROG_CC_C99 +AC_PROG_CXX AC_PROG_INSTALL IT_PROG_INTLTOOL([0.35]) -pkg_modules="gtk+-2.0 >= 2.18.0 libavformat >= 52.111 libavcodec >= 52.123 libavutil" +pkg_modules="libavformat >= 52.111 libavcodec >= 52.123 libavutil" PKG_CHECK_MODULES(SPEK, [$pkg_modules]) AC_SUBST(SPEK_CFLAGS) AC_SUBST(SPEK_LIBS) -SPEK_PACKAGES="--pkg gtk+-2.0 --pkg gio-2.0" -AC_SUBST(SPEK_PACKAGES) - AC_CHECK_LIB(m, log10) -AC_CHECK_LIB(gthread-2.0, g_thread_init) - -# Check for GDK Quartz and MacOSX integration package -_gdk_tgt=`$PKG_CONFIG --variable=target gdk-2.0` -AM_CONDITIONAL([GDK_TARGET_QUARTZ], [test x$_gdk_tgt = xquartz]) -if test "x$_gdk_tgt" = xquartz; then - PKG_CHECK_MODULES(IGE_MAC, ige-mac-integration) - IGE_MAC_LIBS="$IGE_MAC_LIBS -framework CoreFoundation -framework ApplicationServices" - AC_SUBST(IGE_MAC_LIBS) - AC_SUBST(IGE_MAC_CFLAGS) - AC_DEFINE(G_OS_DARWIN, 1, [Platform detection macro missing in GLib]) -fi GETTEXT_PACKAGE=spek AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) @@ -61,7 +41,6 @@ AC_CONFIG_FILES([ man/spek.1 po/Makefile.in src/Makefile - vapi/Makefile web/version ]) -AC_OUTPUT \ No newline at end of file +AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 2734118..863d63b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,39 +1,14 @@ bin_PROGRAMS = spek spek_SOURCES = \ - spek.vala \ - spek-audio.c \ - spek-fft.c \ - spek-pipeline.vala \ - spek-platform.c \ - spek-preferences.vala \ - spek-preferences-dialog.vala \ - spek-ruler.vala \ - spek-spectrogram.vala \ - spek-window.vala + spek.cc AM_CPPFLAGS = \ -include config.h \ $(SPEK_CFLAGS) \ - $(IGE_MAC_CFLAGS) \ -DLOCALEDIR=\""$(localedir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ -DPKGLIBDIR=\""$(pkglibdir)"\" -VALAFLAGS = \ - --thread \ - --vapidir=$(srcdir)/../vapi \ - --pkg config \ - --pkg spek-audio \ - --pkg spek-fft \ - --pkg spek-platform \ - @SPEK_PACKAGES@ - spek_LDADD = \ - $(SPEK_LIBS) \ - $(IGE_MAC_LIBS) - -EXTRA_DIST = \ - spek-audio.h \ - spek-fft.h \ - spek-platform.h + $(SPEK_LIBS) diff --git a/src/spek.cc b/src/spek.cc new file mode 100644 index 0000000..445037a --- /dev/null +++ b/src/spek.cc @@ -0,0 +1,6 @@ +#include + +int main() +{ + printf("Hello, world!\n"); +} diff --git a/vapi/Makefile.am b/vapi/Makefile.am deleted file mode 100644 index f1bef74..0000000 --- a/vapi/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -noinst_DATA = \ - config.vapi \ - spek-audio.vapi \ - spek-fft.vapi \ - spek-platform.vapi - -EXTRA_DIST = \ - $(noinst_DATA) diff --git a/vapi/config.vapi b/vapi/config.vapi deleted file mode 100644 index 68a993a..0000000 --- a/vapi/config.vapi +++ /dev/null @@ -1,16 +0,0 @@ -[CCode (prefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] -namespace Config { - /* Package information */ - public const string PACKAGE_NAME; - public const string PACKAGE_STRING; - public const string PACKAGE_VERSION; - - /* Gettext package */ - public const string GETTEXT_PACKAGE; - - /* Configured paths - these variables are not present in config.h, they are - * passed to underlying C code as cmd line macros. */ - public const string LOCALEDIR; /* /usr/local/share/locale */ - public const string PKGDATADIR; /* /usr/local/share/spek */ - public const string PKGLIBDIR; /* /usr/local/lib/spek */ -} diff --git a/vapi/spek-audio.vapi b/vapi/spek-audio.vapi deleted file mode 100644 index b9cad14..0000000 --- a/vapi/spek-audio.vapi +++ /dev/null @@ -1,29 +0,0 @@ -[CCode (cprefix = "SpekAudio", lower_case_cprefix = "spek_audio_", cheader_filename = "spek-audio.h")] -namespace Spek.Audio { - [Compact] - [CCode (free_function = "spek_audio_close")] - public class Context { - public string file_name; - public string codec_name; - public string error; - public int bit_rate; - public int sample_rate; - public int bits_per_sample; - public int width; - public bool fp; - public int channels; - public double duration; - public uint8 *buffer; - public int64 frames_per_interval; - public int64 error_per_interval; - public int64 error_base; - - [CCode (cname = "spek_audio_open")] - public Context (string file_name); - [CCode (cname = "spek_audio_start")] - public int start (int samples); - [CCode (cname = "spek_audio_read")] - public int read (); - } - public static void init (); -} diff --git a/vapi/spek-fft.vapi b/vapi/spek-fft.vapi deleted file mode 100644 index 0f1a7e4..0000000 --- a/vapi/spek-fft.vapi +++ /dev/null @@ -1,16 +0,0 @@ -[CCode (cprefix = "SpekFft", lower_case_cprefix = "spek_fft_", cheader_filename = "spek-fft.h")] -namespace Spek.Fft { - [Compact] - [CCode (free_function = "spek_fft_destroy")] - public class Plan { - [CCode (array_length = false)] - public unowned float[] input; - [CCode (array_length = false)] - public unowned float[] output; - - [CCode (cname = "spek_fft_plan_new")] - public Plan (int n, int threshold); - [CCode (cname = "spek_fft_execute")] - public void execute (); - } -} diff --git a/vapi/spek-platform.vapi b/vapi/spek-platform.vapi deleted file mode 100644 index bbacef2..0000000 --- a/vapi/spek-platform.vapi +++ /dev/null @@ -1,10 +0,0 @@ -[CCode (cprefix = "SpekPlatform", lower_case_cprefix = "spek_platform_", cheader_filename = "spek-platform.h")] -namespace Spek.Platform { - public static void init (); - public static void fix_args (string[] args); - public static void fix_ui (Gtk.UIManager ui); - public static unowned string locale_dir (); - public static void show_uri (string uri); - public static string read_line (string uri); - public static double get_font_scale (); -} From 71bff01768f1471a3a1e5d0e95f6ea89d278af69 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 16:28:32 -0700 Subject: [PATCH 02/60] Hello, wxWidgets! --- configure.ac | 22 +++++++++++++++- src/Makefile.am | 9 ++++++- src/spek.cc | 68 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 597583a..3227b89 100644 --- a/configure.ac +++ b/configure.ac @@ -11,12 +11,32 @@ AC_PROG_CXX AC_PROG_INSTALL IT_PROG_INTLTOOL([0.35]) +AC_CHECK_LIB(m, log10) + pkg_modules="libavformat >= 52.111 libavcodec >= 52.123 libavutil" PKG_CHECK_MODULES(SPEK, [$pkg_modules]) AC_SUBST(SPEK_CFLAGS) AC_SUBST(SPEK_LIBS) -AC_CHECK_LIB(m, log10) +AM_OPTIONS_WXCONFIG +reqwx=2.8.0 +AM_PATH_WXCONFIG($reqwx, wxWin=1) +if test "$wxWin" != 1; then + AC_MSG_ERROR([ + wxWidgets must be installed on your system. + + Please check that wx-config is in path, the directory + where wxWidgets libraries are installed (returned by + 'wx-config --libs' or 'wx-config --static --libs' command) + is in LD_LIBRARY_PATH or equivalent variable and + wxWidgets version is $reqwx or above. + ]) +fi + +CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" +CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" +CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" +LIBS="$LIBS $WX_LIBS" GETTEXT_PACKAGE=spek AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) diff --git a/src/Makefile.am b/src/Makefile.am index 863d63b..887f7cd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,12 +3,19 @@ bin_PROGRAMS = spek spek_SOURCES = \ spek.cc -AM_CPPFLAGS = \ +spek_CPPFLAGS = \ -include config.h \ $(SPEK_CFLAGS) \ -DLOCALEDIR=\""$(localedir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ -DPKGLIBDIR=\""$(pkglibdir)"\" +spek_CFLAGS = \ + @CFLAGS@ + +spek_CXXFLAGS = \ + @CXXFLAGS@ + spek_LDADD = \ + @LIBS@ \ $(SPEK_LIBS) diff --git a/src/spek.cc b/src/spek.cc index 445037a..6cc10a1 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -1,6 +1,68 @@ -#include +#include -int main() +class MyApp: public wxApp { - printf("Hello, world!\n"); + virtual bool OnInit(); +}; + +class MyFrame: public wxFrame +{ +public: + MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); + + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + +private: + DECLARE_EVENT_TABLE() +}; + +enum +{ + ID_Quit = 1, + ID_About, +}; + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(ID_Quit, MyFrame::OnQuit) + EVT_MENU(ID_About, MyFrame::OnAbout) +END_EVENT_TABLE() + +IMPLEMENT_APP(MyApp) + +bool MyApp::OnInit() +{ + MyFrame *frame = new MyFrame( wxT("Hello World"), wxPoint(50,50), wxSize(450,340) ); + frame->Show( true ); + SetTopWindow( frame ); + return true; +} + +MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame((wxFrame *)NULL, -1, title, pos, size) +{ + wxMenu *menuFile = new wxMenu; + + menuFile->Append( ID_About, wxT("&About...") ); + menuFile->AppendSeparator(); + menuFile->Append( ID_Quit, wxT("E&xit") ); + + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append( menuFile, wxT("&File") ); + + SetMenuBar( menuBar ); + + CreateStatusBar(); + SetStatusText( wxT("Welcome to wxWidgets!") ); +} + +void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close( true ); +} + +void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox( wxT("This is a wxWidgets' Hello world sample"), + wxT("About Hello World"), wxOK | wxICON_INFORMATION ); } From 1b62d0dd3ad8c673613a29721d54f2afea5a1a12 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 17:23:29 -0700 Subject: [PATCH 03/60] SpekWindow --- configure.ac | 8 ++---- src/Makefile.am | 4 ++- src/spek-window.cc | 41 ++++++++++++++++++++++++++++ src/spek-window.h | 21 ++++++++++++++ src/spek.cc | 68 ++++++---------------------------------------- 5 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 src/spek-window.cc create mode 100644 src/spek-window.h diff --git a/configure.ac b/configure.ac index 3227b89..bdebf27 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,13 @@ AC_INIT([spek],[0.7]) AC_CONFIG_SRCDIR([src/spek.cc]) AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) -AM_SILENT_RULES - -AM_MAINTAINER_MODE +AM_INIT_AUTOMAKE([1.11.1 foreign no-dist-gzip dist-xz]) +AM_SILENT_RULES([yes]) AC_PROG_CC_C99 AC_PROG_CXX AC_PROG_INSTALL -IT_PROG_INTLTOOL([0.35]) +IT_PROG_INTLTOOL([0.40.0]) AC_CHECK_LIB(m, log10) diff --git a/src/Makefile.am b/src/Makefile.am index 887f7cd..33b409d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,9 @@ bin_PROGRAMS = spek spek_SOURCES = \ - spek.cc + spek.cc \ + spek-window.h \ + spek-window.cc spek_CPPFLAGS = \ -include config.h \ diff --git a/src/spek-window.cc b/src/spek-window.cc new file mode 100644 index 0000000..f7c5e84 --- /dev/null +++ b/src/spek-window.cc @@ -0,0 +1,41 @@ +#include "spek-window.h" + +enum +{ + ID_Quit = 1, + ID_About, +}; + +BEGIN_EVENT_TABLE(SpekWindow, wxFrame) + EVT_MENU(ID_Quit, SpekWindow::OnQuit) + EVT_MENU(ID_About, SpekWindow::OnAbout) +END_EVENT_TABLE() + +SpekWindow::SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size) + : wxFrame(NULL, -1, title, pos, size) +{ + wxMenu *menuFile = new wxMenu(); + + menuFile->Append(ID_About, wxT("&About...")); + menuFile->AppendSeparator(); + menuFile->Append(ID_Quit, wxT("E&xit")); + + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(menuFile, wxT("&File")); + + SetMenuBar(menuBar); +} + +void SpekWindow::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +void SpekWindow::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox( + wxT("This is a wxWidgets' Hello world sample"), + wxT("About Hello World"), + wxOK | wxICON_INFORMATION + ); +} diff --git a/src/spek-window.h b/src/spek-window.h new file mode 100644 index 0000000..3c0b599 --- /dev/null +++ b/src/spek-window.h @@ -0,0 +1,21 @@ +// -*-c++-*- + +#ifndef SPEK_WINDOW_H_ +#define SPEK_WINDOW_H_ + +#include + +class SpekWindow : public wxFrame +{ +public: + SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size); + +protected: + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + +private: + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/src/spek.cc b/src/spek.cc index 6cc10a1..9574ae3 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -1,68 +1,18 @@ #include -class MyApp: public wxApp +#include "spek-window.h" + +class Spek: public wxApp { virtual bool OnInit(); }; -class MyFrame: public wxFrame +IMPLEMENT_APP(Spek) + +bool Spek::OnInit() { -public: - MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); - - void OnQuit(wxCommandEvent& event); - void OnAbout(wxCommandEvent& event); - -private: - DECLARE_EVENT_TABLE() -}; - -enum -{ - ID_Quit = 1, - ID_About, -}; - -BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(ID_Quit, MyFrame::OnQuit) - EVT_MENU(ID_About, MyFrame::OnAbout) -END_EVENT_TABLE() - -IMPLEMENT_APP(MyApp) - -bool MyApp::OnInit() -{ - MyFrame *frame = new MyFrame( wxT("Hello World"), wxPoint(50,50), wxSize(450,340) ); - frame->Show( true ); - SetTopWindow( frame ); + SpekWindow *window = new SpekWindow(wxT("Hello World"), wxPoint(50,50), wxSize(450,340)); + window->Show(true); + SetTopWindow(window); return true; } - -MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) - : wxFrame((wxFrame *)NULL, -1, title, pos, size) -{ - wxMenu *menuFile = new wxMenu; - - menuFile->Append( ID_About, wxT("&About...") ); - menuFile->AppendSeparator(); - menuFile->Append( ID_Quit, wxT("E&xit") ); - - wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append( menuFile, wxT("&File") ); - - SetMenuBar( menuBar ); - - CreateStatusBar(); - SetStatusText( wxT("Welcome to wxWidgets!") ); -} - -void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) -{ - Close( true ); -} - -void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) -{ - wxMessageBox( wxT("This is a wxWidgets' Hello world sample"), - wxT("About Hello World"), wxOK | wxICON_INFORMATION ); -} From 78eb0119cc9ddef3eece1be45214fd804c93d03a Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 17:24:40 -0700 Subject: [PATCH 04/60] Update .gitignore --- .gitignore | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.gitignore b/.gitignore index e1fede2..90812a4 100644 --- a/.gitignore +++ b/.gitignore @@ -32,15 +32,10 @@ po/.intltool-merge-cache po/POTFILES po/stamp-it samples/ -src/*.c src/*.o src/spek -!src/spek-audio.c -!src/spek-fft.c -!src/spek-platform.c src/*.stamp stamp-h1 -.svn test* web/version xmldocs.make From 48afd3b4e89b15a6fa14e7e4613b78ae8f263ac9 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 17:34:17 -0700 Subject: [PATCH 05/60] Add copyright headers, use .hh for C++ headers --- src/Makefile.am | 4 ++-- src/spek-window.cc | 20 +++++++++++++++++++- src/spek-window.h | 21 --------------------- src/spek-window.hh | 37 +++++++++++++++++++++++++++++++++++++ src/spek.cc | 20 +++++++++++++++++++- 5 files changed, 77 insertions(+), 25 deletions(-) delete mode 100644 src/spek-window.h create mode 100644 src/spek-window.hh diff --git a/src/Makefile.am b/src/Makefile.am index 33b409d..1ad246e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,8 +2,8 @@ bin_PROGRAMS = spek spek_SOURCES = \ spek.cc \ - spek-window.h \ - spek-window.cc + spek-window.cc \ + spek-window.hh spek_CPPFLAGS = \ -include config.h \ diff --git a/src/spek-window.cc b/src/spek-window.cc index f7c5e84..84ae301 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -1,4 +1,22 @@ -#include "spek-window.h" +/* spek-window.cc + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include "spek-window.hh" enum { diff --git a/src/spek-window.h b/src/spek-window.h deleted file mode 100644 index 3c0b599..0000000 --- a/src/spek-window.h +++ /dev/null @@ -1,21 +0,0 @@ -// -*-c++-*- - -#ifndef SPEK_WINDOW_H_ -#define SPEK_WINDOW_H_ - -#include - -class SpekWindow : public wxFrame -{ -public: - SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size); - -protected: - void OnQuit(wxCommandEvent& event); - void OnAbout(wxCommandEvent& event); - -private: - DECLARE_EVENT_TABLE() -}; - -#endif diff --git a/src/spek-window.hh b/src/spek-window.hh new file mode 100644 index 0000000..5163374 --- /dev/null +++ b/src/spek-window.hh @@ -0,0 +1,37 @@ +/* spek-window.hh + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_WINDOW_HH_ +#define SPEK_WINDOW_HH_ + +#include + +class SpekWindow : public wxFrame +{ +public: + SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size); + +protected: + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + +private: + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/src/spek.cc b/src/spek.cc index 9574ae3..3539051 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -1,6 +1,24 @@ +/* spek.vala + * + * Copyright (C) 2010-2011 Alexander Kojevnikov + * + * 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 . + */ + #include -#include "spek-window.h" +#include "spek-window.hh" class Spek: public wxApp { From 546d61c0a8b065f40914e6a298b53b231263cf28 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 17:56:06 -0700 Subject: [PATCH 06/60] Add spek-fft.c --- src/Makefile.am | 2 ++ src/spek-audio.h | 2 +- src/spek-fft.c | 37 ++++++++++++++++++++----------------- src/spek-fft.h | 43 +++++++++++++++++++++++++------------------ 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 1ad246e..844c5fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,8 @@ bin_PROGRAMS = spek spek_SOURCES = \ spek.cc \ + spek-fft.c \ + spek-fft.h \ spek-window.cc \ spek-window.hh diff --git a/src/spek-audio.h b/src/spek-audio.h index 9cc2868..de73df4 100644 --- a/src/spek-audio.h +++ b/src/spek-audio.h @@ -1,6 +1,6 @@ /* spek-audio.h * - * Copyright (C) 2010 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/spek-fft.c b/src/spek-fft.c index 96a83fb..6a27c8e 100644 --- a/src/spek-fft.c +++ b/src/spek-fft.c @@ -1,6 +1,6 @@ /* spek-fft.c * - * Copyright (C) 2010 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,29 +21,31 @@ #include "spek-fft.h" -SpekFftPlan * spek_fft_plan_new (gint n, gint threshold) { - gint bits; - SpekFftPlan *p = g_new0 (SpekFftPlan, 1); - p->input = av_mallocz (sizeof (gfloat) * n); - p->output = av_mallocz (sizeof (gfloat) * (n / 2 + 1)); +struct spek_fft_plan * spek_fft_plan_new(int n, int threshold) +{ + int bits; + struct spek_fft_plan *p = malloc(sizeof(struct spek_fft_plan)); + p->input = av_mallocz(sizeof(float) * n); + p->output = av_mallocz(sizeof(float) * (n / 2 + 1)); p->threshold = threshold; - for (bits = 0; n; n >>= 1, bits++); + for(bits = 0; n; n >>= 1, ++bits); p->n = 1 << --bits; - p->cx = av_rdft_init (bits, DFT_R2C); + p->cx = av_rdft_init(bits, DFT_R2C); return p; } -void spek_fft_execute (SpekFftPlan *p) { +void spek_fft_execute(struct spek_fft_plan *p) +{ int i; int n = p->n; - av_rdft_calc (p->cx, p->input); + av_rdft_calc(p->cx, p->input); - /* Calculate magnitudes */ + // Calculate magnitudes. p->output[0] = p->input[0] * p->input[0] / (n * n); p->output[n / 2] = p->input[1] * p->input[1] / (n * n); for (i = 1; i < n / 2; i++) { - gfloat val; + float val; val = p->input[i * 2] * p->input[i * 2] + p->input[i * 2 + 1] * p->input[i * 2 + 1]; val /= n * n; val = 10.0 * log10f (val); @@ -51,9 +53,10 @@ void spek_fft_execute (SpekFftPlan *p) { } } -void spek_fft_destroy (SpekFftPlan *p) { - av_rdft_end (p->cx); - av_free (p->input); - av_free (p->output); - g_free (p); +void spek_fft_destroy(struct spek_fft_plan *p) +{ + av_rdft_end(p->cx); + av_free(p->input); + av_free(p->output); + free(p); } diff --git a/src/spek-fft.h b/src/spek-fft.h index 0ac3df9..704cde5 100644 --- a/src/spek-fft.h +++ b/src/spek-fft.h @@ -1,6 +1,6 @@ /* spek-fft.h * - * Copyright (C) 2010 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,30 +16,37 @@ * along with Spek. If not, see . */ -#ifndef __SPEK_FFT_H__ -#define __SPEK_FFT_H__ +#ifndef SPEK_FFT_H__ +#define SPEK_FFT_H__ + +#ifdef __cplusplus +extern "C" { +#endif -#include #include -typedef struct { - /* Internal data */ +struct spek_fft_plan { + // Internal data. RDFTContext *cx; - gint n; - gint threshold; + int n; + int threshold; - /* Exposed properties */ - gfloat *input; - gfloat *output; -} SpekFftPlan; + // Exposed properties. + float *input; + float *output; +}; -/* Allocate buffers and create a new FFT plan */ -SpekFftPlan * spek_fft_plan_new (gint n, gint threshold); +// Allocate buffers and create a new FFT plan. +struct spek_fft_plan * spek_fft_plan_new(int n, int threshold); -/* Execute the FFT on plan->input */ -void spek_fft_execute (SpekFftPlan *p); +// Execute the FFT on plan->input. +void spek_fft_execute(struct spek_fft_plan *p); -/* Destroy the plan and de-allocate buffers */ -void spek_fft_destroy (SpekFftPlan *p); +// Destroy the plan and de-allocate buffers. +void spek_fft_delete(struct spek_fft_plan *p); + +#ifdef __cplusplus +} +#endif #endif From d64ffa56e8e97e90bbc06aea40db1070592abb6f Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 18:20:01 -0700 Subject: [PATCH 07/60] C99-ify --- src/spek-fft.c | 18 ++++++++++-------- src/spek-fft.h | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/spek-fft.c b/src/spek-fft.c index 6a27c8e..e9ad371 100644 --- a/src/spek-fft.c +++ b/src/spek-fft.c @@ -23,12 +23,15 @@ struct spek_fft_plan * spek_fft_plan_new(int n, int threshold) { - int bits; struct spek_fft_plan *p = malloc(sizeof(struct spek_fft_plan)); p->input = av_mallocz(sizeof(float) * n); p->output = av_mallocz(sizeof(float) * (n / 2 + 1)); p->threshold = threshold; - for(bits = 0; n; n >>= 1, ++bits); + int bits = 0; + while (n) { + n >>= 1; + ++bits; + } p->n = 1 << --bits; p->cx = av_rdft_init(bits, DFT_R2C); return p; @@ -36,17 +39,16 @@ struct spek_fft_plan * spek_fft_plan_new(int n, int threshold) void spek_fft_execute(struct spek_fft_plan *p) { - int i; - int n = p->n; - av_rdft_calc(p->cx, p->input); // Calculate magnitudes. + int n = p->n; p->output[0] = p->input[0] * p->input[0] / (n * n); p->output[n / 2] = p->input[1] * p->input[1] / (n * n); - for (i = 1; i < n / 2; i++) { - float val; - val = p->input[i * 2] * p->input[i * 2] + p->input[i * 2 + 1] * p->input[i * 2 + 1]; + for (int i = 1; i < n / 2; i++) { + float val = + p->input[i * 2] * p->input[i * 2] + + p->input[i * 2 + 1] * p->input[i * 2 + 1]; val /= n * n; val = 10.0 * log10f (val); p->output[i] = val < p->threshold ? p->threshold : val; diff --git a/src/spek-fft.h b/src/spek-fft.h index 704cde5..5b4ac00 100644 --- a/src/spek-fft.h +++ b/src/spek-fft.h @@ -25,7 +25,8 @@ extern "C" { #include -struct spek_fft_plan { +struct spek_fft_plan +{ // Internal data. RDFTContext *cx; int n; From 188738c6cdba924b3182603387a82b7f2d3899ee Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 19:24:49 -0700 Subject: [PATCH 08/60] Platform detection --- configure.ac | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index bdebf27..1a1ef0e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_INIT([spek],[0.7]) AC_CONFIG_SRCDIR([src/spek.cc]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([1.11.1 foreign no-dist-gzip dist-xz]) +AM_MAINTAINER_MODE([yes]) AM_SILENT_RULES([yes]) AC_PROG_CC_C99 @@ -9,6 +10,24 @@ AC_PROG_CXX AC_PROG_INSTALL IT_PROG_INTLTOOL([0.40.0]) +AC_CANONICAL_HOST +AC_MSG_CHECKING([the OS]) +AS_CASE([$host], + [*-*-mingw*], [ + os="WIN" + AC_DEFINE([OS_WIN], [1], [Platform]) + ], + [*-*-darwin*], [ + os="OSX" + AC_DEFINE([OS_OSX], [1], [Platform]) + ], + [*], [ + os="UNIX" + AC_DEFINE([OS_UNIX], [1], [Platform]) + ] +) +AC_MSG_RESULT([$os]) + AC_CHECK_LIB(m, log10) pkg_modules="libavformat >= 52.111 libavcodec >= 52.123 libavutil" From f408c5584ff50d6720e8a7f3f542988c0f0b3d3d Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 21:57:56 -0700 Subject: [PATCH 09/60] Don't use glib's gettext --- autogen.sh | 5 +++-- configure.ac | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/autogen.sh b/autogen.sh index 78779f1..c3d21c8 100755 --- a/autogen.sh +++ b/autogen.sh @@ -5,6 +5,7 @@ test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. ( cd "$srcdir" && - AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv -Wall + touch config.rpath && + AUTOPOINT='intltoolize --automake --copy' autoreconf -fiv ) || exit -test -n "$NOCONFIGURE" || "$srcdir/configure" --enable-maintainer-mode "$@" \ No newline at end of file +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" \ No newline at end of file diff --git a/configure.ac b/configure.ac index 1a1ef0e..2c52129 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,6 @@ AC_INIT([spek],[0.7]) AC_CONFIG_SRCDIR([src/spek.cc]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([1.11.1 foreign no-dist-gzip dist-xz]) -AM_MAINTAINER_MODE([yes]) AM_SILENT_RULES([yes]) AC_PROG_CC_C99 @@ -58,8 +57,8 @@ LIBS="$LIBS $WX_LIBS" GETTEXT_PACKAGE=spek AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) AC_SUBST(GETTEXT_PACKAGE) -AM_GNU_GETTEXT_VERSION([1.11]) -AM_GLIB_GNU_GETTEXT +AM_GNU_GETTEXT_VERSION([0.18.1]) +AM_GNU_GETTEXT([external]) AC_CONFIG_FILES([ Makefile From 98ba100f0ce41fbf8547a8eb3eecdc0859ba6928 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 22:36:19 -0700 Subject: [PATCH 10/60] Add spek-platform.cc --- src/Makefile.am | 2 ++ src/spek-fft.h | 4 ++-- src/spek-platform.cc | 33 +++++++++++++++++++++++++++++++++ src/spek-platform.h | 34 +++++++++++----------------------- 4 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 src/spek-platform.cc diff --git a/src/Makefile.am b/src/Makefile.am index 844c5fe..b15f390 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,8 @@ spek_SOURCES = \ spek.cc \ spek-fft.c \ spek-fft.h \ + spek-platform.cc \ + spek-platform.h \ spek-window.cc \ spek-window.hh diff --git a/src/spek-fft.h b/src/spek-fft.h index 5b4ac00..b715256 100644 --- a/src/spek-fft.h +++ b/src/spek-fft.h @@ -16,8 +16,8 @@ * along with Spek. If not, see . */ -#ifndef SPEK_FFT_H__ -#define SPEK_FFT_H__ +#ifndef SPEK_FFT_H_ +#define SPEK_FFT_H_ #ifdef __cplusplus extern "C" { diff --git a/src/spek-platform.cc b/src/spek-platform.cc new file mode 100644 index 0000000..2d24962 --- /dev/null +++ b/src/spek-platform.cc @@ -0,0 +1,33 @@ +/* spek-platform.cc + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include + +#include + +#include "spek-platform.h" + +char * spek_platform_short_path(const char *path) +{ +#ifdef OS_WIN + wxFileName file_name(wxString(path, wxConvUTF8)); + return strdup(file_name.GetShortPath().char_str(wxConvFile)); +#endif + return NULL; +} + diff --git a/src/spek-platform.h b/src/spek-platform.h index 5b61b19..f81554c 100644 --- a/src/spek-platform.h +++ b/src/spek-platform.h @@ -1,6 +1,6 @@ /* spek-platform.h * - * Copyright (C) 2010,2011 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,30 +16,18 @@ * along with Spek. If not, see . */ -#ifndef __SPEK_PLATFORM_H__ -#define __SPEK_PLATFORM_H__ +#ifndef SPEK_PLATFORM_H_ +#define SPEK_PLATFORM_H_ -#include +#ifdef __cplusplus +extern "C" { +#endif -/* Platform-specific initialisation */ -void spek_platform_init (); +// Returns a 8.3 version of the UTF8-encoded path on Windows and NULL on other platforms. +char * spek_platform_short_path (const char *path); -/* Convert from UTF-16 to UTF-8 when running on Windows */ -void spek_platform_fix_args (gchar **argv, gint argc); - -/* OSX has its own approach to menus and accelerators */ -void spek_platform_fix_ui (GtkUIManager *ui); - -/* Platform-specific locale directory */ -gchar *spek_platform_locale_dir (); - -/* Open a link in the browser */ -void spek_platform_show_uri (const gchar *uri); - -/* Read a line from a uri */ -gchar *spek_platform_read_line (const gchar *uri); - -/* Fonts are smaller on OS X */ -gdouble spek_platform_get_font_scale (); +#ifdef __cplusplus +} +#endif #endif From 92dd6a8bbfa73b914e6dabd8033afd836394c7e0 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 5 Aug 2012 23:04:29 -0700 Subject: [PATCH 11/60] Add spek-audio.c --- src/Makefile.am | 2 + src/spek-audio.c | 134 ++++++++++++++++++++++++----------------------- src/spek-audio.h | 92 +++++++++++++++++--------------- 3 files changed, 120 insertions(+), 108 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index b15f390..38108a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,8 @@ bin_PROGRAMS = spek spek_SOURCES = \ spek.cc \ + spek-audio.c \ + spek-audio.h \ spek-fft.c \ spek-fft.h \ spek-platform.cc \ diff --git a/src/spek-audio.c b/src/spek-audio.c index 32d1b1f..0c189d3 100644 --- a/src/spek-audio.c +++ b/src/spek-audio.c @@ -1,6 +1,6 @@ /* spek-audio.c * - * Copyright (C) 2010 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,47 +16,48 @@ * along with Spek. If not, see . */ -#include -#include +#include + #include +#include "spek-platform.h" + #include "spek-audio.h" -void spek_audio_init () { - /* TODO: register only audio decoders */ - av_register_all (); +// TODO: move translations to UI code, return an error code instead. +#define _ + +void spek_audio_init() +{ + // TODO: register only audio decoders. + av_register_all(); } -SpekAudioContext * spek_audio_open (const gchar *file_name) { - SpekAudioContext *cx; - int i; +struct spek_audio_context * spek_audio_open(const char *file_name) +{ + struct spek_audio_context *cx = malloc(sizeof(struct spek_audio_context)); + cx->file_name = strdup(file_name); + // av_open_input_file() cannot open files with Unicode chars in it + // when running under Windows. When this happens we will re-try + // using the corresponding short file name. + cx->short_name = spek_platform_short_path(file_name); - cx = g_new0 (SpekAudioContext, 1); - cx->file_name = g_strdup (file_name); -#ifdef G_OS_WIN32 - /* av_open_input_file() cannot open files with Unicode chars in it - * when running under Windows. When this happens we will re-try - * using the corresponding short file name. - */ - cx->short_name = g_win32_locale_filename_from_utf8 (file_name); -#endif - - if (avformat_open_input (&cx->format_context, file_name, NULL, NULL) != 0) { + if (avformat_open_input(&cx->format_context, file_name, NULL, NULL) != 0) { if (!cx->short_name || - avformat_open_input (&cx->format_context, cx->short_name, NULL, NULL) != 0 ) { + avformat_open_input(&cx->format_context, cx->short_name, NULL, NULL) != 0 ) { cx->error = _("Cannot open input file"); return cx; } } - if (avformat_find_stream_info (cx->format_context, NULL) < 0) { - /* 24-bit APE returns an error but parses the stream info just fine */ + if (avformat_find_stream_info(cx->format_context, NULL) < 0) { + // 24-bit APE returns an error but parses the stream info just fine. if (cx->format_context->nb_streams <= 0) { cx->error = _("Cannot find stream info"); return cx; } } cx->audio_stream = -1; - for (i = 0; i < cx->format_context->nb_streams; i++) { + for (int i = 0; i < cx->format_context->nb_streams; i++) { if (cx->format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { cx->audio_stream = i; break; @@ -68,23 +69,23 @@ SpekAudioContext * spek_audio_open (const gchar *file_name) { } cx->stream = cx->format_context->streams[cx->audio_stream]; cx->codec_context = cx->stream->codec; - cx->codec = avcodec_find_decoder (cx->codec_context->codec_id); + cx->codec = avcodec_find_decoder(cx->codec_context->codec_id); if (cx->codec == NULL) { cx->error = _("Cannot find decoder"); return cx; } - /* We can already fill in the stream info even if the codec won't be able to open it */ - cx->codec_name = g_strdup (cx->codec->long_name); + // We can already fill in the stream info even if the codec won't be able to open it. + cx->codec_name = strdup(cx->codec->long_name); cx->bit_rate = cx->codec_context->bit_rate; cx->sample_rate = cx->codec_context->sample_rate; cx->bits_per_sample = cx->codec_context->bits_per_raw_sample; if (!cx->bits_per_sample) { - /* APE uses bpcs, FLAC uses bprs. */ + // APE uses bpcs, FLAC uses bprs. cx->bits_per_sample = cx->codec_context->bits_per_coded_sample; } cx->channels = cx->codec_context->channels; if (cx->stream->duration != AV_NOPTS_VALUE) { - cx->duration = cx->stream->duration * av_q2d (cx->stream->time_base); + cx->duration = cx->stream->duration * av_q2d(cx->stream->time_base); } else if (cx->format_context->duration != AV_NOPTS_VALUE) { cx->duration = cx->format_context->duration / (double) AV_TIME_BASE; } else { @@ -95,63 +96,61 @@ SpekAudioContext * spek_audio_open (const gchar *file_name) { cx->error = _("No audio channels"); return cx; } - if (avcodec_open2 (cx->codec_context, cx->codec, NULL) < 0) { + if (avcodec_open2(cx->codec_context, cx->codec, NULL) < 0) { cx->error = _("Cannot open decoder"); return cx; } switch (cx->codec_context->sample_fmt) { case SAMPLE_FMT_S16: cx->width = 16; - cx->fp = FALSE; + cx->fp = false; break; case SAMPLE_FMT_S32: cx->width = 32; - cx->fp = FALSE; + cx->fp = false; break; case SAMPLE_FMT_FLT: cx->width = 32; - cx->fp = TRUE; + cx->fp = true; break; case SAMPLE_FMT_DBL: cx->width = 64; - cx->fp = TRUE; + cx->fp = true; break; default: cx->error = _("Unsupported sample format"); return cx; } cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; - cx->buffer = av_malloc (cx->buffer_size); - cx->packet = av_mallocz (sizeof (AVPacket)); - av_init_packet (cx->packet); + cx->buffer = av_malloc(cx->buffer_size); + cx->packet = av_mallocz(sizeof(AVPacket)); + av_init_packet(cx->packet); cx->offset = 0; return cx; } -void spek_audio_start (SpekAudioContext *cx, gint samples) { - gint64 rate = cx->sample_rate * (gint64) cx->stream->time_base.num; - gint64 duration = (gint64) (cx->duration * cx->stream->time_base.den / cx->stream->time_base.num); - cx->error_base = samples * (gint64) cx->stream->time_base.den; - cx->frames_per_interval = av_rescale_rnd (duration, rate, cx->error_base, AV_ROUND_DOWN); +void spek_audio_start(struct spek_audio_context *cx, int samples) +{ + int64_t rate = cx->sample_rate * (int64_t) cx->stream->time_base.num; + int64_t duration = (int64_t) + (cx->duration * cx->stream->time_base.den / cx->stream->time_base.num); + cx->error_base = samples * (int64_t)cx->stream->time_base.den; + cx->frames_per_interval = av_rescale_rnd(duration, rate, cx->error_base, AV_ROUND_DOWN); cx->error_per_interval = (duration * rate) % cx->error_base; } -gint spek_audio_read (SpekAudioContext *cx) { - gint buffer_size; - gint len; - gint res; - +int spek_audio_read(struct spek_audio_context *cx) { if (cx->error) { return -1; } for (;;) { while (cx->packet->size > 0) { - buffer_size = cx->buffer_size; - len = avcodec_decode_audio3 ( - cx->codec_context, (int16_t *) cx->buffer, &buffer_size, cx->packet); + int buffer_size = cx->buffer_size; + int len = avcodec_decode_audio3( + cx->codec_context, (int16_t *)cx->buffer, &buffer_size, cx->packet); if (len < 0) { - /* Error, skip the frame. */ + // Error, skip the frame. cx->packet->size = 0; break; } @@ -159,10 +158,10 @@ gint spek_audio_read (SpekAudioContext *cx) { cx->packet->size -= len; cx->offset += len; if (buffer_size <= 0) { - /* No data yet, get more frames */ + // No data yet, get more frames. continue; } - /* We have data, return it and come back for more later */ + // We have data, return it and come back for more later. return buffer_size; } if (cx->packet->data) { @@ -171,46 +170,49 @@ gint spek_audio_read (SpekAudioContext *cx) { cx->offset = 0; av_free_packet (cx->packet); } - while ((res = av_read_frame (cx->format_context, cx->packet)) >= 0) { + + int res = 0; + while ((res = av_read_frame(cx->format_context, cx->packet)) >= 0) { if (cx->packet->stream_index == cx->audio_stream) { break; } - av_free_packet (cx->packet); + av_free_packet(cx->packet); } if (res < 0) { - /* End of file or error. */ + // End of file or error. return 0; } } } -void spek_audio_close (SpekAudioContext *cx) { +void spek_audio_close (struct spek_audio_context *cx) +{ if (cx->file_name != NULL) { - g_free (cx->file_name); + free(cx->file_name); } if (cx->short_name != NULL) { - g_free (cx->short_name); + free(cx->short_name); } if (cx->codec_name != NULL) { - g_free (cx->codec_name); + free(cx->codec_name); } if (cx->buffer) { - av_free (cx->buffer); + av_free(cx->buffer); } if (cx->packet) { if (cx->packet->data) { cx->packet->data -= cx->offset; cx->packet->size += cx->offset; cx->offset = 0; - av_free_packet (cx->packet); + av_free_packet(cx->packet); } - av_free (cx->packet); + av_free(cx->packet); } if (cx->codec_context != NULL) { - avcodec_close (cx->codec_context); + avcodec_close(cx->codec_context); } if (cx->format_context != NULL) { - av_close_input_file (cx->format_context); + av_close_input_file(cx->format_context); } - g_free (cx); + free(cx); } diff --git a/src/spek-audio.h b/src/spek-audio.h index de73df4..d8335f7 100644 --- a/src/spek-audio.h +++ b/src/spek-audio.h @@ -16,62 +16,70 @@ * along with Spek. If not, see . */ -#ifndef __SPEK_AUDIO_H__ -#define __SPEK_AUDIO_H__ +#ifndef SPEK_AUDIO_H_ +#define SPEK_AUDIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include -#include #include #include -typedef struct { - /* Internal data */ - gchar *short_name; +struct spek_audio_context +{ + // Internal data. + char *short_name; AVFormatContext *format_context; - gint audio_stream; + int audio_stream; AVCodecContext *codec_context; AVStream *stream; AVCodec *codec; - gint buffer_size; + int buffer_size; AVPacket *packet; - gint offset; + int offset; - /* Exposed properties */ - gchar *file_name; - gchar *codec_name; - gchar *error; - gint bit_rate; - gint sample_rate; - gint bits_per_sample; - gint width; /* number of bits used to store a sample */ - gboolean fp; /* floating-point sample representation */ - gint channels; - gdouble duration; - guint8 *buffer; - gint64 frames_per_interval; - gint64 error_per_interval; - gint64 error_base; -} SpekAudioContext; + // Exposed properties. + char *file_name; + char *codec_name; + char *error; + int bit_rate; + int sample_rate; + int bits_per_sample; + int width; // number of bits used to store a sample + bool fp; // floating-point sample representation + int channels; + double duration; + uint8_t *buffer; + int64_t frames_per_interval; + int64_t error_per_interval; + int64_t error_base; +}; -/* Initialise FFmpeg, should be called once on start up */ -void spek_audio_init (); +// Initialise FFmpeg, should be called once on start up. +void spek_audio_init(); -/* Open the file, check if it has an audio stream which can be decoded. - * On error, initialises the `error` field in the returned context. - */ -SpekAudioContext * spek_audio_open (const gchar *file_name); +// Open the file, check if it has an audio stream which can be decoded. +// On error, initialises the `error` field in the returned context. +struct spek_audio_context * spek_audio_open(const char *file_name); -/* Prepare the context for reading audio samples. */ -void spek_audio_start (SpekAudioContext *cx, gint samples); +// Prepare the context for reading audio samples. +void spek_audio_start(struct spek_audio_context *cx, int samples); -/* Read and decode the opened audio stream. - * Returns -1 on error, 0 if there's nothing left to read - * or the number of bytes decoded into the buffer. - */ -gint spek_audio_read (SpekAudioContext *cx); +// Read and decode the opened audio stream. +// Returns -1 on error, 0 if there's nothing left to read +// or the number of bytes decoded into the buffer. +int spek_audio_read(struct spek_audio_context *cx); -/* Closes the file opened with spek_audio_open, - * frees all allocated buffers and the context - */ -void spek_audio_close (SpekAudioContext *cx); +// Closes the file opened with spek_audio_open, +// frees all allocated buffers and the context +void spek_audio_close(struct spek_audio_context *cx); + +#ifdef __cplusplus +} +#endif #endif From 0c08e68c5fe503590b624eccb5d9d3cc93fb3290 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Mon, 6 Aug 2012 22:55:30 -0700 Subject: [PATCH 12/60] spek_platform_config_dir() --- src/spek-platform.c | 76 -------------------------------------------- src/spek-platform.cc | 14 ++++++++ src/spek-platform.h | 6 +++- 3 files changed, 19 insertions(+), 77 deletions(-) diff --git a/src/spek-platform.c b/src/spek-platform.c index e036c7d..9c22456 100644 --- a/src/spek-platform.c +++ b/src/spek-platform.c @@ -32,82 +32,6 @@ #include "spek-platform.h" -void spek_platform_init () { -#ifdef G_OS_DARWIN - g_object_new (GTK_TYPE_OSX_APPLICATION, NULL); -#endif -} - -void spek_platform_fix_args (gchar **argv, gint argc) { -#ifdef G_OS_WIN32 - /* Because MinGW does not support Unicode arguments we are going to - * get them using Windows API. In addition, GLib's option parser - * doesn't work well with utf-8 strings on Windows, converting - * them to URIs works around this problem. - */ - int i; - gchar *s, *t; - wchar_t **wargv; - int wargc; - wargv = CommandLineToArgvW (GetCommandLineW (), &wargc); - for (i = 0; i < argc; i++) { - s = g_utf16_to_utf8 (wargv[i], -1, NULL, NULL, NULL); - if (s) { - t = g_filename_to_uri (s, NULL, NULL); - g_free (s); - if (t) { - g_free (argv[i]); - argv[i] = t; - } - } - } - LocalFree (wargv); -#endif -} - -#ifdef G_OS_DARWIN -static void accel_map_foreach (gpointer data, const gchar *accel_path, guint accel_key, GdkModifierType -accel_mods, gboolean changed) -{ - if (accel_mods & GDK_CONTROL_MASK) { - accel_mods &= ~GDK_CONTROL_MASK; - accel_mods |= GDK_META_MASK; - gtk_accel_map_change_entry (accel_path, accel_key, accel_mods, FALSE); - } -} -#endif - -void spek_platform_fix_ui (GtkUIManager *ui) -{ -#ifdef G_OS_DARWIN - GtkOSXApplication *app = NULL; - GtkOSXApplicationMenuGroup *group = NULL; - GtkWidget *menubar = NULL; - GtkWidget *file_quit = NULL; - GtkWidget *edit_preferences = NULL; - GtkWidget *help_about = NULL; - - app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL); - menubar = gtk_ui_manager_get_widget (ui, "/MenuBar"); - file_quit = gtk_ui_manager_get_widget (ui, "/MenuBar/File/FileQuit"); - edit_preferences = gtk_ui_manager_get_widget (ui, "/MenuBar/Edit/EditPreferences"); - help_about = gtk_ui_manager_get_widget (ui, "/MenuBar/Help/HelpAbout"); - - gtk_widget_hide (menubar); - gtk_widget_hide (file_quit); - gtk_osxapplication_set_menu_bar (app, GTK_MENU_SHELL (menubar)); - - group = gtk_osxapplication_add_app_menu_group (app); - gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (help_about)); - group = gtk_osxapplication_add_app_menu_group (app); - gtk_osxapplication_add_app_menu_item (app, group, GTK_MENU_ITEM (edit_preferences)); - - gtk_accel_map_foreach (NULL, accel_map_foreach); - - gtk_osxapplication_ready (app); -#endif -} - gchar *spek_platform_locale_dir () { static gchar *locale_dir = NULL; diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 2d24962..8e2e43f 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -19,6 +19,8 @@ #include #include +#include +#include #include "spek-platform.h" @@ -31,3 +33,15 @@ char * spek_platform_short_path(const char *path) return NULL; } +char * spek_platform_config_dir(const char *app_name) +{ +#ifdef OS_WIN + wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); +#else + wxFileName file_name(wxGetHomeDir()); + file_name.AppendDir(wxT(".config")); +#endif + file_name.AppendDir(wxString(app_name, wxConvUTF8)); + file_name.SetFullName(wxT("preferences")); + return strdup(file_name.GetFullPath().char_str(wxConvUTF8)); +} diff --git a/src/spek-platform.h b/src/spek-platform.h index f81554c..eb0eb10 100644 --- a/src/spek-platform.h +++ b/src/spek-platform.h @@ -24,7 +24,11 @@ extern "C" { #endif // Returns a 8.3 version of the UTF8-encoded path on Windows and NULL on other platforms. -char * spek_platform_short_path (const char *path); +char * spek_platform_short_path(const char *path); + +// Not quite XDG-compatible, but close enough. +// TODO: implement XDG spec in wxWidgets. +char * spek_platform_config_dir(const char *app_name); #ifdef __cplusplus } From 885e3c5a862ca5ab1660f0355eb844b999b7adfd Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 7 Aug 2012 09:41:52 -0700 Subject: [PATCH 13/60] Add spek-preferences.cc --- src/Makefile.am | 4 +- src/spek-audio.c | 2 +- src/spek-platform.cc | 28 +++--- src/{spek-platform.h => spek-platform.hh} | 19 ++-- src/spek-preferences.cc | 81 +++++++++++++++++ src/spek-preferences.hh | 44 ++++++++++ src/spek-preferences.vala | 102 ---------------------- 7 files changed, 155 insertions(+), 125 deletions(-) rename src/{spek-platform.h => spek-platform.hh} (79%) create mode 100644 src/spek-preferences.cc create mode 100644 src/spek-preferences.hh delete mode 100644 src/spek-preferences.vala diff --git a/src/Makefile.am b/src/Makefile.am index 38108a1..90efb29 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,9 @@ spek_SOURCES = \ spek-fft.c \ spek-fft.h \ spek-platform.cc \ - spek-platform.h \ + spek-platform.hh \ + spek-preferences.cc \ + spek-preferences.hh \ spek-window.cc \ spek-window.hh diff --git a/src/spek-audio.c b/src/spek-audio.c index 0c189d3..5012572 100644 --- a/src/spek-audio.c +++ b/src/spek-audio.c @@ -20,7 +20,7 @@ #include -#include "spek-platform.h" +#include "spek-platform.hh" #include "spek-audio.h" diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 8e2e43f..cafd050 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -22,7 +22,20 @@ #include #include -#include "spek-platform.h" +#include "spek-platform.hh" + +wxString SpekPlatform::ConfigPath(const wxString& app_name) +{ +#ifdef OS_WIN + wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); +#else + wxFileName file_name(wxGetHomeDir()); + file_name.AppendDir(wxT(".config")); +#endif + file_name.AppendDir(app_name); + file_name.SetFullName(wxT("preferences")); + return file_name.GetFullPath(); +} char * spek_platform_short_path(const char *path) { @@ -32,16 +45,3 @@ char * spek_platform_short_path(const char *path) #endif return NULL; } - -char * spek_platform_config_dir(const char *app_name) -{ -#ifdef OS_WIN - wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); -#else - wxFileName file_name(wxGetHomeDir()); - file_name.AppendDir(wxT(".config")); -#endif - file_name.AppendDir(wxString(app_name, wxConvUTF8)); - file_name.SetFullName(wxT("preferences")); - return strdup(file_name.GetFullPath().char_str(wxConvUTF8)); -} diff --git a/src/spek-platform.h b/src/spek-platform.hh similarity index 79% rename from src/spek-platform.h rename to src/spek-platform.hh index eb0eb10..703b14f 100644 --- a/src/spek-platform.h +++ b/src/spek-platform.hh @@ -1,4 +1,4 @@ -/* spek-platform.h +/* spek-platform.hh * * Copyright (C) 2010-2012 Alexander Kojevnikov * @@ -16,20 +16,25 @@ * along with Spek. If not, see . */ -#ifndef SPEK_PLATFORM_H_ -#define SPEK_PLATFORM_H_ +#ifndef SPEK_PLATFORM_HH_ +#define SPEK_PLATFORM_HH_ #ifdef __cplusplus +#include + +class SpekPlatform +{ +public: + // Not quite XDG-compatible, but close enough. + static wxString ConfigPath(const wxString& app_name); +}; + extern "C" { #endif // Returns a 8.3 version of the UTF8-encoded path on Windows and NULL on other platforms. char * spek_platform_short_path(const char *path); -// Not quite XDG-compatible, but close enough. -// TODO: implement XDG spec in wxWidgets. -char * spek_platform_config_dir(const char *app_name); - #ifdef __cplusplus } #endif diff --git a/src/spek-preferences.cc b/src/spek-preferences.cc new file mode 100644 index 0000000..cd9f0d5 --- /dev/null +++ b/src/spek-preferences.cc @@ -0,0 +1,81 @@ +/* spek-preferences.cc + * + * Copyright (C) 2011-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include + +#include "spek-platform.hh" + +#include "spek-preferences.hh" + +SpekPreferences& SpekPreferences::Get() +{ + static SpekPreferences instance; + return instance; +} + +SpekPreferences::SpekPreferences() +{ + wxString path = SpekPlatform::ConfigPath(wxT("spek")); + this->config = new wxFileConfig( + wxEmptyString, + wxEmptyString, + path, + wxEmptyString, + wxCONFIG_USE_LOCAL_FILE, + wxConvUTF8 + ); +} + +bool SpekPreferences::GetCheckUpdate() +{ + bool result = true; + this->config->Read(wxT("/update/check"), &result); + return result; +} + +void SpekPreferences::SetCheckUpdate(bool value) +{ + this->config->Write(wxT("/update/check"), value); + this->config->Flush(); +} + +long SpekPreferences::GetLastUpdate() +{ + long result = 0; + this->config->Read(wxT("/update/last"), &result); + return result; +} + +void SpekPreferences::SetLastUpdate(long value) +{ + this->config->Write(wxT("/update/last"), value); + this->config->Flush(); +} + +wxString SpekPreferences::GetLanguage() +{ + wxString result(wxT("")); + this->config->Read(wxT("/general/language"), &result); + return result; +} + +void SpekPreferences::SetLanguage(const wxString& value) +{ + this->config->Write(wxT("/general/language"), value); + this->config->Flush(); +} diff --git a/src/spek-preferences.hh b/src/spek-preferences.hh new file mode 100644 index 0000000..41c52f3 --- /dev/null +++ b/src/spek-preferences.hh @@ -0,0 +1,44 @@ +/* spek-preferences.hh + * + * Copyright (C) 2011-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_PREFERENCES_HH_ +#define SPEK_PREFERENCES_HH_ + +#include + +class SpekPreferences +{ +public: + static SpekPreferences& Get(); + + bool GetCheckUpdate(); + void SetCheckUpdate(bool value); + long GetLastUpdate(); + void SetLastUpdate(long value); + wxString GetLanguage(); + void SetLanguage(const wxString& value); + +private: + SpekPreferences(); + SpekPreferences(const SpekPreferences&); + void operator=(const SpekPreferences&); + + wxFileConfig *config; +}; + +#endif diff --git a/src/spek-preferences.vala b/src/spek-preferences.vala deleted file mode 100644 index ad8e62a..0000000 --- a/src/spek-preferences.vala +++ /dev/null @@ -1,102 +0,0 @@ -/* spek-preferences.vala - * - * Copyright (C) 2011 Alexander Kojevnikov - * - * 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 . - */ - -namespace Spek { - public class Preferences { - private KeyFile key_file; - private string file_name; - private bool can_save = true; - - private Preferences () { - file_name = Path.build_filename (Environment.get_user_config_dir (), "spek"); - if (DirUtils.create_with_parents (file_name, 0755) != 0) { - this.can_save = false; - } - file_name = Path.build_filename (file_name, "preferences"); - this.key_file = new KeyFile (); - try { - key_file.load_from_file (file_name, KeyFileFlags.NONE); - } catch (KeyFileError e) { - } catch (FileError e) { - } - } - - ~Preferences () { - save (); - } - - private static Preferences _instance; - public static Preferences instance { - get { - if (_instance == null) { - _instance = new Preferences (); - } - return _instance; - } - } - - public void save () { - if (!can_save) { - return; - } - var output = FileStream.open (file_name, "w+"); - if (output != null) { - output.puts (key_file.to_data ()); - } - } - - public bool check_update { - get { - try { - return key_file.get_boolean ("update", "check"); - } catch (KeyFileError e) { - } - return true; - } - set { - key_file.set_boolean ("update", "check", value); - } - } - - public int last_update { - get { - try { - return key_file.get_integer ("update", "last"); - } catch (KeyFileError e) { - } - return 0; - } - set { - key_file.set_integer ("update", "last", value); - } - } - - public string language { - owned get { - try { - return key_file.get_string ("general", "language"); - } catch (KeyFileError e) { - } - return ""; - } - set { - key_file.set_string ("general", "language", value); - } - } - } -} \ No newline at end of file From 0d6df1e48c94d1583afacbb5b011a7b99b5b7cb5 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 7 Aug 2012 22:12:58 -0700 Subject: [PATCH 14/60] Correct Makefile.am --- src/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 90efb29..c81bd69 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,17 +15,17 @@ spek_SOURCES = \ spek_CPPFLAGS = \ -include config.h \ - $(SPEK_CFLAGS) \ -DLOCALEDIR=\""$(localedir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ -DPKGLIBDIR=\""$(pkglibdir)"\" spek_CFLAGS = \ + $(SPEK_CFLAGS) \ @CFLAGS@ spek_CXXFLAGS = \ @CXXFLAGS@ spek_LDADD = \ - @LIBS@ \ - $(SPEK_LIBS) + $(SPEK_LIBS) \ + @LIBS@ From c588131005232d911a1f03c40bbc9080ccfd6aa5 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 9 Aug 2012 11:02:33 -0700 Subject: [PATCH 15/60] Parse the command line --- src/spek.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/spek.vala | 32 ------------------------------- 2 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/spek.cc b/src/spek.cc index 3539051..55bc9e6 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -16,21 +16,71 @@ * along with Spek. If not, see . */ -#include +#include +#include #include "spek-window.hh" class Spek: public wxApp { +protected: virtual bool OnInit(); + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); }; IMPLEMENT_APP(Spek) bool Spek::OnInit() { + if (!wxApp::OnInit()) { + return false; + } + SpekWindow *window = new SpekWindow(wxT("Hello World"), wxPoint(50,50), wxSize(450,340)); window->Show(true); SetTopWindow(window); return true; } + +void Spek::OnInitCmdLine(wxCmdLineParser& parser) +{ + wxCmdLineEntryDesc desc[] = {{ + wxCMD_LINE_SWITCH, wxT("h"), + wxT("help"), _("Show this help message"), + wxCMD_LINE_VAL_NONE, + wxCMD_LINE_OPTION_HELP + }, { + wxCMD_LINE_SWITCH, + wxT("V"), + wxT("version"), + _("Display the version and exit") + }, { + wxCMD_LINE_PARAM, + NULL, + NULL, + _("FILE"), + wxCMD_LINE_VAL_STRING, + wxCMD_LINE_PARAM_OPTIONAL + }, { + wxCMD_LINE_NONE + } + }; + + parser.SetDesc(desc); +} + +bool Spek::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if (!wxApp::OnCmdLineParsed(parser)) { + return false; + } + + if (parser.Found(wxT("version"))) { + // TRANSLATORS: first %s is the package name, second %s is the package version. + wxPrintf(_("%s version %s\n"), wxT(PACKAGE_NAME), wxT(PACKAGE_VERSION)); + return false; + } + + return true; +} diff --git a/src/spek.vala b/src/spek.vala index 780628d..5b823c1 100644 --- a/src/spek.vala +++ b/src/spek.vala @@ -21,15 +21,7 @@ namespace Spek { [CCode (array_length = false, array_null_terminated = true)] string[] files = null; - const OptionEntry[] options = { - { "version", 'V', 0, OptionArg.NONE, ref version, N_("Display the version and exit"), null }, - { "", 0, 0, OptionArg.FILENAME_ARRAY, ref files, null, null }, - { null } - }; - int main (string[] args) { - Platform.fix_args (args); - if (Preferences.instance.language.length > 0) { Environment.set_variable ("LANGUAGE", Preferences.instance.language, true); } @@ -38,27 +30,6 @@ namespace Spek { Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); - try { - Gtk.init_with_args (ref args, _("[FILE]"), (OptionEntry[]) options, Config.GETTEXT_PACKAGE); - } catch (Error e) { - print (e.message); - print ("\n"); - print (_("Run `%s --help` to see a full list of available command line options.\n"), args[0]); - return 1; - } - - if (version) { - // TRANSLATORS: first %s is the package name, second %s is the package version. - print (_("%s version %s\n"), Config.PACKAGE_NAME, Config.PACKAGE_VERSION); - return 0; - } - - if (files != null && files.length != 1) { - print (_("Specify a single file\n")); - return 1; - } - - Platform.init (); Audio.init (); var file_name = files == null ? null : files[0]; if (file_name != null && file_name.has_prefix ("file://")) { @@ -67,9 +38,6 @@ namespace Spek { } catch (ConvertError e) { } } - var window = new Window (file_name); - Gtk.main (); - window.destroy (); return 0; } } \ No newline at end of file From d9ed0de8abe3bdab88f5e75ceaf6ded22a6c80e7 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 10 Aug 2012 10:59:01 -0700 Subject: [PATCH 16/60] Init locale --- src/spek-platform.cc | 2 +- src/spek-preferences.cc | 21 ++++++++++++++++++++- src/spek-preferences.hh | 3 +++ src/spek.cc | 11 ++++++++--- src/spek.vala | 4 ---- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/spek-platform.cc b/src/spek-platform.cc index cafd050..987a88d 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -29,7 +29,7 @@ wxString SpekPlatform::ConfigPath(const wxString& app_name) #ifdef OS_WIN wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); #else - wxFileName file_name(wxGetHomeDir()); + wxFileName file_name(wxGetHomeDir(), wxEmptyString); file_name.AppendDir(wxT(".config")); #endif file_name.AppendDir(app_name); diff --git a/src/spek-preferences.cc b/src/spek-preferences.cc index cd9f0d5..559f0ea 100644 --- a/src/spek-preferences.cc +++ b/src/spek-preferences.cc @@ -28,7 +28,26 @@ SpekPreferences& SpekPreferences::Get() return instance; } -SpekPreferences::SpekPreferences() +void SpekPreferences::Init() +{ + if (this->locale) { + delete this->locale; + } + this->locale = new wxLocale(); + + int lang = wxLANGUAGE_DEFAULT; + wxString code = this->GetLanguage(); + if (!code.IsEmpty()) { + const wxLanguageInfo *info = wxLocale::FindLanguageInfo(code); + if (info) { + lang = info->Language; + } + } + this->locale->Init(lang); + this->locale->AddCatalog(wxT(GETTEXT_PACKAGE)); +} + +SpekPreferences::SpekPreferences() : locale(NULL) { wxString path = SpekPlatform::ConfigPath(wxT("spek")); this->config = new wxFileConfig( diff --git a/src/spek-preferences.hh b/src/spek-preferences.hh index 41c52f3..368bcf0 100644 --- a/src/spek-preferences.hh +++ b/src/spek-preferences.hh @@ -20,12 +20,14 @@ #define SPEK_PREFERENCES_HH_ #include +#include class SpekPreferences { public: static SpekPreferences& Get(); + void Init(); bool GetCheckUpdate(); void SetCheckUpdate(bool value); long GetLastUpdate(); @@ -38,6 +40,7 @@ private: SpekPreferences(const SpekPreferences&); void operator=(const SpekPreferences&); + wxLocale *locale; wxFileConfig *config; }; diff --git a/src/spek.cc b/src/spek.cc index 55bc9e6..6e0f281 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -1,6 +1,6 @@ -/* spek.vala +/* spek.cc * - * Copyright (C) 2010-2011 Alexander Kojevnikov + * Copyright (C) 2010-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,8 @@ #include #include +#include "spek-preferences.hh" + #include "spek-window.hh" class Spek: public wxApp @@ -33,6 +35,8 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { + SpekPreferences::Get().Init(); + if (!wxApp::OnInit()) { return false; } @@ -46,7 +50,8 @@ bool Spek::OnInit() void Spek::OnInitCmdLine(wxCmdLineParser& parser) { wxCmdLineEntryDesc desc[] = {{ - wxCMD_LINE_SWITCH, wxT("h"), + wxCMD_LINE_SWITCH, + wxT("h"), wxT("help"), _("Show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP diff --git a/src/spek.vala b/src/spek.vala index 5b823c1..801594b 100644 --- a/src/spek.vala +++ b/src/spek.vala @@ -26,10 +26,6 @@ namespace Spek { Environment.set_variable ("LANGUAGE", Preferences.instance.language, true); } - Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Platform.locale_dir ()); - Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); - Intl.textdomain (Config.GETTEXT_PACKAGE); - Audio.init (); var file_name = files == null ? null : files[0]; if (file_name != null && file_name.has_prefix ("file://")) { From 44cb6f587d72ba148678d3e68a320669e602c303 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 10 Aug 2012 19:22:50 -0700 Subject: [PATCH 17/60] SpekPlatform::CanChangeLanguage() + spek_audio_init() --- src/Makefile.am | 1 + src/spek-platform.c | 57 -------------------------------------------- src/spek-platform.cc | 9 +++++++ src/spek-platform.hh | 4 ++++ src/spek.cc | 2 ++ src/spek.vala | 39 ------------------------------ 6 files changed, 16 insertions(+), 96 deletions(-) delete mode 100644 src/spek.vala diff --git a/src/Makefile.am b/src/Makefile.am index c81bd69..5738034 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,6 +24,7 @@ spek_CFLAGS = \ @CFLAGS@ spek_CXXFLAGS = \ + $(SPEK_CFLAGS) \ @CXXFLAGS@ spek_LDADD = \ diff --git a/src/spek-platform.c b/src/spek-platform.c index 9c22456..d70d514 100644 --- a/src/spek-platform.c +++ b/src/spek-platform.c @@ -32,55 +32,6 @@ #include "spek-platform.h" -gchar *spek_platform_locale_dir () { - static gchar *locale_dir = NULL; - - if (!locale_dir) { -#ifdef G_OS_WIN32 - gchar *win32_dir; - - win32_dir = g_win32_get_package_installation_directory_of_module (NULL); - locale_dir = g_build_filename (win32_dir, "share", "locale", NULL); - - g_free (win32_dir); -#else -#ifdef G_OS_DARWIN - GtkOSXApplication *app = NULL; - const gchar *res_dir; - - app = g_object_new (GTK_TYPE_OSX_APPLICATION, NULL); - res_dir = gtk_osxapplication_get_resource_path (app); - locale_dir = g_build_filename (res_dir, "share", "locale", NULL); -#else - locale_dir = LOCALEDIR; -#endif -#endif - } - - return locale_dir; -} - -void spek_platform_show_uri (const gchar *uri) { -#ifdef G_OS_WIN32 - /* gtk_show_uri doesn't work on Windows... */ - ShellExecuteA (NULL, "open", uri, "", NULL, SW_SHOWNORMAL); -#else -#ifdef G_OS_DARWIN - /* ...or on OS X */ - CFStringRef str = NULL; - CFURLRef url = NULL; - - str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII); - url = CFURLCreateWithString (NULL, str, NULL); - LSOpenCFURLRef (url, NULL); - CFRelease (url); - CFRelease (str); -#else - gtk_show_uri (NULL, uri, gtk_get_current_event_time (), NULL); -#endif -#endif -} - gchar *spek_platform_read_line (const gchar *uri) { #ifdef G_OS_DARWIN /* GIO doesn't work on OS X */ @@ -123,11 +74,3 @@ gchar *spek_platform_read_line (const gchar *uri) { return line; #endif } - -gdouble spek_platform_get_font_scale () { -#ifdef G_OS_DARWIN - /* Pango/Quartz fonts are smaller than on X. */ - return 1.4; -#endif - return 1.0; -} diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 987a88d..b45fe90 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -37,6 +37,15 @@ wxString SpekPlatform::ConfigPath(const wxString& app_name) return file_name.GetFullPath(); } +bool SpekPlatform::CanChangeLanguage() +{ +#ifdef OS_UNIX + return false; +#else + return true; +#endif +} + char * spek_platform_short_path(const char *path) { #ifdef OS_WIN diff --git a/src/spek-platform.hh b/src/spek-platform.hh index 703b14f..5398253 100644 --- a/src/spek-platform.hh +++ b/src/spek-platform.hh @@ -27,6 +27,10 @@ class SpekPlatform public: // Not quite XDG-compatible, but close enough. static wxString ConfigPath(const wxString& app_name); + + // Setting non-default locale under GTK+ is tricky (see e.g. how FileZilla does it). We will + // just disable the language setting for GTK+ users and will always use the system locale. + static bool CanChangeLanguage(); }; extern "C" { diff --git a/src/spek.cc b/src/spek.cc index 6e0f281..a8ae66d 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -19,6 +19,7 @@ #include #include +#include "spek-audio.h" #include "spek-preferences.hh" #include "spek-window.hh" @@ -36,6 +37,7 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { SpekPreferences::Get().Init(); + spek_audio_init(); if (!wxApp::OnInit()) { return false; diff --git a/src/spek.vala b/src/spek.vala deleted file mode 100644 index 801594b..0000000 --- a/src/spek.vala +++ /dev/null @@ -1,39 +0,0 @@ -/* spek.vala - * - * Copyright (C) 2010-2011 Alexander Kojevnikov - * - * 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 . - */ - -namespace Spek { - bool version = false; - [CCode (array_length = false, array_null_terminated = true)] - string[] files = null; - - int main (string[] args) { - if (Preferences.instance.language.length > 0) { - Environment.set_variable ("LANGUAGE", Preferences.instance.language, true); - } - - Audio.init (); - var file_name = files == null ? null : files[0]; - if (file_name != null && file_name.has_prefix ("file://")) { - try { - file_name = Filename.from_uri (file_name); - } catch (ConvertError e) { - } - } - return 0; - } -} \ No newline at end of file From 7e5ca1765a057aee5d65bd9df83dd34fe4618fb3 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 10 Aug 2012 19:38:01 -0700 Subject: [PATCH 18/60] Main menu and toolbar --- src/spek-window.cc | 84 ++++++++++++++++++++++++++++++++------------ src/spek-window.hh | 7 ++-- src/spek-window.vala | 65 ---------------------------------- src/spek.cc | 2 +- 4 files changed, 67 insertions(+), 91 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index 84ae301..e25d546 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -16,44 +16,82 @@ * along with Spek. If not, see . */ +#include + #include "spek-window.hh" -enum -{ - ID_Quit = 1, - ID_About, -}; - BEGIN_EVENT_TABLE(SpekWindow, wxFrame) - EVT_MENU(ID_Quit, SpekWindow::OnQuit) - EVT_MENU(ID_About, SpekWindow::OnAbout) + EVT_MENU(wxID_OPEN, SpekWindow::OnOpen) + EVT_MENU(wxID_SAVE, SpekWindow::OnSave) + EVT_MENU(wxID_EXIT, SpekWindow::OnExit) + EVT_MENU(wxID_PREFERENCES, SpekWindow::OnPreferences) + EVT_MENU(wxID_ABOUT, SpekWindow::OnAbout) END_EVENT_TABLE() -SpekWindow::SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size) - : wxFrame(NULL, -1, title, pos, size) +SpekWindow::SpekWindow(const wxString& title) : wxFrame(NULL, -1, title) { - wxMenu *menuFile = new wxMenu(); + // TODO: test on all platforms + SetIcon(wxIcon(wxT("spek"))); - menuFile->Append(ID_About, wxT("&About...")); - menuFile->AppendSeparator(); - menuFile->Append(ID_Quit, wxT("E&xit")); + wxMenuBar *menu = new wxMenuBar(); - wxMenuBar *menuBar = new wxMenuBar(); - menuBar->Append(menuFile, wxT("&File")); + wxMenu *menu_file = new wxMenu(); + wxMenuItem *menu_file_open = new wxMenuItem(menu_file, wxID_OPEN); + menu_file->Append(menu_file_open); + wxMenuItem *menu_file_save = new wxMenuItem(menu_file, wxID_SAVE); + menu_file->Append(menu_file_save); + menu_file->AppendSeparator(); + menu_file->Append(wxID_EXIT); + menu->Append(menu_file, _("&File")); // TODO: stock text - SetMenuBar(menuBar); + wxMenu *menu_edit = new wxMenu(); + wxMenuItem *menu_edit_prefs = new wxMenuItem(menu_edit, wxID_PREFERENCES); + // TODO: check if this is needed + menu_edit_prefs->SetItemLabel(menu_edit_prefs->GetItemLabelText() + wxT("\tCtrl+E")); + menu_edit->Append(menu_edit_prefs); + menu->Append(menu_edit, _("&Edit")); // TODO: stock text + + wxMenu *menu_help = new wxMenu(); + wxMenuItem *menu_help_about = new wxMenuItem(menu_help, wxID_ABOUT); + // TODO: check if this is needed + menu_help_about->SetItemLabel(menu_help_about->GetItemLabelText() + wxT("\tF1")); + menu_help->Append(menu_help_about); + menu->Append(menu_help, _("&Help")); // TODO: stock text + + SetMenuBar(menu); + + wxToolBar *toolbar = CreateToolBar(); + // TODO: bundled file open/save icons suck, provide our own (tango?) + toolbar->AddTool( + wxID_OPEN, + menu_file_open->GetItemLabelText(), + wxArtProvider::GetBitmap(wxART_FILE_OPEN) + ); + toolbar->AddTool( + wxID_SAVE, + menu_file_save->GetItemLabelText(), + wxArtProvider::GetBitmap(wxART_FILE_SAVE) + ); + toolbar->Realize(); } -void SpekWindow::OnQuit(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::OnOpen(wxCommandEvent& WXUNUSED(event)) +{ +} + +void SpekWindow::OnSave(wxCommandEvent& WXUNUSED(event)) +{ +} + +void SpekWindow::OnExit(wxCommandEvent& WXUNUSED(event)) { Close(true); } +void SpekWindow::OnPreferences(wxCommandEvent& WXUNUSED(event)) +{ +} + void SpekWindow::OnAbout(wxCommandEvent& WXUNUSED(event)) { - wxMessageBox( - wxT("This is a wxWidgets' Hello world sample"), - wxT("About Hello World"), - wxOK | wxICON_INFORMATION - ); } diff --git a/src/spek-window.hh b/src/spek-window.hh index 5163374..f7163c0 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -24,10 +24,13 @@ class SpekWindow : public wxFrame { public: - SpekWindow(const wxString& title, const wxPoint& pos, const wxSize& size); + SpekWindow(const wxString& title); protected: - void OnQuit(wxCommandEvent& event); + void OnOpen(wxCommandEvent& event); + void OnSave(wxCommandEvent& event); + void OnExit(wxCommandEvent& event); + void OnPreferences(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); private: diff --git a/src/spek-window.vala b/src/spek-window.vala index 9cad894..8ea9b78 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -31,72 +31,12 @@ namespace Spek { private FileFilter filter_audio; private FileFilter filter_png; - private const Gtk.ActionEntry[] ACTION_ENTRIES = { - { "File", null, N_("_File") }, - { "FileOpen", Stock.OPEN, null, null, null, on_file_open }, - { "FileSave", Stock.SAVE, null, null, null, on_file_save }, - { "FileQuit", Stock.QUIT, null, null, null, on_file_quit }, - { "Edit", null, N_("_Edit") }, - { "EditPreferences", Stock.PREFERENCES, null, "E", null, on_edit_preferences }, - { "Help", null, N_("_Help") }, - { "HelpAbout", Stock.ABOUT, null, "F1", null, on_help_about } - }; - - private const string UI = """ - - - - - - - - - - - - - - - - - - - - - - - -"""; private const Gtk.TargetEntry[] DEST_TARGET_ENTRIES = { { "text/uri-list", 0, 0 } }; public Window (string? file_name) { - description = title = _("Spek - Acoustic Spectrum Analyser"); - set_default_icon_name ("spek"); - set_default_size (640, 480); - destroy.connect (Gtk.main_quit); - - var actions = new Gtk.ActionGroup ("Actions"); - actions.set_translation_domain (Config.GETTEXT_PACKAGE); - actions.add_actions (ACTION_ENTRIES, this); - ui = new UIManager (); - ui.insert_action_group (actions, 0); - add_accel_group (ui.get_accel_group ()); - try { - ui.add_ui_from_string (UI, -1); - } catch (Error e) { - warning ("Could not load the UI: %s\n", e.message); - } - - var menubar = ui.get_widget ("/MenuBar"); - var toolbar = (Toolbar) ui.get_widget ("/ToolBar"); - toolbar.set_style (ToolbarStyle.BOTH_HORIZ); - ((ToolItem) ui.get_widget ("/ToolBar/FileOpen")).is_important = true; - ((ToolItem) ui.get_widget ("/ToolBar/FileSave")).is_important = true; - ((ToolItem) ui.get_widget ("/ToolBar/HelpAbout")).is_important = true; - info_bar = new InfoBar.with_buttons (Stock.OK, ResponseType.OK); var label = new Label (null); label.use_markup = true; @@ -126,17 +66,12 @@ namespace Spek { } var vbox = new VBox (false, 0); - vbox.pack_start (menubar, false, true, 0); - vbox.pack_start (toolbar, false, true, 0); vbox.pack_start (info_bar, false, true, 0); vbox.pack_start (spectrogram, true, true, 0); add (vbox); - menubar.show_all (); - toolbar.show_all (); spectrogram.show_all (); vbox.show (); - Platform.fix_ui (ui); show (); // Set up Drag and Drop diff --git a/src/spek.cc b/src/spek.cc index a8ae66d..fc2a8c4 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -43,7 +43,7 @@ bool Spek::OnInit() return false; } - SpekWindow *window = new SpekWindow(wxT("Hello World"), wxPoint(50,50), wxSize(450,340)); + SpekWindow *window = new SpekWindow(_("Spek - Acoustic Spectrum Analyser")); window->Show(true); SetTopWindow(window); return true; From 4f8de5bdea721a0ae183fb00a28914c10d5f5afb Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 10 Aug 2012 21:44:09 -0700 Subject: [PATCH 19/60] Open file dialogue --- src/spek-window.cc | 20 ++++++++++++++++++++ src/spek-window.hh | 5 +++-- src/spek-window.vala | 17 ----------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index e25d546..039e195 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -77,6 +77,22 @@ SpekWindow::SpekWindow(const wxString& title) : wxFrame(NULL, -1, title) void SpekWindow::OnOpen(wxCommandEvent& WXUNUSED(event)) { + static wxString cur_dir = wxGetHomeDir(); + wxFileDialog *dlg = new wxFileDialog( + this, + _("Open File"), + cur_dir, + wxEmptyString, + wxT("*.*"), + wxFD_OPEN + ); + + if (dlg->ShowModal() == wxID_OK) { + cur_dir = dlg->GetDirectory(); + Open(dlg->GetPath()); + } + + dlg->Destroy(); } void SpekWindow::OnSave(wxCommandEvent& WXUNUSED(event)) @@ -95,3 +111,7 @@ void SpekWindow::OnPreferences(wxCommandEvent& WXUNUSED(event)) void SpekWindow::OnAbout(wxCommandEvent& WXUNUSED(event)) { } + +void SpekWindow::Open(const wxString& path) +{ +} diff --git a/src/spek-window.hh b/src/spek-window.hh index f7163c0..6bc031c 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -26,14 +26,15 @@ class SpekWindow : public wxFrame public: SpekWindow(const wxString& title); -protected: +private: void OnOpen(wxCommandEvent& event); void OnSave(wxCommandEvent& event); void OnExit(wxCommandEvent& event); void OnPreferences(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); -private: + void Open(const wxString& path); + DECLARE_EVENT_TABLE() }; diff --git a/src/spek-window.vala b/src/spek-window.vala index 8ea9b78..3ee26f0 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -110,23 +110,6 @@ namespace Spek { title = _("Spek - %s").printf (Path.get_basename (file_name)); } - private void on_file_open () { - var chooser = new FileChooserDialog ( - _("Open File"), this, FileChooserAction.OPEN, - Stock.CANCEL, ResponseType.CANCEL, - Stock.OPEN, ResponseType.ACCEPT, null); - chooser.set_default_response (ResponseType.ACCEPT); - chooser.select_multiple = false; - chooser.set_current_folder (cur_dir); - chooser.add_filter (filter_all); - chooser.add_filter (filter_audio); - chooser.set_filter (filter_audio); - if (chooser.run () == ResponseType.ACCEPT) { - open_file (chooser.get_filename ()); - } - chooser.destroy (); - } - private void on_file_save () { var chooser = new FileChooserDialog ( _("Save Spectrogram"), this, FileChooserAction.SAVE, From 093e80037d03cc50a95124e4882c445596f2f003 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 10 Aug 2012 21:55:38 -0700 Subject: [PATCH 20/60] Clean up dependency detection --- configure.ac | 19 ++++++------------- src/Makefile.am | 16 +++++++--------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index 2c52129..2f7dc49 100644 --- a/configure.ac +++ b/configure.ac @@ -14,15 +14,15 @@ AC_MSG_CHECKING([the OS]) AS_CASE([$host], [*-*-mingw*], [ os="WIN" - AC_DEFINE([OS_WIN], [1], [Platform]) + AC_DEFINE([OS_WIN], [1], [Windows]) ], [*-*-darwin*], [ os="OSX" - AC_DEFINE([OS_OSX], [1], [Platform]) + AC_DEFINE([OS_OSX], [1], [OS X]) ], [*], [ os="UNIX" - AC_DEFINE([OS_UNIX], [1], [Platform]) + AC_DEFINE([OS_UNIX], [1], [Unix]) ] ) AC_MSG_RESULT([$os]) @@ -30,14 +30,12 @@ AC_MSG_RESULT([$os]) AC_CHECK_LIB(m, log10) pkg_modules="libavformat >= 52.111 libavcodec >= 52.123 libavutil" -PKG_CHECK_MODULES(SPEK, [$pkg_modules]) -AC_SUBST(SPEK_CFLAGS) -AC_SUBST(SPEK_LIBS) +PKG_CHECK_MODULES(FFMPEG, [$pkg_modules]) AM_OPTIONS_WXCONFIG reqwx=2.8.0 -AM_PATH_WXCONFIG($reqwx, wxWin=1) -if test "$wxWin" != 1; then +AM_PATH_WXCONFIG($reqwx, wx=1) +if test "$wx" != 1; then AC_MSG_ERROR([ wxWidgets must be installed on your system. @@ -49,11 +47,6 @@ if test "$wxWin" != 1; then ]) fi -CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" -CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" -CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" -LIBS="$LIBS $WX_LIBS" - GETTEXT_PACKAGE=spek AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package]) AC_SUBST(GETTEXT_PACKAGE) diff --git a/src/Makefile.am b/src/Makefile.am index 5738034..4c1bab4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,18 +15,16 @@ spek_SOURCES = \ spek_CPPFLAGS = \ -include config.h \ - -DLOCALEDIR=\""$(localedir)"\" \ - -DPKGDATADIR=\""$(pkgdatadir)"\" \ - -DPKGLIBDIR=\""$(pkglibdir)"\" + $(WX_CPPFLAGS) spek_CFLAGS = \ - $(SPEK_CFLAGS) \ - @CFLAGS@ + $(FFMPEG_CFLAGS) \ + $(WX_CFLAGS_ONLY) spek_CXXFLAGS = \ - $(SPEK_CFLAGS) \ - @CXXFLAGS@ + $(FFMPEG_CFLAGS) \ + $(WX_CXXFLAGS_ONLY) spek_LDADD = \ - $(SPEK_LIBS) \ - @LIBS@ + $(FFMPEG_LIBS) \ + $(WX_LIBS) \ No newline at end of file From 40096483971a5678372729adce322778216cb1f4 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sat, 11 Aug 2012 14:46:39 -0700 Subject: [PATCH 21/60] Open file --- src/spek-window.cc | 55 +++++++++++++++++++++++++++++++++++++++++++- src/spek-window.vala | 40 -------------------------------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index 039e195..3cab0e1 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -75,20 +75,73 @@ SpekWindow::SpekWindow(const wxString& title) : wxFrame(NULL, -1, title) toolbar->Realize(); } +// TODO: s/audio/media/ +static const char *audio_extensions[] = { + "3gp", + "aac", + "aif", + "aifc", + "aiff", + "amr", + "awb", + "ape", + "au", + "dts", + "flac", + "gsm", + "m4a", + "m4p", + "mp3", + "mp4", + "mp+", + "mpc", + "mpp", + "oga", + "ogg", + "ra", + "ram", + "snd", + "wav", + "wma", + "wv", + NULL +}; + void SpekWindow::OnOpen(wxCommandEvent& WXUNUSED(event)) { static wxString cur_dir = wxGetHomeDir(); + static wxString filters = wxEmptyString; + static int filter_index = 1; + + if (filters.IsEmpty()) { + filters.Alloc(1024); + filters += _("All files"); + filters += wxT("|*.*|"); + filters += _("Audio files"); + filters += wxT("|"); + for (int i = 0; audio_extensions[i]; ++i) { + if (i) { + filters += wxT(";"); + } + filters += wxT("*."); + filters += wxString::FromAscii(audio_extensions[i]); + } + filters.Shrink(); + } + wxFileDialog *dlg = new wxFileDialog( this, _("Open File"), cur_dir, wxEmptyString, - wxT("*.*"), + filters, wxFD_OPEN ); + dlg->SetFilterIndex(filter_index); if (dlg->ShowModal() == wxID_OK) { cur_dir = dlg->GetDirectory(); + filter_index = dlg->GetFilterIndex(); Open(dlg->GetPath()); } diff --git a/src/spek-window.vala b/src/spek-window.vala index 3ee26f0..1747223 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -51,19 +51,10 @@ namespace Spek { info_bar.response.connect(() => info_bar.hide()); spectrogram = new Spectrogram (); - cur_dir = Environment.get_home_dir (); - filter_all = new FileFilter (); - filter_all.set_name (_("All files")); - filter_all.add_pattern ("*"); filter_png = new FileFilter (); filter_png.set_name (_("PNG images")); filter_png.add_pattern ("*.png"); - filter_audio = new FileFilter (); - filter_audio.set_name (_("Audio files")); - foreach (var ext in audio_extensions) { - filter_audio.add_pattern (ext); - } var vbox = new VBox (false, 0); vbox.pack_start (info_bar, false, true, 0); @@ -202,37 +193,6 @@ namespace Spek { Platform.show_uri (link); } - // TODO: s/audio/media/ - private string[] audio_extensions = { - "*.3gp", - "*.aac", - "*.aif", - "*.aifc", - "*.aiff", - "*.amr", - "*.awb", - "*.ape", - "*.au", - "*.dts", - "*.flac", - "*.gsm", - "*.m4a", - "*.m4p", - "*.mp3", - "*.mp4", - "*.mp+", - "*.mpc", - "*.mpp", - "*.oga", - "*.ogg", - "*.ra", - "*.ram", - "*.snd", - "*.wav", - "*.wma", - "*.wv" - }; - private void * check_version () { // Does the user want to check for updates? var prefs = Preferences.instance; From 063d0433c0dd2e92cd9e1f84b3006a29a105fe1e Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 12 Aug 2012 18:34:24 -0700 Subject: [PATCH 22/60] Show opened file name in the window title --- src/spek-window.cc | 12 +++++++++++- src/spek-window.hh | 2 +- src/spek-window.vala | 4 ---- src/spek.cc | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index 3cab0e1..07d1969 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -17,6 +17,7 @@ */ #include +#include #include "spek-window.hh" @@ -28,8 +29,9 @@ BEGIN_EVENT_TABLE(SpekWindow, wxFrame) EVT_MENU(wxID_ABOUT, SpekWindow::OnAbout) END_EVENT_TABLE() -SpekWindow::SpekWindow(const wxString& title) : wxFrame(NULL, -1, title) +SpekWindow::SpekWindow() : wxFrame(NULL, -1, wxEmptyString) { + SetTitle(_("Spek - Acoustic Spectrum Analyser")); // TODO: test on all platforms SetIcon(wxIcon(wxT("spek"))); @@ -167,4 +169,12 @@ void SpekWindow::OnAbout(wxCommandEvent& WXUNUSED(event)) void SpekWindow::Open(const wxString& path) { + wxFileName file_name(path); + if (file_name.FileExists()) { + wxString full_name = file_name.GetFullName(); + // TRANSLATORS: window title, %s is replaced with the file name + 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); + } } diff --git a/src/spek-window.hh b/src/spek-window.hh index 6bc031c..a89fd5d 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -24,7 +24,7 @@ class SpekWindow : public wxFrame { public: - SpekWindow(const wxString& title); + SpekWindow(); private: void OnOpen(wxCommandEvent& event); diff --git a/src/spek-window.vala b/src/spek-window.vala index 1747223..ee4fffe 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -94,11 +94,7 @@ namespace Spek { } private void open_file (string file_name) { - cur_dir = Path.get_dirname (file_name); spectrogram.open (file_name); - - // TRANSLATORS: window title, %s is replaced with the file name - title = _("Spek - %s").printf (Path.get_basename (file_name)); } private void on_file_save () { diff --git a/src/spek.cc b/src/spek.cc index fc2a8c4..567c24a 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -43,7 +43,7 @@ bool Spek::OnInit() return false; } - SpekWindow *window = new SpekWindow(_("Spek - Acoustic Spectrum Analyser")); + SpekWindow *window = new SpekWindow(); window->Show(true); SetTopWindow(window); return true; From 3ecdad345927a15e2c39cddab1bd843287cd0802 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Mon, 13 Aug 2012 21:38:48 -0700 Subject: [PATCH 23/60] Paint the palette --- src/Makefile.am | 2 + src/spek-spectrogram.cc | 170 ++++++++++++++++++++++++++++++++++++++ src/spek-spectrogram.hh | 45 ++++++++++ src/spek-spectrogram.vala | 124 --------------------------- src/spek-window.cc | 12 ++- src/spek-window.hh | 6 +- src/spek-window.vala | 16 ---- src/spek.cc | 8 +- 8 files changed, 239 insertions(+), 144 deletions(-) create mode 100644 src/spek-spectrogram.cc create mode 100644 src/spek-spectrogram.hh diff --git a/src/Makefile.am b/src/Makefile.am index 4c1bab4..af2657f 100644 --- 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 new file mode 100644 index 0000000..b653502 --- /dev/null +++ b/src/spek-spectrogram.cc @@ -0,0 +1,170 @@ +/* spek-spectrogram.cc + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include + +#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 new file mode 100644 index 0000000..77f5dee --- /dev/null +++ b/src/spek-spectrogram.hh @@ -0,0 +1,45 @@ +/* spek-spectrogram.hh + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_SPECTROGRAM_HH_ +#define SPEK_SPECTROGRAM_HH_ + +#include + +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 index 3ef43d2..328c208 100644 --- 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 index 07d1969..29673ea 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -19,6 +19,8 @@ #include #include +#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 index a89fd5d..323747b 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -21,10 +21,12 @@ #include +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 index ee4fffe..767dea6 100644 --- 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 (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 index 567c24a..1e075ee 100644 --- 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; } From f719354bb57b6d4481976950681cb8a42f4cefab Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Mon, 13 Aug 2012 21:51:11 -0700 Subject: [PATCH 24/60] Lowercase --- src/spek-platform.cc | 4 ++-- src/spek-platform.hh | 4 ++-- src/spek-preferences.cc | 20 ++++++++++---------- src/spek-preferences.hh | 16 ++++++++-------- src/spek-spectrogram.cc | 20 ++++++++++---------- src/spek-spectrogram.hh | 12 ++++++------ src/spek-window.cc | 28 ++++++++++++++-------------- src/spek-window.hh | 13 ++++++------- src/spek.cc | 5 +++-- 9 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/spek-platform.cc b/src/spek-platform.cc index b45fe90..3dc2cdc 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -24,7 +24,7 @@ #include "spek-platform.hh" -wxString SpekPlatform::ConfigPath(const wxString& app_name) +wxString SpekPlatform::config_path(const wxString& app_name) { #ifdef OS_WIN wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); @@ -37,7 +37,7 @@ wxString SpekPlatform::ConfigPath(const wxString& app_name) return file_name.GetFullPath(); } -bool SpekPlatform::CanChangeLanguage() +bool SpekPlatform::can_change_language() { #ifdef OS_UNIX return false; diff --git a/src/spek-platform.hh b/src/spek-platform.hh index 5398253..18144f3 100644 --- a/src/spek-platform.hh +++ b/src/spek-platform.hh @@ -26,11 +26,11 @@ class SpekPlatform { public: // Not quite XDG-compatible, but close enough. - static wxString ConfigPath(const wxString& app_name); + static wxString config_path(const wxString& app_name); // Setting non-default locale under GTK+ is tricky (see e.g. how FileZilla does it). We will // just disable the language setting for GTK+ users and will always use the system locale. - static bool CanChangeLanguage(); + static bool can_change_language(); }; extern "C" { diff --git a/src/spek-preferences.cc b/src/spek-preferences.cc index 559f0ea..54bf895 100644 --- a/src/spek-preferences.cc +++ b/src/spek-preferences.cc @@ -22,13 +22,13 @@ #include "spek-preferences.hh" -SpekPreferences& SpekPreferences::Get() +SpekPreferences& SpekPreferences::get() { static SpekPreferences instance; return instance; } -void SpekPreferences::Init() +void SpekPreferences::init() { if (this->locale) { delete this->locale; @@ -36,7 +36,7 @@ void SpekPreferences::Init() this->locale = new wxLocale(); int lang = wxLANGUAGE_DEFAULT; - wxString code = this->GetLanguage(); + wxString code = this->get_language(); if (!code.IsEmpty()) { const wxLanguageInfo *info = wxLocale::FindLanguageInfo(code); if (info) { @@ -49,7 +49,7 @@ void SpekPreferences::Init() SpekPreferences::SpekPreferences() : locale(NULL) { - wxString path = SpekPlatform::ConfigPath(wxT("spek")); + wxString path = SpekPlatform::config_path(wxT("spek")); this->config = new wxFileConfig( wxEmptyString, wxEmptyString, @@ -60,40 +60,40 @@ SpekPreferences::SpekPreferences() : locale(NULL) ); } -bool SpekPreferences::GetCheckUpdate() +bool SpekPreferences::get_check_update() { bool result = true; this->config->Read(wxT("/update/check"), &result); return result; } -void SpekPreferences::SetCheckUpdate(bool value) +void SpekPreferences::set_check_update(bool value) { this->config->Write(wxT("/update/check"), value); this->config->Flush(); } -long SpekPreferences::GetLastUpdate() +long SpekPreferences::get_last_update() { long result = 0; this->config->Read(wxT("/update/last"), &result); return result; } -void SpekPreferences::SetLastUpdate(long value) +void SpekPreferences::set_last_update(long value) { this->config->Write(wxT("/update/last"), value); this->config->Flush(); } -wxString SpekPreferences::GetLanguage() +wxString SpekPreferences::get_language() { wxString result(wxT("")); this->config->Read(wxT("/general/language"), &result); return result; } -void SpekPreferences::SetLanguage(const wxString& value) +void SpekPreferences::set_language(const wxString& value) { this->config->Write(wxT("/general/language"), value); this->config->Flush(); diff --git a/src/spek-preferences.hh b/src/spek-preferences.hh index 368bcf0..9658043 100644 --- a/src/spek-preferences.hh +++ b/src/spek-preferences.hh @@ -25,15 +25,15 @@ class SpekPreferences { public: - static SpekPreferences& Get(); + static SpekPreferences& get(); - void Init(); - bool GetCheckUpdate(); - void SetCheckUpdate(bool value); - long GetLastUpdate(); - void SetLastUpdate(long value); - wxString GetLanguage(); - void SetLanguage(const wxString& value); + void init(); + bool get_check_update(); + void set_check_update(bool value); + long get_last_update(); + void set_last_update(long value); + wxString get_language(); + void set_language(const wxString& value); private: SpekPreferences(); diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index b653502..d36d5d8 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -21,7 +21,7 @@ #include "spek-spectrogram.hh" BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel) - EVT_PAINT(SpekSpectrogram::OnPaint) + EVT_PAINT(SpekSpectrogram::on_paint) END_EVENT_TABLE() enum @@ -45,7 +45,7 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : // Pre-draw the palette. for (int y = 0; y < BANDS; y++) { - uint32_t color = GetColor(y / (double) BANDS); + uint32_t color = get_color(y / (double) BANDS); this->palette.SetRGB( wxRect(0, BANDS - y - 1, RULER, 1), color >> 16, @@ -55,23 +55,23 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : } } -void SpekSpectrogram::Open(const wxString& path) +void SpekSpectrogram::open(const wxString& path) { this->path = path; - Start(); + start(); } -void SpekSpectrogram::Save(const wxString& path) +void SpekSpectrogram::save(const wxString& path) { } -void SpekSpectrogram::OnPaint(wxPaintEvent& evt) +void SpekSpectrogram::on_paint(wxPaintEvent& evt) { wxAutoBufferedPaintDC dc(this); - Render(dc); + render(dc); } -void SpekSpectrogram::Render(wxDC& dc) +void SpekSpectrogram::render(wxDC& dc) { wxSize size = GetClientSize(); int w = size.GetWidth(); @@ -122,14 +122,14 @@ void SpekSpectrogram::Render(wxDC& dc) dc.DrawBitmap(bmp, w - RPAD + GAP, TPAD); } -void SpekSpectrogram::Start() +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) +uint32_t SpekSpectrogram::get_color(double level) { level *= 0.6625; double r = 0.0, g = 0.0, b = 0.0; diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh index 77f5dee..bd2c137 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -25,15 +25,15 @@ class SpekSpectrogram : public wxPanel { public: SpekSpectrogram(wxFrame *parent); - void Open(const wxString& path); - void Save(const wxString& path); + void open(const wxString& path); + void save(const wxString& path); private: - void OnPaint(wxPaintEvent& evt); - void Render(wxDC& dc); + void on_paint(wxPaintEvent& evt); + void render(wxDC& dc); - void Start(); - uint32_t GetColor(double level); + void start(); + uint32_t get_color(double level); wxString path; wxString info; diff --git a/src/spek-window.cc b/src/spek-window.cc index 29673ea..9e2a7fc 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -24,11 +24,11 @@ #include "spek-window.hh" BEGIN_EVENT_TABLE(SpekWindow, wxFrame) - EVT_MENU(wxID_OPEN, SpekWindow::OnOpen) - EVT_MENU(wxID_SAVE, SpekWindow::OnSave) - EVT_MENU(wxID_EXIT, SpekWindow::OnExit) - EVT_MENU(wxID_PREFERENCES, SpekWindow::OnPreferences) - EVT_MENU(wxID_ABOUT, SpekWindow::OnAbout) + EVT_MENU(wxID_OPEN, SpekWindow::on_open) + EVT_MENU(wxID_SAVE, SpekWindow::on_save) + EVT_MENU(wxID_EXIT, SpekWindow::on_exit) + EVT_MENU(wxID_PREFERENCES, SpekWindow::on_preferences) + EVT_MENU(wxID_ABOUT, SpekWindow::on_about) END_EVENT_TABLE() SpekWindow::SpekWindow(const wxString& path) : wxFrame(NULL, -1, wxEmptyString) @@ -81,7 +81,7 @@ SpekWindow::SpekWindow(const wxString& path) : wxFrame(NULL, -1, wxEmptyString) this->spectrogram = new SpekSpectrogram(this); if (!path.IsEmpty()) { - Open(path); + open(path); } } @@ -117,7 +117,7 @@ static const char *audio_extensions[] = { NULL }; -void SpekWindow::OnOpen(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) { static wxString cur_dir = wxGetHomeDir(); static wxString filters = wxEmptyString; @@ -152,30 +152,30 @@ void SpekWindow::OnOpen(wxCommandEvent& WXUNUSED(event)) if (dlg->ShowModal() == wxID_OK) { cur_dir = dlg->GetDirectory(); filter_index = dlg->GetFilterIndex(); - Open(dlg->GetPath()); + open(dlg->GetPath()); } dlg->Destroy(); } -void SpekWindow::OnSave(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_save(wxCommandEvent& WXUNUSED(event)) { } -void SpekWindow::OnExit(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_exit(wxCommandEvent& WXUNUSED(event)) { Close(true); } -void SpekWindow::OnPreferences(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_preferences(wxCommandEvent& WXUNUSED(event)) { } -void SpekWindow::OnAbout(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_about(wxCommandEvent& WXUNUSED(event)) { } -void SpekWindow::Open(const wxString& path) +void SpekWindow::open(const wxString& path) { wxFileName file_name(path); if (file_name.FileExists()) { @@ -185,6 +185,6 @@ void SpekWindow::Open(const wxString& path) // TODO: make sure the above works on all platforms, both in x32 and x64. SetTitle(title); - this->spectrogram->Open(path); + this->spectrogram->open(path); } } diff --git a/src/spek-window.hh b/src/spek-window.hh index 323747b..7a73aff 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -29,13 +29,12 @@ public: SpekWindow(const wxString& path); private: - void OnOpen(wxCommandEvent& event); - void OnSave(wxCommandEvent& event); - void OnExit(wxCommandEvent& event); - void OnPreferences(wxCommandEvent& event); - void OnAbout(wxCommandEvent& event); - - void Open(const wxString& path); + void on_open(wxCommandEvent& event); + void on_save(wxCommandEvent& event); + void on_exit(wxCommandEvent& event); + void on_preferences(wxCommandEvent& event); + void on_about(wxCommandEvent& event); + void open(const wxString& path); SpekSpectrogram *spectrogram; diff --git a/src/spek.cc b/src/spek.cc index 1e075ee..64f5b7b 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -26,11 +26,12 @@ class Spek: public wxApp { -private: +protected: virtual bool OnInit(); virtual void OnInitCmdLine(wxCmdLineParser& parser); virtual bool OnCmdLineParsed(wxCmdLineParser& parser); +private: wxString path; }; @@ -38,7 +39,7 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { - SpekPreferences::Get().Init(); + SpekPreferences::get().init(); spek_audio_init(); if (!wxApp::OnInit()) { From d9177f7d238405adc2a17594769ac9bdf208e600 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 14 Aug 2012 10:40:26 -0700 Subject: [PATCH 25/60] Fix compilation under MXE --- src/spek-audio.c | 2 ++ src/spek-audio.h | 7 +++++-- src/spek-spectrogram.cc | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/spek-audio.c b/src/spek-audio.c index 5012572..64262b8 100644 --- a/src/spek-audio.c +++ b/src/spek-audio.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include "spek-platform.hh" diff --git a/src/spek-audio.h b/src/spek-audio.h index d8335f7..6e3cf34 100644 --- a/src/spek-audio.h +++ b/src/spek-audio.h @@ -26,8 +26,11 @@ extern "C" { #include #include -#include -#include +struct AVFormatContext; +struct AVCodecContext; +struct AVStream; +struct AVCodec; +struct AVPacket; struct spek_audio_context { diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index d36d5d8..1b09886 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -83,22 +83,22 @@ void SpekSpectrogram::render(wxDC& dc) 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); + wxFont normal_font = wxFont(9, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + wxFont large_font = wxFont(normal_font); + large_font.SetPointSize(10); + large_font.SetWeight(wxFONTWEIGHT_BOLD); + wxFont small_font = wxFont(normal_font); + small_font.SetPointSize(8); + dc.SetFont(normal_font); int normal_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); - dc.SetFont(large); + dc.SetFont(large_font); int large_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); // Clean the background. dc.Clear(); // Spek version - dc.SetFont(large); + dc.SetFont(large_font); wxString package_name(wxT(PACKAGE_NAME)); dc.DrawText( package_name, @@ -106,7 +106,7 @@ void SpekSpectrogram::render(wxDC& dc) TPAD - 2 * GAP - normal_height - large_height ); int package_name_width = dc.GetTextExtent(package_name + wxT(" ")).GetWidth(); - dc.SetFont(normal); + dc.SetFont(normal_font); dc.DrawText( wxT(PACKAGE_VERSION), w - RPAD + GAP + package_name_width, From 9d12bd49fe8bbdf835c958832c869d0133dd9ad3 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 14 Aug 2012 20:45:45 -0700 Subject: [PATCH 26/60] spek_audio_desc --- src/Makefile.am | 2 + src/spek-audio-desc.cc | 95 ++++++++++++++++++++++++++++++++++ src/spek-audio-desc.hh | 28 +++++++++++ src/spek-audio.c | 112 ++++++++++++++++++++++++----------------- src/spek-audio.h | 39 +++++++------- src/spek-pipeline.vala | 33 +----------- 6 files changed, 213 insertions(+), 96 deletions(-) create mode 100644 src/spek-audio-desc.cc create mode 100644 src/spek-audio-desc.hh diff --git a/src/Makefile.am b/src/Makefile.am index af2657f..f4a7e93 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,8 @@ spek_SOURCES = \ spek.cc \ spek-audio.c \ spek-audio.h \ + spek-audio-desc.cc \ + spek-audio-desc.hh \ spek-fft.c \ spek-fft.h \ spek-platform.cc \ diff --git a/src/spek-audio-desc.cc b/src/spek-audio-desc.cc new file mode 100644 index 0000000..e3c51a6 --- /dev/null +++ b/src/spek-audio-desc.cc @@ -0,0 +1,95 @@ +/* spek-audio-desc.cc + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include +#include + +#include "spek-audio.h" + +#include "spek-audio-desc.hh" + +wxString spek_audio_desc(const struct spek_audio_properties *properties) +{ + wxArrayString items; + + if (properties->codec_name) { + items.Add(wxString::FromUTF8(properties->codec_name)); + } + if (properties->bit_rate) { + items.Add(wxString::Format(_("%d kbps"), (properties->bit_rate + 500) / 1000)); + } + if (properties->sample_rate) { + items.Add(wxString::Format(_("%d Hz"), properties->sample_rate)); + } + // Include bits per sample only if there is no bitrate. + if (properties->bits_per_sample && !properties->bit_rate) { + items.Add(wxString::Format( + wxPLURAL("%d bit", "%d bits", properties->bits_per_sample), + properties->bits_per_sample + )); + } + if (properties->channels) { + items.Add(wxString::Format( + wxPLURAL("%d channel", "%d channels", properties->channels), + properties->channels + )); + } + + wxString desc; + for (int i = 0; i < items.GetCount(); ++i) { + if (i) { + desc += wxT(", "); + } + desc += items[i]; + } + + if (properties->error) { + wxString error; + switch (properties->error) { + case SPEK_AUDIO_CANNOT_OPEN_FILE: + error = _("Cannot open input file"); + break; + case SPEK_AUDIO_NO_STREAMS: + error = _("Cannot find stream info"); + break; + case SPEK_AUDIO_NO_AUDIO: + error = _("The file contains no audio streams"); + break; + case SPEK_AUDIO_NO_DECODER: + error = _("Cannot find decoder"); + break; + case SPEK_AUDIO_NO_DURATION: + error = _("Unknown duration"); + break; + case SPEK_AUDIO_NO_CHANNELS: + error = _("No audio channels"); + break; + case SPEK_AUDIO_CANNOT_OPEN_DECODER: + error = _("Cannot open decoder"); + break; + case SPEK_AUDIO_BAD_SAMPLE_FORMAT: + error = _("Unsupported sample format"); + break; + } + + // TRANSLATORS: first %s is the error message, second %s is stream description. + desc = wxString::Format(_("%s: %s"), error.c_str(), desc.c_str()); + } + + return desc; +} diff --git a/src/spek-audio-desc.hh b/src/spek-audio-desc.hh new file mode 100644 index 0000000..85e43b7 --- /dev/null +++ b/src/spek-audio-desc.hh @@ -0,0 +1,28 @@ +/* spek-audio-desc.hh + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_AUDIO_DESC_HH_ +#define SPEK_AUDIO_DESC_HH_ + +#include + +struct spek_audio_properties; + +wxString spek_audio_desc(const struct spek_audio_properties *properties); + +#endif diff --git a/src/spek-audio.c b/src/spek-audio.c index 64262b8..b4db794 100644 --- a/src/spek-audio.c +++ b/src/spek-audio.c @@ -26,8 +26,22 @@ #include "spek-audio.h" -// TODO: move translations to UI code, return an error code instead. -#define _ +struct spek_audio_context +{ + char *file_name; // TODO: needed? + char *short_name; + AVFormatContext *format_context; + int audio_stream; + AVCodecContext *codec_context; + AVStream *stream; + AVCodec *codec; + int buffer_size; + AVPacket *packet; + int offset; + + struct spek_audio_properties properties; +}; + void spek_audio_init() { @@ -35,26 +49,33 @@ void spek_audio_init() av_register_all(); } -struct spek_audio_context * spek_audio_open(const char *file_name) +const struct spek_audio_properties * spek_audio_get_properties(struct spek_audio_context *cx) { - struct spek_audio_context *cx = malloc(sizeof(struct spek_audio_context)); - cx->file_name = strdup(file_name); + return &cx->properties; +} + +struct spek_audio_context * spek_audio_open(const char *path) +{ + // TODO: malloc and initialise explicitely + struct spek_audio_context *cx = calloc(1, sizeof(struct spek_audio_context)); + cx->file_name = strdup(path); // av_open_input_file() cannot open files with Unicode chars in it // when running under Windows. When this happens we will re-try // using the corresponding short file name. - cx->short_name = spek_platform_short_path(file_name); + // TODO: test if it's already fixed in FFmpeg + cx->short_name = spek_platform_short_path(path); - if (avformat_open_input(&cx->format_context, file_name, NULL, NULL) != 0) { + if (avformat_open_input(&cx->format_context, path, NULL, NULL) != 0) { if (!cx->short_name || avformat_open_input(&cx->format_context, cx->short_name, NULL, NULL) != 0 ) { - cx->error = _("Cannot open input file"); + cx->properties.error = SPEK_AUDIO_CANNOT_OPEN_FILE; return cx; } } if (avformat_find_stream_info(cx->format_context, NULL) < 0) { // 24-bit APE returns an error but parses the stream info just fine. if (cx->format_context->nb_streams <= 0) { - cx->error = _("Cannot find stream info"); + cx->properties.error = SPEK_AUDIO_NO_STREAMS; return cx; } } @@ -66,65 +87,65 @@ struct spek_audio_context * spek_audio_open(const char *file_name) } } if (cx->audio_stream == -1) { - cx->error = _("The file contains no audio streams"); + cx->properties.error = SPEK_AUDIO_NO_AUDIO; return cx; } cx->stream = cx->format_context->streams[cx->audio_stream]; cx->codec_context = cx->stream->codec; cx->codec = avcodec_find_decoder(cx->codec_context->codec_id); if (cx->codec == NULL) { - cx->error = _("Cannot find decoder"); + cx->properties.error = SPEK_AUDIO_NO_DECODER; return cx; } // We can already fill in the stream info even if the codec won't be able to open it. - cx->codec_name = strdup(cx->codec->long_name); - cx->bit_rate = cx->codec_context->bit_rate; - cx->sample_rate = cx->codec_context->sample_rate; - cx->bits_per_sample = cx->codec_context->bits_per_raw_sample; - if (!cx->bits_per_sample) { + cx->properties.codec_name = strdup(cx->codec->long_name); + cx->properties.bit_rate = cx->codec_context->bit_rate; + cx->properties.sample_rate = cx->codec_context->sample_rate; + cx->properties.bits_per_sample = cx->codec_context->bits_per_raw_sample; + if (!cx->properties.bits_per_sample) { // APE uses bpcs, FLAC uses bprs. - cx->bits_per_sample = cx->codec_context->bits_per_coded_sample; + cx->properties.bits_per_sample = cx->codec_context->bits_per_coded_sample; } - cx->channels = cx->codec_context->channels; + cx->properties.channels = cx->codec_context->channels; if (cx->stream->duration != AV_NOPTS_VALUE) { - cx->duration = cx->stream->duration * av_q2d(cx->stream->time_base); + cx->properties.duration = cx->stream->duration * av_q2d(cx->stream->time_base); } else if (cx->format_context->duration != AV_NOPTS_VALUE) { - cx->duration = cx->format_context->duration / (double) AV_TIME_BASE; + cx->properties.duration = cx->format_context->duration / (double) AV_TIME_BASE; } else { - cx->error = _("Unknown duration"); + cx->properties.error = SPEK_AUDIO_NO_DURATION; return cx; } - if (cx->channels <= 0) { - cx->error = _("No audio channels"); + if (cx->properties.channels <= 0) { + cx->properties.error = SPEK_AUDIO_NO_CHANNELS; return cx; } if (avcodec_open2(cx->codec_context, cx->codec, NULL) < 0) { - cx->error = _("Cannot open decoder"); + cx->properties.error = SPEK_AUDIO_CANNOT_OPEN_DECODER; return cx; } switch (cx->codec_context->sample_fmt) { case SAMPLE_FMT_S16: - cx->width = 16; - cx->fp = false; + cx->properties.width = 16; + cx->properties.fp = false; break; case SAMPLE_FMT_S32: - cx->width = 32; - cx->fp = false; + cx->properties.width = 32; + cx->properties.fp = false; break; case SAMPLE_FMT_FLT: - cx->width = 32; - cx->fp = true; + cx->properties.width = 32; + cx->properties.fp = true; break; case SAMPLE_FMT_DBL: - cx->width = 64; - cx->fp = true; + cx->properties.width = 64; + cx->properties.fp = true; break; default: - cx->error = _("Unsupported sample format"); + cx->properties.error = SPEK_AUDIO_BAD_SAMPLE_FORMAT; return cx; } cx->buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; - cx->buffer = av_malloc(cx->buffer_size); + cx->properties.buffer = av_malloc(cx->buffer_size); cx->packet = av_mallocz(sizeof(AVPacket)); av_init_packet(cx->packet); cx->offset = 0; @@ -133,16 +154,17 @@ struct spek_audio_context * spek_audio_open(const char *file_name) void spek_audio_start(struct spek_audio_context *cx, int samples) { - int64_t rate = cx->sample_rate * (int64_t) cx->stream->time_base.num; + int64_t rate = cx->properties.sample_rate * (int64_t) cx->stream->time_base.num; int64_t duration = (int64_t) - (cx->duration * cx->stream->time_base.den / cx->stream->time_base.num); - cx->error_base = samples * (int64_t)cx->stream->time_base.den; - cx->frames_per_interval = av_rescale_rnd(duration, rate, cx->error_base, AV_ROUND_DOWN); - cx->error_per_interval = (duration * rate) % cx->error_base; + (cx->properties.duration * cx->stream->time_base.den / cx->stream->time_base.num); + cx->properties.error_base = samples * (int64_t)cx->stream->time_base.den; + cx->properties.frames_per_interval = av_rescale_rnd( + duration, rate, cx->properties.error_base, AV_ROUND_DOWN); + cx->properties.error_per_interval = (duration * rate) % cx->properties.error_base; } int spek_audio_read(struct spek_audio_context *cx) { - if (cx->error) { + if (cx->properties.error) { return -1; } @@ -150,7 +172,7 @@ int spek_audio_read(struct spek_audio_context *cx) { while (cx->packet->size > 0) { int buffer_size = cx->buffer_size; int len = avcodec_decode_audio3( - cx->codec_context, (int16_t *)cx->buffer, &buffer_size, cx->packet); + cx->codec_context, (int16_t *)cx->properties.buffer, &buffer_size, cx->packet); if (len < 0) { // Error, skip the frame. cx->packet->size = 0; @@ -195,11 +217,11 @@ void spek_audio_close (struct spek_audio_context *cx) if (cx->short_name != NULL) { free(cx->short_name); } - if (cx->codec_name != NULL) { - free(cx->codec_name); + if (cx->properties.codec_name != NULL) { + free(cx->properties.codec_name); } - if (cx->buffer) { - av_free(cx->buffer); + if (cx->properties.buffer) { + av_free(cx->properties.buffer); } if (cx->packet) { if (cx->packet->data) { diff --git a/src/spek-audio.h b/src/spek-audio.h index 6e3cf34..9218b1d 100644 --- a/src/spek-audio.h +++ b/src/spek-audio.h @@ -26,29 +26,25 @@ extern "C" { #include #include -struct AVFormatContext; -struct AVCodecContext; -struct AVStream; -struct AVCodec; -struct AVPacket; +struct spek_audio_context; -struct spek_audio_context +enum spek_audio_error { - // Internal data. - char *short_name; - AVFormatContext *format_context; - int audio_stream; - AVCodecContext *codec_context; - AVStream *stream; - AVCodec *codec; - int buffer_size; - AVPacket *packet; - int offset; + SPEK_AUDIO_OK = 0, + SPEK_AUDIO_CANNOT_OPEN_FILE, + SPEK_AUDIO_NO_STREAMS, + SPEK_AUDIO_NO_AUDIO, + SPEK_AUDIO_NO_DECODER, + SPEK_AUDIO_NO_DURATION, + SPEK_AUDIO_NO_CHANNELS, + SPEK_AUDIO_CANNOT_OPEN_DECODER, + SPEK_AUDIO_BAD_SAMPLE_FORMAT, +}; - // Exposed properties. - char *file_name; +struct spek_audio_properties +{ char *codec_name; - char *error; + enum spek_audio_error error; int bit_rate; int sample_rate; int bits_per_sample; @@ -56,6 +52,7 @@ struct spek_audio_context bool fp; // floating-point sample representation int channels; double duration; + // TODO: these four guys don't belong here, move them somewhere else when revamping the pipeline uint8_t *buffer; int64_t frames_per_interval; int64_t error_per_interval; @@ -67,7 +64,9 @@ void spek_audio_init(); // Open the file, check if it has an audio stream which can be decoded. // On error, initialises the `error` field in the returned context. -struct spek_audio_context * spek_audio_open(const char *file_name); +struct spek_audio_context * spek_audio_open(const char *path); + +const struct spek_audio_properties * spek_audio_get_properties(struct spek_audio_context *cs); // Prepare the context for reading audio samples. void spek_audio_start(struct spek_audio_context *cx, int samples); diff --git a/src/spek-pipeline.vala b/src/spek-pipeline.vala index 2fa7440..d369acc 100644 --- a/src/spek-pipeline.vala +++ b/src/spek-pipeline.vala @@ -25,9 +25,6 @@ namespace Spek { public class Pipeline { - public string description { get; private set; } - public int sample_rate { get; private set; } - public double duration { get { return cx.duration; } } public delegate void Callback (int sample, float[] values); private Audio.Context cx; @@ -61,33 +58,7 @@ namespace Spek { this.threshold = threshold; this.cb = cb; - // Build the description string. - string[] items = {}; - if (cx.codec_name != null) { - items += cx.codec_name; - } - if (cx.bit_rate != 0) { - items += _("%d kbps").printf ((cx.bit_rate + 500) / 1000); - } - if (cx.sample_rate != 0) { - items += _("%d Hz").printf (cx.sample_rate); - } - // Show bits per sample only if there is no bitrate. - if (cx.bits_per_sample != 0 && cx.bit_rate == 0) { - items += ngettext ( - "%d bit", "%d bits", cx.bits_per_sample).printf (cx.bits_per_sample); - } - if (cx.channels != 0) { - items += ngettext ("%d channel", "%d channels", cx.channels). - printf (cx.channels); - } - description = items.length > 0 ? string.joinv (", ", items) : ""; - - if (cx.error != null) { - // TRANSLATORS: first %s is the error message, second %s is stream description. - description = _("%s: %s").printf (cx.error, description); - } else { - this.sample_rate = cx.sample_rate; + if (!cx.error) { this.nfft = 2 * bands - 2; this.coss = new float[nfft]; float cf = 2f * (float) Math.PI / this.nfft; @@ -109,7 +80,7 @@ namespace Spek { public void start () { stop (); - if (cx.error != null) return; + if (!cx.error) return; input_pos = 0; reader_mutex = new Mutex (); From 4df42e8258e98431392d4feeb06cdb67457aa221 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 14 Aug 2012 21:53:01 -0700 Subject: [PATCH 27/60] Migrate the pipeline to C and pthreads --- configure.ac | 3 +- src/Makefile.am | 9 +- src/spek-fft.c | 3 +- src/spek-fft.h | 4 +- src/spek-pipeline.c | 355 +++++++++++++++++++++++++++++++++++++++++ src/spek-pipeline.h | 44 +++++ src/spek-pipeline.vala | 273 ------------------------------- 7 files changed, 411 insertions(+), 280 deletions(-) create mode 100644 src/spek-pipeline.c create mode 100644 src/spek-pipeline.h delete mode 100644 src/spek-pipeline.vala diff --git a/configure.ac b/configure.ac index 2f7dc49..409e891 100644 --- a/configure.ac +++ b/configure.ac @@ -29,8 +29,7 @@ AC_MSG_RESULT([$os]) AC_CHECK_LIB(m, log10) -pkg_modules="libavformat >= 52.111 libavcodec >= 52.123 libavutil" -PKG_CHECK_MODULES(FFMPEG, [$pkg_modules]) +PKG_CHECK_MODULES(FFMPEG, [libavformat >= 52.111 libavcodec >= 52.123 libavutil]) AM_OPTIONS_WXCONFIG reqwx=2.8.0 diff --git a/src/Makefile.am b/src/Makefile.am index f4a7e93..d4da183 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,8 @@ spek_SOURCES = \ spek-audio-desc.hh \ spek-fft.c \ spek-fft.h \ + spek-pipeline.c \ + spek-pipeline.h \ spek-platform.cc \ spek-platform.hh \ spek-preferences.cc \ @@ -19,6 +21,7 @@ spek_SOURCES = \ spek_CPPFLAGS = \ -include config.h \ + -pthread \ $(WX_CPPFLAGS) spek_CFLAGS = \ @@ -26,9 +29,11 @@ spek_CFLAGS = \ $(WX_CFLAGS_ONLY) spek_CXXFLAGS = \ - $(FFMPEG_CFLAGS) \ $(WX_CXXFLAGS_ONLY) spek_LDADD = \ $(FFMPEG_LIBS) \ - $(WX_LIBS) \ No newline at end of file + $(WX_LIBS) + +spek_LDFLAGS = \ + -pthread diff --git a/src/spek-fft.c b/src/spek-fft.c index e9ad371..ea545b7 100644 --- a/src/spek-fft.c +++ b/src/spek-fft.c @@ -17,6 +17,7 @@ */ #include +#include #include #include "spek-fft.h" @@ -55,7 +56,7 @@ void spek_fft_execute(struct spek_fft_plan *p) } } -void spek_fft_destroy(struct spek_fft_plan *p) +void spek_fft_delete(struct spek_fft_plan *p) { av_rdft_end(p->cx); av_free(p->input); diff --git a/src/spek-fft.h b/src/spek-fft.h index b715256..dd7f99a 100644 --- a/src/spek-fft.h +++ b/src/spek-fft.h @@ -23,12 +23,12 @@ extern "C" { #endif -#include +struct RDFTContext; struct spek_fft_plan { // Internal data. - RDFTContext *cx; + struct RDFTContext *cx; int n; int threshold; diff --git a/src/spek-pipeline.c b/src/spek-pipeline.c new file mode 100644 index 0000000..2c42e10 --- /dev/null +++ b/src/spek-pipeline.c @@ -0,0 +1,355 @@ +/* spek-pipeline.c + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + * + * Conversion of decoded samples into an FFT-happy format is heavily + * influenced by GstSpectrum which is part of gst-plugins-good. + * The original code: + * (c) 1999 Erik Walthinsen + * (c) 2006 Stefan Kost + * (c) 2007-2009 Sebastian Dröge + */ + +#include +#include +#include +#include +#include + +#include "spek-audio.h" +#include "spek-fft.h" + +#include "spek-pipeline.h" + +enum +{ + NFFT = 64 // Number of FFTs to pre-fetch. +}; + +struct spek_pipeline +{ + struct spek_audio_context *cx; + const struct spek_audio_properties *properties; + int bands; + int samples; + int threshold; + spek_pipeline_cb cb; + + struct spek_fft_plan *fft; + float *coss; // Pre-computed cos table. + int nfft; // Size of the FFT transform. + int input_size; + int input_pos; + float *input; + float *output; + + pthread_t reader_thread; + bool has_reader_thread; + pthread_mutex_t reader_mutex; + bool has_reader_mutex; + pthread_cond_t reader_cond; + bool has_reader_cond; + pthread_t worker_thread; + bool has_worker_thread; + pthread_mutex_t worker_mutex; + bool has_worker_mutex; + pthread_cond_t worker_cond; + bool has_worker_cond; + bool worker_done; + volatile bool quit; +}; + +// Forward declarations. +static void * reader_func(void *); +static void * worker_func(void *); +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) +{ + struct spek_pipeline *p = malloc(sizeof(struct spek_pipeline)); + p->cx = spek_audio_open(path); + p->properties = spek_audio_get_properties(p->cx); + p->bands = bands; + p->samples = samples; + p->threshold = threshold; + p->cb = cb; + + p->coss = NULL; + p->fft = NULL; + p->input = NULL; + p->output = NULL; + p->has_reader_thread = false; + p->has_reader_mutex = false; + p->has_reader_cond = false; + p->has_worker_thread = false; + p->has_worker_mutex = false; + p->has_worker_cond = false; + + if (!p->properties->error) { + p->nfft = 2 * bands - 2; + p->coss = malloc(p->nfft * sizeof(float)); + float cf = 2.0f * (float)M_PI / p->nfft; + for (int i = 0; i < p->nfft; ++i) { + p->coss[i] = cosf(cf * i); + } + p->fft = spek_fft_plan_new(p->nfft, threshold); + p->input_size = p->nfft * (NFFT * 2 + 1); + p->input = malloc(p->input_size * sizeof(float)); + p->output = malloc(bands * sizeof(float)); + spek_audio_start(p->cx, samples); + } +} + +void spek_pipeline_start(struct spek_pipeline *p) +{ + if (!p->properties->error) return; + + p->input_pos = 0; + p->worker_done = false; + p->quit = false; + + p->has_reader_mutex = !pthread_mutex_init(&p->reader_mutex, NULL); + p->has_reader_cond = !pthread_cond_init(&p->reader_cond, NULL); + p->has_worker_mutex = !pthread_mutex_init(&p->worker_mutex, NULL); + p->has_worker_cond = !pthread_cond_init(&p->worker_cond, NULL); + + p->has_reader_thread = !pthread_create(&p->reader_thread, NULL, &reader_func, p); + if (!p->has_reader_thread) { + spek_pipeline_close(p); + } +} + +void spek_pipeline_close(struct spek_pipeline *p) { + if (p->has_reader_thread) { + p->quit = true; + pthread_join(p->reader_thread, NULL); + p->has_reader_thread = false; + } + if (p->has_worker_cond) { + pthread_cond_destroy(&p->worker_cond); + p->has_worker_cond = false; + } + if (p->has_worker_mutex) { + pthread_mutex_destroy(&p->worker_mutex); + p->has_worker_mutex = false; + } + if (p->has_reader_cond) { + pthread_cond_destroy(&p->reader_cond); + p->has_reader_cond = false; + } + if (p->has_reader_mutex) { + pthread_mutex_destroy(&p->reader_mutex); + p->has_reader_mutex = false; + } + if (p->output) { + free(p->output); + p->output = NULL; + } + if (p->input) { + free(p->input); + p->input = NULL; + } + if (p->fft) { + spek_fft_delete(p->fft); + p->fft = NULL; + } + if (p->coss) { + free(p->coss); + p->coss = NULL; + } + if (p->cx) { + spek_audio_close(p->cx); + p->cx = NULL; + } +} + +static void * reader_func (void *pp) { + struct spek_pipeline *p = pp; + + p->has_worker_thread = !pthread_create(&p->worker_thread, NULL, &worker_func, p); + if (!p->has_worker_thread) { + return NULL; + } + + int pos = 0, prev_pos = 0; + int block_size = p->properties->width * p->properties->channels / 8; + int size; + while ((size = spek_audio_read(p->cx)) > 0) { + if (p->quit) break; + + uint8_t *buffer = p->properties->buffer; + while (size >= block_size) { + p->input[pos] = average_input(p, buffer); + buffer += block_size; + size -= block_size; + pos = (pos + 1) % p->input_size; + + // Wake up the worker if we have enough data. + if ((pos > prev_pos ? pos : pos + p->input_size) - prev_pos == p->nfft * NFFT) { + reader_sync(p, prev_pos = pos); + } + } + assert(size == 0); + } + + if (pos != prev_pos) { + // Process the remaining data. + reader_sync(p, pos); + } + + // Force the worker to quit. + reader_sync(p, -1); + pthread_join(p->worker_thread, NULL); + return NULL; +} + +static void reader_sync(struct spek_pipeline *p, int pos) +{ + pthread_mutex_lock(&p->reader_mutex); + while (!p->worker_done) { + pthread_cond_wait(&p->reader_cond, &p->reader_mutex); + } + p->worker_done = false; + pthread_mutex_unlock(&p->reader_mutex); + + pthread_mutex_lock(&p->worker_mutex); + p->input_pos = pos; + pthread_cond_signal(&p->worker_cond); + pthread_mutex_unlock(&p->worker_mutex); +} + +static void * worker_func (void *pp) { + struct spek_pipeline *p = pp; + + int sample = 0; + int64_t frames = 0; + int64_t num_fft = 0; + int64_t acc_error = 0; + int head = 0, tail = 0; + int prev_head = 0; + + memset(p->output, 0, sizeof(float) * p->bands); + + while (true) { + pthread_mutex_lock(&p->reader_mutex); + p->worker_done = true; + pthread_cond_signal(&p->reader_cond); + pthread_mutex_unlock(&p->reader_mutex); + + pthread_mutex_lock(&p->worker_mutex); + while (tail == p->input_pos) { + pthread_cond_wait(&p->worker_cond, &p->worker_mutex); + } + tail = p->input_pos; + pthread_mutex_unlock(&p->worker_mutex); + + if (tail == -1) { + return NULL; + } + + while (true) { + head = (head + 1) % p->input_size; + if (head == tail) { + head = prev_head; + break; + } + frames++; + + // If we have enough frames for an FFT or we have + // all frames required for the interval run and FFT. + bool int_full = + acc_error < p->properties->error_base && + frames == p->properties->frames_per_interval; + bool int_over = + acc_error >= p->properties->error_base && + frames == 1 + p->properties->frames_per_interval; + + if (frames % p->nfft == 0 || ((int_full || int_over) && num_fft == 0)) { + 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]); + p->fft->input[i] = val; + } + spek_fft_execute(p->fft); + num_fft++; + for (int i = 0; i < p->bands; i++) { + p->output[i] += p->fft->output[i]; + } + } + + // Do we have the FFTs for one interval? + if (int_full || int_over) { + if (int_over) { + acc_error -= p->properties->error_base; + } else { + acc_error += p->properties->error_per_interval; + } + + for (int i = 0; i < p->bands; i++) { + p->output[i] /= num_fft; + } + + if (sample == p->samples) break; + p->cb(sample++, p->output); + + memset(p->output, 0, sizeof(float) * p->bands); + frames = 0; + num_fft = 0; + } + } + } +} + +static float average_input(const struct spek_pipeline *p, void *buffer) +{ + int channels = p->properties->channels; + float res = 0.0f; + if (p->properties->fp) { + if (p->properties->width == 32) { + float *b = buffer; + for (int i = 0; i < channels; i++) { + res += b[i]; + } + } else { + assert(p->properties->width == 64); + double *b = buffer; + for (int i = 0; i < channels; i++) { + res += (float) b[i]; + } + } + } else { + if (p->properties->width == 16) { + int16_t *b = buffer; + for (int i = 0; i < channels; i++) { + res += b[i] / (float) INT16_MAX; + } + } else { + assert (p->properties->width == 32); + int32_t *b = buffer; + for (int i = 0; i < channels; i++) { + res += b[i] / (float) INT32_MAX; + } + } + } + return res / channels; +} diff --git a/src/spek-pipeline.h b/src/spek-pipeline.h new file mode 100644 index 0000000..75af2e3 --- /dev/null +++ b/src/spek-pipeline.h @@ -0,0 +1,44 @@ +/* spek-pipeline.h + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_PIPELINE_H_ +#define SPEK_PIPELINE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct spek_pipeline; +struct spek_audio_properties; + +typedef void (*spek_pipeline_cb)(int sample, float *values); + +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 struct spek_audio_properties * spek_pipeline_properties(struct spek_pipeline *pipeline); + +void spek_pipeline_close(struct spek_pipeline *pipeline); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/spek-pipeline.vala b/src/spek-pipeline.vala deleted file mode 100644 index d369acc..0000000 --- a/src/spek-pipeline.vala +++ /dev/null @@ -1,273 +0,0 @@ -/* spek-pipeline.vala - * - * Copyright (C) 2010 Alexander Kojevnikov - * - * 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 . - * - * Conversion of decoded samples into an FFT-happy format is heavily - * influenced by GstSpectrum which is part of gst-plugins-good. - * The original code: - * (c) 1999 Erik Walthinsen - * (c) 2006 Stefan Kost - * (c) 2007-2009 Sebastian Dröge - */ - -namespace Spek { - public class Pipeline { - public delegate void Callback (int sample, float[] values); - - private Audio.Context cx; - private int bands; - private int samples; - private int threshold; - private Callback cb; - - private Fft.Plan fft; - private int nfft; // Size of the FFT transform. - private float[] coss; // Pre-computed cos table. - private const int NFFT = 64; // Number of FFTs to pre-fetch. - private int input_size; - private int input_pos; - private float[] input; - private float[] output; - - private unowned Thread reader_thread = null; - private unowned Thread worker_thread; - private Mutex reader_mutex; - private Cond reader_cond; - private Mutex worker_mutex; - private Cond worker_cond; - private bool worker_done = false; - private bool quit = false; - - public Pipeline (string file_name, int bands, int samples, int threshold, Callback cb) { - this.cx = new Audio.Context (file_name); - this.bands = bands; - this.samples = samples; - this.threshold = threshold; - this.cb = cb; - - if (!cx.error) { - this.nfft = 2 * bands - 2; - this.coss = new float[nfft]; - float cf = 2f * (float) Math.PI / this.nfft; - for (int i = 0; i < this.nfft; i++) { - this.coss[i] = Math.cosf (cf * i); - } - this.fft = new Fft.Plan (nfft, threshold); - this.input_size = nfft * (NFFT * 2 + 1); - this.input = new float[input_size]; - this.output = new float[bands]; - this.cx.start (samples); - } - } - - ~Pipeline () { - stop (); - } - - public void start () { - stop (); - - if (!cx.error) return; - - input_pos = 0; - reader_mutex = new Mutex (); - reader_cond = new Cond (); - worker_mutex = new Mutex (); - worker_cond = new Cond (); - - try { - reader_thread = Thread.create (reader_func, true); - } catch (ThreadError e) { - stop (); - } - } - - public void stop () { - if (reader_thread != null) { - lock (quit) { - quit = true; - } - reader_thread.join (); - quit = false; - reader_thread = null; - } - } - - private void * reader_func () { - var timeval = TimeVal (); - timeval.get_current_time (); - - int pos = 0, prev_pos = 0; - int block_size = cx.width * cx.channels / 8; - int size; - - try { - worker_thread = Thread.create (worker_func, true); - } catch (ThreadError e) { - return null; - } - - while ((size = cx.read ()) > 0) { - lock (quit) if (quit) break; - - uint8 *buffer = (uint8 *) cx.buffer; - while (size >= block_size) { - input[pos] = average_input (buffer); - buffer += block_size; - size -= block_size; - pos = (pos + 1) % input_size; - - // Wake up the worker if we have enough data. - if ((pos > prev_pos ? pos : pos + input_size) - prev_pos == nfft * NFFT) { - reader_sync (prev_pos = pos); - } - } - assert (size == 0); - } - - if (pos != prev_pos) { - // Process the remaining data. - reader_sync (pos); - } - // Force the worker to quit. - reader_sync (-1); - worker_thread.join (); - return null; - } - - private void reader_sync (int pos) { - reader_mutex.lock (); - while (!worker_done) reader_cond.wait (reader_mutex); - worker_done = false; - reader_mutex.unlock (); - - worker_mutex.lock (); - input_pos = pos; - worker_cond.signal (); - worker_mutex.unlock (); - } - - private void * worker_func () { - int sample = 0; - int64 frames = 0; - int64 num_fft = 0; - int64 acc_error = 0; - int head = 0, tail = 0; - int prev_head = 0; - - Memory.set (output, 0, sizeof (float) * bands); - - while (true) { - reader_mutex.lock (); - worker_done = true; - reader_cond.signal (); - reader_mutex.unlock (); - - worker_mutex.lock (); - while (tail == input_pos) worker_cond.wait (worker_mutex); - tail = input_pos; - worker_mutex.unlock (); - - if (tail == -1) { - return null; - } - - while (true) { - head = (head + 1) % input_size; - if (head == tail) { - head = prev_head; - break; - } - frames++; - - // If we have enough frames for an FFT or we have - // all frames required for the interval run and FFT. - bool int_full = acc_error < cx.error_base && frames == cx.frames_per_interval; - bool int_over = acc_error >= cx.error_base && frames == 1 + cx.frames_per_interval; - if (frames % nfft == 0 || ((int_full || int_over) && num_fft == 0)) { - prev_head = head; - for (int i = 0; i < nfft; i++) { - float val = input[(input_size + head - nfft + i) % 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 * (1f - coss[i]); - fft.input[i] = val; - } - fft.execute (); - num_fft++; - for (int i = 0; i < bands; i++) { - output[i] += fft.output[i]; - } - } - // Do we have the FFTs for one interval? - if (int_full || int_over) { - if (int_over) { - acc_error -= cx.error_base; - } else { - acc_error += cx.error_per_interval; - } - - for (int i = 0; i < bands; i++) { - output[i] /= num_fft; - } - - if (sample == samples) break; - cb (sample++, output); - - Memory.set (output, 0, sizeof (float) * bands); - frames = 0; - num_fft = 0; - } - } - } - } - - private float average_input (uint8 *buffer) { - int channels = cx.channels; - float res = 0f; - if (cx.fp) { - if (cx.width == 32) { - float *p = (float *) buffer; - for (int i = 0; i < channels; i++) { - res += p[i]; - } - } else { - assert (cx.width == 64); - double *p = (double *) buffer; - for (int i = 0; i < channels; i++) { - res += (float) p[i]; - } - } - } else { - if (cx.width == 16) { - int16 *p = (int16 *) buffer; - for (int i = 0; i < channels; i++) { - res += p[i] / (float) int16.MAX; - } - } else { - assert (cx.width == 32); - int32 *p = (int32 *) buffer; - for (int i = 0; i < channels; i++) { - res += p[i] / (float) int32.MAX; - } - } - } - return res / channels; - } - } -} From f81ce84826b48f48c655bcf70343d99eb88bac74 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 00:56:20 -0700 Subject: [PATCH 28/60] Run the pipeline --- src/spek-pipeline.c | 12 +++++++-- src/spek-pipeline.h | 8 +++--- src/spek-spectrogram.cc | 57 ++++++++++++++++++++++++++++++++++++++- src/spek-spectrogram.hh | 9 +++++-- src/spek-spectrogram.vala | 36 ------------------------- 5 files changed, 77 insertions(+), 45 deletions(-) diff --git a/src/spek-pipeline.c b/src/spek-pipeline.c index 2c42e10..3f7ce39 100644 --- 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 index 75af2e3..4cc5642 100644 --- 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 index 1b09886..1c99f40 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -16,8 +16,12 @@ * along with Spek. If not, see . */ +#include #include +#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 index bd2c137..0ee94f3 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -21,6 +21,8 @@ #include +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 index 328c208..76680ad 100644 --- 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); From 98b2cb0ab868bcae5a8cbce73672b3ef435ca4f5 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 09:46:50 -0700 Subject: [PATCH 29/60] Draw the spectrogram --- src/spek-pipeline.c | 4 +++- src/spek-spectrogram.cc | 29 ++++++++++++++++++++++++----- src/spek-spectrogram.hh | 2 ++ src/spek-spectrogram.vala | 19 ------------------- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/spek-pipeline.c b/src/spek-pipeline.c index 3f7ce39..e9b868a 100644 --- a/src/spek-pipeline.c +++ b/src/spek-pipeline.c @@ -115,6 +115,8 @@ struct spek_pipeline * spek_pipeline_open( p->output = malloc(bands * sizeof(float)); spek_audio_start(p->cx, samples); } + + return p; } const struct spek_audio_properties * spek_pipeline_properties(struct spek_pipeline *pipeline) @@ -124,7 +126,7 @@ const struct spek_audio_properties * spek_pipeline_properties(struct spek_pipeli void spek_pipeline_start(struct spek_pipeline *p) { - if (!p->properties->error) return; + if (p->properties->error) return; p->input_pos = 0; p->worker_done = false; diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 1c99f40..8391b92 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -26,6 +26,7 @@ BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel) EVT_PAINT(SpekSpectrogram::on_paint) + EVT_SIZE(SpekSpectrogram::on_size) END_EVENT_TABLE() enum @@ -45,7 +46,8 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE), pipeline(NULL), palette(RULER, BANDS), - image() + image(1, 1), + prev_width(-1) { SetBackgroundStyle(wxBG_STYLE_CUSTOM); @@ -77,6 +79,17 @@ void SpekSpectrogram::on_paint(wxPaintEvent& evt) render(dc); } +void SpekSpectrogram::on_size(wxSizeEvent& evt) +{ + wxSize size = GetClientSize(); + bool width_changed = this->prev_width != size.GetWidth(); + this->prev_width = size.GetWidth(); + + if (!this->path.IsEmpty() && width_changed) { + start(); + } +} + void SpekSpectrogram::render(wxDC& dc) { wxSize size = GetClientSize(); @@ -119,6 +132,12 @@ void SpekSpectrogram::render(wxDC& dc) TPAD - 2 * GAP - 2 * normal_height ); + if (this->image.GetHeight() > 1) { + // Draw the spectrogram. + wxBitmap bmp(this->image.Scale(w - LPAD - RPAD, h - TPAD - BPAD /*TODO:, wxIMAGE_QUALITY_HIGH*/)); + dc.DrawBitmap(bmp, LPAD, TPAD); + } + // Border around the spectrogram. // TODO: check if this uses antialiasing dc.DrawRectangle(LPAD, TPAD, w - LPAD - RPAD, h - TPAD - BPAD); @@ -139,20 +158,20 @@ void SpekSpectrogram::pipeline_cb(int sample, float *values, void *cb_data) uint32_t color = get_color(level); s->image.SetRGB( sample, - y, + BANDS - y - 1, color >> 16, (color >> 8) & 0xFF, color & 0xFF ); } - s->Refresh(false); // TODO: refresh only one pixel column + s->Refresh(); // TODO: refresh only one pixel column } void SpekSpectrogram::start() { - if(this->pipeline) { + if (this->pipeline) { spek_pipeline_close(this->pipeline); this->pipeline = NULL; } @@ -178,7 +197,7 @@ void SpekSpectrogram::start() this->image.Create(1, 1); } - Refresh(false); + Refresh(); } // Modified version of Dan Bruton's algorithm: diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh index 0ee94f3..2a9b52a 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -32,6 +32,7 @@ public: private: void on_paint(wxPaintEvent& evt); + void on_size(wxSizeEvent& evt); void render(wxDC& dc); void start(); @@ -43,6 +44,7 @@ private: wxString desc; wxImage palette; wxImage image; + int prev_width; DECLARE_EVENT_TABLE() }; diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala index 76680ad..cdc77a6 100644 --- a/src/spek-spectrogram.vala +++ b/src/spek-spectrogram.vala @@ -36,18 +36,6 @@ namespace Spek { surface.write_to_png (file_name); } - private int prev_width = -1; - protected override void size_allocate (Gdk.Rectangle allocation) { - base.size_allocate (allocation); - - bool width_changed = prev_width != allocation.width; - prev_width = allocation.width; - - if (file_name != null && width_changed) { - start (); - } - } - protected override bool expose_event (EventExpose event) { var window = get_window (); var cr = cairo_create (window); @@ -64,13 +52,6 @@ namespace Spek { int text_width, text_height; if (image != null) { - // Draw the spectrogram. - cr.translate (LPAD, h - BPAD); - cr.scale (1, -(h - TPAD - BPAD) / image.get_height ()); - cr.set_source_surface (image, 0, 0); - cr.paint (); - cr.identity_matrix (); - // Prepare to draw the rulers. cr.set_source_rgb (1, 1, 1); cr.set_line_width (1); From 38cc7f2343a14150e7554b98581579b94f12ffc7 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 09:54:40 -0700 Subject: [PATCH 30/60] Draw file properties --- src/spek-spectrogram.cc | 10 ++++++++++ src/spek-spectrogram.vala | 19 ------------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 8391b92..970f462 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -136,6 +136,16 @@ void SpekSpectrogram::render(wxDC& dc) // Draw the spectrogram. wxBitmap bmp(this->image.Scale(w - LPAD - RPAD, h - TPAD - BPAD /*TODO:, wxIMAGE_QUALITY_HIGH*/)); dc.DrawBitmap(bmp, LPAD, TPAD); + + // File name. + dc.SetFont(large_font); + // TODO: ellipsize + dc.DrawText(this->path, LPAD, TPAD - 2 * GAP - normal_height - large_height); + + // File properties. + dc.SetFont(normal_font); + // TODO: ellipsize + dc.DrawText(this->desc, LPAD, TPAD - GAP - normal_height); } // Border around the spectrogram. diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala index cdc77a6..3d1e7c2 100644 --- a/src/spek-spectrogram.vala +++ b/src/spek-spectrogram.vala @@ -92,25 +92,6 @@ namespace Spek { cr.translate (LPAD, TPAD); rate_ruler.draw (cr, layout); cr.identity_matrix (); - - // File properties. - cr.move_to (LPAD, TPAD - GAP); - layout.set_font_description (FontDescription.from_string ( - "Sans " + (9 * FONT_SCALE).to_string ())); - layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE); - layout.set_ellipsize (EllipsizeMode.END); - layout.set_text (info, -1); - cairo_show_layout_line (cr, layout.get_line (0)); - layout.get_pixel_size (out text_width, out text_height); - - // File name. - cr.move_to (LPAD, TPAD - 2 * GAP - text_height); - layout.set_font_description (FontDescription.from_string ( - "Sans Bold " + (10 * FONT_SCALE).to_string ())); - layout.set_width ((int) (w - LPAD - RPAD) * Pango.SCALE); - layout.set_ellipsize (EllipsizeMode.START); - layout.set_text (file_name, -1); - cairo_show_layout_line (cr, layout.get_line (0)); } // Prepare to draw the ruler. From 3805a551fbfc738cc2f51e3b5c054653e03f0222 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 10:24:22 -0700 Subject: [PATCH 31/60] Force re-paint --- src/spek-spectrogram.cc | 7 +++++++ src/spek-spectrogram.hh | 1 + 2 files changed, 8 insertions(+) diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 970f462..98e4cbc 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -25,6 +25,7 @@ #include "spek-spectrogram.hh" BEGIN_EVENT_TABLE(SpekSpectrogram, wxPanel) + EVT_IDLE(SpekSpectrogram::on_idle) EVT_PAINT(SpekSpectrogram::on_paint) EVT_SIZE(SpekSpectrogram::on_size) END_EVENT_TABLE() @@ -73,6 +74,11 @@ void SpekSpectrogram::save(const wxString& path) { } +void SpekSpectrogram::on_idle(wxIdleEvent& evt) +{ + Update(); +} + void SpekSpectrogram::on_paint(wxPaintEvent& evt) { wxAutoBufferedPaintDC dc(this); @@ -176,6 +182,7 @@ void SpekSpectrogram::pipeline_cb(int sample, float *values, void *cb_data) } s->Refresh(); // TODO: refresh only one pixel column + wxWakeUpIdle(); } diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh index 2a9b52a..9158db3 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -31,6 +31,7 @@ public: void save(const wxString& path); private: + void on_idle(wxIdleEvent& evt); void on_paint(wxPaintEvent& evt); void on_size(wxSizeEvent& evt); void render(wxDC& dc); From 95d5c87fd26ac007581e594ebb4ec46fcf9b7078 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 22:39:35 -0700 Subject: [PATCH 32/60] Fix compile error --- src/spek-spectrogram.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh index 9158db3..db0fd61 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -19,6 +19,7 @@ #ifndef SPEK_SPECTROGRAM_HH_ #define SPEK_SPECTROGRAM_HH_ +#include #include struct spek_pipeline; From f41b33fbac5143b0af4c357539c9a2460f1b76df Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 15 Aug 2012 22:43:28 -0700 Subject: [PATCH 33/60] spek-ruler.cc --- src/Makefile.am | 2 + src/spek-ruler.cc | 85 ++++++++++++++++++++++++++ src/spek-ruler.hh | 54 +++++++++++++++++ src/spek-ruler.vala | 123 -------------------------------------- src/spek-spectrogram.vala | 12 ---- 5 files changed, 141 insertions(+), 135 deletions(-) create mode 100644 src/spek-ruler.cc create mode 100644 src/spek-ruler.hh delete mode 100644 src/spek-ruler.vala diff --git a/src/Makefile.am b/src/Makefile.am index d4da183..844f633 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ spek_SOURCES = \ spek-platform.hh \ spek-preferences.cc \ spek-preferences.hh \ + spek-ruler.cc \ + spek-ruler.hh \ spek-spectrogram.cc \ spek-spectrogram.hh \ spek-window.cc \ diff --git a/src/spek-ruler.cc b/src/spek-ruler.cc new file mode 100644 index 0000000..73cb32c --- /dev/null +++ b/src/spek-ruler.cc @@ -0,0 +1,85 @@ +/* spek-ruler.cc + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include "spek-ruler.hh" + +SpekRuler::SpekRuler(Position pos, wxString sample_label, int *factors, int units, double spacing) : + pos(pos), sample_label(sample_label), factors(factors), units(units), spacing(spacing) +{ +} + +void SpekRuler::draw(wxDC& dc) +{ + // Mesure the sample label. + wxSize size = dc.GetTextExtent(sample_label); + int len = this->pos == TOP || this->pos == BOTTOM ? size.GetWidth() : size.GetHeight(); + + // Select the factor to use, we want some space between the labels. + int factor = 0; + for (int i = 0; factors[i]; ++i) { + if (this->measure(factors[i]) >= this->spacing * len) { + factor = factors[i]; + break; + } + } + + // Draw the ticks. + this->draw_tick(dc, 0); + this->draw_tick(dc, units); + + if (factor > 0) { + for (int tick = factor; tick < units; tick += factor) { + if (this->measure(units - tick) < len * 1.2) { + break; + } + this->draw_tick(dc, tick); + } + } +} + +void SpekRuler::draw_tick(wxDC& dc, int tick) +{ + double GAP = 10; + double TICK_LEN = 4; + + wxString label = format(tick); + double p = place(measure(this->pos == TOP || this->pos == BOTTOM ? tick : this->units - tick)); + wxSize size = dc.GetTextExtent(label); + int w = size.GetWidth(); + int h = size.GetHeight(); + + if (this->pos == TOP) { + dc.DrawText(label, p - w / 2, -GAP - h); + } else if (this->pos == RIGHT){ + dc.DrawText(label, GAP, p + h / 4); + } else if (this->pos == BOTTOM) { + dc.DrawText(label, p - w / 2, GAP + h); + } else if (this->pos == LEFT){ + dc.DrawText(label, -w - GAP, p + h / 4); + } + + if (this->pos == TOP) { + dc.DrawLine(p, 0, p, -TICK_LEN); + } else if (this->pos == RIGHT) { + dc.DrawLine(0, p, TICK_LEN, p); + } else if (this->pos == BOTTOM) { + dc.DrawLine(p, 0, p, TICK_LEN); + } else if (this->pos == LEFT) { + dc.DrawLine(0, p, -TICK_LEN, p); + } +} diff --git a/src/spek-ruler.hh b/src/spek-ruler.hh new file mode 100644 index 0000000..bcc769b --- /dev/null +++ b/src/spek-ruler.hh @@ -0,0 +1,54 @@ +/* spek-ruler.hh + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_RULER_HH_ +#define SPEK_RULER_HH_ + +#include +#include + +class SpekRuler +{ +public: + enum Position + { + TOP, + RIGHT, + BOTTOM, + LEFT + }; + + SpekRuler(Position pos, wxString sample_label, int *factors, int units, double spacing); + + void draw(wxDC& dc); + +protected: + virtual double measure(int unit) = 0; + virtual double place(double p) = 0; + virtual wxString format(int unit) = 0; + + void draw_tick(wxDC& dc, int tick); + + Position pos; + wxString sample_label; + int *factors; + int units; + double spacing; +}; + +#endif diff --git a/src/spek-ruler.vala b/src/spek-ruler.vala deleted file mode 100644 index abd6fa4..0000000 --- a/src/spek-ruler.vala +++ /dev/null @@ -1,123 +0,0 @@ -/* spek-ruler.vala - * - * Copyright (C) 2010,2011 Alexander Kojevnikov - * - * 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 . - */ - -using Cairo; -using Pango; - -namespace Spek { - class Ruler : GLib.Object { - public enum Position { - TOP, - RIGHT, - BOTTOM, - LEFT - } - - private Position pos; - private string sample_label; - private int[] factors; - private int units; - private double spacing; - private Measure measure; - private Place place; - private FormatTick format_tick; - - public delegate double Measure (int unit); - public delegate double Place (double p); - public delegate string FormatTick (int unit); - - public Ruler ( - Position pos, string sample_label, - int[] factors, int units, double spacing, - Measure measure, Place place, FormatTick format_tick) { - this.pos = pos; - this.sample_label = sample_label; - this.factors = factors; - this.units = units; - this.spacing = spacing; - this.measure = measure; - this.place = place; - this.format_tick = format_tick; - } - - public void draw (Cairo.Context cr, Pango.Layout layout) { - // Mesure the sample label. - int w, h; - layout.set_text (sample_label, -1); - layout.get_pixel_size (out w, out h); - var size = pos == Position.TOP || pos == Position.BOTTOM ? w : h; - - // Select the factor to use, we want some space between the labels. - int factor = 0; - foreach (var f in factors) { - if (measure (f) >= spacing * size) { - factor = f; - break; - } - } - - // Add the ticks. - int[] ticks = { 0, units }; - if (factor > 0) { - for (var tick = factor; tick < units; tick += factor) { - if (measure (units - tick) < size * 1.2) { - break; - } - ticks += tick; - } - // TODO: `ticks = ticks[0:-1]` crashes, file a bug. - } - - // Draw the ticks. - double GAP = 10; - double TICK_LEN = 4; - foreach (var tick in ticks) { - var label = format_tick (tick); - var p = place (measure ( - pos == Position.TOP || pos == Position.BOTTOM - ? tick : units - tick)); - layout.set_text (label, -1); - layout.get_pixel_size (out w, out h); - if (pos == Position.TOP) { - cr.move_to (p - w / 2, -GAP - h); - } else if (pos == Position.RIGHT){ - cr.move_to (GAP, p + h / 4); - } else if (pos == Position.BOTTOM) { - cr.move_to (p - w / 2, GAP + h); - } else if (pos == Position.LEFT){ - cr.move_to (-w - GAP, p + h / 4); - } - cairo_show_layout_line (cr, layout.get_line (0)); - if (pos == Position.TOP) { - cr.move_to (p, 0); - cr.rel_line_to (0, -TICK_LEN); - } else if (pos == Position.RIGHT) { - cr.move_to (0, p); - cr.rel_line_to (TICK_LEN, 0); - } else if (pos == Position.BOTTOM) { - cr.move_to (p, 0); - cr.rel_line_to (0, TICK_LEN); - } else if (pos == Position.LEFT) { - cr.move_to (0, p); - cr.rel_line_to (-TICK_LEN, 0); - } - cr.stroke (); - } - } - } -} \ No newline at end of file diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala index 3d1e7c2..253017a 100644 --- a/src/spek-spectrogram.vala +++ b/src/spek-spectrogram.vala @@ -36,18 +36,6 @@ namespace Spek { surface.write_to_png (file_name); } - protected override bool expose_event (EventExpose event) { - var window = get_window (); - var cr = cairo_create (window); - - // Clip to the exposed area. - cr.rectangle (event.area.x, event.area.y, event.area.width, event.area.height); - cr.clip (); - - draw (cr); - return true; - } - private void draw (Cairo.Context cr) { int text_width, text_height; From 144d1fa2cf2c83d491d1c3774a3e9c3941193253 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 16 Aug 2012 00:36:30 -0700 Subject: [PATCH 34/60] Draw rulers --- src/spek-ruler.cc | 37 +++++++++++------- src/spek-ruler.hh | 17 +++++--- src/spek-spectrogram.cc | 82 ++++++++++++++++++++++++++++++++++++++- src/spek-spectrogram.hh | 2 + src/spek-spectrogram.vala | 74 ----------------------------------- 5 files changed, 118 insertions(+), 94 deletions(-) diff --git a/src/spek-ruler.cc b/src/spek-ruler.cc index 73cb32c..0a6464a 100644 --- a/src/spek-ruler.cc +++ b/src/spek-ruler.cc @@ -16,10 +16,18 @@ * along with Spek. If not, see . */ +#include + #include "spek-ruler.hh" -SpekRuler::SpekRuler(Position pos, wxString sample_label, int *factors, int units, double spacing) : - pos(pos), sample_label(sample_label), factors(factors), units(units), spacing(spacing) +SpekRuler::SpekRuler( + int x, int y, Position pos, wxString sample_label, + int *factors, int units, double spacing, + double scale, double offset, formatter_cb formatter) + : + x(x), y(y), pos(pos), sample_label(sample_label), + factors(factors), units(units), spacing(spacing), + scale(scale), offset(offset), formatter(formatter) { } @@ -32,7 +40,7 @@ void SpekRuler::draw(wxDC& dc) // Select the factor to use, we want some space between the labels. int factor = 0; for (int i = 0; factors[i]; ++i) { - if (this->measure(factors[i]) >= this->spacing * len) { + if (fabs(this->scale * factors[i]) >= this->spacing * len) { factor = factors[i]; break; } @@ -44,7 +52,7 @@ void SpekRuler::draw(wxDC& dc) if (factor > 0) { for (int tick = factor; tick < units; tick += factor) { - if (this->measure(units - tick) < len * 1.2) { + if (fabs(this->scale * (units - tick)) < len * 1.2) { break; } this->draw_tick(dc, tick); @@ -57,29 +65,30 @@ void SpekRuler::draw_tick(wxDC& dc, int tick) double GAP = 10; double TICK_LEN = 4; - wxString label = format(tick); - double p = place(measure(this->pos == TOP || this->pos == BOTTOM ? tick : this->units - tick)); + wxString label = this->formatter(tick); + int value = this->pos == TOP || this->pos == BOTTOM ? tick : this->units - tick; + double p = this->offset + this->scale * value; wxSize size = dc.GetTextExtent(label); int w = size.GetWidth(); int h = size.GetHeight(); if (this->pos == TOP) { - dc.DrawText(label, p - w / 2, -GAP - h); + dc.DrawText(label, this->x + p - w / 2, this->y - GAP - h); } else if (this->pos == RIGHT){ - dc.DrawText(label, GAP, p + h / 4); + dc.DrawText(label, this->x + GAP, this->y + p - h / 2); } else if (this->pos == BOTTOM) { - dc.DrawText(label, p - w / 2, GAP + h); + dc.DrawText(label, this->x + p - w / 2, this->y + GAP); } else if (this->pos == LEFT){ - dc.DrawText(label, -w - GAP, p + h / 4); + dc.DrawText(label, this->x - w - GAP, this->y + p - h / 2); } if (this->pos == TOP) { - dc.DrawLine(p, 0, p, -TICK_LEN); + dc.DrawLine(this->x + p, this->y, this->x + p, this->y - TICK_LEN); } else if (this->pos == RIGHT) { - dc.DrawLine(0, p, TICK_LEN, p); + dc.DrawLine(this->x, this->y + p, this->x + TICK_LEN, this->y + p); } else if (this->pos == BOTTOM) { - dc.DrawLine(p, 0, p, TICK_LEN); + dc.DrawLine(this->x + p, this->y, this->x + p, this->y + TICK_LEN); } else if (this->pos == LEFT) { - dc.DrawLine(0, p, -TICK_LEN, p); + dc.DrawLine(this->x, this->y + p, this->x - TICK_LEN, this->y + p); } } diff --git a/src/spek-ruler.hh b/src/spek-ruler.hh index bcc769b..a689114 100644 --- a/src/spek-ruler.hh +++ b/src/spek-ruler.hh @@ -33,22 +33,29 @@ public: LEFT }; - SpekRuler(Position pos, wxString sample_label, int *factors, int units, double spacing); + typedef wxString (*formatter_cb)(int unit); + + SpekRuler( + int x, int y, Position pos, wxString sample_label, + int *factors, int units, double spacing, + double scale, double offset, formatter_cb formatter + ); void draw(wxDC& dc); protected: - virtual double measure(int unit) = 0; - virtual double place(double p) = 0; - virtual wxString format(int unit) = 0; - void draw_tick(wxDC& dc, int tick); + int x; + int y; Position pos; wxString sample_label; int *factors; int units; double spacing; + double scale; + double offset; + formatter_cb formatter; }; #endif diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 98e4cbc..4eaf069 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -19,8 +19,10 @@ #include #include +#include "spek-audio.h" #include "spek-audio-desc.hh" #include "spek-pipeline.h" +#include "spek-ruler.hh" #include "spek-spectrogram.hh" @@ -46,6 +48,7 @@ enum SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE), pipeline(NULL), + properties(NULL), palette(RULER, BANDS), image(1, 1), prev_width(-1) @@ -96,6 +99,22 @@ void SpekSpectrogram::on_size(wxSizeEvent& evt) } } +static wxString time_formatter(int unit) +{ + // TODO: i18n + return wxString::Format(wxT("%d:%02d"), unit / 60, unit % 60); +} + +static wxString freq_formatter(int unit) +{ + return wxString::Format(_("%d kHz"), unit / 1000); +} + +static wxString density_formatter(int unit) +{ + return wxString::Format(_("%d dB"), -unit); +} + void SpekSpectrogram::render(wxDC& dc) { wxSize size = GetClientSize(); @@ -152,6 +171,45 @@ void SpekSpectrogram::render(wxDC& dc) dc.SetFont(normal_font); // TODO: ellipsize dc.DrawText(this->desc, LPAD, TPAD - GAP - normal_height); + + // Prepare to draw the rulers. + dc.SetFont(small_font); + + // Time ruler. + double duration = this->properties->duration; + int time_factors[] = {1, 2, 5, 10, 20, 30, 1*60, 2*60, 5*60, 10*60, 20*60, 30*60, 0}; + SpekRuler time_ruler( + LPAD, + h - BPAD, + SpekRuler::BOTTOM, + // TODO: i18n + wxT("00:00"), + time_factors, + (int)duration, + 1.5, + (w - LPAD - RPAD) / duration, + 0.0, + time_formatter + ); + time_ruler.draw(dc); + + // Frequency ruler. + int freq = this->properties->sample_rate / 2; + int freq_factors[] = {1000, 2000, 5000, 10000, 20000, 0}; + SpekRuler freq_ruler( + LPAD, + TPAD, + SpekRuler::LEFT, + // TRANSLATORS: keep "00" unchanged, it's used to calc the text width + _("00 kHz"), + freq_factors, + freq, + 3.0, + (h - TPAD - BPAD) / (double)freq, + 0.0, + freq_formatter + ); + freq_ruler.draw(dc); } // Border around the spectrogram. @@ -161,6 +219,26 @@ void SpekSpectrogram::render(wxDC& dc) // The palette. wxBitmap bmp(this->palette.Scale(RULER, h - TPAD - BPAD + 1 /*TODO:, wxIMAGE_QUALITY_HIGH*/)); dc.DrawBitmap(bmp, w - RPAD + GAP, TPAD); + + // Prepare to draw the ruler. + dc.SetFont(small_font); + + // Spectral density. + int density_factors[] = {1, 2, 5, 10, 20, 50, 0}; + SpekRuler density_ruler( + w - RPAD + GAP + RULER, + TPAD, + SpekRuler::RIGHT, + // TRANSLATORS: keep "-00" unchanged, it's used to calc the text width + _("-00 dB"), + density_factors, + -THRESHOLD, + 3.0, + (h - TPAD - BPAD) / (double)THRESHOLD, + h - TPAD - BPAD, + density_formatter + ); + density_ruler.draw(dc); } void SpekSpectrogram::pipeline_cb(int sample, float *values, void *cb_data) @@ -191,6 +269,7 @@ void SpekSpectrogram::start() if (this->pipeline) { spek_pipeline_close(this->pipeline); this->pipeline = NULL; + this->properties = NULL; } // The number of samples is the number of pixels available for the image. @@ -209,7 +288,8 @@ void SpekSpectrogram::start() this ); spek_pipeline_start(this->pipeline); - this->desc = spek_audio_desc(spek_pipeline_properties(this->pipeline)); + this->properties = spek_pipeline_properties(this->pipeline); + this->desc = spek_audio_desc(this->properties); } else { this->image.Create(1, 1); } diff --git a/src/spek-spectrogram.hh b/src/spek-spectrogram.hh index db0fd61..c60f314 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -22,6 +22,7 @@ #include #include +struct spek_audio_properties; struct spek_pipeline; class SpekSpectrogram : public wxPanel @@ -42,6 +43,7 @@ private: static uint32_t get_color(double level); spek_pipeline *pipeline; + const spek_audio_properties *properties; wxString path; wxString desc; wxImage palette; diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala index 253017a..15e4154 100644 --- a/src/spek-spectrogram.vala +++ b/src/spek-spectrogram.vala @@ -24,10 +24,6 @@ using Pango; namespace Spek { class Spectrogram : DrawingArea { - private ImageSurface image; - - public Spectrogram () { - public void save (string file_name) { Allocation allocation; get_allocation (out allocation); @@ -35,75 +31,5 @@ namespace Spek { draw (new Cairo.Context (surface)); surface.write_to_png (file_name); } - - private void draw (Cairo.Context cr) { - int text_width, text_height; - - if (image != null) { - // Prepare to draw the rulers. - cr.set_source_rgb (1, 1, 1); - cr.set_line_width (1); - cr.set_antialias (Antialias.NONE); - layout.set_font_description (FontDescription.from_string ( - "Sans " + (8 * FONT_SCALE).to_string ())); - layout.set_width (-1); - - // Time ruler. - var duration_seconds = (int) pipeline.duration; - var time_ruler = new Ruler ( - Ruler.Position.BOTTOM, - // TODO: i18n - "00:00", - {1, 2, 5, 10, 20, 30, 1*60, 2*60, 5*60, 10*60, 20*60, 30*60}, - duration_seconds, - 1.5, - unit => (w - LPAD - RPAD) * unit / duration_seconds, - p => p, - // TODO: i18n - unit => "%d:%02d".printf (unit / 60, unit % 60)); - cr.translate (LPAD, h - BPAD); - time_ruler.draw (cr, layout); - cr.identity_matrix (); - - // Frequency ruler. - var freq = pipeline.sample_rate / 2; - var rate_ruler = new Ruler ( - Ruler.Position.LEFT, - // TRANSLATORS: keep "00" unchanged, it's used to calc the text width - _("00 kHz"), - {1000, 2000, 5000, 10000, 20000}, - freq, - 3.0, - unit => (h - TPAD - BPAD) * unit / freq, - p => p, - unit => _("%d kHz").printf (unit / 1000)); - cr.translate (LPAD, TPAD); - rate_ruler.draw (cr, layout); - cr.identity_matrix (); - } - - // Prepare to draw the ruler. - cr.set_source_rgb (1, 1, 1); - cr.set_line_width (1); - cr.set_antialias (Antialias.NONE); - layout.set_font_description (FontDescription.from_string ( - "Sans " + (8 * FONT_SCALE).to_string ())); - layout.set_width (-1); - - // Spectral density. - var density_ruler = new Ruler ( - Ruler.Position.RIGHT, - // TRANSLATORS: keep "-00" unchanged, it's used to calc the text width - _("-00 dB"), - {1, 2, 5, 10, 20, 50}, - -THRESHOLD, - 3.0, - unit => -(h - TPAD - BPAD) * unit / THRESHOLD, - p => h - TPAD - BPAD - p, - unit => _("%d dB").printf (-unit)); - cr.translate (w - RPAD + GAP + RULER, TPAD); - density_ruler.draw (cr, layout); - cr.identity_matrix (); - } } } From 891db76d6384c42e61bda4432339a7238d240ba6 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 16 Aug 2012 09:35:18 -0700 Subject: [PATCH 35/60] osx: Make it a foreground application --- src/spek-platform.cc | 13 +++++++++++++ src/spek-platform.hh | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 3dc2cdc..31e88fb 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -18,12 +18,25 @@ #include +#ifdef OS_OSX +#include +#endif + #include #include #include #include "spek-platform.hh" +void SpekPlatform::init() +{ +#ifdef OS_OSX + ProcessSerialNumber PSN; + GetCurrentProcess(&PSN); + TransformProcessType(&PSN, kProcessTransformToForegroundApplication); +#endif +} + wxString SpekPlatform::config_path(const wxString& app_name) { #ifdef OS_WIN diff --git a/src/spek-platform.hh b/src/spek-platform.hh index 18144f3..587efc3 100644 --- a/src/spek-platform.hh +++ b/src/spek-platform.hh @@ -25,6 +25,9 @@ class SpekPlatform { public: + // Platform-specific initialisation code. + void init(); + // Not quite XDG-compatible, but close enough. static wxString config_path(const wxString& app_name); From 31df33c9da9446ced92e0f16c8510673c89e7a4e Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 16 Aug 2012 09:51:10 -0700 Subject: [PATCH 36/60] osx: Use a larger font --- src/spek-platform.cc | 9 +++++++++ src/spek-platform.hh | 3 +++ src/spek-spectrogram.cc | 12 +++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 31e88fb..8b26be5 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -59,6 +59,15 @@ bool SpekPlatform::can_change_language() #endif } +double SpekPlatform::font_scale() +{ +#ifdef OS_OSX + return 1.3; +#else + return 1.0; +#endif +} + char * spek_platform_short_path(const char *path) { #ifdef OS_WIN diff --git a/src/spek-platform.hh b/src/spek-platform.hh index 587efc3..e3bd822 100644 --- a/src/spek-platform.hh +++ b/src/spek-platform.hh @@ -34,6 +34,9 @@ public: // Setting non-default locale under GTK+ is tricky (see e.g. how FileZilla does it). We will // just disable the language setting for GTK+ users and will always use the system locale. static bool can_change_language(); + + // Fonts are smaller on OSX. + static double font_scale(); }; extern "C" { diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 4eaf069..216f63d 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -22,6 +22,7 @@ #include "spek-audio.h" #include "spek-audio-desc.hh" #include "spek-pipeline.h" +#include "spek-platform.hh" #include "spek-ruler.hh" #include "spek-spectrogram.hh" @@ -127,12 +128,17 @@ void SpekSpectrogram::render(wxDC& dc) dc.SetPen(*wxWHITE_PEN); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.SetTextForeground(wxColour(255, 255, 255)); - wxFont normal_font = wxFont(9, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + wxFont normal_font = wxFont( + (int)round(9 * SpekPlatform::font_scale()), + wxFONTFAMILY_SWISS, + wxFONTSTYLE_NORMAL, + wxFONTWEIGHT_NORMAL + ); wxFont large_font = wxFont(normal_font); - large_font.SetPointSize(10); + large_font.SetPointSize((int)round(10 * SpekPlatform::font_scale())); large_font.SetWeight(wxFONTWEIGHT_BOLD); wxFont small_font = wxFont(normal_font); - small_font.SetPointSize(8); + small_font.SetPointSize((int)round(8 * SpekPlatform::font_scale())); dc.SetFont(normal_font); int normal_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); dc.SetFont(large_font); From c7f2715130055ffafea162d05549c371d5ed1cbd Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 16 Aug 2012 09:54:47 -0700 Subject: [PATCH 37/60] Platfrom-specific initialisation --- src/spek-platform.hh | 2 +- src/spek.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/spek-platform.hh b/src/spek-platform.hh index e3bd822..8368318 100644 --- a/src/spek-platform.hh +++ b/src/spek-platform.hh @@ -26,7 +26,7 @@ class SpekPlatform { public: // Platform-specific initialisation code. - void init(); + static void init(); // Not quite XDG-compatible, but close enough. static wxString config_path(const wxString& app_name); diff --git a/src/spek.cc b/src/spek.cc index 64f5b7b..2bf2947 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -20,6 +20,7 @@ #include #include "spek-audio.h" +#include "spek-platform.hh" #include "spek-preferences.hh" #include "spek-window.hh" @@ -39,6 +40,7 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { + SpekPlatform::init(); SpekPreferences::get().init(); spek_audio_init(); From 0745673f907a15c208eb83d2b9e93593ef9ea1d4 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Thu, 16 Aug 2012 22:07:33 -0700 Subject: [PATCH 38/60] wxWidgets 2.9 compatibility --- src/spek.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/spek.cc b/src/spek.cc index 2bf2947..4354be0 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -58,20 +58,21 @@ void Spek::OnInitCmdLine(wxCmdLineParser& parser) { wxCmdLineEntryDesc desc[] = {{ wxCMD_LINE_SWITCH, - wxT("h"), - wxT("help"), _("Show this help message"), + wxT_2("h"), + wxT_2("help"), + wxT_2("Show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, { wxCMD_LINE_SWITCH, - wxT("V"), - wxT("version"), - _("Display the version and exit") + wxT_2("V"), + wxT_2("version"), + wxT_2("Display the version and exit") }, { wxCMD_LINE_PARAM, NULL, NULL, - _("FILE"), + wxT_2("FILE"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { From 8544a03c3c996ecb1b30a1b10a65488ad687256b Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 17 Aug 2012 22:15:02 -0700 Subject: [PATCH 39/60] Save spectrogram as an image --- src/spek-spectrogram.cc | 5 +++++ src/spek-spectrogram.vala | 35 --------------------------------- src/spek-window.cc | 41 +++++++++++++++++++++++++++++++++++---- src/spek-window.hh | 2 ++ src/spek-window.vala | 26 ------------------------- src/spek.cc | 2 ++ 6 files changed, 46 insertions(+), 65 deletions(-) delete mode 100644 src/spek-spectrogram.vala diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 216f63d..49425ac 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -76,6 +76,11 @@ void SpekSpectrogram::open(const wxString& path) void SpekSpectrogram::save(const wxString& path) { + wxSize size = GetClientSize(); + wxBitmap bitmap(size.GetWidth(), size.GetHeight()); + wxMemoryDC dc(bitmap); + render(dc); + bitmap.SaveFile(path, wxBITMAP_TYPE_PNG); } void SpekSpectrogram::on_idle(wxIdleEvent& evt) diff --git a/src/spek-spectrogram.vala b/src/spek-spectrogram.vala deleted file mode 100644 index 15e4154..0000000 --- a/src/spek-spectrogram.vala +++ /dev/null @@ -1,35 +0,0 @@ -/* spek-spectrogram.vala - * - * Copyright (C) 2010-2011 Alexander Kojevnikov - * - * 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 . - */ - -using Cairo; -using Gdk; -using Gtk; -using Pango; - -namespace Spek { - class Spectrogram : DrawingArea { - - public void save (string file_name) { - Allocation allocation; - get_allocation (out allocation); - var surface = new ImageSurface (Format.RGB24, allocation.width, allocation.height); - draw (new Cairo.Context (surface)); - surface.write_to_png (file_name); - } - } -} diff --git a/src/spek-window.cc b/src/spek-window.cc index 9e2a7fc..3de7599 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -31,7 +31,8 @@ BEGIN_EVENT_TABLE(SpekWindow, wxFrame) EVT_MENU(wxID_ABOUT, SpekWindow::on_about) END_EVENT_TABLE() -SpekWindow::SpekWindow(const wxString& path) : wxFrame(NULL, -1, wxEmptyString) +SpekWindow::SpekWindow(const wxString& path) : + path(path), wxFrame(NULL, -1, wxEmptyString) { SetTitle(_("Spek - Acoustic Spectrum Analyser")); // TODO: test on all platforms @@ -79,6 +80,7 @@ SpekWindow::SpekWindow(const wxString& path) : wxFrame(NULL, -1, wxEmptyString) toolbar->Realize(); this->spectrogram = new SpekSpectrogram(this); + this->cur_dir = wxGetHomeDir(); if (!path.IsEmpty()) { open(path); @@ -119,7 +121,6 @@ static const char *audio_extensions[] = { void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) { - static wxString cur_dir = wxGetHomeDir(); static wxString filters = wxEmptyString; static int filter_index = 1; @@ -142,7 +143,7 @@ void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) wxFileDialog *dlg = new wxFileDialog( this, _("Open File"), - cur_dir, + this->cur_dir, wxEmptyString, filters, wxFD_OPEN @@ -150,7 +151,7 @@ void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) dlg->SetFilterIndex(filter_index); if (dlg->ShowModal() == wxID_OK) { - cur_dir = dlg->GetDirectory(); + this->cur_dir = dlg->GetDirectory(); filter_index = dlg->GetFilterIndex(); open(dlg->GetPath()); } @@ -160,6 +161,37 @@ void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) void SpekWindow::on_save(wxCommandEvent& WXUNUSED(event)) { + static wxString filters = wxEmptyString; + + if (filters.IsEmpty()) { + filters = _("PNG images"); + filters += wxT("|*.png"); + } + + wxFileDialog *dlg = new wxFileDialog( + this, + _("Save Spectrogram"), + this->cur_dir, + wxEmptyString, + filters, + wxFD_SAVE + ); + + // Suggested name is .png + wxString name = _("Untitled"); + if (!this->path.IsEmpty()) { + wxFileName file_name(this->path); + name = file_name.GetFullName(); + } + name += wxT(".png"); + dlg->SetFilename(name); + + if (dlg->ShowModal() == wxID_OK) { + this->cur_dir = dlg->GetDirectory(); + this->spectrogram->save(dlg->GetPath()); + } + + dlg->Destroy(); } void SpekWindow::on_exit(wxCommandEvent& WXUNUSED(event)) @@ -179,6 +211,7 @@ void SpekWindow::open(const wxString& path) { wxFileName file_name(path); if (file_name.FileExists()) { + this->path = path; wxString full_name = file_name.GetFullName(); // TRANSLATORS: window title, %s is replaced with the file name wxString title = wxString::Format(_("Spek - %s"), full_name.c_str()); diff --git a/src/spek-window.hh b/src/spek-window.hh index 7a73aff..97ee13c 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -37,6 +37,8 @@ private: void open(const wxString& path); SpekSpectrogram *spectrogram; + wxString path; + wxString cur_dir; DECLARE_EVENT_TABLE() }; diff --git a/src/spek-window.vala b/src/spek-window.vala index 767dea6..292f345 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -50,10 +50,6 @@ namespace Spek { info_bar.message_type = MessageType.INFO; info_bar.response.connect(() => info_bar.hide()); - 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); add (vbox); @@ -85,28 +81,6 @@ namespace Spek { drag_finish (cx, false, false, time); } - private void on_file_save () { - var chooser = new FileChooserDialog ( - _("Save Spectrogram"), this, FileChooserAction.SAVE, - Stock.CANCEL, ResponseType.CANCEL, - Stock.SAVE, ResponseType.ACCEPT, null); - chooser.set_default_response (ResponseType.ACCEPT); - chooser.set_current_folder (cur_dir); - - // Suggested name is .png - var file_name = Path.get_basename (spectrogram.file_name ?? _("Untitled")); - file_name += ".png"; - chooser.set_current_name (file_name); - chooser.add_filter (filter_png); - chooser.set_filter (filter_png); - if (chooser.run () == ResponseType.ACCEPT) { - file_name = chooser.get_filename (); - cur_dir = Path.get_dirname (file_name); - spectrogram.save (file_name); - } - chooser.destroy (); - } - private void on_edit_preferences () { var dlg = new PreferencesDialog (); dlg.transient_for = this; diff --git a/src/spek.cc b/src/spek.cc index 4354be0..eb5e757 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -40,6 +40,8 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { + wxInitAllImageHandlers(); + SpekPlatform::init(); SpekPreferences::get().init(); spek_audio_init(); From 93b5dc79a7c72f20fac69af4cfdf3674601ca33b Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 17 Aug 2012 22:19:18 -0700 Subject: [PATCH 40/60] Move out palette code --- src/Makefile.am | 10 ++++--- src/spek-palette.c | 61 +++++++++++++++++++++++++++++++++++++++++ src/spek-palette.h | 34 +++++++++++++++++++++++ src/spek-spectrogram.cc | 48 ++------------------------------ src/spek-spectrogram.hh | 2 -- 5 files changed, 104 insertions(+), 51 deletions(-) create mode 100644 src/spek-palette.c create mode 100644 src/spek-palette.h diff --git a/src/Makefile.am b/src/Makefile.am index 844f633..95cbc62 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,13 +1,14 @@ bin_PROGRAMS = spek spek_SOURCES = \ - spek.cc \ - spek-audio.c \ - spek-audio.h \ spek-audio-desc.cc \ spek-audio-desc.hh \ + spek-audio.c \ + spek-audio.h \ spek-fft.c \ spek-fft.h \ + spek-palette.c \ + spek-palette.h \ spek-pipeline.c \ spek-pipeline.h \ spek-platform.cc \ @@ -19,7 +20,8 @@ spek_SOURCES = \ spek-spectrogram.cc \ spek-spectrogram.hh \ spek-window.cc \ - spek-window.hh + spek-window.hh \ + spek.cc spek_CPPFLAGS = \ -include config.h \ diff --git a/src/spek-palette.c b/src/spek-palette.c new file mode 100644 index 0000000..bdb074c --- /dev/null +++ b/src/spek-palette.c @@ -0,0 +1,61 @@ +/* spek-palette.c + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include "spek-palette.h" + +// Modified version of Dan Bruton's algorithm: +// http://www.physics.sfasu.edu/astro/color/spectra.html +uint32_t spek_palette_spectrum(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-palette.h b/src/spek-palette.h new file mode 100644 index 0000000..7ce84bf --- /dev/null +++ b/src/spek-palette.h @@ -0,0 +1,34 @@ +/* spek-palette.h + * + * Copyright (C) 2010-2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_PALETTE_HH_ +#define SPEK_PALETTE_HH_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint32_t spek_palette_spectrum(double level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 49425ac..cbec6c8 100644 --- 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-palette.h" #include "spek-pipeline.h" #include "spek-platform.hh" #include "spek-ruler.hh" @@ -58,7 +59,7 @@ SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : // Pre-draw the palette. for (int y = 0; y < BANDS; y++) { - uint32_t color = get_color(y / (double) BANDS); + uint32_t color = spek_palette_spectrum(y / (double) BANDS); this->palette.SetRGB( wxRect(0, BANDS - y - 1, RULER, 1), color >> 16, @@ -260,7 +261,7 @@ void SpekSpectrogram::pipeline_cb(int sample, float *values, void *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); + uint32_t color = spek_palette_spectrum(level); s->image.SetRGB( sample, BANDS - y - 1, @@ -307,46 +308,3 @@ void SpekSpectrogram::start() Refresh(); } - -// 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::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 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 index c60f314..ea2f31c 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -19,7 +19,6 @@ #ifndef SPEK_SPECTROGRAM_HH_ #define SPEK_SPECTROGRAM_HH_ -#include #include struct spek_audio_properties; @@ -40,7 +39,6 @@ private: void start(); static void pipeline_cb(int sample, float *values, void *cb_data); - static uint32_t get_color(double level); spek_pipeline *pipeline; const spek_audio_properties *properties; From 703ade32d78676ed30b68ca4c663c06686d10850 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Fri, 17 Aug 2012 22:26:02 -0700 Subject: [PATCH 41/60] Ellipsise file name and properties --- src/spek-spectrogram.cc | 47 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index cbec6c8..01f9c94 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -47,6 +47,9 @@ enum RULER = 10, }; +// Forward declarations. +static wxString trim(wxDC& dc, const wxString& s, int length, bool trim_end); + SpekSpectrogram::SpekSpectrogram(wxFrame *parent) : wxPanel(parent, -1, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE), pipeline(NULL), @@ -176,13 +179,19 @@ void SpekSpectrogram::render(wxDC& dc) // File name. dc.SetFont(large_font); - // TODO: ellipsize - dc.DrawText(this->path, LPAD, TPAD - 2 * GAP - normal_height - large_height); + dc.DrawText( + trim(dc, this->path, w - LPAD - RPAD, false), + LPAD, + TPAD - 2 * GAP - normal_height - large_height + ); // File properties. dc.SetFont(normal_font); - // TODO: ellipsize - dc.DrawText(this->desc, LPAD, TPAD - GAP - normal_height); + dc.DrawText( + trim(dc, this->desc, w - LPAD - RPAD, true), + LPAD, + TPAD - GAP - normal_height + ); // Prepare to draw the rulers. dc.SetFont(small_font); @@ -308,3 +317,33 @@ void SpekSpectrogram::start() Refresh(); } + +// Trim `s` so that it fits into `length`. +static wxString trim(wxDC& dc, const wxString& s, int length, bool trim_end) +{ + if (length <= 0) { + return wxEmptyString; + } + + // Check if the entire string fits. + wxSize size = dc.GetTextExtent(s); + if (size.GetWidth() <= length) { + return s; + } + + // Binary search FTW! + wxString fix(wxT("...")); + int i = 0; + int k = s.length(); + while (k - i > 1) { + int j = (i + k) / 2; + size = dc.GetTextExtent(trim_end ? s.substr(0, j) + fix : fix + s.substr(j)); + if (trim_end != (size.GetWidth() > length)) { + i = j; + } else { + k = j; + } + } + + return trim_end ? s.substr(0, i) + fix : fix + s.substr(k); +} From 4e71509218bbaad75a9106505129e1976d251b82 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sat, 18 Aug 2012 21:58:14 -0700 Subject: [PATCH 42/60] Fix obsolete TODOs --- src/spek-spectrogram.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index 01f9c94..d6d369f 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -174,7 +174,7 @@ void SpekSpectrogram::render(wxDC& dc) if (this->image.GetHeight() > 1) { // Draw the spectrogram. - wxBitmap bmp(this->image.Scale(w - LPAD - RPAD, h - TPAD - BPAD /*TODO:, wxIMAGE_QUALITY_HIGH*/)); + wxBitmap bmp(this->image.Scale(w - LPAD - RPAD, h - TPAD - BPAD)); dc.DrawBitmap(bmp, LPAD, TPAD); // File name. @@ -234,11 +234,10 @@ void SpekSpectrogram::render(wxDC& dc) } // 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*/)); + wxBitmap bmp(this->palette.Scale(RULER, h - TPAD - BPAD + 1)); dc.DrawBitmap(bmp, w - RPAD + GAP, TPAD); // Prepare to draw the ruler. From 0b121ec1c5ce99535d35a6a54c9252bd9f552a7d Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 12:05:57 -0700 Subject: [PATCH 43/60] Proper notification using custom events --- src/Makefile.am | 2 ++ src/spek-events.cc | 45 +++++++++++++++++++++++++++ src/spek-events.hh | 53 ++++++++++++++++++++++++++++++++ src/spek-spectrogram.cc | 68 ++++++++++++++++++++++++++--------------- src/spek-spectrogram.hh | 5 ++- 5 files changed, 148 insertions(+), 25 deletions(-) create mode 100644 src/spek-events.cc create mode 100644 src/spek-events.hh diff --git a/src/Makefile.am b/src/Makefile.am index 95cbc62..10fd4b2 100644 --- 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 new file mode 100644 index 0000000..169307b --- /dev/null +++ b/src/spek-events.cc @@ -0,0 +1,45 @@ +/* spek-events.cc + * + * Copyright (C) 2012 Alexander Kojevnikov + * + * 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 . + */ + +#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 new file mode 100644 index 0000000..5179de2 --- /dev/null +++ b/src/spek-events.hh @@ -0,0 +1,53 @@ +/* spek-events.hh + * + * Copyright (C) 2012 Alexander Kojevnikov + * + * 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 . + */ + +#ifndef SPEK_EVENTS_HH_ +#define SPEK_EVENTS_HH_ + +#include + +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 index d6d369f..f2fdd15 100644 --- 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 index ea2f31c..099ec48 100644 --- a/src/spek-spectrogram.hh +++ b/src/spek-spectrogram.hh @@ -21,6 +21,7 @@ #include +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; From 68989c8b6fd6ccda53ccd14766de5dee78663ead Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 13:09:09 -0700 Subject: [PATCH 44/60] Fix return status code --- src/spek-spectrogram.cc | 1 + src/spek.cc | 60 ++++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index f2fdd15..efc1299 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -123,6 +123,7 @@ void SpekSpectrogram::on_have_sample(SpekHaveSampleEvent& event) int sample = event.get_sample(); const float *values = event.get_values(); + // TODO: check image size, quit if wrong. for (int y = 0; y < bands; y++) { double level = log10(1.0 - THRESHOLD + values[y]) / log10_threshold; if (level > 1.0) level = 1.0; diff --git a/src/spek.cc b/src/spek.cc index eb5e757..7fdbc5a 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -27,13 +27,16 @@ class Spek: public wxApp { +public: + Spek() : wxApp(), quit(false) {} + protected: virtual bool OnInit(); - virtual void OnInitCmdLine(wxCmdLineParser& parser); - virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + virtual int OnRun(); private: wxString path; + bool quit; }; IMPLEMENT_APP(Spek) @@ -46,19 +49,7 @@ bool Spek::OnInit() SpekPreferences::get().init(); spek_audio_init(); - if (!wxApp::OnInit()) { - return false; - } - - SpekWindow *window = new SpekWindow(this->path); - window->Show(true); - SetTopWindow(window); - return true; -} - -void Spek::OnInitCmdLine(wxCmdLineParser& parser) -{ - wxCmdLineEntryDesc desc[] = {{ + static const wxCmdLineEntryDesc desc[] = {{ wxCMD_LINE_SWITCH, wxT_2("h"), wxT_2("help"), @@ -77,27 +68,40 @@ void Spek::OnInitCmdLine(wxCmdLineParser& parser) wxT_2("FILE"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, { - wxCMD_LINE_NONE - } + }, + wxCMD_LINE_DESC_END }; - parser.SetDesc(desc); -} - -bool Spek::OnCmdLineParsed(wxCmdLineParser& parser) -{ - if (!wxApp::OnCmdLineParsed(parser)) { + wxCmdLineParser parser(desc, argc, argv); + int ret = parser.Parse(true); + if (ret == 1) { return false; } - + if (ret == -1) { + this->quit = true; + return true; + } if (parser.Found(wxT("version"))) { // TRANSLATORS: first %s is the package name, second %s is the package version. wxPrintf(_("%s version %s\n"), wxT(PACKAGE_NAME), wxT(PACKAGE_VERSION)); - return false; + this->quit = true; + return true; + } + if (parser.GetParamCount()) { + this->path = parser.GetParam(); } - this->path = parser.GetParam(); - + SpekWindow *window = new SpekWindow(this->path); + window->Show(true); + SetTopWindow(window); return true; } + +int Spek::OnRun() +{ + if (quit) { + return 0; + } + + return wxApp::OnRun(); +} From dcec7595f7b55c829d22d0c04c7179f591e1c9e6 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 13:17:29 -0700 Subject: [PATCH 45/60] Fix compilation under wx28 --- src/spek-window.cc | 2 +- src/spek.cc | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index 3de7599..bcaac68 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -36,7 +36,7 @@ SpekWindow::SpekWindow(const wxString& path) : { SetTitle(_("Spek - Acoustic Spectrum Analyser")); // TODO: test on all platforms - SetIcon(wxIcon(wxT("spek"))); + //SetIcon(wxIcon(wxT("spek"))); wxMenuBar *menu = new wxMenuBar(); diff --git a/src/spek.cc b/src/spek.cc index 7fdbc5a..fa92184 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -68,8 +68,10 @@ bool Spek::OnInit() wxT_2("FILE"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL - }, - wxCMD_LINE_DESC_END + }, { + // TODO: use wxCMD_LINE_DESC_END after settling on wx29. + wxCMD_LINE_NONE, NULL, NULL, NULL, wxCMD_LINE_VAL_NONE, 0 + } }; wxCmdLineParser parser(desc, argc, argv); From 9f381eb03c8db4be403b8c505adbcabe29f81778 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 14:39:17 -0700 Subject: [PATCH 46/60] Drag'n'drop files --- src/spek-window.cc | 51 +++++++++++++++++++++++++++++++------------- src/spek-window.hh | 2 +- src/spek-window.vala | 18 ---------------- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index bcaac68..c557ffe 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -17,6 +17,7 @@ */ #include +#include #include #include "spek-spectrogram.hh" @@ -31,6 +32,24 @@ BEGIN_EVENT_TABLE(SpekWindow, wxFrame) EVT_MENU(wxID_ABOUT, SpekWindow::on_about) END_EVENT_TABLE() +class SpekDropTarget : public wxFileDropTarget +{ +public: + SpekDropTarget(SpekWindow *window) : wxFileDropTarget(), window(window) {} + +protected: + virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames){ + if (filenames.GetCount() == 1) { + window->open(filenames[0]); + return true; + } + return false; + } + +private: + SpekWindow *window; +}; + SpekWindow::SpekWindow(const wxString& path) : path(path), wxFrame(NULL, -1, wxEmptyString) { @@ -85,6 +104,23 @@ SpekWindow::SpekWindow(const wxString& path) : if (!path.IsEmpty()) { open(path); } + + SetDropTarget(new SpekDropTarget(this)); +} + +void SpekWindow::open(const wxString& path) +{ + wxFileName file_name(path); + if (file_name.FileExists()) { + this->path = path; + wxString full_name = file_name.GetFullName(); + // TRANSLATORS: window title, %s is replaced with the file name + 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); + } } // TODO: s/audio/media/ @@ -206,18 +242,3 @@ void SpekWindow::on_preferences(wxCommandEvent& WXUNUSED(event)) void SpekWindow::on_about(wxCommandEvent& WXUNUSED(event)) { } - -void SpekWindow::open(const wxString& path) -{ - wxFileName file_name(path); - if (file_name.FileExists()) { - this->path = path; - wxString full_name = file_name.GetFullName(); - // TRANSLATORS: window title, %s is replaced with the file name - 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 index 97ee13c..4164338 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -27,6 +27,7 @@ class SpekWindow : public wxFrame { public: SpekWindow(const wxString& path); + void open(const wxString& path); private: void on_open(wxCommandEvent& event); @@ -34,7 +35,6 @@ private: void on_exit(wxCommandEvent& event); void on_preferences(wxCommandEvent& event); void on_about(wxCommandEvent& event); - void open(const wxString& path); SpekSpectrogram *spectrogram; wxString path; diff --git a/src/spek-window.vala b/src/spek-window.vala index 292f345..3f3ab78 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -57,30 +57,12 @@ namespace Spek { show (); - // Set up Drag and Drop - drag_dest_set (this, DestDefaults.ALL, DEST_TARGET_ENTRIES, DragAction.COPY); - drag_data_received.connect (on_dropped); - try { Thread.create (check_version, false); } catch (ThreadError e) { } } - void on_dropped (DragContext cx, int x, int y, SelectionData data, uint info, uint time) { - if (data.get_length () > 0 && data.get_format () == 8) { - string[] files = data.get_uris (); - if (files.length > 0) { - try { - open_file (Filename.from_uri (files[0])); - drag_finish (cx, true, false, time); - return; - } catch (ConvertError e) {} - } - } - drag_finish (cx, false, false, time); - } - private void on_edit_preferences () { var dlg = new PreferencesDialog (); dlg.transient_for = this; From 4e87e70934fb0d339c16a58142ff24ac45a9529b Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 18:12:54 -0700 Subject: [PATCH 47/60] osx: Update dist/README --- dist/osx/README | 21 --------------------- dist/osx/README.md | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 21 deletions(-) delete mode 100644 dist/osx/README create mode 100644 dist/osx/README.md diff --git a/dist/osx/README b/dist/osx/README deleted file mode 100644 index 2b58cfc..0000000 --- a/dist/osx/README +++ /dev/null @@ -1,21 +0,0 @@ -Building the OS X bundle -======================== - -Install and configure [jhbuild][1] and [ige-mac-bundler][2]. - -Get the release tarball and unpack it somewhere. Also copy the tarball to ~/gtk/source/pkgs/. - -Add this line to ~/.jhbuildrc-custom: - - moduleset=os.environ['HOME'] + 'path/to/spek/dist/osx/spek.modules' - -Run: - - $ jhbuild build spek - $ jhbuild shell - $ dist/osx/bundle.sh - -Note: On Lion, built in libiconv conflicts with the bundled version. To work around, accompany all jhbuild commands with `--skip=libiconv` so that everything uses the system version of the library (see issue 51). - -[1]: http://sourceforge.net/apps/trac/gtk-osx/wiki/Build -[2]: http://sourceforge.net/apps/trac/gtk-osx/wiki/Bundle diff --git a/dist/osx/README.md b/dist/osx/README.md new file mode 100644 index 0000000..daf12a9 --- /dev/null +++ b/dist/osx/README.md @@ -0,0 +1,34 @@ +# Building the OS X bundle + +Using MacPorts install build dependencies: + + port install git-core autoconf automake intltool yasm. + +Download and build wxWidgets, example configure flags: + + ./configure --prefix=$HOME/usr --disable-shared --with-osx_cocoa \ + --with-jpeg=builtin --with-png=builtin --with-regex=builtin \ + --with-tiff=builtin --with-zlib=builtin --with-expat=builtin + make && make install + +Copy the wxWidgets m4 macro to the MacPorts tree: + + sudo cp $HOME/usr/share/aclocal/wxwin.m4 /opt/local/share/aclocal/ + +Download and build FFmpeg, example configure flags: + + ./configure --prefix=$HOME/usr --disable-shared --disable-debug --disable-doc \ + --enable-gpl --enable-version3 --disable-nonfree --disable-ffmpeg --disable-ffplay \ + --disable-ffprobe --disable-ffserver --disable-avdevice --disable-swscale \ + --disable-postproc --enable-pthreads --disable-encoders --disable-muxers \ + --disable-devices --disable-filters --disable-swresample + make && make install + +Clone and build Spek, example configure flags: + + PKG_CONFIG_PATH=$HOME/usr/lib/pkgconfig ./autogen.sh --with-wx-config=$HOME/usr/bin/wx-config + +Bundle Spek: + + ./dist/osx/bundle.sh + From 2622e55b2c00d7093434ade547111536d71d7928 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 19 Aug 2012 19:06:32 -0700 Subject: [PATCH 48/60] About dialogue --- src/spek-window.cc | 36 +++++++++++++++++++++----- src/spek-window.hh | 1 + src/spek-window.vala | 60 -------------------------------------------- 3 files changed, 31 insertions(+), 66 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index c557ffe..da9b1d2 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -16,6 +16,7 @@ * along with Spek. If not, see . */ +#include #include #include #include @@ -53,7 +54,8 @@ private: SpekWindow::SpekWindow(const wxString& path) : path(path), wxFrame(NULL, -1, wxEmptyString) { - SetTitle(_("Spek - Acoustic Spectrum Analyser")); + this->description = _("Spek - Acoustic Spectrum Analyser"); + SetTitle(this->description); // TODO: test on all platforms //SetIcon(wxIcon(wxT("spek"))); @@ -155,7 +157,7 @@ static const char *audio_extensions[] = { NULL }; -void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_open(wxCommandEvent& event) { static wxString filters = wxEmptyString; static int filter_index = 1; @@ -195,7 +197,7 @@ void SpekWindow::on_open(wxCommandEvent& WXUNUSED(event)) dlg->Destroy(); } -void SpekWindow::on_save(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_save(wxCommandEvent& event) { static wxString filters = wxEmptyString; @@ -230,15 +232,37 @@ void SpekWindow::on_save(wxCommandEvent& WXUNUSED(event)) dlg->Destroy(); } -void SpekWindow::on_exit(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_exit(wxCommandEvent& event) { Close(true); } -void SpekWindow::on_preferences(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_preferences(wxCommandEvent& event) { } -void SpekWindow::on_about(wxCommandEvent& WXUNUSED(event)) +void SpekWindow::on_about(wxCommandEvent& event) { + wxAboutDialogInfo info; + info.AddDeveloper(wxT("Alexander Kojevnikov")); + info.AddDeveloper(wxT("Fabian Deutsch")); + info.AddDeveloper(wxT("Jonathan Gonzalez V")); + info.AddDeveloper(wxT("Stefan Kost")); + info.AddDeveloper(wxT("Thibault North")); + info.AddArtist(wxT("Olga Vasylevska")); + // TRANSLATORS: Add your name here + wxString translator = _("translator-credits"); + if (translator != wxT("translator-credits")) { + info.AddTranslator(translator); + } + info.SetName(wxT("Spek")); + info.SetVersion(wxT(PACKAGE_VERSION)); + info.SetCopyright(_("Copyright (c) 2010-2012 Alexander Kojevnikov and contributors")); + info.SetDescription(this->description); +#ifdef OS_UNIX + info.SetWebSite(wxT("http://spek-project.org/"), _("Spek Website")); + // TODO + // info.SetIcon(); +#endif + wxAboutBox(info); } diff --git a/src/spek-window.hh b/src/spek-window.hh index 4164338..b0283d8 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -39,6 +39,7 @@ private: SpekSpectrogram *spectrogram; wxString path; wxString cur_dir; + wxString description; DECLARE_EVENT_TABLE() }; diff --git a/src/spek-window.vala b/src/spek-window.vala index 3f3ab78..a1f02f9 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -69,66 +69,6 @@ namespace Spek { dlg.run (); } - private void on_help_about () { - string[] authors = { - "Primary Development:", - "\tAlexander Kojevnikov (maintainer)", - "", - "Contributors:", - "\tFabian Deutsch", - "\tJonathan Gonzalez V", - "\tStefan Kost", - "\tThibault North" - }; - string[] artists = { - "Olga Vasylevska" - }; - string license = "Copyright (C) 2010-2011 Alexander Kojevnikov"; - license += "\n\n"; - license += "Spek is free software: you can redistribute it and/or modify "; - license += "it under the terms of the GNU General Public License as published by "; - license += "the Free Software Foundation, either version 3 of the License, or "; - license += "(at your option) any later version."; - license += "\n\n"; - license += "Spek is distributed in the hope that it will be useful, "; - license += "but WITHOUT ANY WARRANTY; without even the implied warranty of "; - license += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "; - license += "GNU General Public License for more details."; - license += "\n\n"; - license += "You should have received a copy of the GNU General Public License "; - license += "along with Spek. If not, see http://www.gnu.org/licenses/"; - - var dlg = new AboutDialog (); - dlg.program_name = "Spek"; - dlg.version = Config.PACKAGE_VERSION; - dlg.copyright = _("Copyright \xc2\xa9 2010-2011 Alexander Kojevnikov"); - dlg.comments = description; - dlg.set ("authors", authors); -// dlg.set ("documenters", documenters); - dlg.set ("artists", artists); - dlg.website_label = _("Spek Website"); - dlg.website = "http://www.spek-project.org/"; - dlg.license = license; - dlg.wrap_license = true; - try { - dlg.logo = IconTheme.get_default ().load_icon ("spek", 128, IconLookupFlags.FORCE_SVG); - } catch (Error e) { - dlg.logo_icon_name = "spek"; - } - // TRANSLATORS: Add your name here - dlg.translator_credits = _("translator-credits"); - dlg.set_transient_for (this); - dlg.destroy_with_parent = true; - dlg.response.connect (id => dlg.destroy ()); - dlg.set_url_hook (url_hook); - dlg.modal = true; - dlg.present (); - } - - private void url_hook (AboutDialog about, string link) { - Platform.show_uri (link); - } - private void * check_version () { // Does the user want to check for updates? var prefs = Preferences.instance; From 02893f9a42339b48daea040715c2882b84ae295c Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Mon, 20 Aug 2012 20:39:24 -0700 Subject: [PATCH 49/60] Fix compilation with FFmpeg 0.11 --- src/spek-audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spek-audio.c b/src/spek-audio.c index b4db794..4a5af10 100644 --- a/src/spek-audio.c +++ b/src/spek-audio.c @@ -124,19 +124,19 @@ struct spek_audio_context * spek_audio_open(const char *path) return cx; } switch (cx->codec_context->sample_fmt) { - case SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S16: cx->properties.width = 16; cx->properties.fp = false; break; - case SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_S32: cx->properties.width = 32; cx->properties.fp = false; break; - case SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_FLT: cx->properties.width = 32; cx->properties.fp = true; break; - case SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_DBL: cx->properties.width = 64; cx->properties.fp = true; break; From 668c8a7c3c5d1591159fdf7932b608a0c613be36 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 21 Aug 2012 01:00:51 -0700 Subject: [PATCH 50/60] Custom info bar --- src/spek-window.cc | 39 +++++++++++++++++++++++++++++++++++++++ src/spek-window.hh | 2 ++ src/spek-window.vala | 34 ---------------------------------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index da9b1d2..b29c3f9 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -100,7 +100,32 @@ SpekWindow::SpekWindow(const wxString& path) : ); toolbar->Realize(); + wxSizer *sizer = new wxBoxSizer(wxVERTICAL); + + // wxInfoBar is too limited, construct a custom one. + wxPanel *info_bar = new wxPanel(this); + info_bar->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); + info_bar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); + wxSizer *info_sizer = new wxBoxSizer(wxHORIZONTAL); + wxStaticText *label = new wxStaticText( + info_bar, -1, _("A new version of Spek is available, click to download.")); + label->SetCursor(*new wxCursor(wxCURSOR_HAND)); + label->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit)); + // This second Connect() handles clicks on the border + info_bar->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit)); + info_sizer->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6); + // TODO: gtk-close won't work on win/osx + wxBitmapButton *button = new wxBitmapButton( + info_bar, -1, wxArtProvider::GetBitmap(wxT("gtk-close")), + wxDefaultPosition, wxDefaultSize, wxNO_BORDER); + button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SpekWindow::on_close)); + info_sizer->Add(button, 0, 0); + info_bar->SetSizer(info_sizer); + sizer->Add(info_bar, 0, wxEXPAND); + this->spectrogram = new SpekSpectrogram(this); + sizer->Add(this->spectrogram, 1, wxEXPAND); + this->cur_dir = wxGetHomeDir(); if (!path.IsEmpty()) { @@ -108,6 +133,8 @@ SpekWindow::SpekWindow(const wxString& path) : } SetDropTarget(new SpekDropTarget(this)); + + SetSizer(sizer); } void SpekWindow::open(const wxString& path) @@ -266,3 +293,15 @@ void SpekWindow::on_about(wxCommandEvent& event) #endif wxAboutBox(info); } + +void SpekWindow::on_visit(wxCommandEvent& event) +{ + wxLaunchDefaultBrowser(wxT("http://spek-project.org")); +} + +void SpekWindow::on_close(wxCommandEvent& event) +{ + wxWindow *self = ((wxWindow *)event.GetEventObject())->GetGrandParent(); + self->GetSizer()->Hide((size_t)0); + self->Layout(); +} diff --git a/src/spek-window.hh b/src/spek-window.hh index b0283d8..4067cea 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -35,6 +35,8 @@ private: void on_exit(wxCommandEvent& event); void on_preferences(wxCommandEvent& event); void on_about(wxCommandEvent& event); + void on_visit(wxCommandEvent& event); + void on_close(wxCommandEvent& event); SpekSpectrogram *spectrogram; wxString path; diff --git a/src/spek-window.vala b/src/spek-window.vala index a1f02f9..931c9a0 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -22,41 +22,7 @@ using Gtk; namespace Spek { public class Window : Gtk.Window { - private UIManager ui; - private InfoBar info_bar; - private Spectrogram spectrogram; - private string description; - private string cur_dir; - private FileFilter filter_all; - private FileFilter filter_audio; - private FileFilter filter_png; - - - private const Gtk.TargetEntry[] DEST_TARGET_ENTRIES = { - { "text/uri-list", 0, 0 } - }; - public Window (string? file_name) { - info_bar = new InfoBar.with_buttons (Stock.OK, ResponseType.OK); - var label = new Label (null); - label.use_markup = true; - label.set_markup (_("A new version of Spek is available on www.spek-project.org")); - label.ellipsize = Pango.EllipsizeMode.END; - label.xalign = 0f; - label.activate_link.connect (uri => { Platform.show_uri (uri); return true; }); - label.show(); - var content_area = (Container) info_bar.get_content_area(); - content_area.add(label); - info_bar.message_type = MessageType.INFO; - info_bar.response.connect(() => info_bar.hide()); - - var vbox = new VBox (false, 0); - vbox.pack_start (info_bar, false, true, 0); - add (vbox); - vbox.show (); - - show (); - try { Thread.create (check_version, false); } catch (ThreadError e) { From 47fc4b95d6d86338673ee048b335af087e0f1696 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 21 Aug 2012 10:15:24 -0700 Subject: [PATCH 51/60] Bump the version number + tidy --- configure.ac | 2 +- src/spek-pipeline.c | 9 ++++++--- src/spek-spectrogram.cc | 8 +++++--- src/spek-window.cc | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 409e891..e67132a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([spek],[0.7]) +AC_INIT([spek],[0.8.0]) AC_CONFIG_SRCDIR([src/spek.cc]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([1.11.1 foreign no-dist-gzip dist-xz]) diff --git a/src/spek-pipeline.c b/src/spek-pipeline.c index e9b868a..49f1d37 100644 --- a/src/spek-pipeline.c +++ b/src/spek-pipeline.c @@ -143,7 +143,8 @@ void spek_pipeline_start(struct spek_pipeline *p) } } -void spek_pipeline_close(struct spek_pipeline *p) { +void spek_pipeline_close(struct spek_pipeline *p) +{ if (p->has_reader_thread) { p->quit = true; pthread_join(p->reader_thread, NULL); @@ -188,7 +189,8 @@ void spek_pipeline_close(struct spek_pipeline *p) { free(p); } -static void * reader_func (void *pp) { +static void * reader_func(void *pp) +{ struct spek_pipeline *p = pp; p->has_worker_thread = !pthread_create(&p->worker_thread, NULL, &worker_func, p); @@ -243,7 +245,8 @@ static void reader_sync(struct spek_pipeline *p, int pos) pthread_mutex_unlock(&p->worker_mutex); } -static void * worker_func (void *pp) { +static void * worker_func(void *pp) +{ struct spek_pipeline *p = pp; int sample = 0; diff --git a/src/spek-spectrogram.cc b/src/spek-spectrogram.cc index efc1299..7d5c7e0 100644 --- a/src/spek-spectrogram.cc +++ b/src/spek-spectrogram.cc @@ -43,7 +43,7 @@ enum BANDS = NFFT / 2 + 1, LPAD = 60, TPAD = 60, - RPAD = 80, + RPAD = 90, BPAD = 40, GAP = 10, RULER = 10, @@ -184,6 +184,8 @@ void SpekSpectrogram::render(wxDC& dc) int normal_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); dc.SetFont(large_font); int large_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); + dc.SetFont(small_font); + int small_height = dc.GetTextExtent(wxT("dummy")).GetHeight(); // Clean the background. dc.Clear(); @@ -197,11 +199,11 @@ void SpekSpectrogram::render(wxDC& dc) TPAD - 2 * GAP - normal_height - large_height ); int package_name_width = dc.GetTextExtent(package_name + wxT(" ")).GetWidth(); - dc.SetFont(normal_font); + dc.SetFont(small_font); dc.DrawText( wxT(PACKAGE_VERSION), w - RPAD + GAP + package_name_width, - TPAD - 2 * GAP - 2 * normal_height + TPAD - 2 * GAP - normal_height - small_height ); if (this->image.GetHeight() > 1) { diff --git a/src/spek-window.cc b/src/spek-window.cc index b29c3f9..54943ca 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -119,7 +119,7 @@ SpekWindow::SpekWindow(const wxString& path) : info_bar, -1, wxArtProvider::GetBitmap(wxT("gtk-close")), wxDefaultPosition, wxDefaultSize, wxNO_BORDER); button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SpekWindow::on_close)); - info_sizer->Add(button, 0, 0); + info_sizer->Add(button, 0, wxALIGN_CENTER_VERTICAL); info_bar->SetSizer(info_sizer); sizer->Add(info_bar, 0, wxEXPAND); From 0d2514e018d1077c32b8ff1388f990e9de1e8c18 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 21 Aug 2012 10:32:16 -0700 Subject: [PATCH 52/60] Check for a new version --- src/spek-window.cc | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/spek-window.hh | 1 + src/spek-window.vala | 43 ------------------------------ 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index 54943ca..c5993d2 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -16,23 +16,33 @@ * along with Spek. If not, see . */ +#include + #include #include #include #include +#include "spek-preferences.hh" #include "spek-spectrogram.hh" #include "spek-window.hh" +DECLARE_EVENT_TYPE(SPEK_NOTIFY_EVENT, -1) +DEFINE_EVENT_TYPE(SPEK_NOTIFY_EVENT) + BEGIN_EVENT_TABLE(SpekWindow, wxFrame) EVT_MENU(wxID_OPEN, SpekWindow::on_open) EVT_MENU(wxID_SAVE, SpekWindow::on_save) EVT_MENU(wxID_EXIT, SpekWindow::on_exit) EVT_MENU(wxID_PREFERENCES, SpekWindow::on_preferences) EVT_MENU(wxID_ABOUT, SpekWindow::on_about) + EVT_COMMAND(-1, SPEK_NOTIFY_EVENT, SpekWindow::on_notify) END_EVENT_TABLE() +// Forward declarations. +static void * check_version(void *); + class SpekDropTarget : public wxFileDropTarget { public: @@ -104,6 +114,7 @@ SpekWindow::SpekWindow(const wxString& path) : // wxInfoBar is too limited, construct a custom one. wxPanel *info_bar = new wxPanel(this); + info_bar->Hide(); info_bar->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT)); info_bar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); wxSizer *info_sizer = new wxBoxSizer(wxHORIZONTAL); @@ -135,6 +146,9 @@ SpekWindow::SpekWindow(const wxString& path) : SetDropTarget(new SpekDropTarget(this)); SetSizer(sizer); + + pthread_t thread; + pthread_create(&thread, NULL, &check_version, this); } void SpekWindow::open(const wxString& path) @@ -294,6 +308,12 @@ void SpekWindow::on_about(wxCommandEvent& event) wxAboutBox(info); } +void SpekWindow::on_notify(wxCommandEvent& event) +{ + this->GetSizer()->Show((size_t)0); + this->Layout(); +} + void SpekWindow::on_visit(wxCommandEvent& event) { wxLaunchDefaultBrowser(wxT("http://spek-project.org")); @@ -305,3 +325,45 @@ void SpekWindow::on_close(wxCommandEvent& event) self->GetSizer()->Hide((size_t)0); self->Layout(); } + +static void * check_version(void *p) +{ + // Does the user want to check for updates? + SpekPreferences& prefs = SpekPreferences::get(); + if (!prefs.get_check_update()) { + return NULL; + } + + // Calculate the number of days since 0001-01-01, borrowed from GLib. + wxDateTime now = wxDateTime::Now(); + int year = now.GetYear() - 1; + int days = year * 365; + days += (year >>= 2); // divide by 4 and add + days -= (year /= 25); // divides original # years by 100 + days += year >> 2; // divides by 4, which divides original by 400 + days += now.GetDayOfYear(); + + // When was the last update? + int diff = days - prefs.get_last_update(); + if (diff < 7) { + return NULL; + } + + // Get the version number. + wxString version = wxT("0.8.1"); //Platform.read_line ("http://www.spek-project.org/version"); + if (version.IsEmpty()) { + return NULL; + } + + if (version > wxT(PACKAGE_VERSION)) { + SpekWindow *self = (SpekWindow *)p; + wxCommandEvent event(SPEK_NOTIFY_EVENT, -1); + event.SetEventObject(self); + wxPostEvent(self, event); + } + + // Update the preferences. + prefs.set_check_update(true); + prefs.set_last_update(days); + return NULL; +} diff --git a/src/spek-window.hh b/src/spek-window.hh index 4067cea..091ac12 100644 --- a/src/spek-window.hh +++ b/src/spek-window.hh @@ -35,6 +35,7 @@ private: void on_exit(wxCommandEvent& event); void on_preferences(wxCommandEvent& event); void on_about(wxCommandEvent& event); + void on_notify(wxCommandEvent& event); void on_visit(wxCommandEvent& event); void on_close(wxCommandEvent& event); diff --git a/src/spek-window.vala b/src/spek-window.vala index 931c9a0..513e993 100644 --- a/src/spek-window.vala +++ b/src/spek-window.vala @@ -22,53 +22,10 @@ using Gtk; namespace Spek { public class Window : Gtk.Window { - public Window (string? file_name) { - try { - Thread.create (check_version, false); - } catch (ThreadError e) { - } - } - private void on_edit_preferences () { var dlg = new PreferencesDialog (); dlg.transient_for = this; dlg.run (); } - - private void * check_version () { - // Does the user want to check for updates? - var prefs = Preferences.instance; - var check = prefs.check_update; - if (!check) { - return null; - } - - // When was the last update? - var time_val = TimeVal (); - time_val.get_current_time (); - Date today = Date (); - today.set_time_val (time_val); - int day = prefs.last_update; - int diff = (int) today.get_julian () - day; - if (diff < 7) { - return null; - } - - // Get the version number. - var version = Platform.read_line ("http://www.spek-project.org/version"); - if (version == null) { - return null; - } - - if (version != null && version > Config.PACKAGE_VERSION) { - Idle.add (() => { info_bar.show_all (); return false; }); - } - - // Update the preferences. - prefs.check_update = check; - prefs.last_update = (int) today.get_julian (); - prefs.save (); - return null; - } } } From d0ae94627238944cc4fc8ca6674fd23dd2be3834 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 21 Aug 2012 22:22:50 -0700 Subject: [PATCH 53/60] Get the latest version from the website --- src/spek-window.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/spek-window.cc b/src/spek-window.cc index c5993d2..8f521d9 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "spek-preferences.hh" #include "spek-spectrogram.hh" @@ -350,7 +352,18 @@ static void * check_version(void *p) } // Get the version number. - wxString version = wxT("0.8.1"); //Platform.read_line ("http://www.spek-project.org/version"); + wxString version; + wxHTTP http; + if (http.Connect(wxT("spek-project.org"))) { + wxInputStream *stream = http.GetInputStream(wxT("/version")); + if (stream) { + wxStringOutputStream out(&version); + stream->Read(out); + version.Trim(); + delete stream; + } + } + if (version.IsEmpty()) { return NULL; } From 6f7c565bd16d9ef82a79a2c0e182fed4d9452747 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Tue, 21 Aug 2012 22:30:22 -0700 Subject: [PATCH 54/60] Fix version check under OSX --- src/spek.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/spek.cc b/src/spek.cc index fa92184..664fdfd 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -18,6 +18,7 @@ #include #include +#include #include "spek-audio.h" #include "spek-platform.hh" @@ -44,6 +45,7 @@ IMPLEMENT_APP(Spek) bool Spek::OnInit() { wxInitAllImageHandlers(); + wxSocketBase::Initialize(); SpekPlatform::init(); SpekPreferences::get().init(); From 873b451cd3a08f89d632c3fac4c5abb02a0e6081 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 22 Aug 2012 09:35:28 -0700 Subject: [PATCH 55/60] Remove obsolete file --- src/spek-platform.c | 76 --------------------------------------------- 1 file changed, 76 deletions(-) delete mode 100644 src/spek-platform.c diff --git a/src/spek-platform.c b/src/spek-platform.c deleted file mode 100644 index d70d514..0000000 --- a/src/spek-platform.c +++ /dev/null @@ -1,76 +0,0 @@ -/* spek-platform.c - * - * Copyright (C) 2010,2011 Alexander Kojevnikov - * - * 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 . - */ - -#include -#include - -#ifdef G_OS_WIN32 -#include -#include -#endif - -#ifdef G_OS_DARWIN -#include -#include -#include -#endif - -#include "spek-platform.h" - -gchar *spek_platform_read_line (const gchar *uri) { -#ifdef G_OS_DARWIN - /* GIO doesn't work on OS X */ - CFStringRef str = NULL; - CFURLRef url = NULL; - CFDataRef data = NULL; - CFIndex length = 0; - gchar *buf = NULL; - - str = CFStringCreateWithCString (NULL, uri, kCFStringEncodingASCII); - url = CFURLCreateWithString (NULL, str, NULL); - if (CFURLCreateDataAndPropertiesFromResource (NULL, url, &data, NULL, NULL, NULL)) { - length = CFDataGetLength (data); - buf = (gchar *) g_malloc (length + 1); - CFDataGetBytes (data, CFRangeMake (0, length), (UInt8 *) buf); - buf[length] = '\0'; - g_strchomp (buf); - CFRelease (data); - } - CFRelease (url); - CFRelease (str); - return buf; -#else - gchar *line = NULL; - GFile *file = NULL; - GFileInputStream *file_stream = NULL; - - file = g_file_new_for_uri (uri); - file_stream = g_file_read (file, NULL, NULL); - if (file_stream) { - GDataInputStream *data_stream = NULL; - - data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream)); - line = g_data_input_stream_read_line (data_stream, NULL, NULL, NULL); - - g_object_unref (data_stream); - g_object_unref (file_stream); - } - g_object_unref (file); - return line; -#endif -} From 1ff2597fdbe183cc32aeeed2718e0598c9fe3d55 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Wed, 22 Aug 2012 09:40:50 -0700 Subject: [PATCH 56/60] Make config dir if it doesn't exist --- src/spek-platform.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spek-platform.cc b/src/spek-platform.cc index 8b26be5..8595361 100644 --- a/src/spek-platform.cc +++ b/src/spek-platform.cc @@ -40,12 +40,13 @@ void SpekPlatform::init() wxString SpekPlatform::config_path(const wxString& app_name) { #ifdef OS_WIN - wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir()); + wxFileName file_name(wxStandardPaths::Get().GetUserConfigDir(), wxEmptyString); #else wxFileName file_name(wxGetHomeDir(), wxEmptyString); file_name.AppendDir(wxT(".config")); #endif file_name.AppendDir(app_name); + file_name.Mkdir(0755, wxPATH_MKDIR_FULL); file_name.SetFullName(wxT("preferences")); return file_name.GetFullPath(); } From dc7ce9a4c27b572cd90fea71401fbf42330be463 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 26 Aug 2012 18:39:41 -0700 Subject: [PATCH 57/60] Preferences dialogue --- src/Makefile.am | 2 + src/spek-preferences-dialog.cc | 113 ++++++++++++++++++ ...window.vala => spek-preferences-dialog.hh} | 33 +++-- src/spek-preferences-dialog.vala | 109 ----------------- src/spek-window.cc | 3 + 5 files changed, 138 insertions(+), 122 deletions(-) create mode 100644 src/spek-preferences-dialog.cc rename src/{spek-window.vala => spek-preferences-dialog.hh} (58%) delete mode 100644 src/spek-preferences-dialog.vala diff --git a/src/Makefile.am b/src/Makefile.am index 10fd4b2..7ff668d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,8 @@ spek_SOURCES = \ spek-pipeline.h \ spek-platform.cc \ spek-platform.hh \ + spek-preferences-dialog.cc \ + spek-preferences-dialog.hh \ spek-preferences.cc \ spek-preferences.hh \ spek-ruler.cc \ diff --git a/src/spek-preferences-dialog.cc b/src/spek-preferences-dialog.cc new file mode 100644 index 0000000..5d66ec5 --- /dev/null +++ b/src/spek-preferences-dialog.cc @@ -0,0 +1,113 @@ +/* spek-preferences-dialog.cc + * + * Copyright (C) 2011-2012 Alexander Kojevnikov + * + * 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 . + */ + +#include "spek-preferences.hh" + +#include "spek-preferences-dialog.hh" + +// List all languages with a decent (e.g. 80%) number of translated +// strings. Don't translate language names. Keep the first line intact. +static const char *available_languages[] = +{ + "", "", + "cs", "Čeština", + "de", "Deutsch", + "en", "English", + "eo", "Esperanto", + "es", "Español", + "fr", "Français", + "it", "Italiano", + "ja", "日本語", + "nl", "Nederlands", + "pl", "Polski", + "pt_BR", "Português brasileiro", + "ru", "Русский", + "sv", "Svenska", + "uk", "Українська", + "zh_CN", "中文(简体)", + "zh_TW", "中文(台灣)", + NULL +}; + +#ifndef wxCLOSE +// wxWidgets 2.8 doesn't have wxCLOSE, replace with wxOK for now. +#define wxCLOSE wxOK +#endif + +#define ID_LANGUAGE (wxID_HIGHEST + 1) +#define ID_CHECK (wxID_HIGHEST + 2) + +BEGIN_EVENT_TABLE(SpekPreferencesDialog, wxDialog) + EVT_CHOICE(ID_LANGUAGE, SpekPreferencesDialog::on_language) + EVT_CHECKBOX(ID_CHECK, SpekPreferencesDialog::on_check) +END_EVENT_TABLE() + +SpekPreferencesDialog::SpekPreferencesDialog(wxWindow *parent) : + wxDialog(parent, -1, _("Preferences")) +{ + for (int i = 0; available_languages[i]; ++i) { + this->languages.Add(wxString::FromUTF8(available_languages[i])); + } + this->languages[1] = _("(system default)"); + + wxSizer *sizer = new wxBoxSizer(wxVERTICAL); + wxSizer *inner_sizer = new wxBoxSizer(wxVERTICAL); + sizer->Add(inner_sizer, 1, wxALL, 12); + + // TRANSLATORS: The name of a section in the Preferences dialog. + wxStaticText *general_label = new wxStaticText(this, -1, _("General")); + wxFont font = general_label->GetFont(); + font.SetWeight(wxFONTWEIGHT_BOLD); + general_label->SetFont(font); + inner_sizer->Add(general_label); + + wxSizer *language_sizer = new wxBoxSizer(wxHORIZONTAL); + inner_sizer->Add(language_sizer, 0, wxLEFT | wxTOP, 12); + wxStaticText *language_label = new wxStaticText(this, -1, _("Language:")); + language_sizer->Add(language_label, 0, wxALIGN_CENTER_VERTICAL); + + wxChoice *language_choice = new wxChoice(this, ID_LANGUAGE); + language_sizer->Add(language_choice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 12); + int active_index = 0; + wxString active_language = SpekPreferences::get().get_language(); + for (int i = 0; i < this->languages.GetCount(); i += 2) { + language_choice->Append(this->languages[i + 1]); + if (this->languages[i] == active_language) { + active_index = i / 2; + } + } + language_choice->SetSelection(active_index); + + wxCheckBox *check_update = new wxCheckBox(this, ID_CHECK, _("Check for &updates")); + inner_sizer->Add(check_update, 0 ,wxLEFT | wxTOP, 12); + check_update->SetValue(SpekPreferences::get().get_check_update()); + + sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxALIGN_RIGHT | wxBOTTOM | wxRIGHT, 12); + sizer->SetSizeHints(this); + SetSizer(sizer); +} + +void SpekPreferencesDialog::on_language(wxCommandEvent& event) +{ + SpekPreferences::get().set_language(this->languages[event.GetSelection() * 2]); +} + +void SpekPreferencesDialog::on_check(wxCommandEvent& event) +{ + SpekPreferences::get().set_check_update(event.IsChecked()); +} diff --git a/src/spek-window.vala b/src/spek-preferences-dialog.hh similarity index 58% rename from src/spek-window.vala rename to src/spek-preferences-dialog.hh index 513e993..e9267b7 100644 --- a/src/spek-window.vala +++ b/src/spek-preferences-dialog.hh @@ -1,6 +1,6 @@ -/* spek-window.vala +/* spek-preferences-dialog.hh * - * Copyright (C) 2010-2011 Alexander Kojevnikov + * Copyright (C) 2011-2012 Alexander Kojevnikov * * Spek is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,16 +16,23 @@ * along with Spek. If not, see . */ -using Gdk; -using Gtk; +#ifndef SPEK_PREFERENCES_DIALOG_HH_ +#define SPEK_PREFERENCES_DIALOG_HH_ -namespace Spek { - public class Window : Gtk.Window { +#include - private void on_edit_preferences () { - var dlg = new PreferencesDialog (); - dlg.transient_for = this; - dlg.run (); - } - } -} +class SpekPreferencesDialog : public wxDialog +{ +public: + SpekPreferencesDialog(wxWindow *parent); + +private: + void on_language(wxCommandEvent& event); + void on_check(wxCommandEvent& event); + + wxArrayString languages; + + DECLARE_EVENT_TABLE() +}; + +#endif diff --git a/src/spek-preferences-dialog.vala b/src/spek-preferences-dialog.vala deleted file mode 100644 index 0221481..0000000 --- a/src/spek-preferences-dialog.vala +++ /dev/null @@ -1,109 +0,0 @@ -/* spek-preferences-dialog.vala - * - * Copyright (C) 2011 Alexander Kojevnikov - * - * 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 . - */ - -using Gtk; - -namespace Spek { - public class PreferencesDialog : Gtk.Dialog { - // List all languages with a decent (e.g. 80%) number of translated - // strings. Don't translate language names. Keep the first line intact. - private static string[,] languages = { - {"", null}, - {"cs", "Čeština"}, - {"de", "Deutsch"}, - {"en", "English"}, - {"eo", "Esperanto"}, - {"es", "Español"}, - {"fr", "Français"}, - {"it", "Italiano"}, - {"ja", "日本語"}, - {"nl", "Nederlands"}, - {"pl", "Polski"}, - {"pt_BR", "Português brasileiro"}, - {"ru", "Русский"}, - {"sv", "Svenska"}, - {"uk", "Українська"}, - {"zh_CN", "中文(简体)"}, - {"zh_TW", "中文(台灣)"} - }; - - public PreferencesDialog () { - title = _("Preferences"); - modal = true; - resizable = false; - window_position = WindowPosition.CENTER_ON_PARENT; - languages[0,1] = _("(system default)"); - - var alignment = new Alignment (0.5f, 0.5f, 1f, 1f); - alignment.set_padding (12, 12, 12, 12); - var box = new VBox (false, 0); - - var general_box = new VBox (false, 6); - // TRANSLATORS: The name of a section in the Preferences dialog. - var general_label = new Label (_("General")); - var attributes = new Pango.AttrList (); - attributes.insert (Pango.attr_weight_new (Pango.Weight.BOLD)); - general_label.attributes = attributes; - general_label.xalign = 0; - general_box.pack_start (general_label, false, false, 0); - var general_alignment = new Alignment (0.5f, 0.5f, 1f, 1f); - general_alignment.left_padding = 12; - var general_subbox = new VBox (false, 6); - var language_box = new HBox (false, 12); - var language_label = new Label.with_mnemonic (_("_Language:")); - language_box.pack_start (language_label, false, false, 0); - var language_combo = new ComboBox.text (); - int active_language = 0; - var prefs = Preferences.instance; - for (int i = 0; i < languages.length[0]; i++) { - language_combo.append_text (languages[i,1]); - if (languages[i,0] == prefs.language) { - active_language = i; - } - } - language_combo.active = active_language; - language_combo.changed.connect ( - () => prefs.language = languages[language_combo.active,0]); - language_label.mnemonic_widget = language_combo; - language_box.pack_start (language_combo, false, false, 0); - general_subbox.pack_start(language_box, false, false, 0); - var check_update = new CheckButton.with_mnemonic (_("Check for _updates")); - check_update.active = prefs.check_update; - check_update.toggled.connect ( - () => prefs.check_update = check_update.active); - general_subbox.pack_start (check_update, false, false, 0); - general_alignment.add (general_subbox); - general_box.pack_start (general_alignment, false, false, 0); - - box.pack_start (general_box, false, false, 0); - alignment.add (box); - var vbox = (VBox) get_content_area (); - vbox.pack_start (alignment, false, false, 0); - vbox.show_all (); - - add_button (Stock.CLOSE, ResponseType.CLOSE); - set_default_response (ResponseType.CLOSE); - response.connect (on_response); - } - - private void on_response (Dialog dialog, int response_id) { - Preferences.instance.save (); - destroy (); - } - } -} \ No newline at end of file diff --git a/src/spek-window.cc b/src/spek-window.cc index 8f521d9..8b860ac 100644 --- a/src/spek-window.cc +++ b/src/spek-window.cc @@ -25,6 +25,7 @@ #include #include +#include "spek-preferences-dialog.hh" #include "spek-preferences.hh" #include "spek-spectrogram.hh" @@ -282,6 +283,8 @@ void SpekWindow::on_exit(wxCommandEvent& event) void SpekWindow::on_preferences(wxCommandEvent& event) { + SpekPreferencesDialog dlg(this); + dlg.ShowModal(); } void SpekWindow::on_about(wxCommandEvent& event) From a23952031322b7cbf6cf307a1e4e412edb5e56e8 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 26 Aug 2012 18:47:30 -0700 Subject: [PATCH 58/60] i18n: Update POTFILES --- po/POTFILES.in | 13 +++++-------- po/POTFILES.skip | 6 ------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 2dada74..44c74c3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,10 +1,7 @@ [encoding: UTF-8] data/spek.desktop.in.in -src/spek-audio.c -src/spek-pipeline.vala -src/spek-preferences-dialog.vala -src/spek-preferences.vala -src/spek-ruler.vala -src/spek-spectrogram.vala -src/spek-window.vala -src/spek.vala +src/spek-audio-desc.cc +src/spek-preferences-dialog.cc +src/spek-spectrogram.cc +src/spek-window.cc +src/spek.cc diff --git a/po/POTFILES.skip b/po/POTFILES.skip index b723dac..dbe2d10 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -1,7 +1 @@ data/spek.desktop.in -src/spek.c -src/spek-pipeline.c -src/spek-preferences-dialog.c -src/spek-preferences.c -src/spek-spectrogram.c -src/spek-window.c From b2420a777e48686237fa9338808dab018a5de2d6 Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 26 Aug 2012 19:50:05 -0700 Subject: [PATCH 59/60] i18n: Don't ask to translate \n --- src/spek.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spek.cc b/src/spek.cc index 664fdfd..72e0bec 100644 --- a/src/spek.cc +++ b/src/spek.cc @@ -87,7 +87,8 @@ bool Spek::OnInit() } if (parser.Found(wxT("version"))) { // TRANSLATORS: first %s is the package name, second %s is the package version. - wxPrintf(_("%s version %s\n"), wxT(PACKAGE_NAME), wxT(PACKAGE_VERSION)); + wxPrintf(_("%s version %s"), wxT(PACKAGE_NAME), wxT(PACKAGE_VERSION)); + wxPrintf(wxT("\n")); this->quit = true; return true; } From ff8b2eda43631bceb2cdd4e27f095bf9cf1d7a0a Mon Sep 17 00:00:00 2001 From: Alexander Kojevnikov Date: Sun, 26 Aug 2012 19:55:00 -0700 Subject: [PATCH 60/60] i18n: Update pot file --- po/spek.pot | 198 ++++++++++++++++++++++------------------------------ 1 file changed, 82 insertions(+), 116 deletions(-) diff --git a/po/spek.pot b/po/spek.pot index 51f8563..398438d 100644 --- a/po/spek.pot +++ b/po/spek.pot @@ -8,15 +8,14 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-08-26 19:30-0700\n" +"POT-Creation-Date: 2012-08-26 19:50-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ../data/spek.desktop.in.in.h:1 msgid "Spectrum Analyser" @@ -34,194 +33,161 @@ msgstr "" msgid "View spectrograms of your audio files" msgstr "" -#: ../src/spek-audio.c:47 -msgid "Cannot open input file" -msgstr "" - -#: ../src/spek-audio.c:54 -msgid "Cannot find stream info" -msgstr "" - -#: ../src/spek-audio.c:66 -msgid "The file contains no audio streams" -msgstr "" - -#: ../src/spek-audio.c:73 -msgid "Cannot find decoder" -msgstr "" - -#: ../src/spek-audio.c:91 -msgid "Unknown duration" -msgstr "" - -#: ../src/spek-audio.c:95 -msgid "No audio channels" -msgstr "" - -#: ../src/spek-audio.c:99 -msgid "Cannot open decoder" -msgstr "" - -#: ../src/spek-audio.c:120 -msgid "Unsupported sample format" -msgstr "" - -#: ../src/spek-pipeline.vala:70 +#: ../src/spek-audio-desc.cc:34 #, c-format msgid "%d kbps" msgstr "" -#: ../src/spek-pipeline.vala:73 +#: ../src/spek-audio-desc.cc:37 #, c-format msgid "%d Hz" msgstr "" -#: ../src/spek-pipeline.vala:78 -#, c-format -msgid "%d bit" -msgid_plural "%d bits" -msgstr[0] "" -msgstr[1] "" +#: ../src/spek-audio-desc.cc:65 +msgid "Cannot open input file" +msgstr "" -#: ../src/spek-pipeline.vala:81 -#, c-format -msgid "%d channel" -msgid_plural "%d channels" -msgstr[0] "" -msgstr[1] "" +#: ../src/spek-audio-desc.cc:68 +msgid "Cannot find stream info" +msgstr "" + +#: ../src/spek-audio-desc.cc:71 +msgid "The file contains no audio streams" +msgstr "" + +#: ../src/spek-audio-desc.cc:74 +msgid "Cannot find decoder" +msgstr "" + +#: ../src/spek-audio-desc.cc:77 +msgid "Unknown duration" +msgstr "" + +#: ../src/spek-audio-desc.cc:80 +msgid "No audio channels" +msgstr "" + +#: ../src/spek-audio-desc.cc:83 +msgid "Cannot open decoder" +msgstr "" + +#: ../src/spek-audio-desc.cc:86 +msgid "Unsupported sample format" +msgstr "" #. TRANSLATORS: first %s is the error message, second %s is stream description. -#: ../src/spek-pipeline.vala:88 +#: ../src/spek-audio-desc.cc:91 #, c-format msgid "%s: %s" msgstr "" -#: ../src/spek-preferences-dialog.vala:47 +#: ../src/spek-preferences-dialog.cc:62 msgid "Preferences" msgstr "" -#: ../src/spek-preferences-dialog.vala:51 +#: ../src/spek-preferences-dialog.cc:67 msgid "(system default)" msgstr "" #. TRANSLATORS: The name of a section in the Preferences dialog. -#: ../src/spek-preferences-dialog.vala:59 +#: ../src/spek-preferences-dialog.cc:74 msgid "General" msgstr "" -#: ../src/spek-preferences-dialog.vala:69 -msgid "_Language:" +#: ../src/spek-preferences-dialog.cc:82 +msgid "Language:" msgstr "" -#: ../src/spek-preferences-dialog.vala:86 -msgid "Check for _updates" +#: ../src/spek-preferences-dialog.cc:97 +msgid "Check for &updates" msgstr "" -#. TRANSLATORS: keep "00" unchanged, it's used to calc the text width -#: ../src/spek-spectrogram.vala:200 -msgid "00 kHz" -msgstr "" - -#: ../src/spek-spectrogram.vala:206 +#: ../src/spek-spectrogram.cc:152 #, c-format msgid "%d kHz" msgstr "" -#. TRANSLATORS: keep "-00" unchanged, it's used to calc the text width -#: ../src/spek-spectrogram.vala:257 -msgid "-00 dB" -msgstr "" - -#: ../src/spek-spectrogram.vala:263 +#: ../src/spek-spectrogram.cc:157 #, c-format msgid "%d dB" msgstr "" -#: ../src/spek-window.vala:35 -msgid "_File" +#. TRANSLATORS: keep "00" unchanged, it's used to calc the text width +#: ../src/spek-spectrogram.cc:259 +msgid "00 kHz" msgstr "" -#: ../src/spek-window.vala:39 -msgid "_Edit" +#. TRANSLATORS: keep "-00" unchanged, it's used to calc the text width +#: ../src/spek-spectrogram.cc:287 +msgid "-00 dB" msgstr "" -#: ../src/spek-window.vala:41 -msgid "_Help" -msgstr "" - -#: ../src/spek-window.vala:76 +#: ../src/spek-window.cc:70 msgid "Spek - Acoustic Spectrum Analyser" msgstr "" -#: ../src/spek-window.vala:103 -msgid "" -"A new version of Spek is available on www.spek-project.org" +#: ../src/spek-window.cc:84 +msgid "&File" msgstr "" -#: ../src/spek-window.vala:117 -msgid "All files" +#: ../src/spek-window.cc:91 +msgid "&Edit" msgstr "" -#: ../src/spek-window.vala:120 -msgid "PNG images" +#: ../src/spek-window.cc:98 +msgid "&Help" msgstr "" -#: ../src/spek-window.vala:123 -msgid "Audio files" +#: ../src/spek-window.cc:125 +msgid "A new version of Spek is available, click to download." msgstr "" #. TRANSLATORS: window title, %s is replaced with the file name -#: ../src/spek-window.vala:175 +#: ../src/spek-window.cc:164 #, c-format msgid "Spek - %s" msgstr "" -#: ../src/spek-window.vala:180 +#: ../src/spek-window.cc:211 +msgid "All files" +msgstr "" + +#: ../src/spek-window.cc:213 +msgid "Audio files" +msgstr "" + +#: ../src/spek-window.cc:227 msgid "Open File" msgstr "" -#: ../src/spek-window.vala:197 +#: ../src/spek-window.cc:249 +msgid "PNG images" +msgstr "" + +#: ../src/spek-window.cc:255 msgid "Save Spectrogram" msgstr "" #. Suggested name is .png -#: ../src/spek-window.vala:204 +#: ../src/spek-window.cc:263 msgid "Untitled" msgstr "" -#: ../src/spek-window.vala:259 -msgid "Copyright © 2010-2011 Alexander Kojevnikov" -msgstr "" - -#: ../src/spek-window.vala:264 -msgid "Spek Website" -msgstr "" - #. TRANSLATORS: Add your name here -#: ../src/spek-window.vala:274 +#: ../src/spek-window.cc:300 msgid "translator-credits" msgstr "" -#: ../src/spek.vala:25 -msgid "Display the version and exit" +#: ../src/spek-window.cc:306 +msgid "Copyright (c) 2010-2012 Alexander Kojevnikov and contributors" msgstr "" -#: ../src/spek.vala:42 -msgid "[FILE]" -msgstr "" - -#: ../src/spek.vala:46 -#, c-format -msgid "Run `%s --help` to see a full list of available command line options.\n" +#: ../src/spek-window.cc:309 +msgid "Spek Website" msgstr "" #. TRANSLATORS: first %s is the package name, second %s is the package version. -#: ../src/spek.vala:52 +#: ../src/spek.cc:90 #, c-format -msgid "%s version %s\n" -msgstr "" - -#: ../src/spek.vala:57 -msgid "Specify a single file\n" +msgid "%s version %s" msgstr ""