summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--README3
-rw-r--r--configure.ac14
-rw-r--r--deadbeef.h21
-rw-r--r--fftsg.c3322
-rw-r--r--playlist.c2
-rw-r--r--plugins.c2
-rw-r--r--plugins/artwork/artwork.c19
-rw-r--r--plugins/gtkui/Makefile.am6
-rw-r--r--plugins/gtkui/callbacks.c55
-rw-r--r--plugins/gtkui/callbacks.h4
-rw-r--r--plugins/gtkui/coverart.c68
-rw-r--r--plugins/gtkui/coverart.h4
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.c14
-rw-r--r--plugins/gtkui/ddbcellrenderertextmultiline.h9
-rw-r--r--plugins/gtkui/ddbequalizer.c3
-rw-r--r--plugins/gtkui/ddbequalizer.h3
-rw-r--r--plugins/gtkui/ddblistview.c48
-rw-r--r--plugins/gtkui/ddbseekbar.c27
-rw-r--r--plugins/gtkui/ddbseekbar.h5
-rw-r--r--plugins/gtkui/ddbtabstrip.c30
-rw-r--r--plugins/gtkui/deadbeef.glade45
-rw-r--r--plugins/gtkui/fileman.c16
-rw-r--r--plugins/gtkui/gtkui.c212
-rw-r--r--plugins/gtkui/gtkui.h10
-rw-r--r--plugins/gtkui/gtkui_api.h98
-rw-r--r--plugins/gtkui/gtkuigl.c52
-rw-r--r--plugins/gtkui/gtkuigl.h36
-rw-r--r--plugins/gtkui/interface.c136
-rw-r--r--plugins/gtkui/mainplaylist.c25
-rw-r--r--plugins/gtkui/mainplaylist.h5
-rw-r--r--plugins/gtkui/plcommon.c34
-rw-r--r--plugins/gtkui/plcommon.h12
-rw-r--r--plugins/gtkui/prefwin.c30
-rw-r--r--plugins/gtkui/search.c18
-rw-r--r--plugins/gtkui/trkproperties.c45
-rw-r--r--plugins/gtkui/trkproperties.h8
-rw-r--r--plugins/gtkui/widgets.c2225
-rw-r--r--plugins/gtkui/widgets.h105
-rw-r--r--plugins/medialib/Makefile.am8
-rw-r--r--plugins/medialib/medialib.c256
-rw-r--r--plugins/supereq/Makefile.am41
-rwxr-xr-xscripts/quickinstall.sh1
-rw-r--r--streamer.c56
-rw-r--r--streamer.h3
-rw-r--r--tools/pluginfo/pluginfo.c13
46 files changed, 6785 insertions, 367 deletions
diff --git a/Makefile.am b/Makefile.am
index bc58549e..34bff094 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,7 +36,8 @@ deadbeef_SOURCES =\
gettext.h\
ringbuf.c ringbuf.h\
dsppreset.c dsppreset.h\
- replaygain.c replaygain.h
+ replaygain.c replaygain.h\
+ fftsg.c
# ConvertUTF/ConvertUTF.c ConvertUTF/ConvertUTF.h
diff --git a/README b/README
index 583b0dcc..e4fc8c1a 100644
--- a/README
+++ b/README
@@ -41,13 +41,14 @@ most of them are optional, which means deadbeef will build and run without them,
libsndfile: for sndfile plugin
libcdio + libcddb: for cd audio plugin
ffmpeg < 0.11: for ffmpeg plugin (versions >= 0.11 are not supported)
- xlib: for global hotkeys
+ xlib: for global hotkeys and for gtkui opengl support
dbus: for notification daemon support (OSD current song notifications)
pulseaudio: for PulseAudio output plugin
faad2: for AAC plugin
zlib: for Audio Overload plugin (psf, psf2, etc), GME (for vgz)
libzip: for vfs_zip plugin
yasm: required to build assembly portions of ffap plugin on supported platforms (x86, x86_64)
+ gtkglext: for gtkui opengl support
actual package names for your Linux distribution may vary.
diff --git a/configure.ac b/configure.ac
index f880c5e6..0f90e27a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,6 +105,7 @@ AC_ARG_ENABLE(m3u, [AS_HELP_STRING([--enable-m3u ], [build m3u plugin
AC_ARG_ENABLE(vfs-zip, [AS_HELP_STRING([--enable-vfs-zip ], [build vfs_zip plugin (default: auto)])], [enable_vfs_zip=$enableval], [enable_vfs_zip=yes])
AC_ARG_ENABLE(converter, [AS_HELP_STRING([--enable-converter ], [build converter plugin (default: auto)])], [enable_converter=$enableval], [enable_converter=yes])
AC_ARG_ENABLE(artwork-imlib2, [AS_HELP_STRING([--enable-artwork-imlib2 ], [use imlib2 in artwork plugin (default: auto)])], [enable_artwork_imlib2=$enableval], [enable_artwork_imlib2=yes])
+AC_ARG_ENABLE(medialib, [AS_HELP_STRING([--enable-medialib ], [build medialibrary plugin (default: auto)])], [enable_medialib=$enableval], [enable_medialib=yes])
AC_ARG_ENABLE(dumb, [AS_HELP_STRING([--enable-dumb ], [build DUMB plugin (default: auto)])], [enable_dumb=$enableval], [enable_dumb=yes])
AC_ARG_ENABLE(shn, [AS_HELP_STRING([--enable-shn ], [build SHN plugin (default: auto)])], [enable_shn=$enableval], [enable_shn=yes])
AC_ARG_ENABLE(psf, [AS_HELP_STRING([--enable-psf ], [build AOSDK-based PSF(,QSF,SSF,DSF) plugin (default: auto)])], [enable_psf=$enableval], [enable_psf=yes])
@@ -179,7 +180,7 @@ else
fi
if test "x$enable_gtk2" == "xyes" ; then
- PKG_CHECK_MODULES(GTK2_DEPS, gtk+-2.0 >= 2.12 gthread-2.0 glib-2.0, HAVE_GTK2=yes, HAVE_GTK2=no)
+ PKG_CHECK_MODULES(GTK2_DEPS, gtk+-2.0 >= 2.12 gthread-2.0 glib-2.0 gtkglext-1.0, HAVE_GTK2=yes, HAVE_GTK2=no)
AC_CHECK_LIB([SM], [main], [HAVE_SM=yes;SM_LIBS="-lSM";AC_SUBST(SM_LIBS)])
AC_CHECK_LIB([ICE], [main], [HAVE_ICE=yes;ICE_LIBS="-lICE";AC_SUBST(ICE_LIBS)])
else
@@ -568,6 +569,11 @@ if test "x$enable_converter" != "xno" ; then
fi
fi
+<<<<<<< HEAD
+if test "x$enable_medialib" != "xno" ; then
+ HAVE_MEDIALIB=yes
+fi
+
if test "x$enable_shellexecui" != "xno" ; then
if test "x$HAVE_GTK2" = "xyes" || test "x$HAVE_GTK3" = "xyes" ; then
HAVE_SHELLEXECUI=yes
@@ -594,8 +600,7 @@ if test "x$enable_alac" != "xno" ; then
HAVE_ALAC=yes
fi
-
-PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/ao plugins/mono2stereo plugins/shellexecui plugins/alac"
+PLUGINS_DIRS="plugins/lastfm plugins/mpgmad plugins/vorbis plugins/flac plugins/wavpack plugins/sndfile plugins/vfs_curl plugins/cdda plugins/gtkui plugins/alsa plugins/ffmpeg plugins/hotkeys plugins/oss plugins/artwork plugins/adplug plugins/ffap plugins/sid plugins/nullout plugins/supereq plugins/vtx plugins/gme plugins/pulse plugins/notify plugins/musepack plugins/wildmidi plugins/tta plugins/dca plugins/aac plugins/mms plugins/shellexec plugins/dsp_libsrc plugins/m3u plugins/vfs_zip plugins/converter plugins/dumb plugins/shn plugins/ao plugins/mono2stereo plugins/shellexecui plugins/alac plugins/medialib"
AM_CONDITIONAL(HAVE_VORBIS, test "x$HAVE_VORBISPLUGIN" = "xyes")
AM_CONDITIONAL(HAVE_FLAC, test "x$HAVE_FLACPLUGIN" = "xyes")
@@ -640,6 +645,7 @@ AM_CONDITIONAL(HAVE_IMLIB2, test "x$HAVE_IMLIB2" = "xyes")
AM_CONDITIONAL(HAVE_JPEG, test "x$HAVE_JPEG" = "xyes")
AM_CONDITIONAL(HAVE_PNG, test "x$HAVE_PNG" = "xyes")
AM_CONDITIONAL(HAVE_YASM, test "x$HAVE_YASM" = "xyes")
+AM_CONDITIONAL(HAVE_MEDIALIB, test "x$HAVE_MEDIALIB" = "xyes")
AM_CONDITIONAL(HAVE_DUMB, test "x$HAVE_DUMB" = "xyes")
AM_CONDITIONAL(HAVE_PSF, test "x$HAVE_PSF" = "xyes")
AM_CONDITIONAL(HAVE_SHN, test "x$HAVE_SHN" = "xyes")
@@ -709,6 +715,7 @@ PRINT_PLUGIN_INFO([dsp_src],[High quality samplerate conversion using libsampler
PRINT_PLUGIN_INFO([m3u],[M3U and PLS playlist support],[test "x$HAVE_M3U" = "xyes"])
PRINT_PLUGIN_INFO([vfs_zip],[zip archive support],[test "x$HAVE_VFS_ZIP" = "xyes"])
PRINT_PLUGIN_INFO([converter],[plugin for converting files to any formats],[test "x$HAVE_CONVERTER" = "xyes"])
+PRINT_PLUGIN_INFO([medialib],[media library support plugin],[test "x$HAVE_MEDIALIB" = "xyes"])
PRINT_PLUGIN_INFO([psf],[PSF format plugin, using AOSDK],[test "x$HAVE_PSF" = "xyes"])
PRINT_PLUGIN_INFO([dumb],[DUMB module plugin, for MOD, S3M, etc],[test "x$HAVE_DUMB" = "xyes"])
PRINT_PLUGIN_INFO([shn],[SHN plugin based on xmms-shn],[test "x$HAVE_SHN" = "xyes"])
@@ -756,6 +763,7 @@ plugins/dsp_libsrc/Makefile
plugins/m3u/Makefile
plugins/vfs_zip/Makefile
plugins/converter/Makefile
+plugins/medialib/Makefile
plugins/dumb/Makefile
plugins/ao/Makefile
plugins/shn/Makefile
diff --git a/deadbeef.h b/deadbeef.h
index c362a512..aede0fba 100644
--- a/deadbeef.h
+++ b/deadbeef.h
@@ -273,12 +273,17 @@ enum {
DB_EV_ACTIONSCHANGED = 20, // plugin actions were changed, e.g. for reinitializing gui
DB_EV_DSPCHAINCHANGED = 21, // emitted when any parameter of the main dsp chain has been changed
+ // new in 1.2
+ DB_EV_SELCHANGED = 20, // selection changed in playlist p1 iter p2
+
DB_EV_FIRST = 1000,
DB_EV_SONGCHANGED = 1000, // current song changed from one to another, ctx=ddb_event_trackchange_t
DB_EV_SONGSTARTED = 1001, // song started playing, ctx=ddb_event_track_t
DB_EV_SONGFINISHED = 1002, // song finished playing, ctx=ddb_event_track_t
DB_EV_TRACKINFOCHANGED = 1004, // trackinfo was changed (included medatata and playback status), ctx=ddb_event_track_t
DB_EV_SEEKED = 1005, // seek happened, ctx=ddb_event_playpos_t
+ // new in 1.4
+ DB_EV_TRACKFOCUSCURRENT = 1006, // user wants to highlight/find the current playing track
DB_EV_MAX
};
@@ -305,6 +310,14 @@ enum ddb_sort_order_t {
DDB_SORT_RANDOM, // available since API 1.3
};
+enum ddb_audio_data_type_t {
+ DDB_AUDIO_WAVEFORM,
+ DDB_AUDIO_FREQ,
+};
+
+// audio memory constants
+#define DDB_AUDIO_MEMORY_FRAMES 512
+
// typecasting macros
#define DB_PLUGIN(x) ((DB_plugin_t *)(x))
#define DB_CALLBACK(x) ((DB_callback_t)(x))
@@ -767,6 +780,14 @@ typedef struct {
// fast way to test if a field exists in playitem
int (*pl_meta_exists) (DB_playItem_t *it, const char *key);
+
+ // FIXME ******* devel branch only *******
+ // access real-time audio data (e.g. for visualization)
+ // returns data size in bytes
+ // fmt and data will be filled with last bytes that came to the output plugin
+ // data size must be float[DDB_AUDIO_MEMORY_FRAMES]
+ void (*audio_get_waveform_data) (int type, float *data);
+
} DB_functions_t;
// NOTE: an item placement must be selected like this
diff --git a/fftsg.c b/fftsg.c
new file mode 100644
index 00000000..265b722e
--- /dev/null
+++ b/fftsg.c
@@ -0,0 +1,3322 @@
+/*
+ Copyright Takuya OOURA, 1996-2001
+ http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
+
+ You may use, copy, modify and distribute this code for any purpose (include commercial use) and without fee.
+ Please refer to this package when you modify this code.
+*/
+
+/*
+Fast Fourier/Cosine/Sine Transform
+ dimension :one
+ data length :power of 2
+ decimation :frequency
+ radix :split-radix
+ data :inplace
+ table :use
+functions
+ cdft: Complex Discrete Fourier Transform
+ rdft: Real Discrete Fourier Transform
+ ddct: Discrete Cosine Transform
+ ddst: Discrete Sine Transform
+ dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+ dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+ void cdft(int, int, float *, int *, float *);
+ void rdft(int, int, float *, int *, float *);
+ void ddct(int, int, float *, int *, float *);
+ void ddst(int, int, float *, int *, float *);
+ void dfct(int, float *, float *, int *, float *);
+ void dfst(int, float *, float *, int *, float *);
+macro definitions
+ USE_CDFT_PTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=8192
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=65536
+ USE_CDFT_WINTHREADS : default=not defined
+ CDFT_THREADS_BEGIN_N : must be >= 512, default=32768
+ CDFT_4THREADS_BEGIN_N : must be >= 512, default=524288
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+ [definition]
+ <case1>
+ X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+ <case2>
+ X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+ (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ cdft(2*n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ cdft(2*n, -1, a, ip, w);
+ [parameters]
+ 2*n :data length (int)
+ n >= 1, n = power of 2
+ a[0...2*n-1] :input/output data (float *)
+ input data
+ a[2*j] = Re(x[j]),
+ a[2*j+1] = Im(x[j]), 0<=j<n
+ output data
+ a[2*k] = Re(X[k]),
+ a[2*k+1] = Im(X[k]), 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ cdft(2*n, -1, a, ip, w);
+ is
+ cdft(2*n, 1, a, ip, w);
+ for (j = 0; j <= 2 * n - 1; j++) {
+ a[j] *= 1.0 / n;
+ }
+ .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+ [definition]
+ <case1> RDFT
+ R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+ I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
+ <case2> IRDFT (excluding scale)
+ a[k] = (R[0] + R[n/2]*cos(pi*k))/2 +
+ sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) +
+ sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ rdft(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ rdft(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ <case1>
+ output data
+ a[2*k] = R[k], 0<=k<n/2
+ a[2*k+1] = I[k], 0<k<n/2
+ a[1] = R[n/2]
+ <case2>
+ input data
+ a[2*j] = R[j], 0<=j<n/2
+ a[2*j+1] = I[j], 0<j<n/2
+ a[1] = R[n/2]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n/2-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ rdft(n, 1, a, ip, w);
+ is
+ rdft(n, -1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+ [definition]
+ <case1> IDCT (excluding scale)
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DCT
+ C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddct(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddct(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ output data
+ a[k] = C[k], 0<=k<n
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddct(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddct(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+ [definition]
+ <case1> IDST (excluding scale)
+ S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+ <case2> DST
+ S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+ [usage]
+ <case1>
+ ip[0] = 0; // first time only
+ ddst(n, 1, a, ip, w);
+ <case2>
+ ip[0] = 0; // first time only
+ ddst(n, -1, a, ip, w);
+ [parameters]
+ n :data length (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ <case1>
+ input data
+ a[j] = A[j], 0<j<n
+ a[0] = A[n]
+ output data
+ a[k] = S[k], 0<=k<n
+ <case2>
+ output data
+ a[k] = S[k], 0<k<n
+ a[0] = S[n]
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/2)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/4-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ ddst(n, -1, a, ip, w);
+ is
+ a[0] *= 0.5;
+ ddst(n, 1, a, ip, w);
+ for (j = 0; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+ [definition]
+ C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+ [usage]
+ ip[0] = 0; // first time only
+ dfct(n, a, t, ip, w);
+ [parameters]
+ n :data length - 1 (int)
+ n >= 2, n = power of 2
+ a[0...n] :input/output data (float *)
+ output data
+ a[k] = C[k], 0<=k<=n
+ t[0...n/2] :work area (float *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ is
+ a[0] *= 0.5;
+ a[n] *= 0.5;
+ dfct(n, a, t, ip, w);
+ for (j = 0; j <= n; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+ [definition]
+ S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
+ [usage]
+ ip[0] = 0; // first time only
+ dfst(n, a, t, ip, w);
+ [parameters]
+ n :data length + 1 (int)
+ n >= 2, n = power of 2
+ a[0...n-1] :input/output data (float *)
+ output data
+ a[k] = S[k], 0<k<n
+ (a[0] is used for work area)
+ t[0...n/2-1] :work area (float *)
+ ip[0...*] :work area for bit reversal (int *)
+ length of ip >= 2+sqrt(n/4)
+ strictly,
+ length of ip >=
+ 2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+ ip[0],ip[1] are pointers of the cos/sin table.
+ w[0...n*5/8-1] :cos/sin table (float *)
+ w[],ip[] are initialized if ip[0] == 0.
+ [remark]
+ Inverse of
+ dfst(n, a, t, ip, w);
+ is
+ dfst(n, a, t, ip, w);
+ for (j = 1; j <= n - 1; j++) {
+ a[j] *= 2.0 / n;
+ }
+ .
+
+
+Appendix :
+ The cos/sin table is recalculated when the larger table required.
+ w[] and ip[] are compatible with all routines.
+*/
+
+
+void cdft(int n, int isgn, float *a, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void cftbsub(int n, float *a, int *ip, int nw, float *w);
+ int nw;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ if (isgn >= 0) {
+ cftfsub(n, a, ip, nw, w);
+ } else {
+ cftbsub(n, a, ip, nw, w);
+ }
+}
+
+
+void rdft(int n, int isgn, float *a, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void makect(int nc, int *ip, float *c);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void cftbsub(int n, float *a, int *ip, int nw, float *w);
+ void rftfsub(int n, float *a, int nc, float *c);
+ void rftbsub(int n, float *a, int nc, float *c);
+ int nw, nc;
+ float xi;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 2)) {
+ nc = n >> 2;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xi = a[0] - a[1];
+ a[0] += a[1];
+ a[1] = xi;
+ } else {
+ a[1] = 0.5 * (a[0] - a[1]);
+ a[0] -= a[1];
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+}
+
+
+void ddct(int n, int isgn, float *a, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void makect(int nc, int *ip, float *c);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void cftbsub(int n, float *a, int *ip, int nw, float *w);
+ void rftfsub(int n, float *a, int nc, float *c);
+ void rftbsub(int n, float *a, int nc, float *c);
+ void dctsub(int n, float *a, int nc, float *c);
+ int j, nw, nc;
+ float xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = a[j] - a[j - 1];
+ a[j] += a[j - 1];
+ }
+ a[1] = a[0] - xr;
+ a[0] += xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dctsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = a[j] - a[j + 1];
+ a[j] += a[j + 1];
+ }
+ a[n - 1] = xr;
+ }
+}
+
+
+void ddst(int n, int isgn, float *a, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void makect(int nc, int *ip, float *c);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void cftbsub(int n, float *a, int *ip, int nw, float *w);
+ void rftfsub(int n, float *a, int nc, float *c);
+ void rftbsub(int n, float *a, int nc, float *c);
+ void dstsub(int n, float *a, int nc, float *c);
+ int j, nw, nc;
+ float xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = -a[j] - a[j - 1];
+ a[j] -= a[j - 1];
+ }
+ a[1] = a[0] + xr;
+ a[0] -= xr;
+ if (n > 4) {
+ rftbsub(n, a, nc, w + nw);
+ cftbsub(n, a, ip, nw, w);
+ } else if (n == 4) {
+ cftbsub(n, a, ip, nw, w);
+ }
+ }
+ dstsub(n, a, nc, w + nw);
+ if (isgn >= 0) {
+ if (n > 4) {
+ cftfsub(n, a, ip, nw, w);
+ rftfsub(n, a, nc, w + nw);
+ } else if (n == 4) {
+ cftfsub(n, a, ip, nw, w);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = -a[j] - a[j + 1];
+ a[j] -= a[j + 1];
+ }
+ a[n - 1] = -xr;
+ }
+}
+
+
+void dfct(int n, float *a, float *t, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void makect(int nc, int *ip, float *c);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void rftfsub(int n, float *a, int nc, float *c);
+ void dctsub(int n, float *a, int nc, float *c);
+ int j, k, l, m, mh, nw, nc;
+ float xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ m = n >> 1;
+ yi = a[m];
+ xi = a[0] + a[n];
+ a[0] -= a[n];
+ t[0] = xi - yi;
+ t[m] = xi + yi;
+ if (n > 2) {
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] - a[n - j];
+ xi = a[j] + a[n - j];
+ yr = a[k] - a[n - k];
+ yi = a[k] + a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi - yi;
+ t[k] = xi + yi;
+ }
+ t[mh] = a[mh] + a[n - mh];
+ a[mh] -= a[n - mh];
+ dctsub(m, a, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, w);
+ }
+ a[n - 1] = a[0] - a[1];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] + a[j + 1];
+ a[2 * j - 1] = a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dctsub(m, t, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, w);
+ }
+ a[n - l] = t[0] - t[1];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = t[j] - t[j + 1];
+ a[k + l] = t[j] + t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 0; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] - t[m + j];
+ t[k] = t[m + k] + t[m + j];
+ }
+ t[mh] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ a[n] = t[2] - t[1];
+ a[0] = t[2] + t[1];
+ } else {
+ a[1] = a[0];
+ a[2] = t[0];
+ a[0] = t[1];
+ }
+}
+
+
+void dfst(int n, float *a, float *t, int *ip, float *w)
+{
+ void makewt(int nw, int *ip, float *w);
+ void makect(int nc, int *ip, float *c);
+ void cftfsub(int n, float *a, int *ip, int nw, float *w);
+ void rftfsub(int n, float *a, int nc, float *c);
+ void dstsub(int n, float *a, int nc, float *c);
+ int j, k, l, m, mh, nw, nc;
+ float xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ if (n > 2) {
+ m = n >> 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] + a[n - j];
+ xi = a[j] - a[n - j];
+ yr = a[k] + a[n - k];
+ yi = a[k] - a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi + yi;
+ t[k] = xi - yi;
+ }
+ t[0] = a[mh] - a[n - mh];
+ a[mh] += a[n - mh];
+ a[0] = a[m];
+ dstsub(m, a, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, a, ip, nw, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, ip, nw, w);
+ }
+ a[n - 1] = a[1] - a[0];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] - a[j + 1];
+ a[2 * j - 1] = -a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dstsub(m, t, nc, w + nw);
+ if (m > 4) {
+ cftfsub(m, t, ip, nw, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, ip, nw, w);
+ }
+ a[n - l] = t[1] - t[0];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = -t[j] - t[j + 1];
+ a[k + l] = t[j] - t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] + t[m + j];
+ t[k] = t[m + k] - t[m + j];
+ }
+ t[0] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ }
+ a[0] = 0;
+}
+
+
+/* -------- initializing routines -------- */
+
+
+#include <math.h>
+
+void makewt(int nw, int *ip, float *w)
+{
+ void makeipt(int nw, int *ip);
+ int j, nwh, nw0, nw1;
+ float delta, wn4r, wk1r, wk1i, wk3r, wk3i;
+
+ ip[0] = nw;
+ ip[1] = 1;
+ if (nw > 2) {
+ nwh = nw >> 1;
+ delta = atan(1.0) / nwh;
+ wn4r = cos(delta * nwh);
+ w[0] = 1;
+ w[1] = wn4r;
+ if (nwh == 4) {
+ w[2] = cos(delta * 2);
+ w[3] = sin(delta * 2);
+ } else if (nwh > 4) {
+ makeipt(nw, ip);
+ w[2] = 0.5 / cos(delta * 2);
+ w[3] = 0.5 / cos(delta * 6);
+ for (j = 4; j < nwh; j += 4) {
+ w[j] = cos(delta * j);
+ w[j + 1] = sin(delta * j);
+ w[j + 2] = cos(3 * delta * j);
+ w[j + 3] = -sin(3 * delta * j);
+ }
+ }
+ nw0 = 0;
+ while (nwh > 2) {
+ nw1 = nw0 + nwh;
+ nwh >>= 1;
+ w[nw1] = 1;
+ w[nw1 + 1] = wn4r;
+ if (nwh == 4) {
+ wk1r = w[nw0 + 4];
+ wk1i = w[nw0 + 5];
+ w[nw1 + 2] = wk1r;
+ w[nw1 + 3] = wk1i;
+ } else if (nwh > 4) {
+ wk1r = w[nw0 + 4];
+ wk3r = w[nw0 + 6];
+ w[nw1 + 2] = 0.5 / wk1r;
+ w[nw1 + 3] = 0.5 / wk3r;
+ for (j = 4; j < nwh; j += 4) {
+ wk1r = w[nw0 + 2 * j];
+ wk1i = w[nw0 + 2 * j + 1];
+ wk3r = w[nw0 + 2 * j + 2];
+ wk3i = w[nw0 + 2 * j + 3];
+ w[nw1 + j] = wk1r;
+ w[nw1 + j + 1] = wk1i;
+ w[nw1 + j + 2] = wk3r;
+ w[nw1 + j + 3] = wk3i;
+ }
+ }
+ nw0 = nw1;
+ }
+ }
+}
+
+
+void makeipt(int nw, int *ip)
+{
+ int j, l, m, m2, p, q;
+
+ ip[2] = 0;
+ ip[3] = 16;
+ m = 2;
+ for (l = nw; l > 32; l >>= 2) {
+ m2 = m << 1;
+ q = m2 << 3;
+ for (j = m; j < m2; j++) {
+ p = ip[j] << 2;
+ ip[m + j] = p;
+ ip[m2 + j] = p + q;
+ }
+ m = m2;
+ }
+}
+
+
+void makect(int nc, int *ip, float *c)
+{
+ int j, nch;
+ float delta;
+
+ ip[1] = nc;
+ if (nc > 1) {
+ nch = nc >> 1;
+ delta = atan(1.0) / nch;
+ c[0] = cos(delta * nch);
+ c[nch] = 0.5 * c[0];
+ for (j = 1; j < nch; j++) {
+ c[j] = 0.5 * cos(delta * j);
+ c[nc - j] = 0.5 * sin(delta * j);
+ }
+ }
+}
+
+
+/* -------- child routines -------- */
+
+
+#ifdef USE_CDFT_PTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 8192
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 65536
+#endif
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t pthread_t
+#define cdft_thread_create(thp,func,argp) { \
+ if (pthread_create(thp, NULL, func, (void *) argp) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ if (pthread_join(th, NULL) != 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#endif /* USE_CDFT_PTHREADS */
+
+
+#ifdef USE_CDFT_WINTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 32768
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 524288
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t HANDLE
+#define cdft_thread_create(thp,func,argp) { \
+ DWORD thid; \
+ *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, (LPVOID) argp, 0, &thid); \
+ if (*(thp) == 0) { \
+ fprintf(stderr, "cdft thread error\n"); \
+ exit(1); \
+ } \
+}
+#define cdft_thread_wait(th) { \
+ WaitForSingleObject(th, INFINITE); \
+ CloseHandle(th); \
+}
+#endif /* USE_CDFT_WINTHREADS */
+
+
+void cftfsub(int n, float *a, int *ip, int nw, float *w)
+{
+ void bitrv2(int n, int *ip, float *a);
+ void bitrv216(float *a);
+ void bitrv208(float *a);
+ void cftf1st(int n, float *a, float *w);
+ void cftrec4(int n, float *a, int nw, float *w);
+ void cftleaf(int n, int isplt, float *a, int nw, float *w);
+ void cftfx41(int n, float *a, int nw, float *w);
+ void cftf161(float *a, float *w);
+ void cftf081(float *a, float *w);
+ void cftf040(float *a);
+ void cftx020(float *a);
+#ifdef USE_CDFT_THREADS
+ void cftrec4_th(int n, float *a, int nw, float *w);
+#endif /* USE_CDFT_THREADS */
+
+ if (n > 8) {
+ if (n > 32) {
+ cftf1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216(a);
+ } else {
+ cftf081(a, w);
+ bitrv208(a);
+ }
+ } else if (n == 8) {
+ cftf040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+void cftbsub(int n, float *a, int *ip, int nw, float *w)
+{
+ void bitrv2conj(int n, int *ip, float *a);
+ void bitrv216neg(float *a);
+ void bitrv208neg(float *a);
+ void cftb1st(int n, float *a, float *w);
+ void cftrec4(int n, float *a, int nw, float *w);
+ void cftleaf(int n, int isplt, float *a, int nw, float *w);
+ void cftfx41(int n, float *a, int nw, float *w);
+ void cftf161(float *a, float *w);
+ void cftf081(float *a, float *w);
+ void cftb040(float *a);
+ void cftx020(float *a);
+#ifdef USE_CDFT_THREADS
+ void cftrec4_th(int n, float *a, int nw, float *w);
+#endif /* USE_CDFT_THREADS */
+
+ if (n > 8) {
+ if (n > 32) {
+ cftb1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+ if (n > CDFT_THREADS_BEGIN_N) {
+ cftrec4_th(n, a, nw, w);
+ } else
+#endif /* USE_CDFT_THREADS */
+ if (n > 512) {
+ cftrec4(n, a, nw, w);
+ } else if (n > 128) {
+ cftleaf(n, 1, a, nw, w);
+ } else {
+ cftfx41(n, a, nw, w);
+ }
+ bitrv2conj(n, ip, a);
+ } else if (n == 32) {
+ cftf161(a, &w[nw - 8]);
+ bitrv216neg(a);
+ } else {
+ cftf081(a, w);
+ bitrv208neg(a);
+ }
+ } else if (n == 8) {
+ cftb040(a);
+ } else if (n == 4) {
+ cftx020(a);
+ }
+}
+
+
+void bitrv2(int n, int *ip, float *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ float xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= 2;
+ k1 -= nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh + 2;
+ k1 += nh + 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh - nm;
+ k1 += 2 * nm - 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ } else {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + j];
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = a[j1 + 1];
+ yr = a[k1];
+ yi = a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ }
+}
+
+
+void bitrv2conj(int n, int *ip, float *a)
+{
+ int j, j1, k, k1, l, m, nh, nm;
+ float xr, xi, yr, yi;
+
+ m = 1;
+ for (l = n >> 2; l > 8; l >>= 2) {
+ m <<= 1;
+ }
+ nh = n >> 1;
+ nm = 4 * m;
+ if (l == 8) {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + 2 * ip[m + k];
+ k1 = 4 * k + 2 * ip[m + j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + 2 * ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += 2 * nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= 2;
+ k1 -= nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh + 2;
+ k1 += nh + 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh - nm;
+ k1 += 2 * nm - 2;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ } else {
+ for (k = 0; k < m; k++) {
+ for (j = 0; j < k; j++) {
+ j1 = 4 * j + ip[m + k];
+ k1 = 4 * k + ip[m + j];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nh;
+ k1 += 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += 2;
+ k1 += nh;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 += nm;
+ k1 += nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nh;
+ k1 -= 2;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ j1 -= nm;
+ k1 -= nm;
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ }
+ k1 = 4 * k + ip[m + k];
+ j1 = k1 + 2;
+ k1 += nh;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ j1 += nm;
+ k1 += nm;
+ a[j1 - 1] = -a[j1 - 1];
+ xr = a[j1];
+ xi = -a[j1 + 1];
+ yr = a[k1];
+ yi = -a[k1 + 1];
+ a[j1] = yr;
+ a[j1 + 1] = yi;
+ a[k1] = xr;
+ a[k1 + 1] = xi;
+ a[k1 + 3] = -a[k1 + 3];
+ }
+ }
+}
+
+
+void bitrv216(float *a)
+{
+ float x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i,
+ x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ a[2] = x8r;
+ a[3] = x8i;
+ a[4] = x4r;
+ a[5] = x4i;
+ a[6] = x12r;
+ a[7] = x12i;
+ a[8] = x2r;
+ a[9] = x2i;
+ a[10] = x10r;
+ a[11] = x10i;
+ a[14] = x14r;
+ a[15] = x14i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[20] = x5r;
+ a[21] = x5i;
+ a[22] = x13r;
+ a[23] = x13i;
+ a[24] = x3r;
+ a[25] = x3i;
+ a[26] = x11r;
+ a[27] = x11i;
+ a[28] = x7r;
+ a[29] = x7i;
+}
+
+
+void bitrv216neg(float *a)
+{
+ float x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i,
+ x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i,
+ x13r, x13i, x14r, x14i, x15r, x15i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ x8r = a[16];
+ x8i = a[17];
+ x9r = a[18];
+ x9i = a[19];
+ x10r = a[20];
+ x10i = a[21];
+ x11r = a[22];
+ x11i = a[23];
+ x12r = a[24];
+ x12i = a[25];
+ x13r = a[26];
+ x13i = a[27];
+ x14r = a[28];
+ x14i = a[29];
+ x15r = a[30];
+ x15i = a[31];
+ a[2] = x15r;
+ a[3] = x15i;
+ a[4] = x7r;
+ a[5] = x7i;
+ a[6] = x11r;
+ a[7] = x11i;
+ a[8] = x3r;
+ a[9] = x3i;
+ a[10] = x13r;
+ a[11] = x13i;
+ a[12] = x5r;
+ a[13] = x5i;
+ a[14] = x9r;
+ a[15] = x9i;
+ a[16] = x1r;
+ a[17] = x1i;
+ a[18] = x14r;
+ a[19] = x14i;
+ a[20] = x6r;
+ a[21] = x6i;
+ a[22] = x10r;
+ a[23] = x10i;
+ a[24] = x2r;
+ a[25] = x2i;
+ a[26] = x12r;
+ a[27] = x12i;
+ a[28] = x4r;
+ a[29] = x4i;
+ a[30] = x8r;
+ a[31] = x8i;
+}
+
+
+void bitrv208(float *a)
+{
+ float x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x6r = a[12];
+ x6i = a[13];
+ a[2] = x4r;
+ a[3] = x4i;
+ a[6] = x6r;
+ a[7] = x6i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[12] = x3r;
+ a[13] = x3i;
+}
+
+
+void bitrv208neg(float *a)
+{
+ float x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i,
+ x5r, x5i, x6r, x6i, x7r, x7i;
+
+ x1r = a[2];
+ x1i = a[3];
+ x2r = a[4];
+ x2i = a[5];
+ x3r = a[6];
+ x3i = a[7];
+ x4r = a[8];
+ x4i = a[9];
+ x5r = a[10];
+ x5i = a[11];
+ x6r = a[12];
+ x6i = a[13];
+ x7r = a[14];
+ x7i = a[15];
+ a[2] = x7r;
+ a[3] = x7i;
+ a[4] = x3r;
+ a[5] = x3i;
+ a[6] = x5r;
+ a[7] = x5i;
+ a[8] = x1r;
+ a[9] = x1i;
+ a[10] = x6r;
+ a[11] = x6i;
+ a[12] = x2r;
+ a[13] = x2i;
+ a[14] = x4r;
+ a[15] = x4i;
+}
+
+
+void cftf1st(int n, float *a, float *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = a[j + 3] + a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = a[j + 3] - a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = a[j0 - 1] + a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i + y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i - y2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = a[j0 - 1] + a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = a[j0 - 1] - a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i + x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = a[j0 + 3] + a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = a[j0 + 3] - a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i + x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+void cftb1st(int n, float *a, float *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i,
+ wd1r, wd1i, wd3r, wd3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = -a[1] - a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = -a[1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j2] = x1r + x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r - x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ csc1 = w[2];
+ csc3 = w[3];
+ wd1r = 1;
+ wd1i = 0;
+ wd3r = 1;
+ wd3i = 0;
+ k = 0;
+ for (j = 2; j < mh - 2; j += 4) {
+ k += 4;
+ wk1r = csc1 * (wd1r + w[k]);
+ wk1i = csc1 * (wd1i + w[k + 1]);
+ wk3r = csc3 * (wd3r + w[k + 2]);
+ wk3i = csc3 * (wd3i + w[k + 3]);
+ wd1r = w[k];
+ wd1i = w[k + 1];
+ wd3r = w[k + 2];
+ wd3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = -a[j + 1] - a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = -a[j + 1] + a[j2 + 1];
+ y0r = a[j + 2] + a[j2 + 2];
+ y0i = -a[j + 3] - a[j2 + 3];
+ y1r = a[j + 2] - a[j2 + 2];
+ y1i = -a[j + 3] + a[j2 + 3];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 + 2] + a[j3 + 2];
+ y2i = a[j1 + 3] + a[j3 + 3];
+ y3r = a[j1 + 2] - a[j3 + 2];
+ y3i = a[j1 + 3] - a[j3 + 3];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i - x2i;
+ a[j + 2] = y0r + y2r;
+ a[j + 3] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 + 2] = y0r - y2r;
+ a[j1 + 3] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+ a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+ a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ y0r = a[j0 - 2] + a[j2 - 2];
+ y0i = -a[j0 - 1] - a[j2 - 1];
+ y1r = a[j0 - 2] - a[j2 - 2];
+ y1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ y2r = a[j1 - 2] + a[j3 - 2];
+ y2i = a[j1 - 1] + a[j3 - 1];
+ y3r = a[j1 - 2] - a[j3 - 2];
+ y3i = a[j1 - 1] - a[j3 - 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j0 - 2] = y0r + y2r;
+ a[j0 - 1] = y0i - y2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ a[j1 - 2] = y0r - y2r;
+ a[j1 - 1] = y0i + y2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = y1r + y3i;
+ x0i = y1i + y3r;
+ a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+ a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ x0r = y1r - y3i;
+ x0i = y1i - y3r;
+ a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+ a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+ }
+ wk1r = csc1 * (wd1r + wn4r);
+ wk1i = csc1 * (wd1i + wn4r);
+ wk3r = csc3 * (wd3r - wn4r);
+ wk3i = csc3 * (wd3i - wn4r);
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0 - 2] + a[j2 - 2];
+ x0i = -a[j0 - 1] - a[j2 - 1];
+ x1r = a[j0 - 2] - a[j2 - 2];
+ x1i = -a[j0 - 1] + a[j2 - 1];
+ x2r = a[j1 - 2] + a[j3 - 2];
+ x2i = a[j1 - 1] + a[j3 - 1];
+ x3r = a[j1 - 2] - a[j3 - 2];
+ x3i = a[j1 - 1] - a[j3 - 1];
+ a[j0 - 2] = x0r + x2r;
+ a[j0 - 1] = x0i - x2i;
+ a[j1 - 2] = x0r - x2r;
+ a[j1 - 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+ a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+ a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+ x0r = a[j0] + a[j2];
+ x0i = -a[j0 + 1] - a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = -a[j0 + 1] + a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i - x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+ x0r = a[j0 + 2] + a[j2 + 2];
+ x0i = -a[j0 + 3] - a[j2 + 3];
+ x1r = a[j0 + 2] - a[j2 + 2];
+ x1i = -a[j0 + 3] + a[j2 + 3];
+ x2r = a[j1 + 2] + a[j3 + 2];
+ x2i = a[j1 + 3] + a[j3 + 3];
+ x3r = a[j1 + 2] - a[j3 + 2];
+ x3i = a[j1 + 3] - a[j3 + 3];
+ a[j0 + 2] = x0r + x2r;
+ a[j0 + 3] = x0i - x2i;
+ a[j1 + 2] = x0r - x2r;
+ a[j1 + 3] = x0i + x2i;
+ x0r = x1r + x3i;
+ x0i = x1i + x3r;
+ a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r - x3i;
+ x0i = x1i - x3r;
+ a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+#ifdef USE_CDFT_THREADS
+struct cdft_arg_st {
+ int n0;
+ int n;
+ float *a;
+ int nw;
+ float *w;
+};
+typedef struct cdft_arg_st cdft_arg_t;
+
+
+void cftrec4_th(int n, float *a, int nw, float *w)
+{
+ void *cftrec1_th(void *p);
+ void *cftrec2_th(void *p);
+ int i, idiv4, m, nthread;
+ cdft_thread_t th[4];
+ cdft_arg_t ag[4];
+
+ nthread = 2;
+ idiv4 = 0;
+ m = n >> 1;
+ if (n > CDFT_4THREADS_BEGIN_N) {
+ nthread = 4;
+ idiv4 = 1;
+ m >>= 1;
+ }
+ for (i = 0; i < nthread; i++) {
+ ag[i].n0 = n;
+ ag[i].n = m;
+ ag[i].a = &a[i * m];
+ ag[i].nw = nw;
+ ag[i].w = w;
+ if (i != idiv4) {
+ cdft_thread_create(&th[i], cftrec1_th, &ag[i]);
+ } else {
+ cdft_thread_create(&th[i], cftrec2_th, &ag[i]);
+ }
+ }
+ for (i = 0; i < nthread; i++) {
+ cdft_thread_wait(th[i]);
+ }
+}
+
+
+void *cftrec1_th(void *p)
+{
+ int cfttree(int n, int j, int k, float *a, int nw, float *w);
+ void cftleaf(int n, int isplt, float *a, int nw, float *w);
+ void cftmdl1(int n, float *a, float *w);
+ int isplt, j, k, m, n, n0, nw;
+ float *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+
+
+void *cftrec2_th(void *p)
+{
+ int cfttree(int n, int j, int k, float *a, int nw, float *w);
+ void cftleaf(int n, int isplt, float *a, int nw, float *w);
+ void cftmdl2(int n, float *a, float *w);
+ int isplt, j, k, m, n, n0, nw;
+ float *a, *w;
+
+ n0 = ((cdft_arg_t *) p)->n0;
+ n = ((cdft_arg_t *) p)->n;
+ a = ((cdft_arg_t *) p)->a;
+ nw = ((cdft_arg_t *) p)->nw;
+ w = ((cdft_arg_t *) p)->w;
+ k = 1;
+ m = n0;
+ while (m > 512) {
+ m >>= 2;
+ k <<= 2;
+ cftmdl2(m, &a[n - m], &w[nw - m]);
+ }
+ cftleaf(m, 0, &a[n - m], nw, w);
+ k >>= 1;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+ return (void *) 0;
+}
+#endif /* USE_CDFT_THREADS */
+
+
+void cftrec4(int n, float *a, int nw, float *w)
+{
+ int cfttree(int n, int j, int k, float *a, int nw, float *w);
+ void cftleaf(int n, int isplt, float *a, int nw, float *w);
+ void cftmdl1(int n, float *a, float *w);
+ int isplt, j, k, m;
+
+ m = n;
+ while (m > 512) {
+ m >>= 2;
+ cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+ }
+ cftleaf(m, 1, &a[n - m], nw, w);
+ k = 0;
+ for (j = n - m; j > 0; j -= m) {
+ k++;
+ isplt = cfttree(m, j, k, a, nw, w);
+ cftleaf(m, isplt, &a[j - m], nw, w);
+ }
+}
+
+
+int cfttree(int n, int j, int k, float *a, int nw, float *w)
+{
+ void cftmdl1(int n, float *a, float *w);
+ void cftmdl2(int n, float *a, float *w);
+ int i, isplt, m;
+
+ if ((k & 3) != 0) {
+ isplt = k & 1;
+ if (isplt != 0) {
+ cftmdl1(n, &a[j - n], &w[nw - (n >> 1)]);
+ } else {
+ cftmdl2(n, &a[j - n], &w[nw - n]);
+ }
+ } else {
+ m = n;
+ for (i = k; (i & 3) == 0; i >>= 2) {
+ m <<= 2;
+ }
+ isplt = i & 1;
+ if (isplt != 0) {
+ while (m > 128) {
+ cftmdl1(m, &a[j - m], &w[nw - (m >> 1)]);
+ m >>= 2;
+ }
+ } else {
+ while (m > 128) {
+ cftmdl2(m, &a[j - m], &w[nw - m]);
+ m >>= 2;
+ }
+ }
+ }
+ return isplt;
+}
+
+
+void cftleaf(int n, int isplt, float *a, int nw, float *w)
+{
+ void cftmdl1(int n, float *a, float *w);
+ void cftmdl2(int n, float *a, float *w);
+ void cftf161(float *a, float *w);
+ void cftf162(float *a, float *w);
+ void cftf081(float *a, float *w);
+ void cftf082(float *a, float *w);
+
+ if (n == 512) {
+ cftmdl1(128, a, &w[nw - 64]);
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ cftmdl2(128, &a[128], &w[nw - 128]);
+ cftf161(&a[128], &w[nw - 8]);
+ cftf162(&a[160], &w[nw - 32]);
+ cftf161(&a[192], &w[nw - 8]);
+ cftf162(&a[224], &w[nw - 32]);
+ cftmdl1(128, &a[256], &w[nw - 64]);
+ cftf161(&a[256], &w[nw - 8]);
+ cftf162(&a[288], &w[nw - 32]);
+ cftf161(&a[320], &w[nw - 8]);
+ cftf161(&a[352], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(128, &a[384], &w[nw - 64]);
+ cftf161(&a[480], &w[nw - 8]);
+ } else {
+ cftmdl2(128, &a[384], &w[nw - 128]);
+ cftf162(&a[480], &w[nw - 32]);
+ }
+ cftf161(&a[384], &w[nw - 8]);
+ cftf162(&a[416], &w[nw - 32]);
+ cftf161(&a[448], &w[nw - 8]);
+ } else {
+ cftmdl1(64, a, &w[nw - 32]);
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ cftmdl2(64, &a[64], &w[nw - 64]);
+ cftf081(&a[64], &w[nw - 8]);
+ cftf082(&a[80], &w[nw - 8]);
+ cftf081(&a[96], &w[nw - 8]);
+ cftf082(&a[112], &w[nw - 8]);
+ cftmdl1(64, &a[128], &w[nw - 32]);
+ cftf081(&a[128], &w[nw - 8]);
+ cftf082(&a[144], &w[nw - 8]);
+ cftf081(&a[160], &w[nw - 8]);
+ cftf081(&a[176], &w[nw - 8]);
+ if (isplt != 0) {
+ cftmdl1(64, &a[192], &w[nw - 32]);
+ cftf081(&a[240], &w[nw - 8]);
+ } else {
+ cftmdl2(64, &a[192], &w[nw - 64]);
+ cftf082(&a[240], &w[nw - 8]);
+ }
+ cftf081(&a[192], &w[nw - 8]);
+ cftf082(&a[208], &w[nw - 8]);
+ cftf081(&a[224], &w[nw - 8]);
+ }
+}
+
+
+void cftmdl1(int n, float *a, float *w)
+{
+ int j, j0, j1, j2, j3, k, m, mh;
+ float wn4r, wk1r, wk1i, wk3r, wk3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] + a[j2];
+ x0i = a[1] + a[j2 + 1];
+ x1r = a[0] - a[j2];
+ x1i = a[1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ a[j2] = x1r - x3i;
+ a[j2 + 1] = x1i + x3r;
+ a[j3] = x1r + x3i;
+ a[j3 + 1] = x1i - x3r;
+ wn4r = w[1];
+ k = 0;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] + a[j2];
+ x0i = a[j + 1] + a[j2 + 1];
+ x1r = a[j] - a[j2];
+ x1i = a[j + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j] = x0r + x2r;
+ a[j + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1r * x0r - wk1i * x0i;
+ a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3r * x0r + wk3i * x0i;
+ a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wk1i * x0r - wk1r * x0i;
+ a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = wk3i * x0r + wk3r * x0i;
+ a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+ }
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] + a[j2];
+ x0i = a[j0 + 1] + a[j2 + 1];
+ x1r = a[j0] - a[j2];
+ x1i = a[j0 + 1] - a[j2 + 1];
+ x2r = a[j1] + a[j3];
+ x2i = a[j1 + 1] + a[j3 + 1];
+ x3r = a[j1] - a[j3];
+ x3i = a[j1 + 1] - a[j3 + 1];
+ a[j0] = x0r + x2r;
+ a[j0 + 1] = x0i + x2i;
+ a[j1] = x0r - x2r;
+ a[j1 + 1] = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ a[j2] = wn4r * (x0r - x0i);
+ a[j2 + 1] = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ a[j3] = -wn4r * (x0r + x0i);
+ a[j3 + 1] = -wn4r * (x0i - x0r);
+}
+
+
+void cftmdl2(int n, float *a, float *w)
+{
+ int j, j0, j1, j2, j3, k, kr, m, mh;
+ float wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i;
+
+ mh = n >> 3;
+ m = 2 * mh;
+ wn4r = w[1];
+ j1 = m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[0] - a[j2 + 1];
+ x0i = a[1] + a[j2];
+ x1r = a[0] + a[j2 + 1];
+ x1i = a[1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wn4r * (x2r - x2i);
+ y0i = wn4r * (x2i + x2r);
+ a[0] = x0r + y0r;
+ a[1] = x0i + y0i;
+ a[j1] = x0r - y0r;
+ a[j1 + 1] = x0i - y0i;
+ y0r = wn4r * (x3r - x3i);
+ y0i = wn4r * (x3i + x3r);
+ a[j2] = x1r - y0i;
+ a[j2 + 1] = x1i + y0r;
+ a[j3] = x1r + y0i;
+ a[j3 + 1] = x1i - y0r;
+ k = 0;
+ kr = 2 * m;
+ for (j = 2; j < mh; j += 2) {
+ k += 4;
+ wk1r = w[k];
+ wk1i = w[k + 1];
+ wk3r = w[k + 2];
+ wk3i = w[k + 3];
+ kr -= 4;
+ wd1i = w[kr];
+ wd1r = w[kr + 1];
+ wd3i = w[kr + 2];
+ wd3r = w[kr + 3];
+ j1 = j + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j] - a[j2 + 1];
+ x0i = a[j + 1] + a[j2];
+ x1r = a[j] + a[j2 + 1];
+ x1i = a[j + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wd1r * x2r - wd1i * x2i;
+ y2i = wd1r * x2i + wd1i * x2r;
+ a[j] = y0r + y2r;
+ a[j + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk3r * x1r + wk3i * x1i;
+ y0i = wk3r * x1i - wk3i * x1r;
+ y2r = wd3r * x3r + wd3i * x3i;
+ y2i = wd3r * x3i - wd3i * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ j0 = m - j;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wd1i * x0r - wd1r * x0i;
+ y0i = wd1i * x0i + wd1r * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wd3i * x1r + wd3r * x1i;
+ y0i = wd3i * x1i - wd3r * x1r;
+ y2r = wk3i * x3r + wk3r * x3i;
+ y2i = wk3i * x3i - wk3r * x3r;
+ a[j2] = y0r + y2r;
+ a[j2 + 1] = y0i + y2i;
+ a[j3] = y0r - y2r;
+ a[j3 + 1] = y0i - y2i;
+ }
+ wk1r = w[m];
+ wk1i = w[m + 1];
+ j0 = mh;
+ j1 = j0 + m;
+ j2 = j1 + m;
+ j3 = j2 + m;
+ x0r = a[j0] - a[j2 + 1];
+ x0i = a[j0 + 1] + a[j2];
+ x1r = a[j0] + a[j2 + 1];
+ x1i = a[j0 + 1] - a[j2];
+ x2r = a[j1] - a[j3 + 1];
+ x2i = a[j1 + 1] + a[j3];
+ x3r = a[j1] + a[j3 + 1];
+ x3i = a[j1 + 1] - a[j3];
+ y0r = wk1r * x0r - wk1i * x0i;
+ y0i = wk1r * x0i + wk1i * x0r;
+ y2r = wk1i * x2r - wk1r * x2i;
+ y2i = wk1i * x2i + wk1r * x2r;
+ a[j0] = y0r + y2r;
+ a[j0 + 1] = y0i + y2i;
+ a[j1] = y0r - y2r;
+ a[j1 + 1] = y0i - y2i;
+ y0r = wk1i * x1r - wk1r * x1i;
+ y0i = wk1i * x1i + wk1r * x1r;
+ y2r = wk1r * x3r - wk1i * x3i;
+ y2i = wk1r * x3i + wk1i * x3r;
+ a[j2] = y0r - y2r;
+ a[j2 + 1] = y0i - y2i;
+ a[j3] = y0r + y2r;
+ a[j3 + 1] = y0i + y2i;
+}
+
+
+void cftfx41(int n, float *a, int nw, float *w)
+{
+ void cftf161(float *a, float *w);
+ void cftf162(float *a, float *w);
+ void cftf081(float *a, float *w);
+ void cftf082(float *a, float *w);
+
+ if (n == 128) {
+ cftf161(a, &w[nw - 8]);
+ cftf162(&a[32], &w[nw - 32]);
+ cftf161(&a[64], &w[nw - 8]);
+ cftf161(&a[96], &w[nw - 8]);
+ } else {
+ cftf081(a, &w[nw - 8]);
+ cftf082(&a[16], &w[nw - 8]);
+ cftf081(&a[32], &w[nw - 8]);
+ cftf081(&a[48], &w[nw - 8]);
+ }
+}
+
+
+void cftf161(float *a, float *w)
+{
+ float wn4r, wk1r, wk1i,
+ x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ x0r = a[0] + a[16];
+ x0i = a[1] + a[17];
+ x1r = a[0] - a[16];
+ x1i = a[1] - a[17];
+ x2r = a[8] + a[24];
+ x2i = a[9] + a[25];
+ x3r = a[8] - a[24];
+ x3i = a[9] - a[25];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y4r = x0r - x2r;
+ y4i = x0i - x2i;
+ y8r = x1r - x3i;
+ y8i = x1i + x3r;
+ y12r = x1r + x3i;
+ y12i = x1i - x3r;
+ x0r = a[2] + a[18];
+ x0i = a[3] + a[19];
+ x1r = a[2] - a[18];
+ x1i = a[3] - a[19];
+ x2r = a[10] + a[26];
+ x2i = a[11] + a[27];
+ x3r = a[10] - a[26];
+ x3i = a[11] - a[27];
+ y1r = x0r + x2r;
+ y1i = x0i + x2i;
+ y5r = x0r - x2r;
+ y5i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y9r = wk1r * x0r - wk1i * x0i;
+ y9i = wk1r * x0i + wk1i * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y13r = wk1i * x0r - wk1r * x0i;
+ y13i = wk1i * x0i + wk1r * x0r;
+ x0r = a[4] + a[20];
+ x0i = a[5] + a[21];
+ x1r = a[4] - a[20];
+ x1i = a[5] - a[21];
+ x2r = a[12] + a[28];
+ x2i = a[13] + a[29];
+ x3r = a[12] - a[28];
+ x3i = a[13] - a[29];
+ y2r = x0r + x2r;
+ y2i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y10r = wn4r * (x0r - x0i);
+ y10i = wn4r * (x0i + x0r);
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y14r = wn4r * (x0r + x0i);
+ y14i = wn4r * (x0i - x0r);
+ x0r = a[6] + a[22];
+ x0i = a[7] + a[23];
+ x1r = a[6] - a[22];
+ x1i = a[7] - a[23];
+ x2r = a[14] + a[30];
+ x2i = a[15] + a[31];
+ x3r = a[14] - a[30];
+ x3i = a[15] - a[31];
+ y3r = x0r + x2r;
+ y3i = x0i + x2i;
+ y7r = x0r - x2r;
+ y7i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ y11r = wk1i * x0r - wk1r * x0i;
+ y11i = wk1i * x0i + wk1r * x0r;
+ x0r = x1r + x3i;
+ x0i = x1i - x3r;
+ y15r = wk1r * x0r - wk1i * x0i;
+ y15i = wk1r * x0i + wk1i * x0r;
+ x0r = y12r - y14r;
+ x0i = y12i - y14i;
+ x1r = y12r + y14r;
+ x1i = y12i + y14i;
+ x2r = y13r - y15r;
+ x2i = y13i - y15i;
+ x3r = y13r + y15r;
+ x3i = y13i + y15i;
+ a[24] = x0r + x2r;
+ a[25] = x0i + x2i;
+ a[26] = x0r - x2r;
+ a[27] = x0i - x2i;
+ a[28] = x1r - x3i;
+ a[29] = x1i + x3r;
+ a[30] = x1r + x3i;
+ a[31] = x1i - x3r;
+ x0r = y8r + y10r;
+ x0i = y8i + y10i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ x3r = y9r - y11r;
+ x3i = y9i - y11i;
+ a[16] = x0r + x2r;
+ a[17] = x0i + x2i;
+ a[18] = x0r - x2r;
+ a[19] = x0i - x2i;
+ a[20] = x1r - x3i;
+ a[21] = x1i + x3r;
+ a[22] = x1r + x3i;
+ a[23] = x1i - x3r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x3r = wn4r * (x0r - x0i);
+ x3i = wn4r * (x0i + x0r);
+ x0r = y4r - y6i;
+ x0i = y4i + y6r;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ a[8] = x0r + x2r;
+ a[9] = x0i + x2i;
+ a[10] = x0r - x2r;
+ a[11] = x0i - x2i;
+ a[12] = x1r - x3i;
+ a[13] = x1i + x3r;
+ a[14] = x1r + x3i;
+ a[15] = x1i - x3r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ x3r = y1r - y3r;
+ x3i = y1i - y3i;
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x0r - x2r;
+ a[3] = x0i - x2i;
+ a[4] = x1r - x3i;
+ a[5] = x1i + x3r;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+void cftf162(float *a, float *w)
+{
+ float wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i,
+ x0r, x0i, x1r, x1i, x2r, x2i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i,
+ y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i,
+ y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+
+ wn4r = w[1];
+ wk1r = w[4];
+ wk1i = w[5];
+ wk3r = w[6];
+ wk3i = -w[7];
+ wk2r = w[8];
+ wk2i = w[9];
+ x1r = a[0] - a[17];
+ x1i = a[1] + a[16];
+ x0r = a[8] - a[25];
+ x0i = a[9] + a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y0r = x1r + x2r;
+ y0i = x1i + x2i;
+ y4r = x1r - x2r;
+ y4i = x1i - x2i;
+ x1r = a[0] + a[17];
+ x1i = a[1] - a[16];
+ x0r = a[8] + a[25];
+ x0i = a[9] - a[24];
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ y8r = x1r - x2i;
+ y8i = x1i + x2r;
+ y12r = x1r + x2i;
+ y12i = x1i - x2r;
+ x0r = a[2] - a[19];
+ x0i = a[3] + a[18];
+ x1r = wk1r * x0r - wk1i * x0i;
+ x1i = wk1r * x0i + wk1i * x0r;
+ x0r = a[10] - a[27];
+ x0i = a[11] + a[26];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y1r = x1r + x2r;
+ y1i = x1i + x2i;
+ y5r = x1r - x2r;
+ y5i = x1i - x2i;
+ x0r = a[2] + a[19];
+ x0i = a[3] - a[18];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[10] + a[27];
+ x0i = a[11] - a[26];
+ x2r = wk1r * x0r + wk1i * x0i;
+ x2i = wk1r * x0i - wk1i * x0r;
+ y9r = x1r - x2r;
+ y9i = x1i - x2i;
+ y13r = x1r + x2r;
+ y13i = x1i + x2i;
+ x0r = a[4] - a[21];
+ x0i = a[5] + a[20];
+ x1r = wk2r * x0r - wk2i * x0i;
+ x1i = wk2r * x0i + wk2i * x0r;
+ x0r = a[12] - a[29];
+ x0i = a[13] + a[28];
+ x2r = wk2i * x0r - wk2r * x0i;
+ x2i = wk2i * x0i + wk2r * x0r;
+ y2r = x1r + x2r;
+ y2i = x1i + x2i;
+ y6r = x1r - x2r;
+ y6i = x1i - x2i;
+ x0r = a[4] + a[21];
+ x0i = a[5] - a[20];
+ x1r = wk2i * x0r - wk2r * x0i;
+ x1i = wk2i * x0i + wk2r * x0r;
+ x0r = a[12] + a[29];
+ x0i = a[13] - a[28];
+ x2r = wk2r * x0r - wk2i * x0i;
+ x2i = wk2r * x0i + wk2i * x0r;
+ y10r = x1r - x2r;
+ y10i = x1i - x2i;
+ y14r = x1r + x2r;
+ y14i = x1i + x2i;
+ x0r = a[6] - a[23];
+ x0i = a[7] + a[22];
+ x1r = wk3r * x0r - wk3i * x0i;
+ x1i = wk3r * x0i + wk3i * x0r;
+ x0r = a[14] - a[31];
+ x0i = a[15] + a[30];
+ x2r = wk1i * x0r - wk1r * x0i;
+ x2i = wk1i * x0i + wk1r * x0r;
+ y3r = x1r + x2r;
+ y3i = x1i + x2i;
+ y7r = x1r - x2r;
+ y7i = x1i - x2i;
+ x0r = a[6] + a[23];
+ x0i = a[7] - a[22];
+ x1r = wk1i * x0r + wk1r * x0i;
+ x1i = wk1i * x0i - wk1r * x0r;
+ x0r = a[14] + a[31];
+ x0i = a[15] - a[30];
+ x2r = wk3i * x0r - wk3r * x0i;
+ x2i = wk3i * x0i + wk3r * x0r;
+ y11r = x1r + x2r;
+ y11i = x1i + x2i;
+ y15r = x1r - x2r;
+ y15i = x1i - x2i;
+ x1r = y0r + y2r;
+ x1i = y0i + y2i;
+ x2r = y1r + y3r;
+ x2i = y1i + y3i;
+ a[0] = x1r + x2r;
+ a[1] = x1i + x2i;
+ a[2] = x1r - x2r;
+ a[3] = x1i - x2i;
+ x1r = y0r - y2r;
+ x1i = y0i - y2i;
+ x2r = y1r - y3r;
+ x2i = y1i - y3i;
+ a[4] = x1r - x2i;
+ a[5] = x1i + x2r;
+ a[6] = x1r + x2i;
+ a[7] = x1i - x2r;
+ x1r = y4r - y6i;
+ x1i = y4i + y6r;
+ x0r = y5r - y7i;
+ x0i = y5i + y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[8] = x1r + x2r;
+ a[9] = x1i + x2i;
+ a[10] = x1r - x2r;
+ a[11] = x1i - x2i;
+ x1r = y4r + y6i;
+ x1i = y4i - y6r;
+ x0r = y5r + y7i;
+ x0i = y5i - y7r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[12] = x1r - x2i;
+ a[13] = x1i + x2r;
+ a[14] = x1r + x2i;
+ a[15] = x1i - x2r;
+ x1r = y8r + y10r;
+ x1i = y8i + y10i;
+ x2r = y9r - y11r;
+ x2i = y9i - y11i;
+ a[16] = x1r + x2r;
+ a[17] = x1i + x2i;
+ a[18] = x1r - x2r;
+ a[19] = x1i - x2i;
+ x1r = y8r - y10r;
+ x1i = y8i - y10i;
+ x2r = y9r + y11r;
+ x2i = y9i + y11i;
+ a[20] = x1r - x2i;
+ a[21] = x1i + x2r;
+ a[22] = x1r + x2i;
+ a[23] = x1i - x2r;
+ x1r = y12r - y14i;
+ x1i = y12i + y14r;
+ x0r = y13r + y15i;
+ x0i = y13i - y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[24] = x1r + x2r;
+ a[25] = x1i + x2i;
+ a[26] = x1r - x2r;
+ a[27] = x1i - x2i;
+ x1r = y12r + y14i;
+ x1i = y12i - y14r;
+ x0r = y13r - y15i;
+ x0i = y13i + y15r;
+ x2r = wn4r * (x0r - x0i);
+ x2i = wn4r * (x0i + x0r);
+ a[28] = x1r - x2i;
+ a[29] = x1i + x2r;
+ a[30] = x1r + x2i;
+ a[31] = x1i - x2r;
+}
+
+
+void cftf081(float *a, float *w)
+{
+ float wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ x0r = a[0] + a[8];
+ x0i = a[1] + a[9];
+ x1r = a[0] - a[8];
+ x1i = a[1] - a[9];
+ x2r = a[4] + a[12];
+ x2i = a[5] + a[13];
+ x3r = a[4] - a[12];
+ x3i = a[5] - a[13];
+ y0r = x0r + x2r;
+ y0i = x0i + x2i;
+ y2r = x0r - x2r;
+ y2i = x0i - x2i;
+ y1r = x1r - x3i;
+ y1i = x1i + x3r;
+ y3r = x1r + x3i;
+ y3i = x1i - x3r;
+ x0r = a[2] + a[10];
+ x0i = a[3] + a[11];
+ x1r = a[2] - a[10];
+ x1i = a[3] - a[11];
+ x2r = a[6] + a[14];
+ x2i = a[7] + a[15];
+ x3r = a[6] - a[14];
+ x3i = a[7] - a[15];
+ y4r = x0r + x2r;
+ y4i = x0i + x2i;
+ y6r = x0r - x2r;
+ y6i = x0i - x2i;
+ x0r = x1r - x3i;
+ x0i = x1i + x3r;
+ x2r = x1r + x3i;
+ x2i = x1i - x3r;
+ y5r = wn4r * (x0r - x0i);
+ y5i = wn4r * (x0r + x0i);
+ y7r = wn4r * (x2r - x2i);
+ y7i = wn4r * (x2r + x2i);
+ a[8] = y1r + y5r;
+ a[9] = y1i + y5i;
+ a[10] = y1r - y5r;
+ a[11] = y1i - y5i;
+ a[12] = y3r - y7i;
+ a[13] = y3i + y7r;
+ a[14] = y3r + y7i;
+ a[15] = y3i - y7r;
+ a[0] = y0r + y4r;
+ a[1] = y0i + y4i;
+ a[2] = y0r - y4r;
+ a[3] = y0i - y4i;
+ a[4] = y2r - y6i;
+ a[5] = y2i + y6r;
+ a[6] = y2r + y6i;
+ a[7] = y2i - y6r;
+}
+
+
+void cftf082(float *a, float *w)
+{
+ float wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i,
+ y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i,
+ y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+
+ wn4r = w[1];
+ wk1r = w[2];
+ wk1i = w[3];
+ y0r = a[0] - a[9];
+ y0i = a[1] + a[8];
+ y1r = a[0] + a[9];
+ y1i = a[1] - a[8];
+ x0r = a[4] - a[13];
+ x0i = a[5] + a[12];
+ y2r = wn4r * (x0r - x0i);
+ y2i = wn4r * (x0i + x0r);
+ x0r = a[4] + a[13];
+ x0i = a[5] - a[12];
+ y3r = wn4r * (x0r - x0i);
+ y3i = wn4r * (x0i + x0r);
+ x0r = a[2] - a[11];
+ x0i = a[3] + a[10];
+ y4r = wk1r * x0r - wk1i * x0i;
+ y4i = wk1r * x0i + wk1i * x0r;
+ x0r = a[2] + a[11];
+ x0i = a[3] - a[10];
+ y5r = wk1i * x0r - wk1r * x0i;
+ y5i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] - a[15];
+ x0i = a[7] + a[14];
+ y6r = wk1i * x0r - wk1r * x0i;
+ y6i = wk1i * x0i + wk1r * x0r;
+ x0r = a[6] + a[15];
+ x0i = a[7] - a[14];
+ y7r = wk1r * x0r - wk1i * x0i;
+ y7i = wk1r * x0i + wk1i * x0r;
+ x0r = y0r + y2r;
+ x0i = y0i + y2i;
+ x1r = y4r + y6r;
+ x1i = y4i + y6i;
+ a[0] = x0r + x1r;
+ a[1] = x0i + x1i;
+ a[2] = x0r - x1r;
+ a[3] = x0i - x1i;
+ x0r = y0r - y2r;
+ x0i = y0i - y2i;
+ x1r = y4r - y6r;
+ x1i = y4i - y6i;
+ a[4] = x0r - x1i;
+ a[5] = x0i + x1r;
+ a[6] = x0r + x1i;
+ a[7] = x0i - x1r;
+ x0r = y1r - y3i;
+ x0i = y1i + y3r;
+ x1r = y5r - y7r;
+ x1i = y5i - y7i;
+ a[8] = x0r + x1r;
+ a[9] = x0i + x1i;
+ a[10] = x0r - x1r;
+ a[11] = x0i - x1i;
+ x0r = y1r + y3i;
+ x0i = y1i - y3r;
+ x1r = y5r + y7r;
+ x1i = y5i + y7i;
+ a[12] = x0r - x1i;
+ a[13] = x0i + x1r;
+ a[14] = x0r + x1i;
+ a[15] = x0i - x1r;
+}
+
+
+void cftf040(float *a)
+{
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r - x3i;
+ a[3] = x1i + x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r + x3i;
+ a[7] = x1i - x3r;
+}
+
+
+void cftb040(float *a)
+{
+ float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+
+ x0r = a[0] + a[4];
+ x0i = a[1] + a[5];
+ x1r = a[0] - a[4];
+ x1i = a[1] - a[5];
+ x2r = a[2] + a[6];
+ x2i = a[3] + a[7];
+ x3r = a[2] - a[6];
+ x3i = a[3] - a[7];
+ a[0] = x0r + x2r;
+ a[1] = x0i + x2i;
+ a[2] = x1r + x3i;
+ a[3] = x1i - x3r;
+ a[4] = x0r - x2r;
+ a[5] = x0i - x2i;
+ a[6] = x1r - x3i;
+ a[7] = x1i + x3r;
+}
+
+
+void cftx020(float *a)
+{
+ float x0r, x0i;
+
+ x0r = a[0] - a[2];
+ x0i = a[1] - a[3];
+ a[0] += a[2];
+ a[1] += a[3];
+ a[2] = x0r;
+ a[3] = x0i;
+}
+
+
+void rftfsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr - wki * xi;
+ yi = wkr * xi + wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+void rftbsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr, xi, yr, yi;
+
+ m = n >> 1;
+ ks = 2 * nc / m;
+ kk = 0;
+ for (j = 2; j < m; j += 2) {
+ k = n - j;
+ kk += ks;
+ wkr = 0.5 - c[nc - kk];
+ wki = c[kk];
+ xr = a[j] - a[k];
+ xi = a[j + 1] + a[k + 1];
+ yr = wkr * xr + wki * xi;
+ yi = wkr * xi - wki * xr;
+ a[j] -= yr;
+ a[j + 1] -= yi;
+ a[k] += yr;
+ a[k + 1] -= yi;
+ }
+}
+
+
+void dctsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[j] - wkr * a[k];
+ a[j] = wkr * a[j] + wki * a[k];
+ a[k] = xr;
+ }
+ a[m] *= c[0];
+}
+
+
+void dstsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[k] - wkr * a[j];
+ a[k] = wkr * a[k] + wki * a[j];
+ a[j] = xr;
+ }
+ a[m] *= c[0];
+}
+
diff --git a/playlist.c b/playlist.c
index d998ca8a..e6b6facc 100644
--- a/playlist.c
+++ b/playlist.c
@@ -2701,7 +2701,7 @@ pl_format_time (float t, char *dur, int size) {
}
}
else {
- strcpy (dur, "-:--");
+ strcpy (dur, "∞");
}
}
diff --git a/plugins.c b/plugins.c
index 1cdb5111..1a0216fa 100644
--- a/plugins.c
+++ b/plugins.c
@@ -332,6 +332,8 @@ static DB_functions_t deadbeef_api = {
.pl_get_meta_raw = (int (*) (DB_playItem_t *it, const char *key, char *val, int size))pl_get_meta_raw,
.plt_get_meta = (int (*) (ddb_playlist_t *handle, const char *key, char *val, int size))plt_get_meta,
.pl_meta_exists = (int (*) (DB_playItem_t *it, const char *key))pl_meta_exists,
+ // FIXME ******* devel branch only *******
+ .audio_get_waveform_data = audio_get_waveform_data,
};
DB_functions_t *deadbeef = &deadbeef_api;
diff --git a/plugins/artwork/artwork.c b/plugins/artwork/artwork.c
index 7ba418fc..5a5a9800 100644
--- a/plugins/artwork/artwork.c
+++ b/plugins/artwork/artwork.c
@@ -132,6 +132,9 @@ queue_add (const char *fname, const char *artist, const char *album, int img_siz
for (cover_query_t *q = queue; q; q = q->next) {
if (!strcasecmp (artist, q->artist) || !strcasecmp (album, q->album)) {
deadbeef->mutex_unlock (mutex);
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return; // already in queue
}
}
@@ -169,6 +172,9 @@ queue_pop (void) {
if (queue->album) {
free (queue->album);
}
+ if (queue->callback) {
+ queue->callback (NULL, NULL, NULL, queue->user_data);
+ }
free (queue);
}
queue = next;
@@ -1133,6 +1139,7 @@ fetcher_thread (void *none)
}
if (param->callback) {
param->callback (param->fname, param->artist, param->album, param->user_data);
+ param->callback = NULL;
}
}
queue_pop ();
@@ -1187,16 +1194,25 @@ get_album_art (const char *fname, const char *artist, const char *album, int siz
if (!*artist || !*album)
{
//give up
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return size == -1 ? strdup (get_default_cover ()) : NULL;
}
if (!deadbeef->is_local_file (fname)) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return size == -1 ? strdup (get_default_cover ()) : NULL;
}
make_cache_path (path, sizeof (path), album, artist, size);
char *p = find_image (path);
if (p) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return p;
}
@@ -1215,6 +1231,9 @@ get_album_art (const char *fname, const char *artist, const char *album, int siz
else {
int res = copy_file (unscaled_path, path, size);
if (!res) {
+ if (callback) {
+ callback (NULL, NULL, NULL, user_data);
+ }
return strdup (path);
}
}
diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am
index bb3bfca5..9cb86c04 100644
--- a/plugins/gtkui/Makefile.am
+++ b/plugins/gtkui/Makefile.am
@@ -36,12 +36,12 @@ GTKUI_SOURCES = gtkui.c gtkui.h\
tagwritersettings.c tagwritersettings.h\
wingeom.c wingeom.h\
pluginconf.h\
+ widgets.c widgets.h\
ddbseekbar.h ddbequalizer.h ddbcellrenderertextmultiline.h\
ddbseekbar.c ddbequalizer.c ddbcellrenderertextmultiline.c\
+ gtkuigl.c gtkuigl.h\
$(SM_SOURCES)
-
-
sdkdir = $(pkgincludedir)
sdk_HEADERS = gtkui_api.h
@@ -76,7 +76,7 @@ ddb_gui_GTK2_la_LIBADD = $(LDADD) -L$(GTK_ROOT_216)/lib -lgtk-x11-2.0 -lgdk-x11-
ddb_gui_GTK2_la_CFLAGS = -std=c99 -I$(GTK_ROOT_216)/include/gtk-2.0 -I$(GTK_ROOT_216)/lib/gtk-2.0/include -I$(GTK_ROOT_216)/include/atk-1.0 -I$(GTK_ROOT_216)/include/cairo -I$(GTK_ROOT_216)/include/pango-1.0 -I$(GTK_ROOT_216)/include -I$(GTK_ROOT_216)/include/glib-2.0 -I$(GTK_ROOT_216)/lib/glib-2.0/include $(SM_CFLAGS)
else
-ddb_gui_GTK2_la_LIBADD = $(LDADD) $(GTK2_DEPS_LIBS) $(SM_LIBADD)
+ddb_gui_GTK2_la_LIBADD = $(LDADD) $(GTK2_DEPS_LIBS) $(SM_LIBADD) -lGLU
ddb_gui_GTK2_la_CFLAGS = -std=c99 $(GTK2_DEPS_CFLAGS) $(SM_CFLAGS)
endif
diff --git a/plugins/gtkui/callbacks.c b/plugins/gtkui/callbacks.c
index 74b92e8e..2ac935e8 100644
--- a/plugins/gtkui/callbacks.c
+++ b/plugins/gtkui/callbacks.c
@@ -44,6 +44,7 @@
#include "drawing.h"
#include "eq.h"
#include "wingeom.h"
+#include "widgets.h"
//#define trace(...) { fprintf (stderr, __VA_ARGS__); }
#define trace(fmt,...)
@@ -284,9 +285,8 @@ on_select_all1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
deadbeef->pl_select_all ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
- pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
+ DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
@@ -387,9 +387,6 @@ on_mainwin_key_press_event (GtkWidget *widget,
deadbeef->conf_set_int ("playlist.current", pl);
}
}
- else {
- ddb_listview_handle_keypress (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), event->keyval, event->state);
- }
return FALSE;
}
@@ -870,6 +867,8 @@ void
on_toggle_column_headers_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
+ // FIXME!
+ return;
GtkWidget *playlist = lookup_widget (mainwin, "playlist");
if (playlist) {
if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
@@ -936,6 +935,8 @@ void
on_toggle_tabs (GtkMenuItem *menuitem,
gpointer user_data)
{
+ // FIXME!
+ return;
GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
deadbeef->conf_set_int ("gtkui.tabs.visible", 0);
@@ -981,9 +982,8 @@ on_deselect_all1_activate (GtkMenuItem *menuitem,
it = next;
}
deadbeef->pl_unlock ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
- pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
+ DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
if (pl) {
ddb_listview_refresh (pl, DDB_REFRESH_LIST);
}
@@ -1008,8 +1008,7 @@ on_invert_selection1_activate (GtkMenuItem *menuitem,
it = next;
}
deadbeef->pl_unlock ();
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_LIST);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1121,7 +1120,7 @@ void
on_jump_to_current_track1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- gtkui_focus_on_playing_track ();
+ deadbeef->sendmessage (DB_EV_TRACKFOCUSCURRENT, 0, 0, 0);
}
static GtkWidget *translatorswindow;
@@ -1175,9 +1174,7 @@ on_sort_by_title_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%t", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1189,9 +1186,7 @@ on_sort_by_track_nr_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%n", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1203,9 +1198,7 @@ on_sort_by_album_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%b", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1217,9 +1210,7 @@ on_sort_by_artist_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, "%a", DDB_SORT_ASCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1246,9 +1237,7 @@ on_sort_by_random_activate (GtkMenuItem *menuitem,
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -1282,12 +1271,18 @@ on_sort_by_custom_activate (GtkMenuItem *menuitem,
deadbeef->plt_sort (plt, PL_MAIN, -1, fmt, order == 0 ? DDB_SORT_ASCENDING : DDB_SORT_DESCENDING);
deadbeef->plt_unref (plt);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_clear_sort (pl);
- ddb_listview_refresh (pl, DDB_REFRESH_LIST | DDB_LIST_CHANGED);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
gtk_widget_destroy (dlg);
dlg = NULL;
}
+void
+on_design_mode1_activate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
+ w_set_design_mode (act ? 1 : 0);
+}
+
diff --git a/plugins/gtkui/callbacks.h b/plugins/gtkui/callbacks.h
index 05f150e9..c0442b2e 100644
--- a/plugins/gtkui/callbacks.h
+++ b/plugins/gtkui/callbacks.h
@@ -1161,6 +1161,10 @@ on_convert8to16_toggled (GtkToggleButton *togglebutton,
gpointer user_data);
void
+on_design_mode1_activate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
on_reset_autostop_toggled (GtkToggleButton *togglebutton,
gpointer user_data);
diff --git a/plugins/gtkui/coverart.c b/plugins/gtkui/coverart.c
index e0451f5a..a2f1119a 100644
--- a/plugins/gtkui/coverart.c
+++ b/plugins/gtkui/coverart.c
@@ -45,6 +45,8 @@ typedef struct {
typedef struct load_query_s {
char *fname;
int width;
+ void (*callback) (void *user_data);
+ void *user_data;
struct load_query_s *next;
} load_query_t;
@@ -57,7 +59,7 @@ load_query_t *queue;
load_query_t *tail;
static void
-queue_add (const char *fname, int width) {
+queue_add (const char *fname, int width, void (*callback) (void *user_data), void *user_data) {
deadbeef->mutex_lock (mutex);
load_query_t *q;
for (q = queue; q; q = q->next) {
@@ -70,6 +72,8 @@ queue_add (const char *fname, int width) {
memset (q, 0, sizeof (load_query_t));
q->fname = strdup (fname);
q->width = width;
+ q->callback = callback;
+ q->user_data = user_data;
if (tail) {
tail->next = q;
tail = q;
@@ -108,7 +112,7 @@ loading_thread (void *none) {
for (;;) {
trace ("covercache: waiting for signal\n");
deadbeef->cond_wait (cond, mutex);
- trace ("covercache: signal received\n");
+ trace ("covercache: signal received (terminate=%d, queue=%p)\n", terminate, queue);
deadbeef->mutex_unlock (mutex);
while (!terminate && queue) {
int cache_min = 0;
@@ -144,6 +148,7 @@ loading_thread (void *none) {
if (stat (queue->fname, &stat_buf) < 0) {
trace ("failed to stat file %s\n", queue->fname);
}
+ trace ("covercache: caching pixbuf for %s\n", queue->fname);
GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_file_at_scale (queue->fname, queue->width, queue->width, TRUE, &error);
@@ -182,8 +187,12 @@ loading_thread (void *none) {
struct stat stat_buf;
deadbeef->mutex_unlock (mutex);
}
+
+ if (queue->callback) {
+ queue->callback (queue->user_data);
+ }
queue_pop ();
- g_idle_add (redraw_playlist_cb, NULL);
+ //g_idle_add (redraw_playlist_cb, NULL);
}
if (terminate) {
break;
@@ -191,20 +200,30 @@ loading_thread (void *none) {
}
}
-void
+typedef struct {
+ int width;
+ void (*callback)(void *user_data);
+ void *user_data;
+} cover_avail_info_t;
+
+static void
cover_avail_callback (const char *fname, const char *artist, const char *album, void *user_data) {
+ if (!fname) {
+ free (user_data);
+ return;
+ }
+ cover_avail_info_t *dt = user_data;
// means requested image is now in disk cache
// load it into main memory
- GdkPixbuf *pb = get_cover_art (fname, artist, album, (intptr_t)user_data);
+ GdkPixbuf *pb = get_cover_art_callb (fname, artist, album, dt->width, dt->callback, dt->user_data);
if (pb) {
g_object_unref (pb);
- // already in cache, redraw
- g_idle_add (redraw_playlist_cb, NULL);
}
+ free (dt);
}
static GdkPixbuf *
-get_pixbuf (const char *fname, int width) {
+get_pixbuf (const char *fname, int width, void (*callback)(void *user_data), void *user_data) {
int requested_width = width;
// find in cache
deadbeef->mutex_lock (mutex);
@@ -232,18 +251,45 @@ get_pixbuf (const char *fname, int width) {
}
#endif
deadbeef->mutex_unlock (mutex);
- queue_add (fname, width);
+ queue_add (fname, width, callback, user_data);
return NULL;
}
+static void
+redraw_playlist (void *user_data) {
+ g_idle_add (redraw_playlist_cb, NULL);
+}
+
GdkPixbuf *
get_cover_art (const char *fname, const char *artist, const char *album, int width) {
if (!coverart_plugin) {
return NULL;
}
- char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void *)(intptr_t)width);
+ cover_avail_info_t *dt = malloc (sizeof (cover_avail_info_t));
+ dt->width = width;
+ dt->callback = redraw_playlist;
+ dt->user_data = NULL;
+ char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, (void*)dt);
+ if (image_fname) {
+ GdkPixbuf *pb = get_pixbuf (image_fname, width, redraw_playlist, NULL);
+ free (image_fname);
+ return pb;
+ }
+ return NULL;
+}
+
+GdkPixbuf *
+get_cover_art_callb (const char *fname, const char *artist, const char *album, int width, void (*callback) (void *user_data), void *user_data) {
+ if (!coverart_plugin) {
+ return NULL;
+ }
+ cover_avail_info_t *dt = malloc (sizeof (cover_avail_info_t));
+ dt->width = width;
+ dt->callback = callback;
+ dt->user_data = user_data;
+ char *image_fname = coverart_plugin->get_album_art (fname, artist, album, -1, cover_avail_callback, dt);
if (image_fname) {
- GdkPixbuf *pb = get_pixbuf (image_fname, width);
+ GdkPixbuf *pb = get_pixbuf (image_fname, width, callback, user_data);
free (image_fname);
return pb;
}
diff --git a/plugins/gtkui/coverart.h b/plugins/gtkui/coverart.h
index 490f62e1..a4914b6f 100644
--- a/plugins/gtkui/coverart.h
+++ b/plugins/gtkui/coverart.h
@@ -32,6 +32,10 @@
GdkPixbuf *
get_cover_art (const char *fname, const char *artist, const char *album, int width);
+GdkPixbuf *
+get_cover_art_callb (const char *fname, const char *artist, const char *album, int width, void
+(*cover_avail_callback) (void *user_data), void *user_data);
+
void
coverart_reset_queue (void);
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.c b/plugins/gtkui/ddbcellrenderertextmultiline.c
index f7e72cf6..81f77fce 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.c
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.c
@@ -1,6 +1,3 @@
-/* ddbcellrenderertextmultiline.c generated by valac 0.14.0, the Vala compiler
- * generated from ddbcellrenderertextmultiline.vala, do not modify */
-
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
@@ -48,7 +45,7 @@ static gpointer ddb_cell_editable_text_view_parent_class = NULL;
static GtkCellEditableIface* ddb_cell_editable_text_view_gtk_cell_editable_parent_iface = NULL;
static gpointer ddb_cell_renderer_text_multiline_parent_class = NULL;
-GType ddb_cell_editable_text_view_get_type (void) G_GNUC_CONST;
+GType ddb_cell_editable_text_view_get_type (void);
enum {
DDB_CELL_EDITABLE_TEXT_VIEW_DUMMY_PROPERTY
};
@@ -57,7 +54,7 @@ static void ddb_cell_editable_text_view_real_start_editing (GtkCellEditable* bas
DdbCellEditableTextView* ddb_cell_editable_text_view_new (void);
DdbCellEditableTextView* ddb_cell_editable_text_view_construct (GType object_type);
static void ddb_cell_editable_text_view_finalize (GObject* obj);
-GType ddb_cell_renderer_text_multiline_get_type (void) G_GNUC_CONST;
+GType ddb_cell_renderer_text_multiline_get_type (void);
#define DDB_CELL_RENDERER_TEXT_MULTILINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DDB_TYPE_CELL_RENDERER_TEXT_MULTILINE, DdbCellRendererTextMultilinePrivate))
#define DDB_CELL_EDITABLE_TEXT_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DDB_TYPE_CELL_EDITABLE_TEXT_VIEW, DdbCellEditableTextViewPrivate))
enum {
@@ -122,12 +119,12 @@ static gboolean ddb_cell_editable_text_view_real_key_press_event (GtkWidget* bas
return result;
}
-
static void ddb_cell_editable_text_view_real_start_editing (GtkCellEditable* base, GdkEvent* event) {
DdbCellEditableTextView * self;
self = (DdbCellEditableTextView*) base;
}
+
#if GTK_CHECK_VERSION(2,20,0)
static void ddb_cell_editable_text_view_real_editing_canceled (GtkCellRenderer* base) {
}
@@ -217,6 +214,10 @@ static void ddb_cell_editable_text_view_class_init (DdbCellEditableTextViewClass
g_object_class_install_property (gobject_class, PROP_EDITING_CANCELED, obj_properties[PROP_EDITING_CANCELED]);
}
+void ddb_cell_editable_text_view_start_editing (DdbCellEditableTextView* self, GdkEvent* event) {
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (event != NULL);
+}
static void ddb_cell_editable_text_view_gtk_cell_editable_interface_init (GtkCellEditableIface * iface) {
ddb_cell_editable_text_view_gtk_cell_editable_parent_iface = g_type_interface_peek_parent (iface);
@@ -307,6 +308,7 @@ static void ddb_cell_renderer_text_multiline_gtk_cell_renderer_text_editing_done
g_signal_emit_by_name ((GtkCellRendererText*) _tmp14_, "edited", _tmp16_, new_text);
_g_free0 (new_text);
_g_object_unref0 (buf);
+ _g_free0 (new_text);
}
diff --git a/plugins/gtkui/ddbcellrenderertextmultiline.h b/plugins/gtkui/ddbcellrenderertextmultiline.h
index bdfec5ec..622a19a6 100644
--- a/plugins/gtkui/ddbcellrenderertextmultiline.h
+++ b/plugins/gtkui/ddbcellrenderertextmultiline.h
@@ -1,6 +1,3 @@
-/* ddbcellrenderertextmultiline.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBCELLRENDERERTEXTMULTILINE_H__
#define __DDBCELLRENDERERTEXTMULTILINE_H__
@@ -8,6 +5,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
+#include <gdk/gdk.h>
G_BEGIN_DECLS
@@ -54,10 +52,11 @@ struct _DdbCellRendererTextMultilineClass {
};
-GType ddb_cell_editable_text_view_get_type (void) G_GNUC_CONST;
+GType ddb_cell_editable_text_view_get_type (void);
+void ddb_cell_editable_text_view_start_editing (DdbCellEditableTextView* self, GdkEvent* event);
DdbCellEditableTextView* ddb_cell_editable_text_view_new (void);
DdbCellEditableTextView* ddb_cell_editable_text_view_construct (GType object_type);
-GType ddb_cell_renderer_text_multiline_get_type (void) G_GNUC_CONST;
+GType ddb_cell_renderer_text_multiline_get_type (void);
DdbCellRendererTextMultiline* ddb_cell_renderer_text_multiline_new (void);
DdbCellRendererTextMultiline* ddb_cell_renderer_text_multiline_construct (GType object_type);
diff --git a/plugins/gtkui/ddbequalizer.c b/plugins/gtkui/ddbequalizer.c
index 05f42547..02946aea 100644
--- a/plugins/gtkui/ddbequalizer.c
+++ b/plugins/gtkui/ddbequalizer.c
@@ -44,7 +44,6 @@ typedef struct _DdbEqualizerClass DdbEqualizerClass;
typedef struct _DdbEqualizerPrivate DdbEqualizerPrivate;
#define _gdk_cursor_unref0(var) ((var == NULL) ? NULL : (var = (gdk_cursor_unref (var), NULL)))
#define _g_free0(var) (var = (g_free (var), NULL))
-#define _pango_font_description_free0(var) ((var == NULL) ? NULL : (var = (pango_font_description_free (var), NULL)))
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL)))
@@ -73,7 +72,7 @@ struct _DdbEqualizerPrivate {
static gpointer ddb_equalizer_parent_class = NULL;
-GType ddb_equalizer_get_type (void) G_GNUC_CONST;
+GType ddb_equalizer_get_type (void);
#define DDB_EQUALIZER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DDB_TYPE_EQUALIZER, DdbEqualizerPrivate))
enum {
DDB_EQUALIZER_DUMMY_PROPERTY
diff --git a/plugins/gtkui/ddbequalizer.h b/plugins/gtkui/ddbequalizer.h
index c9e49988..02df70af 100644
--- a/plugins/gtkui/ddbequalizer.h
+++ b/plugins/gtkui/ddbequalizer.h
@@ -1,6 +1,3 @@
-/* ddbequalizer.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBEQUALIZER_H__
#define __DDBEQUALIZER_H__
diff --git a/plugins/gtkui/ddblistview.c b/plugins/gtkui/ddblistview.c
index 19493806..557da26b 100644
--- a/plugins/gtkui/ddblistview.c
+++ b/plugins/gtkui/ddblistview.c
@@ -275,6 +275,14 @@ ddb_listview_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event,
gpointer user_data);
+gboolean
+ddb_listview_list_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
+
+gboolean
+ddb_listview_list_focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer user_data);
+
+gboolean
+ddb_listview_list_focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer user_data);
static void
ddb_listview_class_init(DdbListviewClass *class)
@@ -370,7 +378,9 @@ ddb_listview_init(DdbListview *listview)
listview->list = gtk_drawing_area_new ();
gtk_widget_show (listview->list);
gtk_box_pack_start (GTK_BOX (vbox), listview->list, TRUE, TRUE, 0);
- int events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK;
+ gtk_widget_set_can_focus (listview->list, TRUE);
+ gtk_widget_set_can_default (listview->list, TRUE);
+ int events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK;
#if GTK_CHECK_VERSION(3,0,0)
events |= GDK_SCROLL_MASK;
#endif
@@ -413,7 +423,7 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->header, "motion_notify_event",
G_CALLBACK (ddb_listview_header_motion_notify_event),
NULL);
- g_signal_connect ((gpointer) listview->header, "button_press_event",
+ g_signal_connect_after ((gpointer) listview->header, "button_press_event",
G_CALLBACK (ddb_listview_header_button_press_event),
NULL);
g_signal_connect ((gpointer) listview->header, "button_release_event",
@@ -431,7 +441,7 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->list, "realize",
G_CALLBACK (ddb_listview_list_realize),
NULL);
- g_signal_connect ((gpointer) listview->list, "button_press_event",
+ g_signal_connect_after ((gpointer) listview->list, "button_press_event",
G_CALLBACK (ddb_listview_list_button_press_event),
NULL);
g_signal_connect ((gpointer) listview->list, "scroll_event",
@@ -470,6 +480,10 @@ ddb_listview_init(DdbListview *listview)
g_signal_connect ((gpointer) listview->hscrollbar, "value_changed",
G_CALLBACK (ddb_listview_hscroll_value_changed),
NULL);
+
+ g_signal_connect ((gpointer)listview->list, "key_press_event", G_CALLBACK (ddb_listview_list_key_press_event), NULL);
+ g_signal_connect ((gpointer)listview->list, "focus_in_event", G_CALLBACK (ddb_listview_list_focus_in_event), NULL);
+ g_signal_connect ((gpointer)listview->list, "focus_out_event", G_CALLBACK (ddb_listview_list_focus_out_event), NULL);
}
GtkWidget * ddb_listview_new()
@@ -1271,7 +1285,7 @@ ddb_listview_list_render_row_background (DdbListview *ps, cairo_t *cr, DdbListvi
if (gtk_widget_get_style (treeview)->depth == -1) {
return; // drawing was called too early
}
- GTK_WIDGET_SET_FLAGS (GTK_WIDGET (treeview), GTK_HAS_FOCUS);
+ gtk_widget_set_can_focus (GTK_WIDGET (treeview), TRUE);
#endif
}
int sel = it && ps->binding->is_selected (it);
@@ -1473,6 +1487,7 @@ ddb_listview_click_selection (DdbListview *ps, int ex, int ey, DdbListviewGroup
UNREF (it);
}
deadbeef->pl_unlock ();
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, deadbeef->plt_get_curr_idx (), PL_MAIN);
}
// {{{ expected behaviour for mouse1 without modifiers:
@@ -2580,7 +2595,7 @@ ddb_listview_header_button_press_event (GtkWidget *widget,
}
ps->prev_header_x = -1;
ps->last_header_motion_ev = -1;
- return FALSE;
+ return TRUE;
}
gboolean
@@ -2730,6 +2745,7 @@ ddb_listview_list_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
+ gtk_widget_grab_focus (widget);
DdbListview *ps = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
if (event->button == 1) {
ddb_listview_list_mouse1_pressed (ps, event->state, event->x, event->y, event->type);
@@ -2771,7 +2787,7 @@ ddb_listview_list_button_press_event (GtkWidget *widget,
UNREF (it);
}
}
- return FALSE;
+ return TRUE;
}
gboolean
@@ -3138,3 +3154,23 @@ ddb_listview_clear_sort (DdbListview *listview) {
}
gtk_widget_queue_draw (listview->header);
}
+
+gboolean
+ddb_listview_list_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) {
+ DdbListview *listview = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
+ ddb_listview_handle_keypress (listview, event->keyval, event->state);
+ return FALSE;
+
+}
+
+gboolean
+ddb_listview_list_focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ gtk_widget_set_can_focus (widget, TRUE);
+ return FALSE;
+}
+
+gboolean
+ddb_listview_list_focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ gtk_widget_set_can_focus (widget, FALSE);
+ return FALSE;
+}
diff --git a/plugins/gtkui/ddbseekbar.c b/plugins/gtkui/ddbseekbar.c
index bcb8b7fe..6f0d01fe 100644
--- a/plugins/gtkui/ddbseekbar.c
+++ b/plugins/gtkui/ddbseekbar.c
@@ -48,7 +48,7 @@ struct _DdbSeekbarClass {
static gpointer ddb_seekbar_parent_class = NULL;
-GType ddb_seekbar_get_type (void) G_GNUC_CONST;
+GType ddb_seekbar_get_type (void);
enum {
DDB_SEEKBAR_DUMMY_PROPERTY
};
@@ -148,6 +148,26 @@ static gboolean ddb_seekbar_real_motion_notify_event (GtkWidget* base, GdkEventM
_tmp0_ = *event;
_tmp1_ = on_seekbar_motion_notify_event ((GtkWidget*) self, &_tmp0_);
result = _tmp1_;
+
+ DB_playItem_t *trk = deadbeef->streamer_get_playing_track ();
+ if (trk) {
+ GtkAllocation a;
+ gtk_widget_get_allocation (base, &a);
+ float time = (event->x - a.x) * deadbeef->pl_get_item_duration (trk) / (a.width);
+ if (time < 0) {
+ time = 0;
+ }
+ deadbeef->pl_item_unref (trk);
+ char s[1000];
+ int hr = time/360;
+ int mn = (time-hr*360)/60;
+ int sc = time-hr*360-mn*60;
+ snprintf (s, sizeof (s), "%02d:%02d:%02d", hr, mn, sc);
+
+ printf ("set tooltip text %s\n", s);
+ gtk_widget_set_tooltip_text (base, s);
+ gtk_widget_trigger_tooltip_query (base);
+ }
return result;
}
@@ -164,8 +184,8 @@ static gboolean ddb_seekbar_real_configure_event (GtkWidget* base, GdkEventConfi
DdbSeekbar* ddb_seekbar_construct (GType object_type) {
- DdbSeekbar * self = NULL;
- self = (DdbSeekbar*) gtk_widget_new (object_type, NULL);
+ DdbSeekbar * self;
+ self = g_object_newv (object_type, 0, NULL);
return self;
}
@@ -206,6 +226,7 @@ static void ddb_seekbar_class_init (DdbSeekbarClass * klass) {
static void ddb_seekbar_instance_init (DdbSeekbar * self) {
gtk_widget_set_has_window ((GtkWidget*) self, FALSE);
+ gtk_widget_set_has_tooltip ((GtkWidget*) self, TRUE);
}
diff --git a/plugins/gtkui/ddbseekbar.h b/plugins/gtkui/ddbseekbar.h
index 71b753c0..ee455087 100644
--- a/plugins/gtkui/ddbseekbar.h
+++ b/plugins/gtkui/ddbseekbar.h
@@ -1,6 +1,3 @@
-/* ddbseekbar.h generated by valac 0.14.0, the Vala compiler, do not modify */
-
-
#ifndef __DDBSEEKBAR_H__
#define __DDBSEEKBAR_H__
@@ -31,7 +28,7 @@ struct _DdbSeekbarClass {
};
-GType ddb_seekbar_get_type (void) G_GNUC_CONST;
+GType ddb_seekbar_get_type (void);
DdbSeekbar* ddb_seekbar_new (void);
DdbSeekbar* ddb_seekbar_construct (GType object_type);
diff --git a/plugins/gtkui/ddbtabstrip.c b/plugins/gtkui/ddbtabstrip.c
index b1b18b3d..f367b0f8 100644
--- a/plugins/gtkui/ddbtabstrip.c
+++ b/plugins/gtkui/ddbtabstrip.c
@@ -26,7 +26,7 @@
#include "gtkui.h"
#include "interface.h"
#include "support.h"
-#include "ddblistview.h"
+#include "mainplaylist.h"
#define GLADE_HOOKUP_OBJECT(component,widget,name) \
g_object_set_data_full (G_OBJECT (component), name, \
@@ -280,7 +280,7 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
memcpy (mem, ptr, len);
mem[len] = 0;
// we don't pass control structure, but there's only one drag-drop view currently
- ps->binding->external_drag_n_drop (NULL, mem, len);
+ gtkui_receive_fm_drop (NULL, mem, len);
}
else if (target_type == 1) {
uint32_t *d= (uint32_t *)ptr;
@@ -289,7 +289,7 @@ on_tabstrip_drag_data_received (GtkWidget *widget,
int length = (len/4)-1;
ddb_playlist_t *p = deadbeef->plt_get_for_idx (plt);
if (p) {
- ps->binding->drag_n_drop (NULL, p, d, length, gdk_drag_context_get_selected_action (drag_context) == GDK_ACTION_COPY ? 1 : 0);
+ main_drag_n_drop (NULL, p, d, length, gdk_drag_context_get_selected_action (drag_context) == GDK_ACTION_COPY ? 1 : 0);
deadbeef->plt_unref (p);
}
}
@@ -301,16 +301,16 @@ on_tabstrip_drag_leave (GtkWidget *widget,
GdkDragContext *drag_context,
guint time)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_list_drag_leave (pl->list, drag_context, time, NULL);
+// DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_list_drag_leave (pl->list, drag_context, time, NULL);
}
void
on_tabstrip_drag_end (GtkWidget *widget,
GdkDragContext *drag_context)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_list_drag_end (pl->list, drag_context, NULL);
+// DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_list_drag_end (pl->list, drag_context, NULL);
}
GtkWidget * ddb_tabstrip_new() {
@@ -866,8 +866,6 @@ on_remove_playlist1_activate (GtkMenuItem *menuitem,
{
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
int playlist = deadbeef->plt_get_curr_idx ();
deadbeef->conf_set_int ("playlist.current", playlist);
@@ -1141,7 +1139,7 @@ on_tabstrip_button_press_event(GtkWidget *widget,
ts->scroll_direction = -1;
ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts);
}
- return FALSE;
+ return TRUE;
}
else if (event->x >= a.width - arrow_widget_width) {
if (event->type == GDK_BUTTON_PRESS) {
@@ -1149,7 +1147,7 @@ on_tabstrip_button_press_event(GtkWidget *widget,
ts->scroll_direction = 1;
ts->scroll_timer = g_timeout_add (300, tabstrip_scroll_cb, ts);
}
- return FALSE;
+ return TRUE;
}
}
if (tab_clicked != -1) {
@@ -1162,9 +1160,9 @@ on_tabstrip_button_press_event(GtkWidget *widget,
if (playlist != -1) {
gtkui_playlist_set_curr (playlist);
}
- return FALSE;
+ return TRUE;
}
- return FALSE;
+ return TRUE;
}
// adjust scroll if clicked tab spans border
@@ -1200,21 +1198,19 @@ on_tabstrip_button_press_event(GtkWidget *widget,
if (playlist != -1) {
gtkui_playlist_set_curr (playlist);
}
- return FALSE;
+ return TRUE;
}
else if (deadbeef->conf_get_int ("gtkui.mmb_delete_playlist", 1)) {
if (tab_clicked != -1) {
deadbeef->plt_remove (tab_clicked);
// force invalidation of playlist cache
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
int playlist = deadbeef->plt_get_curr_idx ();
deadbeef->conf_set_int ("playlist.current", playlist);
}
}
}
- return FALSE;
+ return TRUE;
}
diff --git a/plugins/gtkui/deadbeef.glade b/plugins/gtkui/deadbeef.glade
index 18f7b6e9..907a35be 100644
--- a/plugins/gtkui/deadbeef.glade
+++ b/plugins/gtkui/deadbeef.glade
@@ -453,6 +453,16 @@
<signal name="activate" handler="on_toggle_eq" last_modification_time="Sat, 20 Mar 2010 12:28:50 GMT"/>
</widget>
</child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="design_mode1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Design mode</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_design_mode1_activate" last_modification_time="Fri, 17 Jun 2011 19:10:50 GMT"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -938,37 +948,6 @@
</child>
<child>
- <widget class="Custom" id="tabstrip">
- <property name="height_request">24</property>
- <property name="visible">True</property>
- <property name="creation_function">create_tabstrip_widget</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Thu, 18 Feb 2010 18:05:36 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="Custom" id="playlist">
- <property name="visible">True</property>
- <property name="creation_function">create_ddb_listview_widget</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Sat, 13 Feb 2010 20:26:03 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
<widget class="GtkVBox" id="plugins_bottom_vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
@@ -980,8 +959,8 @@
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
diff --git a/plugins/gtkui/fileman.c b/plugins/gtkui/fileman.c
index bd52b4ab..72a5dfa8 100644
--- a/plugins/gtkui/fileman.c
+++ b/plugins/gtkui/fileman.c
@@ -111,17 +111,15 @@ open_files_worker (void *data) {
gtkpl_add_files (lst);
deadbeef->pl_save_all ();
deadbeef->conf_save ();
- gtkui_playlist_changed ();
- extern GtkWidget *mainwin;
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_set_cursor (pl, 0);
+ deadbeef->pl_set_cursor (PL_MAIN, 0);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
deadbeef->sendmessage (DB_EV_PLAY_CURRENT, 0, 1, 0);
}
void
gtkui_open_files (struct _GSList *lst) {
deadbeef->pl_clear ();
- playlist_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
intptr_t tid = deadbeef->thread_start (open_files_worker, lst);
deadbeef->thread_detach (tid);
@@ -171,13 +169,14 @@ strcopy_special (char *dest, const char *src, int len) {
static gboolean
set_dnd_cursor_idle (gpointer data) {
- DdbListview *listview = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
if (!data) {
- ddb_listview_set_cursor (listview, -1);
+ deadbeef->pl_set_cursor (PL_MAIN, -1);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
return FALSE;
}
int cursor = deadbeef->pl_get_idx_of (DB_PLAYITEM (data));
- ddb_listview_set_cursor (listview, cursor);
+ deadbeef->pl_set_cursor (PL_MAIN, cursor);
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
return FALSE;
}
@@ -189,7 +188,6 @@ gtkpl_add_fm_dropped_files (DB_playItem_t *drop_before, char *ptr, int length) {
deadbeef->plt_unref (plt);
return;
}
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
DdbListviewIter first = NULL;
DdbListviewIter after = NULL;
diff --git a/plugins/gtkui/gtkui.c b/plugins/gtkui/gtkui.c
index b5286536..6bffa367 100644
--- a/plugins/gtkui/gtkui.c
+++ b/plugins/gtkui/gtkui.c
@@ -29,7 +29,6 @@
#include "../../gettext.h"
#include "gtkui.h"
#include "ddblistview.h"
-#include "mainplaylist.h"
#include "search.h"
#include "progress.h"
#include "interface.h"
@@ -47,6 +46,8 @@
#include "pluginconf.h"
#include "gtkui_api.h"
#include "wingeom.h"
+#include "widgets.h"
+#include "X11/Xlib.h"
#ifdef EGG_SM_CLIENT_BACKEND_XSMP
#include "smclient/eggsmclient.h"
#endif
@@ -351,7 +352,7 @@ activate_cb (gpointer nothing) {
}
void
-redraw_queued_tracks (DdbListview *pl, int list) {
+redraw_queued_tracks (DdbListview *pl) {
DB_playItem_t *it;
int idx = 0;
deadbeef->pl_lock ();
@@ -366,14 +367,14 @@ redraw_queued_tracks (DdbListview *pl, int list) {
deadbeef->pl_unlock ();
}
-static gboolean
-redraw_queued_tracks_cb (gpointer nothing) {
+gboolean
+redraw_queued_tracks_cb (gpointer plt) {
+ DdbListview *list = plt;
int iconified = gdk_window_get_state(gtk_widget_get_window(mainwin)) & GDK_WINDOW_STATE_ICONIFIED;
if (!gtk_widget_get_visible (mainwin) || iconified) {
return FALSE;
}
- redraw_queued_tracks (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), PL_MAIN);
- redraw_queued_tracks (DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")), PL_SEARCH);
+ redraw_queued_tracks (list);
return FALSE;
}
@@ -390,7 +391,12 @@ gtkpl_songchanged_wrapper (DB_playItem_t *from, DB_playItem_t *to) {
}
g_idle_add (update_win_title_idle, ft);
g_idle_add (redraw_seekbar_cb, NULL);
- g_idle_add (redraw_queued_tracks_cb, NULL);
+ if (searchwin && gtk_widget_get_window (searchwin)) {
+ int iconified = gdk_window_get_state(gtk_widget_get_window (searchwin)) & GDK_WINDOW_STATE_ICONIFIED;
+ if (gtk_widget_get_visible (searchwin) && !iconified) {
+ g_idle_add (redraw_queued_tracks_cb, DDB_LISTVIEW (lookup_widget (searchwin, "searchlist")));
+ }
+ }
}
void
@@ -429,8 +435,8 @@ trackinfochanged_wrapper (DdbListview *playlist, DB_playItem_t *track, int iter)
void
gtkui_trackinfochanged (DB_playItem_t *track) {
- GtkWidget *playlist = lookup_widget (mainwin, "playlist");
- trackinfochanged_wrapper (DDB_LISTVIEW (playlist), track, PL_MAIN);
+// GtkWidget *playlist = lookup_widget (mainwin, "playlist");
+// trackinfochanged_wrapper (DDB_LISTVIEW (playlist), track, PL_MAIN);
if (searchwin && gtk_widget_get_visible (searchwin)) {
GtkWidget *search = lookup_widget (searchwin, "searchlist");
@@ -455,22 +461,10 @@ trackinfochanged_cb (gpointer data) {
return FALSE;
}
-static gboolean
-paused_cb (gpointer nothing) {
- DB_playItem_t *curr = deadbeef->streamer_get_playing_track ();
- if (curr) {
- int idx = deadbeef->pl_get_idx_of (curr);
- GtkWidget *playlist = lookup_widget (mainwin, "playlist");
- ddb_listview_draw_row (DDB_LISTVIEW (playlist), idx, (DdbListviewIter)curr);
- deadbeef->pl_item_unref (curr);
- }
- return FALSE;
-}
-
void
playlist_refresh (void) {
- DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+// DdbListview *ps = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// ddb_listview_refresh (ps, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
search_refresh ();
}
@@ -487,26 +481,6 @@ gtkui_playlist_changed (void) {
static gboolean
playlistswitch_cb (gpointer none) {
- GtkWidget *tabstrip = lookup_widget (mainwin, "tabstrip");
- int curr = deadbeef->plt_get_curr_idx ();
- char conf[100];
- snprintf (conf, sizeof (conf), "playlist.scroll.%d", curr);
- int scroll = deadbeef->conf_get_int (conf, 0);
- snprintf (conf, sizeof (conf), "playlist.cursor.%d", curr);
- int cursor = deadbeef->conf_get_int (conf, -1);
- ddb_tabstrip_refresh (DDB_TABSTRIP (tabstrip));
- DdbListview *listview = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- deadbeef->pl_set_cursor (PL_MAIN, cursor);
- if (cursor != -1) {
- DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (cursor, PL_MAIN);
- if (it) {
- deadbeef->pl_set_selected (it, 1);
- deadbeef->pl_item_unref (it);
- }
- }
-
- ddb_listview_refresh (listview, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
- ddb_listview_set_vscroll (listview, scroll);
search_refresh ();
return FALSE;
}
@@ -840,40 +814,6 @@ on_add_location_activate (GtkMenuItem *menuitem,
gtk_widget_destroy (dlg);
}
-static void
-songchanged (DdbListview *ps, DB_playItem_t *from, DB_playItem_t *to) {
- int to_idx = -1;
- if (!ddb_listview_is_scrolling (ps) && to) {
- int cursor_follows_playback = deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 0);
- int scroll_follows_playback = deadbeef->conf_get_int ("playlist.scroll.followplayback", 0);
- int plt = deadbeef->streamer_get_current_playlist ();
- if (plt != -1) {
- if (cursor_follows_playback && plt != deadbeef->plt_get_curr_idx ()) {
- deadbeef->plt_set_curr_idx (plt);
- }
- to_idx = deadbeef->pl_get_idx_of (to);
- if (to_idx != -1) {
- if (cursor_follows_playback) {
- ddb_listview_set_cursor_noscroll (ps, to_idx);
- }
- if (scroll_follows_playback && plt == deadbeef->plt_get_curr_idx ()) {
- ddb_listview_scroll_to (ps, to_idx);
- }
- }
- }
- }
-
- if (from) {
- int idx = deadbeef->pl_get_idx_of (from);
- if (idx != -1) {
- ddb_listview_draw_row (ps, idx, from);
- }
- }
- if (to && to_idx != -1) {
- ddb_listview_draw_row (ps, to_idx, to);
- }
-}
-
static gboolean
update_win_title_idle (gpointer data) {
struct fromto_t *ft = (struct fromto_t *)data;
@@ -897,8 +837,6 @@ update_win_title_idle (gpointer data) {
gtkui_set_titlebar (NULL);
}
}
- // update playlist view
- songchanged (DDB_LISTVIEW (lookup_widget (mainwin, "playlist")), from, to);
if (from) {
deadbeef->pl_item_unref (from);
}
@@ -956,11 +894,11 @@ volumebar_redraw (void) {
gdk_window_invalidate_rect (gtk_widget_get_window (volumebar), NULL, FALSE);
}
-void
-tabstrip_redraw (void) {
- GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
- ddb_tabstrip_refresh (DDB_TABSTRIP (ts));
-}
+//void
+//tabstrip_redraw (void) {
+// GtkWidget *ts = lookup_widget (mainwin, "tabstrip");
+// ddb_tabstrip_refresh (DDB_TABSTRIP (ts));
+//}
static int gtk_initialized = 0;
static gint refresh_timeout = 0;
@@ -985,6 +923,16 @@ gtkui_setup_gui_refresh (void) {
refresh_timeout = g_timeout_add (tm, gtkui_on_frameupdate, NULL);
}
+static void
+send_messages_to_widgets (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ send_messages_to_widgets (c, id, ctx, p1, p2);
+ }
+ if (w->message) {
+ w->message (w, id, ctx, p1, p2);
+ }
+}
+
gboolean
add_mainmenu_actions_cb (void *data) {
add_mainmenu_actions ();
@@ -993,6 +941,10 @@ add_mainmenu_actions_cb (void *data) {
int
gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ ddb_gtkui_widget_t *rootwidget = w_get_rootwidget ();
+ if (rootwidget) {
+ send_messages_to_widgets (rootwidget, id, ctx, p1, p2);
+ }
switch (id) {
case DB_EV_ACTIVATED:
g_idle_add (activate_cb, NULL);
@@ -1012,9 +964,9 @@ gtkui_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
g_idle_add (trackinfochanged_cb, ev->track);
}
break;
- case DB_EV_PAUSED:
- g_idle_add (paused_cb, NULL);
- break;
+// case DB_EV_PAUSED:
+// g_idle_add (paused_cb, NULL);
+// break;
case DB_EV_PLAYLISTCHANGED:
gtkui_playlist_changed ();
break;
@@ -1068,6 +1020,14 @@ unlock_playlist_columns_cb (void *ctx) {
void
gtkui_thread (void *ctx) {
+ XInitThreads (); // gtkglext/xcb doesn't work without this
+ // let's start some gtk
+ g_thread_init (NULL);
+// add_pixmap_directory (PREFIX "/share/deadbeef/pixmaps");
+ add_pixmap_directory (deadbeef->get_pixmap_dir ());
+ gdk_threads_init ();
+ gdk_threads_enter ();
+
int argc = 2;
const char **argv = alloca (sizeof (char *) * argc);
argv[0] = "deadbeef";
@@ -1109,7 +1069,45 @@ gtkui_thread (void *ctx) {
gtk_init (&argc, (char ***)&argv);
+ // register widget types
+ w_reg_widget ("tabbed_playlist", _("Playlist with tabs"), w_tabbed_playlist_create);
+ w_reg_widget ("box", NULL, w_box_create);
+ w_reg_widget ("vsplitter", _("Splitter (top and bottom)"), w_vsplitter_create);
+ w_reg_widget ("hsplitter", _("Splitter (left and right)"), w_hsplitter_create);
+ w_reg_widget ("placeholder", NULL, w_placeholder_create);
+ w_reg_widget ("tabs", _("Tabs"), w_tabs_create);
+ w_reg_widget ("tabstrip", _("Playlist tabs"), w_tabstrip_create);
+ w_reg_widget ("playlist", _("Playlist"), w_playlist_create);
+ w_reg_widget ("selproperties", _("Selection properties"), w_selproperties_create);
+ w_reg_widget ("coverart", _("Album art display"), w_coverart_create);
+ w_reg_widget ("scope", _("Scope"), w_scope_create);
+ w_reg_widget ("spectrum", _("Spectrum"), w_spectrum_create);
+
mainwin = create_mainwin ();
+
+ // construct mainwindow widgets
+ {
+
+ w_init ();
+ ddb_gtkui_widget_t *rootwidget = w_get_rootwidget ();
+ gtk_widget_show (rootwidget->widget);
+ gtk_box_pack_start (GTK_BOX(lookup_widget(mainwin, "plugins_bottom_vbox")), rootwidget->widget, TRUE, TRUE, 0);
+
+ // load layout
+ char layout[4000];
+ deadbeef->conf_get_str ("gtkui.layout", "tabbed_playlist { }", layout, sizeof (layout));
+
+ ddb_gtkui_widget_t *w = NULL;
+ w_create_from_string (layout, &w);
+ if (!w) {
+ ddb_gtkui_widget_t *plt = w_create ("tabbed_playlist");
+ w_append (rootwidget, plt);
+ gtk_widget_show (plt->widget);
+ }
+ else {
+ w_append (rootwidget, w);
+ }
+ }
#if GTK_CHECK_VERSION(3,0,0)
gtk_widget_set_events (GTK_WIDGET (mainwin), gtk_widget_get_events (GTK_WIDGET (mainwin)) | GDK_SCROLL_MASK);
#endif
@@ -1155,16 +1153,13 @@ gtkui_thread (void *ctx) {
searchwin = create_searchwin ();
gtk_window_set_transient_for (GTK_WINDOW (searchwin), GTK_WINDOW (mainwin));
- DdbListview *main_playlist = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- main_playlist_init (GTK_WIDGET (main_playlist));
-
+// DdbListview *main_playlist = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
+// main_playlist_init (GTK_WIDGET (main_playlist));
if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (header_mi), TRUE);
- ddb_listview_show_header (main_playlist, 1);
}
else {
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (header_mi), FALSE);
- ddb_listview_show_header (main_playlist, 0);
}
DdbListview *search_playlist = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
@@ -1188,6 +1183,8 @@ gtkui_thread (void *ctx) {
gtk_main ();
+ w_free ();
+
if (refresh_timeout) {
g_source_remove (refresh_timeout);
refresh_timeout = 0;
@@ -1278,24 +1275,6 @@ gtkui_plt_load (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname, in
}
void
-gtkui_focus_on_playing_track (void) {
- DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
- if (it) {
- int plt = deadbeef->streamer_get_current_playlist ();
- if (plt != deadbeef->plt_get_curr_idx ()) {
- deadbeef->plt_set_curr_idx (plt);
- }
- int idx = deadbeef->pl_get_idx_of (it);
- if (idx != -1) {
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_scroll_to (pl, idx);
- ddb_listview_set_cursor (pl, idx);
- }
- deadbeef->pl_item_unref (it);
- }
-}
-
-void
gtkui_playlist_set_curr (int playlist) {
deadbeef->plt_set_curr_idx (playlist);
deadbeef->conf_set_int ("playlist.current", playlist);
@@ -1406,7 +1385,7 @@ gtkui_stop (void) {
deadbeef->thread_join (gtk_tid);
trace ("gtk thread finished\n");
gtk_tid = 0;
- main_playlist_free ();
+ //main_playlist_free ();
trace ("gtkui_stop completed\n");
return 0;
}
@@ -1482,4 +1461,15 @@ static ddb_gtkui_t plugin = {
.gui.plugin.message = gtkui_message,
.gui.run_dialog = gtkui_run_dialog_root,
.get_mainwin = gtkui_get_mainwin,
+ .w_reg_widget = w_reg_widget,
+ .w_unreg_widget = w_unreg_widget,
+ .w_is_registered = w_is_registered,
+ .w_get_rootwidget = w_get_rootwidget,
+ .w_create = w_create,
+ .w_set_name = w_set_name,
+ .w_destroy = w_destroy,
+ .w_append = w_append,
+ .w_replace = w_replace,
+ .w_remove = w_remove,
+ .api_version = GTKUI_API_VERSION,
};
diff --git a/plugins/gtkui/gtkui.h b/plugins/gtkui/gtkui.h
index 0f764901..56f57e8d 100644
--- a/plugins/gtkui/gtkui.h
+++ b/plugins/gtkui/gtkui.h
@@ -111,8 +111,8 @@ on_seekbar_motion_notify_event (GtkWidget *widget,
void
volumebar_redraw (void);
-void
-tabstrip_redraw (void);
+//void
+//tabstrip_redraw (void);
void
gtkui_playlist_changed (void);
@@ -136,9 +136,6 @@ extern int (*gtkui_original_plt_add_dir) (ddb_playlist_t *plt, const char *dirna
extern int (*gtkui_original_plt_add_file) (ddb_playlist_t *plt, const char *fname, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
void
-gtkui_focus_on_playing_track (void);
-
-void
gtkui_playlist_set_curr (int playlist);
void
@@ -150,6 +147,9 @@ gtkui_get_curr_playlist_mod (void);
void
gtkui_trackinfochanged (DB_playItem_t *it);
+gboolean
+redraw_queued_tracks_cb (gpointer plt);
+
extern DB_playItem_t * (*gtkui_original_plt_load) (ddb_playlist_t *plt, DB_playItem_t *after, const char *fname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
#endif
diff --git a/plugins/gtkui/gtkui_api.h b/plugins/gtkui/gtkui_api.h
index 7fa7944f..30bf7090 100644
--- a/plugins/gtkui/gtkui_api.h
+++ b/plugins/gtkui/gtkui_api.h
@@ -25,9 +25,105 @@
#ifndef __GTKUI_API_H
#define __GTKUI_API_H
+#define GTKUI_API_VERSION 1 // for compile-time checking
+
+typedef struct ddb_gtkui_widget_s {
+ const char *type;
+ char *name;
+
+ struct ddb_gtkui_widget_s *parent;
+
+ GtkWidget *widget;
+
+ uint32_t flags;
+
+ // all the functions here are overloads, so they are not mandatory
+ // they can be implemented to add custom code to normal widget code
+ // they can be NULL if you don't need them, or you can set them to
+ // standard functions (more below)
+
+ // this function will be called after the widget is visible and needs to
+ // [re]initialize itself
+ // e.g. splitter widget sets the grip position in the init
+ void (*init) (struct ddb_gtkui_widget_s *container);
+
+ // save your custom parameters in the string using strncat
+ // for example, if you need to write width and height:
+ // strncat (s, "100 200", sz);
+ void (*save) (struct ddb_gtkui_widget_s *w, char *s, int sz);
+
+ // this is to read custom widget parameters, e.g. width and height
+ // you will be passed a string looking like "100 200 {"
+ // you will need to read params, and return the new pointer, normally it
+ // should be pointing to the "{"
+ const char *(*load) (struct ddb_gtkui_widget_s *w, const char *s);
+
+ // custom destructor code
+ void (*destroy) (struct ddb_gtkui_widget_s *w);
+
+ // custom append code
+ // if left NULL, appending will not be supported
+ // you should use standard w_container_add if your widget is derived from
+ // GTK_CONTAINER
+ void (*append) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child);
+
+ // custom remove code
+ // you should use w_container_remove if your widget is derived from
+ // GTK_CONTAINER
+ void (*remove) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child);
+
+ // custom replace code
+ // default replace will call remove;destroy;append
+ // but you can override if you need smarter behaviour
+ // look at the splitter and tabs implementation for more details
+ void (*replace) (struct ddb_gtkui_widget_s *container, struct ddb_gtkui_widget_s *child, struct ddb_gtkui_widget_s *newchild);
+
+ // implement this if you want to handle deadbeef broadcast messages/events
+ int (*message) (struct ddb_gtkui_widget_s *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2);
+
+ // this will be called to setup the menu widget in design mode
+ void (*initmenu) (struct ddb_gtkui_widget_s *w, GtkWidget *menu);
+
+ // you shouldn't touch this list normally, the system takes care of it
+ struct ddb_gtkui_widget_s *children;
+ struct ddb_gtkui_widget_s *next; // points to next widget in the same container
+} ddb_gtkui_widget_t;
+
typedef struct {
DB_gui_t gui;
+ int api_version;
+
+ // returns main window ptr
GtkWidget * (*get_mainwin) (void);
-} ddb_gtkui_t;
+ // register the new widget
+ void (*w_reg_widget) (const char *type, const char *title, ddb_gtkui_widget_t *(*create_func) (void));
+
+ // unregister the widget
+ void (*w_unreg_widget) (const char *type);
+
+ // returns 1 if a widget of the specified is registered
+ int (*w_is_registered) (const char *type);
+
+ // returns toplevel widget
+ ddb_gtkui_widget_t * (*w_get_rootwidget) (void);
+
+ // create a widget oof specified type
+ ddb_gtkui_widget_t * (*w_create) (const char *type);
+
+ // set widget name
+ void (*w_set_name) (ddb_gtkui_widget_t *w, const char *name);
+
+ // destroy the widget
+ void (*w_destroy) (ddb_gtkui_widget_t *w);
+
+ // append the widget to container
+ void (*w_append) (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+
+ // replace existing child widget with another widget
+ void (*w_replace) (ddb_gtkui_widget_t *w, ddb_gtkui_widget_t *from, ddb_gtkui_widget_t *to);
+
+ // remove the widget from its container
+ void (*w_remove) (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+} ddb_gtkui_t;
#endif
diff --git a/plugins/gtkui/gtkuigl.c b/plugins/gtkui/gtkuigl.c
new file mode 100644
index 00000000..db2a5667
--- /dev/null
+++ b/plugins/gtkui/gtkuigl.c
@@ -0,0 +1,52 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2012 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include "../../deadbeef.h"
+#include "gtkui.h"
+#include "support.h"
+#include "gtkuigl.h"
+
+static int gl_initialized;
+static int gl_init_state;
+//PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI;
+
+int
+gtkui_gl_init (void) {
+ if (gl_initialized) {
+ return gl_init_state;
+ }
+ gl_initialized = 1;
+ int argc = 1;
+ const char **argv = alloca (sizeof (char *) * argc);
+ argv[0] = "deadbeef";
+ gboolean success = gdk_gl_init_check (&argc, (char ***)&argv);
+ if (!success) {
+ fprintf (stderr, "gdk_gl_init_check failed\n");
+ gl_init_state = -1;
+ return -1;
+ }
+// glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
+ fprintf (stderr, "gdk_gl_init_check success\n");
+ gl_init_state = 0;
+ return 0;
+}
+
+void
+gtkui_gl_free (void) {
+ // ???
+}
diff --git a/plugins/gtkui/gtkuigl.h b/plugins/gtkui/gtkuigl.h
new file mode 100644
index 00000000..ddba54dd
--- /dev/null
+++ b/plugins/gtkui/gtkuigl.h
@@ -0,0 +1,36 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2012 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __GTKUIGL_H
+#define __GTKUIGL_H
+
+#include <gtk/gtkgl.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+//#include <GL/glx.h>
+//#include <GL/glxext.h>
+//
+//#ifndef GLX_SGI_swap_control
+//typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval);
+//#endif
+//extern PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI;
+
+int
+gtkui_gl_init (void);
+
+#endif
diff --git a/plugins/gtkui/interface.c b/plugins/gtkui/interface.c
index 8c38adf7..2b9f06ef 100644
--- a/plugins/gtkui/interface.c
+++ b/plugins/gtkui/interface.c
@@ -35,12 +35,21 @@ create_mainwin (void)
GtkWidget *File;
GtkWidget *File_menu;
GtkWidget *open;
+<<<<<<< HEAD
+ GtkWidget *image563;
+ GtkWidget *separator2;
+ GtkWidget *add_files;
+ GtkWidget *image564;
+ GtkWidget *add_folders;
+ GtkWidget *image565;
+=======
GtkWidget *image587;
GtkWidget *separator2;
GtkWidget *add_files;
GtkWidget *image588;
GtkWidget *add_folders;
GtkWidget *image589;
+>>>>>>> master
GtkWidget *add_location1;
GtkWidget *separatormenuitem1;
GtkWidget *new_playlist1;
@@ -48,18 +57,30 @@ create_mainwin (void)
GtkWidget *playlist_save_as;
GtkWidget *separator8;
GtkWidget *quit;
+<<<<<<< HEAD
+ GtkWidget *image566;
+ GtkWidget *Edit;
+ GtkWidget *Edit_menu;
+ GtkWidget *clear1;
+ GtkWidget *image567;
+=======
GtkWidget *image590;
GtkWidget *Edit;
GtkWidget *Edit_menu;
GtkWidget *clear1;
GtkWidget *image591;
+>>>>>>> master
GtkWidget *select_all1;
GtkWidget *deselect_all1;
GtkWidget *invert_selection1;
GtkWidget *Selection;
GtkWidget *Selection_menu;
GtkWidget *remove1;
+<<<<<<< HEAD
+ GtkWidget *image568;
+=======
GtkWidget *image592;
+>>>>>>> master
GtkWidget *crop1;
GtkWidget *find1;
GtkWidget *sort_by1;
@@ -79,6 +100,7 @@ create_mainwin (void)
GtkWidget *view_headers;
GtkWidget *view_tabs;
GtkWidget *view_eq;
+ GtkWidget *design_mode1;
GtkWidget *Playback;
GtkWidget *Playback_menu;
GtkWidget *Order;
@@ -102,16 +124,26 @@ create_mainwin (void)
GtkWidget *Help;
GtkWidget *Help_menu;
GtkWidget *help1;
+<<<<<<< HEAD
+ GtkWidget *image569;
+=======
GtkWidget *image593;
+>>>>>>> master
GtkWidget *changelog1;
GtkWidget *separator10;
GtkWidget *gpl1;
GtkWidget *lgpl1;
GtkWidget *separator9;
GtkWidget *about1;
+<<<<<<< HEAD
+ GtkWidget *image570;
+ GtkWidget *translators1;
+ GtkWidget *image571;
+=======
GtkWidget *image594;
GtkWidget *translators1;
GtkWidget *image595;
+>>>>>>> master
GtkWidget *hbox2;
GtkWidget *hbox3;
GtkWidget *stopbtn;
@@ -126,8 +158,11 @@ create_mainwin (void)
GtkWidget *image5;
GtkWidget *seekbar;
GtkWidget *volumebar;
+<<<<<<< HEAD
+=======
GtkWidget *tabstrip;
GtkWidget *playlist;
+>>>>>>> master
GtkWidget *plugins_bottom_vbox;
GtkWidget *statusbar;
GtkAccelGroup *accel_group;
@@ -161,9 +196,15 @@ create_mainwin (void)
GDK_O, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
+<<<<<<< HEAD
+ image563 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image563);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image563);
+=======
image587 = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_MENU);
gtk_widget_show (image587);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (open), image587);
+>>>>>>> master
separator2 = gtk_separator_menu_item_new ();
gtk_widget_show (separator2);
@@ -174,17 +215,29 @@ create_mainwin (void)
gtk_widget_show (add_files);
gtk_container_add (GTK_CONTAINER (File_menu), add_files);
+<<<<<<< HEAD
+ image564 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image564);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image564);
+=======
image588 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
gtk_widget_show (image588);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_files), image588);
+>>>>>>> master
add_folders = gtk_image_menu_item_new_with_mnemonic (_("Add folder(s)"));
gtk_widget_show (add_folders);
gtk_container_add (GTK_CONTAINER (File_menu), add_folders);
+<<<<<<< HEAD
+ image565 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image565);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image565);
+=======
image589 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
gtk_widget_show (image589);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_folders), image589);
+>>>>>>> master
add_location1 = gtk_menu_item_new_with_mnemonic (_("Add location"));
gtk_widget_show (add_location1);
@@ -222,9 +275,15 @@ create_mainwin (void)
GDK_Q, (GdkModifierType) GDK_CONTROL_MASK,
GTK_ACCEL_VISIBLE);
+<<<<<<< HEAD
+ image566 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image566);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image566);
+=======
image590 = gtk_image_new_from_stock ("gtk-quit", GTK_ICON_SIZE_MENU);
gtk_widget_show (image590);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (quit), image590);
+>>>>>>> master
Edit = gtk_menu_item_new_with_mnemonic (_("_Edit"));
gtk_widget_show (Edit);
@@ -237,9 +296,15 @@ create_mainwin (void)
gtk_widget_show (clear1);
gtk_container_add (GTK_CONTAINER (Edit_menu), clear1);
+<<<<<<< HEAD
+ image567 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image567);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image567);
+=======
image591 = gtk_image_new_from_stock ("gtk-clear", GTK_ICON_SIZE_MENU);
gtk_widget_show (image591);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (clear1), image591);
+>>>>>>> master
select_all1 = gtk_menu_item_new_with_mnemonic (_("Select all"));
gtk_widget_show (select_all1);
@@ -270,9 +335,15 @@ create_mainwin (void)
gtk_widget_show (remove1);
gtk_container_add (GTK_CONTAINER (Selection_menu), remove1);
+<<<<<<< HEAD
+ image568 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image568);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image568);
+=======
image592 = gtk_image_new_from_stock ("gtk-remove", GTK_ICON_SIZE_MENU);
gtk_widget_show (image592);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (remove1), image592);
+>>>>>>> master
crop1 = gtk_menu_item_new_with_mnemonic (_("Crop"));
gtk_widget_show (crop1);
@@ -352,6 +423,10 @@ create_mainwin (void)
gtk_widget_show (view_eq);
gtk_container_add (GTK_CONTAINER (View_menu), view_eq);
+ design_mode1 = gtk_check_menu_item_new_with_mnemonic (_("Design mode"));
+ gtk_widget_show (design_mode1);
+ gtk_container_add (GTK_CONTAINER (View_menu), design_mode1);
+
Playback = gtk_menu_item_new_with_mnemonic (_("_Playback"));
gtk_widget_show (Playback);
gtk_container_add (GTK_CONTAINER (menubar1), Playback);
@@ -454,9 +529,15 @@ create_mainwin (void)
gtk_widget_show (help1);
gtk_container_add (GTK_CONTAINER (Help_menu), help1);
+<<<<<<< HEAD
+ image569 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image569);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image569);
+=======
image593 = gtk_image_new_from_stock ("gtk-help", GTK_ICON_SIZE_MENU);
gtk_widget_show (image593);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (help1), image593);
+>>>>>>> master
changelog1 = gtk_menu_item_new_with_mnemonic (_("_ChangeLog"));
gtk_widget_show (changelog1);
@@ -484,17 +565,29 @@ create_mainwin (void)
gtk_widget_show (about1);
gtk_container_add (GTK_CONTAINER (Help_menu), about1);
+<<<<<<< HEAD
+ image570 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image570);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image570);
+=======
image594 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
gtk_widget_show (image594);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (about1), image594);
+>>>>>>> master
translators1 = gtk_image_menu_item_new_with_mnemonic (_("_Translators"));
gtk_widget_show (translators1);
gtk_container_add (GTK_CONTAINER (Help_menu), translators1);
+<<<<<<< HEAD
+ image571 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image571);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image571);
+=======
image595 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_MENU);
gtk_widget_show (image595);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (translators1), image595);
+>>>>>>> master
hbox2 = gtk_hbox_new (FALSE, 0);
gtk_widget_show (hbox2);
@@ -592,6 +685,8 @@ create_mainwin (void)
gtk_widget_set_can_focus(volumebar, FALSE);
gtk_widget_set_can_default(volumebar, FALSE);
+<<<<<<< HEAD
+=======
tabstrip = create_tabstrip_widget ("tabstrip", "", "", 0, 0);
gtk_widget_show (tabstrip);
gtk_box_pack_start (GTK_BOX (vbox1), tabstrip, FALSE, TRUE, 0);
@@ -605,9 +700,10 @@ create_mainwin (void)
gtk_widget_set_can_focus(playlist, FALSE);
gtk_widget_set_can_default(playlist, FALSE);
+>>>>>>> master
plugins_bottom_vbox = gtk_vbox_new (FALSE, 0);
gtk_widget_show (plugins_bottom_vbox);
- gtk_box_pack_start (GTK_BOX (vbox1), plugins_bottom_vbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox1), plugins_bottom_vbox, TRUE, TRUE, 0);
statusbar = gtk_statusbar_new ();
gtk_widget_show (statusbar);
@@ -721,6 +817,9 @@ create_mainwin (void)
g_signal_connect ((gpointer) view_eq, "activate",
G_CALLBACK (on_toggle_eq),
NULL);
+ g_signal_connect ((gpointer) design_mode1, "activate",
+ G_CALLBACK (on_design_mode1_activate),
+ NULL);
g_signal_connect ((gpointer) order_linear, "activate",
G_CALLBACK (on_order_linear_activate),
NULL);
@@ -795,12 +894,21 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, File, "File");
GLADE_HOOKUP_OBJECT (mainwin, File_menu, "File_menu");
GLADE_HOOKUP_OBJECT (mainwin, open, "open");
+<<<<<<< HEAD
+ GLADE_HOOKUP_OBJECT (mainwin, image563, "image563");
+ GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2");
+ GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files");
+ GLADE_HOOKUP_OBJECT (mainwin, image564, "image564");
+ GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders");
+ GLADE_HOOKUP_OBJECT (mainwin, image565, "image565");
+=======
GLADE_HOOKUP_OBJECT (mainwin, image587, "image587");
GLADE_HOOKUP_OBJECT (mainwin, separator2, "separator2");
GLADE_HOOKUP_OBJECT (mainwin, add_files, "add_files");
GLADE_HOOKUP_OBJECT (mainwin, image588, "image588");
GLADE_HOOKUP_OBJECT (mainwin, add_folders, "add_folders");
GLADE_HOOKUP_OBJECT (mainwin, image589, "image589");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, add_location1, "add_location1");
GLADE_HOOKUP_OBJECT (mainwin, separatormenuitem1, "separatormenuitem1");
GLADE_HOOKUP_OBJECT (mainwin, new_playlist1, "new_playlist1");
@@ -808,18 +916,30 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, playlist_save_as, "playlist_save_as");
GLADE_HOOKUP_OBJECT (mainwin, separator8, "separator8");
GLADE_HOOKUP_OBJECT (mainwin, quit, "quit");
+<<<<<<< HEAD
+ GLADE_HOOKUP_OBJECT (mainwin, image566, "image566");
+ GLADE_HOOKUP_OBJECT (mainwin, Edit, "Edit");
+ GLADE_HOOKUP_OBJECT (mainwin, Edit_menu, "Edit_menu");
+ GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1");
+ GLADE_HOOKUP_OBJECT (mainwin, image567, "image567");
+=======
GLADE_HOOKUP_OBJECT (mainwin, image590, "image590");
GLADE_HOOKUP_OBJECT (mainwin, Edit, "Edit");
GLADE_HOOKUP_OBJECT (mainwin, Edit_menu, "Edit_menu");
GLADE_HOOKUP_OBJECT (mainwin, clear1, "clear1");
GLADE_HOOKUP_OBJECT (mainwin, image591, "image591");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, select_all1, "select_all1");
GLADE_HOOKUP_OBJECT (mainwin, deselect_all1, "deselect_all1");
GLADE_HOOKUP_OBJECT (mainwin, invert_selection1, "invert_selection1");
GLADE_HOOKUP_OBJECT (mainwin, Selection, "Selection");
GLADE_HOOKUP_OBJECT (mainwin, Selection_menu, "Selection_menu");
GLADE_HOOKUP_OBJECT (mainwin, remove1, "remove1");
+<<<<<<< HEAD
+ GLADE_HOOKUP_OBJECT (mainwin, image568, "image568");
+=======
GLADE_HOOKUP_OBJECT (mainwin, image592, "image592");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, crop1, "crop1");
GLADE_HOOKUP_OBJECT (mainwin, find1, "find1");
GLADE_HOOKUP_OBJECT (mainwin, sort_by1, "sort_by1");
@@ -839,6 +959,7 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, view_headers, "view_headers");
GLADE_HOOKUP_OBJECT (mainwin, view_tabs, "view_tabs");
GLADE_HOOKUP_OBJECT (mainwin, view_eq, "view_eq");
+ GLADE_HOOKUP_OBJECT (mainwin, design_mode1, "design_mode1");
GLADE_HOOKUP_OBJECT (mainwin, Playback, "Playback");
GLADE_HOOKUP_OBJECT (mainwin, Playback_menu, "Playback_menu");
GLADE_HOOKUP_OBJECT (mainwin, Order, "Order");
@@ -860,16 +981,26 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, Help, "Help");
GLADE_HOOKUP_OBJECT (mainwin, Help_menu, "Help_menu");
GLADE_HOOKUP_OBJECT (mainwin, help1, "help1");
+<<<<<<< HEAD
+ GLADE_HOOKUP_OBJECT (mainwin, image569, "image569");
+=======
GLADE_HOOKUP_OBJECT (mainwin, image593, "image593");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, changelog1, "changelog1");
GLADE_HOOKUP_OBJECT (mainwin, separator10, "separator10");
GLADE_HOOKUP_OBJECT (mainwin, gpl1, "gpl1");
GLADE_HOOKUP_OBJECT (mainwin, lgpl1, "lgpl1");
GLADE_HOOKUP_OBJECT (mainwin, separator9, "separator9");
GLADE_HOOKUP_OBJECT (mainwin, about1, "about1");
+<<<<<<< HEAD
+ GLADE_HOOKUP_OBJECT (mainwin, image570, "image570");
+ GLADE_HOOKUP_OBJECT (mainwin, translators1, "translators1");
+ GLADE_HOOKUP_OBJECT (mainwin, image571, "image571");
+=======
GLADE_HOOKUP_OBJECT (mainwin, image594, "image594");
GLADE_HOOKUP_OBJECT (mainwin, translators1, "translators1");
GLADE_HOOKUP_OBJECT (mainwin, image595, "image595");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, hbox2, "hbox2");
GLADE_HOOKUP_OBJECT (mainwin, hbox3, "hbox3");
GLADE_HOOKUP_OBJECT (mainwin, stopbtn, "stopbtn");
@@ -884,8 +1015,11 @@ create_mainwin (void)
GLADE_HOOKUP_OBJECT (mainwin, image5, "image5");
GLADE_HOOKUP_OBJECT (mainwin, seekbar, "seekbar");
GLADE_HOOKUP_OBJECT (mainwin, volumebar, "volumebar");
+<<<<<<< HEAD
+=======
GLADE_HOOKUP_OBJECT (mainwin, tabstrip, "tabstrip");
GLADE_HOOKUP_OBJECT (mainwin, playlist, "playlist");
+>>>>>>> master
GLADE_HOOKUP_OBJECT (mainwin, plugins_bottom_vbox, "plugins_bottom_vbox");
GLADE_HOOKUP_OBJECT (mainwin, statusbar, "statusbar");
diff --git a/plugins/gtkui/mainplaylist.c b/plugins/gtkui/mainplaylist.c
index f056d2f4..b3a7f7d2 100644
--- a/plugins/gtkui/mainplaylist.c
+++ b/plugins/gtkui/mainplaylist.c
@@ -128,8 +128,8 @@ void main_external_drag_n_drop (DdbListviewIter before, char *mem, int length) {
gboolean
playlist_tooltip_handler (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer unused)
{
- GtkWidget *pl = lookup_widget (mainwin, "playlist");
- DB_playItem_t *it = (DB_playItem_t *)ddb_listview_get_iter_from_coord (DDB_LISTVIEW (pl), 0, y);
+ DdbListview *pl = DDB_LISTVIEW (g_object_get_data (G_OBJECT (widget), "owner"));
+ DB_playItem_t *it = (DB_playItem_t *)ddb_listview_get_iter_from_coord (pl, 0, y);
if (it) {
deadbeef->pl_lock ();
gtk_tooltip_set_text (tooltip, deadbeef->pl_find_meta (it, ":URI"));
@@ -161,6 +161,7 @@ void main_selection_changed (DdbListviewIter it, int idx) {
else {
ddb_listview_draw_row (search, search_get_idx ((DB_playItem_t *)it), it);
}
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, deadbeef->plt_get_curr_idx (), PL_MAIN);
}
void main_draw_group_title (DdbListview *listview, cairo_t *drawable, DdbListviewIter it, int x, int y, int width, int height) {
@@ -256,6 +257,14 @@ main_vscroll_changed (int pos) {
deadbeef->conf_set_int (conf, pos);
}
+void
+main_header_context_menu (DdbListview *ps, int column) {
+ GtkWidget *menu = create_headermenu (1);
+ set_last_playlist_cm (ps); // playlist ptr for context menu
+ set_active_column_cm (column);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
+}
+
DdbListviewBinding main_binding = {
// rows
.count = main_get_count,
@@ -292,7 +301,7 @@ DdbListviewBinding main_binding = {
// callbacks
.handle_doubleclick = main_handle_doubleclick,
.selection_changed = main_selection_changed,
- .header_context_menu = header_context_menu,
+ .header_context_menu = main_header_context_menu,
.list_context_menu = list_context_menu,
.delete_selected = main_delete_selected,
.vscroll_changed = main_vscroll_changed,
@@ -334,8 +343,9 @@ main_playlist_init (GtkWidget *widget) {
GValue value = {0, };
g_value_init (&value, G_TYPE_BOOLEAN);
g_value_set_boolean (&value, TRUE);
- g_object_set_property (G_OBJECT (widget), "has-tooltip", &value);
- g_signal_connect (G_OBJECT (widget), "query-tooltip", G_CALLBACK (playlist_tooltip_handler), NULL);
+ DdbListview *pl = DDB_LISTVIEW (widget);
+ g_object_set_property (G_OBJECT (pl->list), "has-tooltip", &value);
+ g_signal_connect (G_OBJECT (pl->list), "query-tooltip", G_CALLBACK (playlist_tooltip_handler), NULL);
}
deadbeef->conf_lock ();
strncpy (group_by_str, deadbeef->conf_get_str_fast ("playlist.group_by", ""), sizeof (group_by_str));
@@ -352,9 +362,6 @@ main_playlist_free (void) {
void
main_refresh (void) {
- if (mainwin && gtk_widget_get_visible (mainwin)) {
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- ddb_listview_refresh (pl, DDB_REFRESH_VSCROLL | DDB_REFRESH_LIST);
- }
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
diff --git a/plugins/gtkui/mainplaylist.h b/plugins/gtkui/mainplaylist.h
index 34cc67bc..1b25ca6b 100644
--- a/plugins/gtkui/mainplaylist.h
+++ b/plugins/gtkui/mainplaylist.h
@@ -19,6 +19,8 @@
#ifndef __MAINPLAYLIST_H
#define __MAINPLAYLIST_H
+#include "ddblistview.h"
+
void
main_playlist_init (GtkWidget *widget);
@@ -31,4 +33,7 @@ main_refresh (void);
int
main_get_idx (DdbListviewIter it);
+void
+main_drag_n_drop (DdbListviewIter before, DdbPlaylistHandle from_playlist, uint32_t *indices, int length, int copy);
+
#endif
diff --git a/plugins/gtkui/plcommon.c b/plugins/gtkui/plcommon.c
index c633cb60..3a00503c 100644
--- a/plugins/gtkui/plcommon.c
+++ b/plugins/gtkui/plcommon.c
@@ -303,8 +303,7 @@ on_clear1_activate (GtkMenuItem *menuitem,
{
deadbeef->pl_clear ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_refresh ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -313,8 +312,7 @@ on_remove1_activate (GtkMenuItem *menuitem,
{
int cursor = deadbeef->pl_delete_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_redraw ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
@@ -322,11 +320,9 @@ void
on_crop1_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
- DdbListview *pl = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
deadbeef->pl_crop_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_redraw ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -335,8 +331,7 @@ on_remove2_activate (GtkMenuItem *menuitem,
{
int cursor = deadbeef->pl_delete_selected ();
deadbeef->pl_save_all ();
- main_refresh ();
- search_redraw ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -374,8 +369,7 @@ on_remove_from_disk_activate (GtkMenuItem *menuitem,
deadbeef->pl_save_all ();
deadbeef->pl_unlock ();
- main_refresh ();
- search_redraw ();
+ deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, 0, 0);
}
void
@@ -729,6 +723,16 @@ static DdbListview *last_playlist;
static int active_column;
void
+set_last_playlist_cm (DdbListview *pl) {
+ last_playlist = pl;
+}
+
+void
+set_active_column_cm (int col) {
+ active_column = col;
+}
+
+void
append_column_from_textdef (DdbListview *listview, const uint8_t *def) {
// syntax: "title" "format" id width alignright
char token[MAX_TOKEN];
@@ -1064,14 +1068,6 @@ create_headermenu (int groupby)
}
void
-header_context_menu (DdbListview *ps, int column) {
- GtkWidget *menu = create_headermenu (GTK_WIDGET (ps) == lookup_widget (mainwin, "playlist") ? 1 : 0);
- last_playlist = ps;
- active_column = column;
- gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
-}
-
-void
add_column_helper (DdbListview *listview, const char *title, int width, int id, const char *format, int align_right) {
if (!format) {
format = "";
diff --git a/plugins/gtkui/plcommon.h b/plugins/gtkui/plcommon.h
index 3c24f00f..f5c04e35 100644
--- a/plugins/gtkui/plcommon.h
+++ b/plugins/gtkui/plcommon.h
@@ -41,12 +41,18 @@ void
list_context_menu (DdbListview *listview, DdbListviewIter it, int idx);
void
-header_context_menu (DdbListview *ps, int column);
-
-void
append_column_from_textdef (DdbListview *listview, const uint8_t *def);
void
add_column_helper (DdbListview *listview, const char *title, int width, int id, const char *format, int align_right);
+GtkWidget*
+create_headermenu (int groupby);
+
+void
+set_last_playlist_cm (DdbListview *pl);
+
+void
+set_active_column_cm (int col);
+
#endif // __PLCOLUMNS_H
diff --git a/plugins/gtkui/prefwin.c b/plugins/gtkui/prefwin.c
index ddecb632..546759a0 100644
--- a/plugins/gtkui/prefwin.c
+++ b/plugins/gtkui/prefwin.c
@@ -912,8 +912,9 @@ on_tabstrip_light_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_light", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
@@ -928,8 +929,9 @@ on_tabstrip_mid_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_mid", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
@@ -944,8 +946,9 @@ on_tabstrip_dark_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_dark", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -959,8 +962,9 @@ on_tabstrip_base_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_base", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -974,8 +978,9 @@ on_tabstrip_text_color_set (GtkColorButton *colorbutton,
deadbeef->conf_set_str ("gtkui.color.tabstrip_text", str);
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
@@ -1136,8 +1141,9 @@ on_override_tabstrip_colors_toggled (GtkToggleButton *togglebutton,
deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
gtkui_init_theme_colors ();
prefwin_init_theme_colors ();
- redraw_headers ();
- tabstrip_redraw ();
+// redraw_headers ();
+// tabstrip_redraw ();
+ gtk_widget_queue_draw (mainwin);
}
void
diff --git a/plugins/gtkui/search.c b/plugins/gtkui/search.c
index 432c7022..6634f12f 100644
--- a/plugins/gtkui/search.c
+++ b/plugins/gtkui/search.c
@@ -341,13 +341,7 @@ void search_handle_doubleclick (DdbListview *listview, DdbListviewIter iter, int
}
void search_selection_changed (DdbListviewIter it, int idx) {
- DdbListview *main = DDB_LISTVIEW (lookup_widget (mainwin, "playlist"));
- if (idx == -1) {
- ddb_listview_refresh (main, DDB_REFRESH_LIST);
- }
- else {
- ddb_listview_draw_row (main, main_get_idx ((DB_playItem_t *)it), it);
- }
+ deadbeef->sendmessage (DB_EV_SELCHANGED, 0, 0, 0);
}
void
@@ -357,6 +351,14 @@ search_delete_selected (void) {
search_refresh ();
}
+void
+search_header_context_menu (DdbListview *ps, int column) {
+ GtkWidget *menu = create_headermenu (0);
+ set_last_playlist_cm (ps); // playlist ptr for context menu
+ set_active_column_cm (column);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, ps, 3, gtk_get_current_event_time());
+}
+
DdbListviewBinding search_binding = {
// rows
.count = search_get_count,
@@ -393,7 +395,7 @@ DdbListviewBinding search_binding = {
// callbacks
.handle_doubleclick = search_handle_doubleclick,
.selection_changed = search_selection_changed,
- .header_context_menu = header_context_menu,
+ .header_context_menu = search_header_context_menu,
.list_context_menu = list_context_menu,
.delete_selected = search_delete_selected,
.modification_idx = gtkui_get_curr_playlist_mod,
diff --git a/plugins/gtkui/trkproperties.c b/plugins/gtkui/trkproperties.c
index 3b35273b..36d3d2c4 100644
--- a/plugins/gtkui/trkproperties.c
+++ b/plugins/gtkui/trkproperties.c
@@ -52,8 +52,8 @@ static int numtracks;
static GtkWidget *progressdlg;
static int progress_aborted;
-static int
-build_key_list (const char ***pkeys, int props) {
+int
+build_key_list (const char ***pkeys, int props, DB_playItem_t **tracks, int numtracks) {
int sz = 20;
const char **keys = malloc (sizeof (const char *) * sz);
if (!keys) {
@@ -100,7 +100,7 @@ equals_ptr (const char *a, const char *b) {
}
static int
-get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_playItem_t *it, const char *key), int (*equals)(const char *a, const char *b)) {
+get_field_value (char *out, int size, const char *key, const char *(*getter)(DB_playItem_t *it, const char *key), int (*equals)(const char *a, const char *b), DB_playItem_t **tracks, int numtracks) {
int multiple = 0;
*out = 0;
if (numtracks == 0) {
@@ -274,13 +274,13 @@ static const char *hc_props[] = {
};
void
-add_field (GtkListStore *store, const char *key, const char *title, int is_prop) {
+add_field (GtkListStore *store, const char *key, const char *title, int is_prop, DB_playItem_t **tracks, int numtracks) {
// get value to edit
const char *mult = is_prop ? "" : _("[Multiple values] ");
char val[1000];
size_t ml = strlen (mult);
memcpy (val, mult, ml+1);
- int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta_raw, equals_ptr);
+ int n = get_field_value (val + ml, sizeof (val) - ml, key, deadbeef->pl_find_meta_raw, equals_ptr, tracks, numtracks);
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
@@ -304,23 +304,20 @@ add_field (GtkListStore *store, const char *key, const char *title, int is_prop)
}
void
-trkproperties_fill_metadata (void) {
- if (!trackproperties) {
+trkproperties_fill_meta (GtkListStore *store, DB_playItem_t **tracks, int numtracks) {
+ gtk_list_store_clear (store);
+ if (!tracks) {
return;
}
- trkproperties_modified = 0;
- gtk_list_store_clear (store);
- gtk_list_store_clear (propstore);
- deadbeef->pl_lock ();
const char **keys = NULL;
- int nkeys = build_key_list (&keys, 0);
+ int nkeys = build_key_list (&keys, 0, tracks, numtracks);
int k;
// add "standard" fields
for (int i = 0; types[i]; i += 2) {
- add_field (store, types[i], _(types[i+1]), 0);
+ add_field (store, types[i], _(types[i+1]), 0, tracks, numtracks);
}
// add all other fields
@@ -339,19 +336,31 @@ trkproperties_fill_metadata (void) {
if (!types[i]) {
snprintf (title, sizeof (title), "<%s>", keys[k]);
}
- add_field (store, keys[k], title, 0);
+ add_field (store, keys[k], title, 0, tracks, numtracks);
}
if (keys) {
free (keys);
}
+}
+
+void
+trkproperties_fill_metadata (void) {
+ if (!trackproperties) {
+ return;
+ }
+ trkproperties_modified = 0;
+ deadbeef->pl_lock ();
+
+ trkproperties_fill_meta (store, tracks, numtracks);
+ gtk_list_store_clear (propstore);
// hardcoded properties
for (int i = 0; hc_props[i]; i += 2) {
- add_field (propstore, hc_props[i], _(hc_props[i+1]), 1);
+ add_field (propstore, hc_props[i], _(hc_props[i+1]), 1, tracks, numtracks);
}
// properties
- keys = NULL;
- nkeys = build_key_list (&keys, 1);
+ const char **keys = NULL;
+ int nkeys = build_key_list (&keys, 1, tracks, numtracks);
for (int k = 0; k < nkeys; k++) {
int i;
for (i = 0; hc_props[i]; i += 2) {
@@ -364,7 +373,7 @@ trkproperties_fill_metadata (void) {
}
char title[1000];
snprintf (title, sizeof (title), "<%s>", keys[k]+1);
- add_field (propstore, keys[k], title, 1);
+ add_field (propstore, keys[k], title, 1, tracks, numtracks);
}
if (keys) {
free (keys);
diff --git a/plugins/gtkui/trkproperties.h b/plugins/gtkui/trkproperties.h
index 8b2b6311..ef1e530c 100644
--- a/plugins/gtkui/trkproperties.h
+++ b/plugins/gtkui/trkproperties.h
@@ -19,6 +19,8 @@
#ifndef __TRKPROPERTIES_H
#define __TRKPROPERTIES_H
+#include "../../deadbeef.h"
+
struct DB_playItem_s;
void
@@ -30,4 +32,10 @@ trkproperties_destroy (void);
void
trkproperties_fill_metadata (void);
+int
+build_key_list (const char ***pkeys, int props, DB_playItem_t **tracks, int numtracks);
+
+void
+trkproperties_fill_meta (GtkListStore *store, DB_playItem_t **tracks, int numtracks);
+
#endif
diff --git a/plugins/gtkui/widgets.c b/plugins/gtkui/widgets.c
new file mode 100644
index 00000000..79ec9c66
--- /dev/null
+++ b/plugins/gtkui/widgets.c
@@ -0,0 +1,2225 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include "gtkui.h"
+#include "widgets.h"
+#include "ddbtabstrip.h"
+#include "ddblistview.h"
+#include "mainplaylist.h"
+#include "../../gettext.h"
+#include "parser.h"
+#include "trkproperties.h"
+#include "coverart.h"
+#include "gtkuigl.h"
+
+#define min(x,y) ((x)<(y)?(x):(y))
+#define max(x,y) ((x)>(y)?(x):(y))
+
+typedef struct w_creator_s {
+ const char *type;
+ const char *title; // set to NULL to avoid exposing this widget type to user
+ ddb_gtkui_widget_t *(*create_func) (void);
+ struct w_creator_s *next;
+} w_creator_t;
+
+static w_creator_t *w_creators;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *box; // hack to support splitter locking, can be a vbox or a hbox
+ int position;
+ int locked;
+} w_splitter_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_box_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+} w_tabstrip_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ DdbTabStrip *tabstrip;
+ DdbListview *list;
+} w_tabbed_playlist_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ DdbListview *list;
+} w_playlist_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *drawarea;
+} w_placeholder_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ int clicked_page;
+} w_tabs_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *tree;
+} w_selproperties_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *drawarea;
+} w_coverart_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *drawarea;
+ guint drawtimer;
+ GdkGLContext *glcontext;
+} w_scope_t;
+
+typedef struct {
+ ddb_gtkui_widget_t base;
+ GtkWidget *drawarea;
+ guint drawtimer;
+ GdkGLContext *glcontext;
+} w_spectrum_t;
+
+static int design_mode;
+static ddb_gtkui_widget_t *rootwidget;
+
+//// common functions
+
+void
+w_init (void) {
+ rootwidget = w_create ("box");
+}
+
+void
+w_free (void) {
+ w_save ();
+ w_creator_t *next = NULL;
+ for (w_creator_t *cr = w_creators; cr; cr = next) {
+ next = cr->next;
+ free (cr);
+ }
+ w_creators = NULL;
+}
+
+ddb_gtkui_widget_t *
+w_get_rootwidget (void) {
+ return rootwidget;
+}
+
+static void
+set_design_mode (ddb_gtkui_widget_t *w) {
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ set_design_mode (c);
+ }
+}
+
+void
+w_set_design_mode (int active) {
+ design_mode = active;
+ set_design_mode (rootwidget);
+}
+
+void
+w_append (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ child->parent = cont;
+ if (!cont->children) {
+ cont->children = child;
+ }
+ else {
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next) {
+ if (!c->next) {
+ c->next = child;
+ break;
+ }
+ }
+ }
+
+ if (cont->append) {
+ cont->append (cont, child);
+ }
+ if (child->init) {
+ child->init (child);
+ }
+}
+
+void
+w_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ if (cont->remove) {
+ cont->remove (cont, child);
+ }
+ child->widget = NULL;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next) {
+ if (c == child) {
+ if (prev) {
+ prev->next = c->next;
+ }
+ else {
+ cont->children = c->next;
+ }
+ break;
+ }
+ prev = c;
+ }
+ child->parent = NULL;
+}
+
+gboolean
+w_init_cb (void *data) {
+ ddb_gtkui_widget_t *w = data;
+ if (w->init) {
+ w->init (w);
+ }
+ return FALSE;
+}
+
+void
+w_replace (ddb_gtkui_widget_t *w, ddb_gtkui_widget_t *from, ddb_gtkui_widget_t *to) {
+ if (w->replace) {
+ w->replace (w, from, to);
+ if (to->init) {
+ g_idle_add (w_init_cb, to);
+ }
+ }
+ else {
+ w_remove (w, from);
+ w_destroy (from);
+ w_append (w, to);
+ }
+}
+
+const char *
+w_create_from_string (const char *s, ddb_gtkui_widget_t **parent) {
+ char t[MAX_TOKEN];
+ s = gettoken (s, t);
+ if (!s) {
+ return NULL;
+ }
+ ddb_gtkui_widget_t *w = w_create (t);
+ // nuke all default children
+ while (w->children) {
+ w_remove (w, w->children);
+ }
+
+ // name
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ if (t[0]) {
+ w_set_name (w, t);
+ }
+
+ // load widget params
+ if (w->load) {
+ s = w->load (w, s);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ }
+
+ // {
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ if (strcmp (t, "{")) {
+ w_destroy (w);
+ return NULL;
+ }
+
+ const char *back = s;
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ for (;;) {
+ if (!strcmp (t, "}")) {
+ break;
+ }
+
+ s = w_create_from_string (back, &w);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+
+ back = s;
+ s = gettoken (s, t);
+ if (!s) {
+ w_destroy (w);
+ return NULL;
+ }
+ }
+
+ if (*parent) {
+ w_append (*parent, w);
+ }
+ else {
+ *parent = w;
+ }
+ return s;
+}
+
+static ddb_gtkui_widget_t *current_widget;
+static int hidden = 0;
+
+static gboolean
+w_draw_event (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
+ if (hidden && user_data == current_widget) {
+ cairo_set_source_rgb (cr, 0.17f, 0, 0.83f);
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(widget, &allocation);
+
+ if (!gtk_widget_get_has_window (widget)) {
+ cairo_reset_clip (cr);
+ cairo_rectangle (cr, allocation.x, allocation.y, allocation.width, allocation.height);
+ }
+ else {
+ cairo_reset_clip (cr);
+ cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+ }
+ cairo_fill (cr);
+ }
+ return FALSE;
+}
+
+gboolean
+w_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ gboolean res = w_draw_event (widget, cr, user_data);
+ cairo_destroy (cr);
+ return res;
+}
+
+static char paste_buffer[1000];
+
+void
+save_widget_to_string (char *str, int sz, ddb_gtkui_widget_t *w) {
+ strcat (str, w->type);
+ strcat (str, " \"");
+ strcat (str, w->name ? w->name : "");
+ strcat (str, "\"");
+ if (w->save) {
+ w->save (w, str, sz);
+ }
+ strcat (str, " {");
+ for (ddb_gtkui_widget_t *c = w->children; c; c = c->next) {
+ save_widget_to_string (str, sz, c);
+ }
+ strcat (str, "} ");
+}
+
+void
+w_save (void) {
+ char buf[4000] = "";
+ save_widget_to_string (buf, sizeof (buf), rootwidget->children);
+ deadbeef->conf_set_str ("gtkui.layout", buf);
+ deadbeef->conf_save ();
+}
+
+static void
+on_replace_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ for (w_creator_t *cr = w_creators; cr; cr = cr->next) {
+ if (cr->type == user_data) {
+ w_replace (current_widget->parent, current_widget, w_create (user_data));
+ }
+ }
+ w_save ();
+}
+
+static void
+on_delete_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w_create ("placeholder"));
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w_create ("placeholder");
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+static void
+on_cut_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ // save hierarchy to string
+ // FIXME: use real clipboard
+ paste_buffer[0] = 0;
+ save_widget_to_string (paste_buffer, sizeof (paste_buffer), current_widget);
+
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w_create ("placeholder"));
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w_create ("placeholder");
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+static void
+on_copy_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!strcmp (current_widget->type, "placeholder")) {
+ return;
+ }
+ // save hierarchy to string
+ // FIXME: use real clipboard
+ paste_buffer[0] = 0;
+ save_widget_to_string (paste_buffer, sizeof (paste_buffer), current_widget);
+}
+
+static void
+on_paste_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ ddb_gtkui_widget_t *parent = current_widget->parent;
+ if (!paste_buffer[0]) {
+ return;
+ }
+ ddb_gtkui_widget_t *w = NULL;
+ w_create_from_string (paste_buffer, &w);
+ if (parent->replace) {
+ parent->replace (parent, current_widget, w);
+ }
+ else {
+ w_remove (parent, current_widget);
+ w_destroy (current_widget);
+ current_widget = w;
+ w_append (parent, current_widget);
+ }
+ w_save ();
+}
+
+void
+hide_widget (GtkWidget *widget, gpointer data) {
+ gtk_widget_hide (widget);
+}
+
+void
+show_widget (GtkWidget *widget, gpointer data) {
+ gtk_widget_show (widget);
+}
+
+void
+w_menu_deactivate (GtkMenuShell *menushell, gpointer user_data) {
+ hidden = 0;
+ ddb_gtkui_widget_t *w = user_data;
+ if (GTK_IS_CONTAINER (w->widget)) {
+ gtk_container_foreach (GTK_CONTAINER (w->widget), show_widget, NULL);
+ }
+ gtk_widget_set_app_paintable (w->widget, FALSE);
+ gtk_widget_queue_draw (w->widget);
+}
+
+gboolean
+w_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
+ if (!design_mode || event->button != 3) {
+ return FALSE;
+ }
+
+ current_widget = user_data;
+ widget = current_widget->widget;
+ hidden = 1;
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_foreach (GTK_CONTAINER (widget), hide_widget, NULL);
+ }
+ gtk_widget_set_app_paintable (widget, TRUE);
+ gtk_widget_queue_draw (((ddb_gtkui_widget_t *)user_data)->widget);
+ GtkWidget *menu;
+ GtkWidget *submenu;
+ GtkWidget *item;
+ menu = gtk_menu_new ();
+ if (strcmp (current_widget->type, "placeholder")) {
+ item = gtk_menu_item_new_with_mnemonic (_("Replace with..."));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ }
+ else {
+ item = gtk_menu_item_new_with_mnemonic (_("Insert..."));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ }
+
+ submenu = gtk_menu_new ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+
+ for (w_creator_t *cr = w_creators; cr; cr = cr->next) {
+ if (cr->title) {
+ item = gtk_menu_item_new_with_mnemonic (cr->title);
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (submenu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_replace_activate),
+ (void *)cr->type);
+ }
+ }
+
+ if (strcmp (current_widget->type, "placeholder")) {
+ item = gtk_menu_item_new_with_mnemonic (_("Delete"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_delete_activate),
+ NULL);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Cut"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_cut_activate),
+ NULL);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Copy"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_copy_activate),
+ NULL);
+ }
+ item = gtk_menu_item_new_with_mnemonic ("Paste");
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_paste_activate),
+ NULL);
+
+ if (current_widget->initmenu) {
+ current_widget->initmenu (current_widget, menu);
+ }
+
+ g_signal_connect ((gpointer) menu, "deactivate", G_CALLBACK (w_menu_deactivate), user_data);
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, widget, 0, gtk_get_current_event_time());
+ return TRUE;
+}
+
+static void
+w_override_signals (GtkWidget *widget, gpointer user_data) {
+ g_signal_connect ((gpointer) widget, "button_press_event", G_CALLBACK (w_button_press_event), user_data);
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect ((gpointer) widget, "expose_event", G_CALLBACK (w_expose_event), user_data);
+#else
+ g_signal_connect ((gpointer) widget, "draw", G_CALLBACK (w_draw_event), user_data);
+#endif
+ if (GTK_IS_CONTAINER (widget)) {
+ gtk_container_forall (GTK_CONTAINER (widget), w_override_signals, user_data);
+ }
+}
+
+void
+w_reg_widget (const char *type, const char *title, ddb_gtkui_widget_t *(*create_func) (void)) {
+ w_creator_t *c;
+ for (c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ fprintf (stderr, "gtkui w_reg_widget: widget type %s already registered\n", type);
+ return;
+ }
+ }
+ c = malloc (sizeof (w_creator_t));
+ memset (c, 0, sizeof (w_creator_t));
+ c->type = type;
+ c->title = title;
+ c->create_func = create_func;
+ c->next = w_creators;
+ w_creators = c;
+}
+
+void
+w_unreg_widget (const char *type) {
+ w_creator_t *c, *prev = NULL;
+ for (c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ if (prev) {
+ prev->next = c->next;
+ }
+ else {
+ w_creators = c->next;
+ }
+ free (c);
+ return;
+ }
+ prev = c;
+ }
+ fprintf (stderr, "gtkui w_unreg_widget: widget type %s is not registered\n", type);
+}
+
+int
+w_is_registered (const char *type) {
+ // FIXME
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_create (const char *type) {
+ for (w_creator_t *c = w_creators; c; c = c->next) {
+ if (!strcmp (c->type, type)) {
+ ddb_gtkui_widget_t *w = c->create_func ();
+ w->type = c->type;
+
+ return w;
+ }
+ }
+ return NULL;
+}
+
+void
+w_set_name (ddb_gtkui_widget_t *w, const char *name) {
+ if (w->name) {
+ free (w->name);
+ w->name = NULL;
+ }
+ if (name) {
+ w->name = strdup (name);
+ }
+}
+
+void
+w_destroy (ddb_gtkui_widget_t *w) {
+ if (w->destroy) {
+ w->destroy (w);
+ }
+ if (w->widget) {
+ gtk_widget_destroy (w->widget);
+ }
+ if (w->name) {
+ free (w->name);
+ }
+ free (w);
+}
+
+///// gtk_container convenience functions
+void
+w_container_add (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *container = NULL;
+ container = cont->widget;
+ gtk_container_add (GTK_CONTAINER (container), child->widget);
+ gtk_widget_show (child->widget);
+}
+
+void
+w_container_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *container = NULL;
+ container = cont->widget;
+ gtk_container_remove (GTK_CONTAINER (container), child->widget);
+
+}
+
+////// placeholder widget
+gboolean
+w_placeholder_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
+ cairo_set_source_rgb (cr, 255, 0, 0);
+ cairo_surface_t *checker;
+ cairo_t *cr2;
+
+ checker = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 12, 12);
+ cr2 = cairo_create (checker);
+
+ cairo_set_source_rgb (cr2, 0.5, 0.5 ,0.5);
+ cairo_paint (cr2);
+ cairo_set_source_rgb (cr2, 0, 0, 0);
+ cairo_move_to (cr2, 0, 0);
+ cairo_line_to (cr2, 12, 12);
+ cairo_move_to (cr2, 1, 12);
+ cairo_line_to (cr2, 12, 1);
+ cairo_set_line_width (cr2, 1);
+ cairo_set_antialias (cr2, CAIRO_ANTIALIAS_NONE);
+ cairo_stroke (cr2);
+ cairo_fill (cr2);
+ cairo_destroy (cr2);
+
+ cairo_set_source_surface (cr, checker, 0, 0);
+ cairo_pattern_t *pt = cairo_get_source(cr);
+ cairo_pattern_set_extend (pt, CAIRO_EXTEND_REPEAT);
+ GtkAllocation a;
+ gtk_widget_get_allocation (widget, &a);
+ cairo_rectangle (cr, 0, 0, a.width, a.height);
+ cairo_paint (cr);
+ cairo_surface_destroy (checker);
+ return FALSE;
+}
+
+gboolean
+w_placeholder_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ gboolean res = w_placeholder_draw (widget, cr, user_data);
+ cairo_destroy (cr);
+ return res;
+}
+
+ddb_gtkui_widget_t *
+w_placeholder_create (void) {
+ w_placeholder_t *w = malloc (sizeof (w_placeholder_t));
+ memset (w, 0, sizeof (w_placeholder_t));
+
+ w->base.widget = gtk_event_box_new ();
+ w->drawarea = gtk_drawing_area_new ();
+ gtk_widget_show (w->drawarea);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (w_placeholder_expose_event), w);
+#else
+ g_signal_connect_after ((gpointer) w->drawarea, "draw", G_CALLBACK (w_placeholder_draw), w);
+#endif
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t*)w;
+}
+
+// common splitter funcs
+const char *
+w_splitter_load (struct ddb_gtkui_widget_s *w, const char *s) {
+ char t[MAX_TOKEN];
+ s = gettoken (s, t);
+ if (!s) {
+ return NULL;
+ }
+ ((w_splitter_t *)w)->position = atoi (t);
+ s = gettoken (s, t);
+ if (!s) {
+ return NULL;
+ }
+ ((w_splitter_t *)w)->locked = atoi (t);
+ return s;
+}
+
+void
+w_splitter_save (struct ddb_gtkui_widget_s *w, char *s, int sz) {
+ int pos = ((w_splitter_t *)w)->box ? ((w_splitter_t *)w)->position : gtk_paned_get_position (GTK_PANED(w->widget));
+ char spos[10];
+ snprintf (spos, sizeof (spos), " %d %d", pos, ((w_splitter_t *)w)->locked);
+ strncat (s, spos, sz);
+}
+
+void
+w_splitter_add (ddb_gtkui_widget_t *w, ddb_gtkui_widget_t *child) {
+ w_container_add (w, child);
+ if (((w_splitter_t *)w)->locked) {
+ if (child == w->children) {
+ if (GTK_IS_VBOX (((w_splitter_t *)w)->box)) {
+ gtk_widget_set_size_request (child->widget, -1, ((w_splitter_t *)w)->position);
+ }
+ else {
+ gtk_widget_set_size_request (child->widget, ((w_splitter_t *)w)->position, -1);
+ }
+ }
+ }
+ else {
+ gtk_paned_set_position (GTK_PANED(w->widget), ((w_splitter_t *)w)->position);
+ }
+}
+
+void
+w_splitter_init_signals (w_splitter_t *w) {
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+#else
+ g_signal_connect ((gpointer) w->base.widget, "draw", G_CALLBACK (w_draw_event), w);
+#endif
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+}
+
+void
+w_splitter_lock (w_splitter_t *w) {
+ // we can't change GtkPaned behavior, so convert to vbox for now
+ if (w->locked) {
+ return;
+ }
+ w->locked = 1;
+
+ int vert = w->base.type == "vsplitter";
+
+ GtkWidget *box = vert ? gtk_vbox_new (FALSE, 6) : gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (box);
+
+ w->position = gtk_paned_get_position (GTK_PANED (w->base.widget));
+
+ GtkAllocation a;
+ gtk_widget_get_allocation (w->base.widget, &a);
+
+ GtkWidget *c1 = gtk_paned_get_child1 (GTK_PANED (w->base.widget));
+ g_object_ref (c1);
+ GtkWidget *c2 = gtk_paned_get_child2 (GTK_PANED (w->base.widget));
+ g_object_ref (c2);
+ gtk_container_remove (GTK_CONTAINER (w->base.widget), c1);
+ gtk_container_remove (GTK_CONTAINER (w->base.widget), c2);
+
+ gtk_box_pack_start (GTK_BOX (box), c1, FALSE, FALSE, 0);
+ gtk_widget_set_size_request (c1, vert ? -1 : w->position, vert ? w->position : -1);
+ gtk_box_pack_end (GTK_BOX (box), c2, TRUE, TRUE, 0);
+
+ ddb_gtkui_widget_t *parent = w->base.parent;
+ if (w->base.parent) {
+ gtk_container_remove (GTK_CONTAINER (parent->widget), w->base.widget);
+ }
+ GtkWidget *eventbox = gtk_event_box_new ();
+ gtk_widget_show (eventbox);
+ gtk_container_add (GTK_CONTAINER (eventbox), box);
+ w->base.widget = eventbox;
+ w->box = box;
+ if (w->base.parent) {
+ gtk_container_add (GTK_CONTAINER (parent->widget), w->base.widget);
+ }
+ w_splitter_init_signals (w);
+}
+
+void
+w_splitter_unlock (w_splitter_t *w) {
+ if (!w->locked) {
+ return;
+ }
+ w->locked = 0;
+
+ int vert = w->base.type == "vsplitter";
+ // convert back to vpaned
+ GtkWidget *paned = vert ? gtk_vpaned_new () : gtk_hpaned_new ();
+ gtk_widget_show (paned);
+
+ GList *lst = gtk_container_get_children (GTK_CONTAINER (w->box));
+
+ GtkWidget *c1 = lst->data;
+ g_object_ref (c1);
+ GtkWidget *c2 = lst->next->data;
+ g_object_ref (c2);
+ gtk_container_remove (GTK_CONTAINER (w->box), c1);
+ gtk_container_remove (GTK_CONTAINER (w->box), c2);
+
+ gtk_container_add (GTK_CONTAINER (paned), c1);
+ gtk_container_add (GTK_CONTAINER (paned), c2);
+ gtk_paned_set_position (GTK_PANED (paned), w->position);
+
+ ddb_gtkui_widget_t *parent = w->base.parent;
+ if (w->base.parent) {
+ gtk_container_remove (GTK_CONTAINER (parent->widget), w->base.widget);
+ }
+ w->base.widget = paned;
+ w->box = NULL;
+ if (w->base.parent) {
+ gtk_container_add (GTK_CONTAINER (parent->widget), w->base.widget);
+ }
+ w_splitter_init_signals (w);
+}
+
+void
+on_splitter_lock_movement_toggled (GtkCheckMenuItem *checkmenuitem, gpointer user_data) {
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (checkmenuitem))) {
+ w_splitter_lock (user_data);
+ }
+ else {
+ w_splitter_unlock (user_data);
+ }
+}
+
+void
+w_splitter_initmenu (struct ddb_gtkui_widget_s *w, GtkWidget *menu) {
+ GtkWidget *item;
+ item = gtk_check_menu_item_new_with_mnemonic (_("Lock movement"));
+ gtk_widget_show (item);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), ((w_splitter_t *)w)->locked);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "toggled",
+ G_CALLBACK (on_splitter_lock_movement_toggled),
+ w);
+}
+
+void
+w_splitter_replace (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child, ddb_gtkui_widget_t *newchild) {
+ int ntab = 0;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; c = c->next, ntab++) {
+ if (c == child) {
+ newchild->next = c->next;
+ if (prev) {
+ prev->next = newchild;
+ }
+ else {
+ cont->children = newchild;
+ }
+ newchild->parent = cont;
+ GtkWidget *container = ((w_splitter_t *)cont)->locked ? ((w_splitter_t *)cont)->box : cont->widget;
+ gtk_container_remove (GTK_CONTAINER(container), c->widget);
+ c->widget = NULL;
+ w_destroy (c);
+ gtk_widget_show (newchild->widget);
+ if (((w_splitter_t *)cont)->locked) {
+ if (ntab == 0) {
+ gtk_box_pack_start (GTK_BOX (container), newchild->widget, TRUE, TRUE, 0);
+ }
+ else {
+ gtk_box_pack_end (GTK_BOX (container), newchild->widget, TRUE, TRUE, 0);
+ }
+ }
+ else {
+ if (ntab == 0) {
+ gtk_paned_add1 (GTK_PANED (container), newchild->widget);
+ }
+ else {
+ gtk_paned_add2 (GTK_PANED (container), newchild->widget);
+ }
+ }
+ break;
+ }
+ prev = c;
+ }
+}
+
+void
+w_splitter_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *container = NULL;
+ w_splitter_t *w = (w_splitter_t *)cont;
+ if (w->locked) {
+ container = w->box;
+ }
+ else {
+ container = cont->widget;
+ }
+ gtk_container_remove (GTK_CONTAINER (container), child->widget);
+}
+
+////// vsplitter widget
+void
+w_vsplitter_init (ddb_gtkui_widget_t *base) {
+ w_splitter_t *w = (w_splitter_t *)base;
+ int pos = ((w_splitter_t *)w)->position; // prevent lock/unlock from overwriting position
+ if (w->locked && !w->box) {
+ w->locked = 0;
+ w_splitter_lock (w);
+ }
+ else if (!w->locked && w->box) {
+ w->locked = 1;
+ w_splitter_unlock (w);
+ }
+ if (pos == -1) {
+ GtkAllocation a;
+ gtk_widget_get_allocation (w->base.widget, &a);
+ pos = a.height/2;
+ }
+ w->position = pos;
+ if (!w->box) {
+ gtk_widget_set_size_request (w->base.children->widget, -1, -1);
+ gtk_paned_set_position (GTK_PANED(w->base.widget), pos);
+ }
+ else {
+ gtk_widget_set_size_request (w->base.children->widget, -1, w->position);
+ }
+}
+
+ddb_gtkui_widget_t *
+w_vsplitter_create (void) {
+ w_splitter_t *w = malloc (sizeof (w_splitter_t));
+ memset (w, 0, sizeof (w_splitter_t));
+ w->position = -1;
+ w->base.widget = gtk_vpaned_new ();
+ w->base.append = w_splitter_add;
+ w->base.remove = w_splitter_remove;
+ w->base.replace = w_splitter_replace;
+ w->base.load = w_splitter_load;
+ w->base.save = w_splitter_save;
+ w->base.init = w_vsplitter_init;
+ w->base.initmenu = w_splitter_initmenu;
+
+ ddb_gtkui_widget_t *ph1, *ph2;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+
+ w_splitter_init_signals (w);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+////// hsplitter widget
+void
+w_hsplitter_init (ddb_gtkui_widget_t *base) {
+ w_splitter_t *w = (w_splitter_t *)base;
+ int pos = ((w_splitter_t *)w)->position; // prevent lock/unlock from overwriting position
+ if (w->locked && !w->box) {
+ w->locked = 0;
+ w_splitter_lock (w);
+ }
+ else if (!w->locked && w->box) {
+ w->locked = 1;
+ w_splitter_unlock (w);
+ }
+ if (pos == -1) {
+ GtkAllocation a;
+ gtk_widget_get_allocation (w->base.widget, &a);
+ pos = a.width/2;
+ }
+ w->position = pos;
+ if (!w->box) {
+ gtk_widget_set_size_request (w->base.children->widget, -1, -1);
+ gtk_paned_set_position (GTK_PANED(w->base.widget), pos);
+ }
+ else {
+ gtk_widget_set_size_request (w->base.children->widget, w->position, -1);
+ }
+}
+
+ddb_gtkui_widget_t *
+w_hsplitter_create (void) {
+ w_splitter_t *w = malloc (sizeof (w_splitter_t));
+ memset (w, 0, sizeof (w_splitter_t));
+ w->position = -1;
+ w->base.widget = gtk_hpaned_new ();
+ w->base.append = w_splitter_add;
+ w->base.remove = w_splitter_remove;
+ w->base.replace = w_splitter_replace;
+ w->base.load = w_splitter_load;
+ w->base.save = w_splitter_save;
+ w->base.init = w_hsplitter_init;
+ w->base.initmenu = w_splitter_initmenu;
+
+ ddb_gtkui_widget_t *ph1, *ph2;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+
+ w_splitter_init_signals (w);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+///// tabs widget
+static gboolean
+tab_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
+
+static void
+on_remove_tab_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page) {
+ w_remove ((ddb_gtkui_widget_t *)w, c);
+ return;
+ }
+ }
+}
+
+static void
+on_add_tab_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ ddb_gtkui_widget_t *ph;
+ ph = w_create ("placeholder");
+ w_append ((ddb_gtkui_widget_t*)w, ph);
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++);
+ w->clicked_page = i-1;
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page);
+
+}
+
+static void
+on_move_tab_left_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+ if (w->clicked_page <= 0) {
+ return;
+ }
+
+ // remove and save widget
+ int i = 0;
+ ddb_gtkui_widget_t *newchild = NULL;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page) {
+ char buf[4000] = "";
+ save_widget_to_string (buf, sizeof (buf), c);
+ w_create_from_string (buf, &newchild);
+
+ w_remove ((ddb_gtkui_widget_t *)w, c);
+ break;
+ }
+ }
+ if (!newchild) {
+ return;
+ }
+
+ // add new child at new position
+ i = 0;
+ prev = NULL;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++) {
+ if (i == w->clicked_page-1) {
+ if (prev) {
+ newchild->next = prev->next;
+ prev->next = newchild;
+ }
+ else {
+ newchild->next = w->base.children;
+ w->base.children = newchild;
+ }
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (newchild->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", w);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), newchild->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (newchild->widget);
+
+ gtk_notebook_insert_page (GTK_NOTEBOOK (w->base.widget), newchild->widget, eventbox, w->clicked_page-1);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page-1);
+ w->clicked_page--;
+ break;
+ }
+ prev = c;
+ }
+}
+
+static void
+on_move_tab_right_activate (GtkMenuItem *menuitem, gpointer user_data) {
+ w_tabs_t *w = user_data;
+
+ int i = 0;
+ for (ddb_gtkui_widget_t *c = w->base.children; c; c = c->next, i++);
+ if (w->clicked_page >= i)
+ return;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (w->base.widget), ++w->clicked_page);
+ on_move_tab_left_activate (menuitem, user_data);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (w->base.widget), ++w->clicked_page);
+}
+
+static gboolean
+tab_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
+ if (event->button != 3) {
+ return FALSE;
+ }
+ // user_data is child widget
+ if (design_mode) {
+ w_tabs_t *w = (w_tabs_t *)g_object_get_data (G_OBJECT (widget), "owner");
+ GtkWidget *menu;
+ GtkWidget *item;
+ menu = gtk_menu_new ();
+
+ item = gtk_menu_item_new_with_mnemonic (_("Move tab left"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_move_tab_left_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Move tab right"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_move_tab_right_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Remove tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_remove_tab_activate),
+ w);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Rename tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+
+ w->clicked_page = gtk_notebook_page_num (GTK_NOTEBOOK (w->base.widget), user_data);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (w->base.widget), w->clicked_page);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, widget, 0, gtk_get_current_event_time());
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+w_tabs_add (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child) {
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (child->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", cont);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), child->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (child->widget);
+ gtk_notebook_append_page (GTK_NOTEBOOK (cont->widget), child->widget, eventbox);
+}
+
+void
+w_tabs_replace (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child, ddb_gtkui_widget_t *newchild) {
+ int ntab = 0;
+ ddb_gtkui_widget_t *prev = NULL;
+ for (ddb_gtkui_widget_t *c = cont->children; c; prev = c, c = c->next, ntab++) {
+ if (c == child) {
+ newchild->next = c->next;
+ if (prev) {
+ prev->next = newchild;
+ }
+ else {
+ cont->children = newchild;
+ }
+ newchild->parent = cont;
+ gtk_notebook_remove_page (GTK_NOTEBOOK(cont->widget), ntab);
+ c->widget = NULL;
+ w_destroy (c);
+ GtkWidget *eventbox = gtk_event_box_new ();
+ GtkWidget *label = gtk_label_new (newchild->type);
+ gtk_widget_show (eventbox);
+ g_object_set_data (G_OBJECT (eventbox), "owner", cont);
+ g_signal_connect ((gpointer) eventbox, "button_press_event", G_CALLBACK (tab_button_press_event), newchild->widget);
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (eventbox), label);
+ gtk_widget_show (newchild->widget);
+ int pos = gtk_notebook_insert_page (GTK_NOTEBOOK (cont->widget), newchild->widget, eventbox, ntab);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (cont->widget), pos);
+ break;
+ }
+ }
+}
+
+void
+w_tabs_initmenu (struct ddb_gtkui_widget_s *w, GtkWidget *menu) {
+ GtkWidget *item;
+ item = gtk_menu_item_new_with_mnemonic (_("Add new tab"));
+ gtk_widget_show (item);
+ gtk_container_add (GTK_CONTAINER (menu), item);
+ g_signal_connect ((gpointer) item, "activate",
+ G_CALLBACK (on_add_tab_activate),
+ w);
+}
+
+ddb_gtkui_widget_t *
+w_tabs_create (void) {
+ w_tabs_t *w = malloc (sizeof (w_tabs_t));
+ memset (w, 0, sizeof (w_tabs_t));
+ w->base.widget = gtk_notebook_new ();
+ w->base.append = w_tabs_add;
+ w->base.remove = w_container_remove;
+ w->base.replace = w_tabs_replace;
+ w->base.initmenu = w_tabs_initmenu;
+
+ ddb_gtkui_widget_t *ph1, *ph2, *ph3;
+ ph1 = w_create ("placeholder");
+ ph2 = w_create ("placeholder");
+ ph3 = w_create ("placeholder");
+
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect ((gpointer) w->base.widget, "expose_event", G_CALLBACK (w_expose_event), w);
+#else
+ g_signal_connect ((gpointer) w->base.widget, "draw", G_CALLBACK (w_draw_event), w);
+#endif
+ g_signal_connect ((gpointer) w->base.widget, "button_press_event", G_CALLBACK (w_button_press_event), w);
+
+ w_append ((ddb_gtkui_widget_t*)w, ph1);
+ w_append ((ddb_gtkui_widget_t*)w, ph2);
+ w_append ((ddb_gtkui_widget_t*)w, ph3);
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// box widget
+//// this widget should not be exposed to user, it is used as a top level
+//// container (rootwidget)
+
+ddb_gtkui_widget_t *
+w_box_create (void) {
+ w_box_t *w = malloc (sizeof (w_box_t));
+ memset (w, 0, sizeof (w_box_t));
+ w->base.widget = gtk_vbox_new (FALSE, 0);
+ w->base.append = w_container_add;
+ w->base.remove = w_container_remove;
+
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// tabstrip widget
+
+ddb_gtkui_widget_t *
+w_tabstrip_create (void) {
+ w_tabstrip_t *w = malloc (sizeof (w_tabstrip_t));
+ memset (w, 0, sizeof (w_tabstrip_t));
+ w->base.widget = gtk_event_box_new ();
+ GtkWidget *ts = ddb_tabstrip_new ();
+ gtk_widget_show (ts);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), ts);
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t*)w;
+}
+
+//// tabbed playlist widget
+
+typedef struct {
+ ddb_gtkui_widget_t *w;
+ DB_playItem_t *trk;
+} w_trackdata_t;
+
+static gboolean
+tabbed_trackinfochanged_cb (gpointer p) {
+ w_trackdata_t *d = p;
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)d->w;
+ ddb_playlist_t *plt = deadbeef->plt_get_curr ();
+ if (plt) {
+ int idx = deadbeef->plt_get_item_idx (plt, (DB_playItem_t *)d->trk, PL_MAIN);
+ if (idx != -1) {
+ ddb_listview_draw_row (tp->list, idx, (DdbListviewIter)d->trk);
+ }
+ deadbeef->plt_unref (plt);
+ }
+ if (d->trk) {
+ deadbeef->pl_item_unref (d->trk);
+ }
+ free (d);
+ return FALSE;
+}
+
+static gboolean
+trackinfochanged_cb (gpointer data) {
+ w_trackdata_t *d = data;
+ w_playlist_t *p = (w_playlist_t *)d->w;
+ ddb_playlist_t *plt = deadbeef->plt_get_curr ();
+ if (plt) {
+ int idx = deadbeef->plt_get_item_idx (plt, (DB_playItem_t *)d->trk, PL_MAIN);
+ if (idx != -1) {
+ ddb_listview_draw_row (DDB_LISTVIEW (p->list), idx, (DdbListviewIter)d->trk);
+ }
+ deadbeef->plt_unref (plt);
+ }
+ if (d->trk) {
+ deadbeef->pl_item_unref (d->trk);
+ }
+ free (d);
+ return FALSE;
+}
+
+static gboolean
+tabbed_paused_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ DB_playItem_t *curr = deadbeef->streamer_get_playing_track ();
+ if (curr) {
+ int idx = deadbeef->pl_get_idx_of (curr);
+ ddb_listview_draw_row (tp->list, idx, (DdbListviewIter)curr);
+ deadbeef->pl_item_unref (curr);
+ }
+ return FALSE;
+}
+
+static gboolean
+paused_cb (gpointer data) {
+ w_playlist_t *p = (w_playlist_t *)data;
+ DB_playItem_t *curr = deadbeef->streamer_get_playing_track ();
+ if (curr) {
+ int idx = deadbeef->pl_get_idx_of (curr);
+ ddb_listview_draw_row (p->list, idx, (DdbListviewIter)curr);
+ deadbeef->pl_item_unref (curr);
+ }
+ return FALSE;
+}
+
+static gboolean
+tabbed_refresh_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ ddb_listview_clear_sort (tp->list);
+ ddb_listview_refresh (tp->list, DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ return FALSE;
+}
+
+static gboolean
+refresh_cb (gpointer data) {
+ w_playlist_t *p = (w_playlist_t *)data;
+ ddb_listview_clear_sort (DDB_LISTVIEW (p->list));
+ ddb_listview_refresh (DDB_LISTVIEW (p->list), DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ return FALSE;
+}
+
+static gboolean
+tabbed_playlistswitch_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)p;
+ int curr = deadbeef->plt_get_curr_idx ();
+ char conf[100];
+ snprintf (conf, sizeof (conf), "playlist.scroll.%d", curr);
+ int scroll = deadbeef->conf_get_int (conf, 0);
+ snprintf (conf, sizeof (conf), "playlist.cursor.%d", curr);
+ int cursor = deadbeef->conf_get_int (conf, -1);
+ ddb_tabstrip_refresh (tp->tabstrip);
+ deadbeef->pl_set_cursor (PL_MAIN, cursor);
+ if (cursor != -1) {
+ DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (cursor, PL_MAIN);
+ if (it) {
+ deadbeef->pl_set_selected (it, 1);
+ deadbeef->pl_item_unref (it);
+ }
+ }
+
+ ddb_listview_refresh (tp->list, DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ ddb_listview_set_vscroll (tp->list, scroll);
+ return FALSE;
+}
+
+static gboolean
+playlistswitch_cb (gpointer data) {
+ w_playlist_t *p = (w_playlist_t *)data;
+ int curr = deadbeef->plt_get_curr_idx ();
+ char conf[100];
+ snprintf (conf, sizeof (conf), "playlist.scroll.%d", curr);
+ int scroll = deadbeef->conf_get_int (conf, 0);
+ snprintf (conf, sizeof (conf), "playlist.cursor.%d", curr);
+ int cursor = deadbeef->conf_get_int (conf, -1);
+ deadbeef->pl_set_cursor (PL_MAIN, cursor);
+ if (cursor != -1) {
+ DB_playItem_t *it = deadbeef->pl_get_for_idx_and_iter (cursor, PL_MAIN);
+ if (it) {
+ deadbeef->pl_set_selected (it, 1);
+ deadbeef->pl_item_unref (it);
+ }
+ }
+
+ ddb_listview_refresh (DDB_LISTVIEW (p->list), DDB_LIST_CHANGED | DDB_REFRESH_LIST | DDB_REFRESH_VSCROLL);
+ ddb_listview_set_vscroll (DDB_LISTVIEW (p->list), scroll);
+ return FALSE;
+}
+
+struct fromto_t {
+ ddb_gtkui_widget_t *w;
+ DB_playItem_t *from;
+ DB_playItem_t *to;
+};
+
+static gboolean
+tabbed_songchanged_cb (gpointer p) {
+ struct fromto_t *ft = p;
+ DB_playItem_t *from = ft->from;
+ DB_playItem_t *to = ft->to;
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)ft->w;
+ int to_idx = -1;
+ if (!ddb_listview_is_scrolling (tp->list) && to) {
+ int cursor_follows_playback = deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 0);
+ int scroll_follows_playback = deadbeef->conf_get_int ("playlist.scroll.followplayback", 0);
+ int plt = deadbeef->streamer_get_current_playlist ();
+ if (plt != -1) {
+ if (cursor_follows_playback && plt != deadbeef->plt_get_curr_idx ()) {
+ deadbeef->plt_set_curr_idx (plt);
+ }
+ to_idx = deadbeef->pl_get_idx_of (to);
+ if (to_idx != -1) {
+ if (cursor_follows_playback) {
+ ddb_listview_set_cursor_noscroll (tp->list, to_idx);
+ }
+ if (scroll_follows_playback && plt == deadbeef->plt_get_curr_idx ()) {
+ ddb_listview_scroll_to (tp->list, to_idx);
+ }
+ }
+ }
+ }
+
+ if (from) {
+ int idx = deadbeef->pl_get_idx_of (from);
+ if (idx != -1) {
+ ddb_listview_draw_row (tp->list, idx, from);
+ }
+ }
+ if (to && to_idx != -1) {
+ ddb_listview_draw_row (tp->list, to_idx, to);
+ }
+ if (ft->from) {
+ deadbeef->pl_item_unref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_unref (ft->to);
+ }
+ free (ft);
+ return FALSE;
+}
+
+static gboolean
+songchanged_cb (gpointer data) {
+ struct fromto_t *ft = data;
+ DB_playItem_t *from = ft->from;
+ DB_playItem_t *to = ft->to;
+ w_playlist_t *p = (w_playlist_t *)ft->w;
+ int to_idx = -1;
+ if (!ddb_listview_is_scrolling (DDB_LISTVIEW (p->list)) && to) {
+ int cursor_follows_playback = deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 0);
+ int scroll_follows_playback = deadbeef->conf_get_int ("playlist.scroll.followplayback", 0);
+ int plt = deadbeef->streamer_get_current_playlist ();
+ if (plt != -1) {
+ if (cursor_follows_playback && plt != deadbeef->plt_get_curr_idx ()) {
+ deadbeef->plt_set_curr_idx (plt);
+ }
+ to_idx = deadbeef->pl_get_idx_of (to);
+ if (to_idx != -1) {
+ if (cursor_follows_playback) {
+ ddb_listview_set_cursor_noscroll (DDB_LISTVIEW (p->list), to_idx);
+ }
+ if (scroll_follows_playback && plt == deadbeef->plt_get_curr_idx ()) {
+ ddb_listview_scroll_to (DDB_LISTVIEW (p->list), to_idx);
+ }
+ }
+ }
+ }
+
+ if (from) {
+ int idx = deadbeef->pl_get_idx_of (from);
+ if (idx != -1) {
+ ddb_listview_draw_row (DDB_LISTVIEW (p->list), idx, from);
+ }
+ }
+ if (to && to_idx != -1) {
+ ddb_listview_draw_row (DDB_LISTVIEW (p->list), to_idx, to);
+ }
+ if (ft->from) {
+ deadbeef->pl_item_unref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_unref (ft->to);
+ }
+ free (ft);
+ return FALSE;
+}
+
+static gboolean
+tabbed_trackfocus_cb (gpointer p) {
+ w_tabbed_playlist_t *tp = p;
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (it) {
+ int idx = deadbeef->pl_get_idx_of (it);
+ if (idx != -1) {
+ ddb_listview_scroll_to (tp->list, idx);
+ ddb_listview_set_cursor (tp->list, idx);
+ }
+ deadbeef->pl_item_unref (it);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+trackfocus_cb (gpointer p) {
+ w_playlist_t *tp = p;
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (it) {
+ int idx = deadbeef->pl_get_idx_of (it);
+ if (idx != -1) {
+ ddb_listview_scroll_to (tp->list, idx);
+ ddb_listview_set_cursor (tp->list, idx);
+ }
+ deadbeef->pl_item_unref (it);
+ }
+
+ return FALSE;
+}
+
+static int
+w_tabbed_playlist_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)w;
+ switch (id) {
+ case DB_EV_SONGCHANGED:
+ g_idle_add (redraw_queued_tracks_cb, tp->list);
+ ddb_event_trackchange_t *ev = (ddb_event_trackchange_t *)ctx;
+ struct fromto_t *ft = malloc (sizeof (struct fromto_t));
+ ft->from = ev->from;
+ ft->to = ev->to;
+ if (ft->from) {
+ deadbeef->pl_item_ref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_ref (ft->to);
+ }
+ ft->w = w;
+ g_idle_add (tabbed_songchanged_cb, ft);
+ break;
+ case DB_EV_TRACKINFOCHANGED:
+ {
+ ddb_event_track_t *ev = (ddb_event_track_t *)ctx;
+ if (ev->track) {
+ deadbeef->pl_item_ref (ev->track);
+ }
+ w_trackdata_t *d = malloc (sizeof (w_trackdata_t));
+ memset (d, 0, sizeof (w_trackdata_t));
+ d->w = w;
+ d->trk = ev->track;
+ g_idle_add (tabbed_trackinfochanged_cb, d);
+ }
+ break;
+ case DB_EV_PAUSED:
+ g_idle_add (tabbed_paused_cb, w);
+ break;
+ case DB_EV_PLAYLISTCHANGED:
+ g_idle_add (tabbed_refresh_cb, w);
+ break;
+ case DB_EV_PLAYLISTSWITCHED:
+ g_idle_add (tabbed_playlistswitch_cb, w);
+ break;
+ case DB_EV_TRACKFOCUSCURRENT:
+ g_idle_add (tabbed_trackfocus_cb, w);
+ break;
+ }
+ return 0;
+}
+
+static int
+w_playlist_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_playlist_t *p = (w_playlist_t *)w;
+ switch (id) {
+ case DB_EV_SONGCHANGED:
+ g_idle_add (redraw_queued_tracks_cb, p->list);
+ ddb_event_trackchange_t *ev = (ddb_event_trackchange_t *)ctx;
+ struct fromto_t *ft = malloc (sizeof (struct fromto_t));
+ ft->from = ev->from;
+ ft->to = ev->to;
+ if (ft->from) {
+ deadbeef->pl_item_ref (ft->from);
+ }
+ if (ft->to) {
+ deadbeef->pl_item_ref (ft->to);
+ }
+ ft->w = w;
+ g_idle_add (songchanged_cb, ft);
+ break;
+ case DB_EV_TRACKINFOCHANGED:
+ {
+ ddb_event_track_t *ev = (ddb_event_track_t *)ctx;
+ if (ev->track) {
+ deadbeef->pl_item_ref (ev->track);
+ }
+ w_trackdata_t *d = malloc (sizeof (w_trackdata_t));
+ memset (d, 0, sizeof (w_trackdata_t));
+ d->w = w;
+ d->trk = ev->track;
+ g_idle_add (trackinfochanged_cb, d);
+ }
+ break;
+ case DB_EV_PAUSED:
+ g_idle_add (paused_cb, w);
+ break;
+ case DB_EV_PLAYLISTCHANGED:
+ g_idle_add (refresh_cb, w);
+ break;
+ case DB_EV_PLAYLISTSWITCHED:
+ g_idle_add (playlistswitch_cb, w);
+ break;
+ case DB_EV_TRACKFOCUSCURRENT:
+ g_idle_add (trackfocus_cb, w);
+ break;
+ }
+ return 0;
+}
+ddb_gtkui_widget_t *
+w_tabbed_playlist_create (void) {
+ w_tabbed_playlist_t *w = malloc (sizeof (w_tabbed_playlist_t));
+ memset (w, 0, sizeof (w_tabbed_playlist_t));
+
+ GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
+ w->base.widget = vbox;
+ gtk_widget_show (vbox);
+
+ GtkWidget *tabstrip = ddb_tabstrip_new ();
+ w->tabstrip = (DdbTabStrip *)tabstrip;
+ gtk_widget_show (tabstrip);
+ GtkWidget *list = ddb_listview_new ();
+ w->list = (DdbListview *)list;
+ gtk_widget_show (list);
+ GtkWidget *frame = gtk_frame_new (NULL);
+ gtk_widget_show (frame);
+
+ gtk_box_pack_start (GTK_BOX (vbox), tabstrip, FALSE, TRUE, 0);
+ gtk_widget_set_size_request (tabstrip, -1, 24);
+ gtk_widget_set_can_focus (tabstrip, FALSE);
+ gtk_widget_set_can_default (tabstrip, FALSE);
+
+ gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (frame), 1);
+
+ gtk_container_add (GTK_CONTAINER (frame), list);
+ main_playlist_init (list);
+ if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
+ ddb_listview_show_header (w->list, 1);
+ }
+ else {
+ ddb_listview_show_header (w->list, 0);
+ }
+
+// gtk_container_forall (GTK_CONTAINER (w->base.widget), w_override_signals, w);
+ w_override_signals (w->base.widget, w);
+
+ w->base.message = w_tabbed_playlist_message;
+ return (ddb_gtkui_widget_t*)w;
+}
+
+///// playlist widget
+
+ddb_gtkui_widget_t *
+w_playlist_create (void) {
+ w_playlist_t *w = malloc (sizeof (w_playlist_t));
+ memset (w, 0, sizeof (w_playlist_t));
+ w->base.widget = gtk_event_box_new ();
+ w->list = DDB_LISTVIEW (ddb_listview_new ());
+ gtk_widget_show (GTK_WIDGET (w->list));
+ main_playlist_init (GTK_WIDGET (w->list));
+ if (deadbeef->conf_get_int ("gtkui.headers.visible", 1)) {
+ ddb_listview_show_header (DDB_LISTVIEW (w->list), 1);
+ }
+ else {
+ ddb_listview_show_header (DDB_LISTVIEW (w->list), 0);
+ }
+
+ gtk_container_add (GTK_CONTAINER (w->base.widget), GTK_WIDGET (w->list));
+ w_override_signals (w->base.widget, w);
+ w->base.message = w_playlist_message;
+ return (ddb_gtkui_widget_t*)w;
+}
+
+////// selection properties widget
+
+gboolean
+fill_selproperties_cb (gpointer data) {
+ w_selproperties_t *w = data;
+ DB_playItem_t **tracks = NULL;
+ int numtracks = 0;
+ deadbeef->pl_lock ();
+ int nsel = deadbeef->pl_getselcount ();
+ if (0 < nsel) {
+ tracks = malloc (sizeof (DB_playItem_t *) * nsel);
+ if (tracks) {
+ int n = 0;
+ DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
+ while (it) {
+ if (deadbeef->pl_is_selected (it)) {
+ assert (n < nsel);
+ deadbeef->pl_item_ref (it);
+ tracks[n++] = it;
+ }
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ numtracks = nsel;
+ }
+ else {
+ deadbeef->pl_unlock ();
+ return FALSE;
+ }
+ }
+ GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (w->tree)));
+ trkproperties_fill_meta (store, tracks, numtracks);
+ if (tracks) {
+ for (int i = 0; i < numtracks; i++) {
+ deadbeef->pl_item_unref (tracks[i]);
+ }
+ free (tracks);
+ tracks = NULL;
+ numtracks = 0;
+ }
+ deadbeef->pl_unlock ();
+ return FALSE;
+}
+
+static int
+selproperties_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_tabbed_playlist_t *tp = (w_tabbed_playlist_t *)w;
+ switch (id) {
+ case DB_EV_PLAYLISTCHANGED:
+ case DB_EV_SELCHANGED:
+ {
+ g_idle_add (fill_selproperties_cb, w);
+ }
+ break;
+ }
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_selproperties_create (void) {
+ w_selproperties_t *w = malloc (sizeof (w_selproperties_t));
+ memset (w, 0, sizeof (w_selproperties_t));
+
+ w->base.widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w->base.widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ w->tree = gtk_tree_view_new ();
+ gtk_widget_show (w->tree);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->tree);
+ w->base.message = selproperties_message;
+
+ GtkListStore *store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (w->tree), GTK_TREE_MODEL (store));
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (w->tree), TRUE);
+
+ GtkCellRenderer *rend1 = gtk_cell_renderer_text_new ();
+ GtkCellRenderer *rend2 = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *col1 = gtk_tree_view_column_new_with_attributes (_("Key"), rend1, "text", 0, NULL);
+ gtk_tree_view_column_set_resizable (col1, TRUE);
+ GtkTreeViewColumn *col2 = gtk_tree_view_column_new_with_attributes (_("Value"), rend2, "text", 1, NULL);
+ gtk_tree_view_column_set_resizable (col2, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w->tree), col1);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (w->tree), col2);
+ GtkCellRenderer *rend_propkey = gtk_cell_renderer_text_new ();
+ GtkCellRenderer *rend_propvalue = gtk_cell_renderer_text_new ();
+ gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (w->tree), TRUE);
+ w_override_signals (w->base.widget, w);
+
+ return (ddb_gtkui_widget_t *)w;
+}
+
+///// cover art display
+void
+coverart_avail_callback (void *user_data) {
+ w_coverart_t *w = user_data;
+ gtk_widget_queue_draw (w->drawarea);
+}
+
+static gboolean
+coverart_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (!it) {
+ return FALSE;
+ }
+ GtkAllocation a;
+ gtk_widget_get_allocation (widget, &a);
+ int width = a.width;
+ int height = a.height;
+ const char *album = deadbeef->pl_find_meta (it, "album");
+ const char *artist = deadbeef->pl_find_meta (it, "artist");
+ if (!album || !*album) {
+ album = deadbeef->pl_find_meta (it, "title");
+ }
+ GdkPixbuf *pixbuf = get_cover_art_callb (deadbeef->pl_find_meta ((it), ":URI"), artist, album, min(width,height), coverart_avail_callback, user_data);
+ if (pixbuf) {
+ int pw = gdk_pixbuf_get_width (pixbuf);
+ int ph = gdk_pixbuf_get_height (pixbuf);
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+ cairo_rectangle (cr, 0, 0, pw, ph);
+ cairo_fill (cr);
+// gdk_draw_pixbuf (gtk_widget_get_window (widget), widget->style->white_gc, pixbuf, 0, 0, a.width/2-pw/2, a.height/2-ph/2, pw, ph, GDK_RGB_DITHER_NONE, 0, 0);
+ g_object_unref (pixbuf);
+ }
+ deadbeef->pl_item_unref (it);
+ return TRUE;
+}
+
+static gboolean
+coverart_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ gboolean res = coverart_draw (widget, cr, user_data);
+ cairo_destroy (cr);
+ return res;
+}
+
+static gboolean
+coverart_redraw_cb (void *user_data) {
+ w_coverart_t *w = user_data;
+ gtk_widget_queue_draw (w->drawarea);
+ return FALSE;
+}
+
+static int
+coverart_message (ddb_gtkui_widget_t *w, uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ w_coverart_t *ca = (w_coverart_t *)w;
+ switch (id) {
+ case DB_EV_TRACKINFOCHANGED:
+ {
+ ddb_event_track_t *ev = (ddb_event_track_t *)ctx;
+ DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
+ if (it == ev->track) {
+ g_idle_add (coverart_redraw_cb, w);
+ }
+ if (it) {
+ deadbeef->pl_item_unref (it);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+ddb_gtkui_widget_t *
+w_coverart_create (void) {
+ w_coverart_t *w = malloc (sizeof (w_coverart_t));
+ memset (w, 0, sizeof (w_coverart_t));
+
+ w->base.widget = gtk_event_box_new ();
+ w->base.message = coverart_message;
+ w->drawarea = gtk_drawing_area_new ();
+ gtk_widget_show (w->drawarea);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (coverart_expose_event), w);
+#else
+ g_signal_connect_after ((gpointer) w->drawarea, "draw", G_CALLBACK (coverart_draw), w);
+#endif
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t *)w;
+}
+
+///// scope vis
+void
+w_scope_destroy (ddb_gtkui_widget_t *w) {
+ w_scope_t *s = (w_scope_t *)w;
+ if (s->drawtimer) {
+ g_source_remove (s->drawtimer);
+ s->drawtimer = 0;
+ }
+ if (s->glcontext) {
+ gdk_gl_context_destroy (s->glcontext);
+ s->glcontext = NULL;
+ }
+}
+
+gboolean
+w_scope_draw_cb (void *data) {
+ w_scope_t *s = data;
+ gtk_widget_queue_draw (s->drawarea);
+ return TRUE;
+}
+
+gboolean
+scope_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) {
+ ddb_waveformat_t fmt;
+ float data[DDB_AUDIO_MEMORY_FRAMES];
+ deadbeef->audio_get_waveform_data (DDB_AUDIO_WAVEFORM, data);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ cairo_set_line_width (cr, 1);
+ GtkAllocation a;
+ gtk_widget_get_allocation (widget, &a);
+
+ float incr = (float)DDB_AUDIO_MEMORY_FRAMES / a.width;
+ float pos = 0;
+ for (int x = 0; x < a.width; x++, pos += incr) {
+ float s = data[(int)pos];
+ cairo_line_to (cr, x, s * a.height/2 / 0x7fff + a.height/2);
+ }
+ cairo_stroke (cr);
+
+ return FALSE;
+}
+
+gboolean
+scope_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ w_scope_t *w = user_data;
+ float data[DDB_AUDIO_MEMORY_FRAMES];
+ deadbeef->audio_get_waveform_data (DDB_AUDIO_WAVEFORM, data);
+ GtkAllocation a;
+ gtk_widget_get_allocation (widget, &a);
+
+ GdkGLDrawable *d = gtk_widget_get_gl_drawable (widget);
+ gdk_gl_drawable_gl_begin (d, w->glcontext);
+ // if (glXSwapIntervalSGI) {
+ // glXSwapIntervalSGI (1);
+ // }
+
+ glClear (GL_COLOR_BUFFER_BIT);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ gluOrtho2D(0,a.width,a.height,0);
+ glMatrixMode (GL_MODELVIEW);
+ glViewport (0, 0, a.width, a.height);
+
+#if 0
+ // vsync test
+ static int box = 0;
+ static int speed = 5;
+ if (box > a.width-50) {
+ box = a.width-50;
+ speed = -5;
+ }
+ else if (box < 0) {
+ box = 0;
+ speed = 5;
+ }
+ box += speed;
+
+ glBegin (GL_QUADS);
+ glVertex2f (box, 0);
+ glVertex2f (box+50, 0);
+ glVertex2f (box+50, 50);
+ glVertex2f (box, 50);
+ glEnd ();
+#endif
+ glBegin (GL_LINE_STRIP);
+
+ short *samples = (short *)data;
+
+ float incr = a.width / (float)DDB_AUDIO_MEMORY_FRAMES;
+ int pos = 0;
+ for (float x = 0; x < a.width && pos < DDB_AUDIO_MEMORY_FRAMES; x += incr, pos ++) {
+ float s = data[(int)pos];
+ glVertex2f (x, s * a.height/2 + a.height/2);
+ }
+
+ glEnd();
+ gdk_gl_drawable_swap_buffers (d);
+
+ gdk_gl_drawable_gl_end (d);
+
+ return FALSE;
+
+ cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (widget));
+ gboolean res = scope_draw (widget, cr, user_data);
+ cairo_destroy (cr);
+ return res;
+}
+
+void
+w_scope_init (ddb_gtkui_widget_t *w) {
+ w_scope_t *s = (w_scope_t *)w;
+ if (s->drawtimer) {
+ g_source_remove (s->drawtimer);
+ s->drawtimer = 0;
+ }
+ if (!gtkui_gl_init ()) {
+ s->drawtimer = g_timeout_add (33, w_scope_draw_cb, w);
+ }
+}
+
+void
+scope_realize (GtkWidget *widget, gpointer data) {
+ w_scope_t *w = data;
+ w->glcontext = gtk_widget_create_gl_context (w->drawarea, NULL, TRUE, GDK_GL_RGBA_TYPE);
+}
+
+ddb_gtkui_widget_t *
+w_scope_create (void) {
+ w_scope_t *w = malloc (sizeof (w_scope_t));
+ memset (w, 0, sizeof (w_scope_t));
+
+ w->base.widget = gtk_event_box_new ();
+ w->base.init = w_scope_init;
+ w->base.destroy = w_scope_destroy;
+ w->drawarea = gtk_drawing_area_new ();
+ int attrlist[] = {GDK_GL_ATTRIB_LIST_NONE};
+ GdkGLConfig *conf = gdk_gl_config_new_by_mode ((GdkGLConfigMode)(GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DOUBLE));
+ gboolean cap = gtk_widget_set_gl_capability (w->drawarea, conf, NULL, TRUE, GDK_GL_RGBA_TYPE);
+ gtk_widget_show (w->drawarea);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (scope_expose_event), w);
+#else
+ g_signal_connect_after ((gpointer) w->drawarea, "draw", G_CALLBACK (scope_draw), w);
+#endif
+ g_signal_connect_after (G_OBJECT (w->drawarea), "realize", G_CALLBACK (scope_realize), w);
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t *)w;
+}
+
+///// spectrum vis
+void
+w_spectrum_destroy (ddb_gtkui_widget_t *w) {
+ w_spectrum_t *s = (w_spectrum_t *)w;
+ if (s->drawtimer) {
+ g_source_remove (s->drawtimer);
+ s->drawtimer = 0;
+ }
+ if (s->glcontext) {
+ gdk_gl_context_destroy (s->glcontext);
+ s->glcontext = NULL;
+ }
+}
+
+gboolean
+w_spectrum_draw_cb (void *data) {
+ w_spectrum_t *s = data;
+ gtk_widget_queue_draw (s->drawarea);
+ return TRUE;
+}
+
+// spectrum analyzer based on cairo-spectrum from audacious
+// Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
+#define MAX_BANDS 256
+#define VIS_DELAY 1
+#define VIS_DELAY_PEAK 10
+#define VIS_FALLOFF 3
+#define VIS_FALLOFF_PEAK 1
+#define BAND_WIDTH 5
+static float xscale[MAX_BANDS + 1];
+static int bars[MAX_BANDS + 1];
+static int delay[MAX_BANDS + 1];
+static int peaks[MAX_BANDS + 1];
+static int delay_peak[MAX_BANDS + 1];
+
+static void calculate_bands(int bands)
+{
+ int i;
+
+ for (i = 0; i < bands; i++)
+ xscale[i] = powf(257., ((float) i / (float) bands)) - 1;
+}
+
+
+gboolean
+spectrum_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) {
+ w_spectrum_t *w = user_data;
+ float data[DDB_AUDIO_MEMORY_FRAMES];
+ float *freq = data;
+ deadbeef->audio_get_waveform_data (DDB_AUDIO_FREQ, data);
+
+ GtkAllocation a;
+ gtk_widget_get_allocation (widget, &a);
+
+ int width, height, bands;
+ bands = a.width/BAND_WIDTH;
+ bands = CLAMP(bands, 4, MAX_BANDS);
+ width = a.width;
+ height = a.height;
+ calculate_bands(bands);
+
+ for (int i = 0; i < bands; i ++)
+ {
+ int a = ceil (xscale[i]);
+ int b = floor (xscale[i + 1]);
+ float n = 0;
+
+ if (b < a)
+ n += freq[b] * (xscale[i + 1] - xscale[i]);
+ else
+ {
+ if (a > 0)
+ n += freq[a - 1] * (a - xscale[i]);
+ for (; a < b; a ++)
+ n += freq[a];
+ if (b < 256)
+ n += freq[b] * (xscale[i + 1] - b);
+ }
+
+ /* 40 dB range */
+ int x = 20 * log10 (n * 100);
+ x = CLAMP (x, 0, 40);
+
+ bars[i] -= MAX (0, VIS_FALLOFF - delay[i]);
+ peaks[i] -= MAX (0, VIS_FALLOFF_PEAK - delay_peak[i]);;
+
+ if (delay[i])
+ delay[i]--;
+ if (delay_peak[i])
+ delay_peak[i]--;
+
+ if (x > bars[i])
+ {
+ bars[i] = x;
+ delay[i] = VIS_DELAY;
+ }
+ if (x > peaks[i]) {
+ peaks[i] = x;
+ delay_peak[i] = VIS_DELAY_PEAK;
+ }
+ }
+
+ GdkGLDrawable *d = gtk_widget_get_gl_drawable (widget);
+ gdk_gl_drawable_gl_begin (d, w->glcontext);
+
+ glClear (GL_COLOR_BUFFER_BIT);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ gluOrtho2D(0,a.width,a.height,0);
+ glMatrixMode (GL_MODELVIEW);
+ glViewport (0, 0, a.width, a.height);
+
+ glBegin (GL_QUADS);
+ float base_s = (height / 40.f);
+
+ for (gint i = 0; i <= bands; i++)
+ {
+ gint x = ((width / bands) * i) + 2;
+ int y = a.height - bars[i] * base_s;
+ glColor3f (0, 0.5, 1);
+ glVertex2f (x + 1, y);
+ glVertex2f (x + 1 + (width / bands) - 1, y);
+ glVertex2f (x + 1 + (width / bands) - 1, a.height);
+ glVertex2f (x + 1, a.height);
+
+ // peak
+ glColor3f (1, 1, 1);
+ y = a.height - peaks[i] * base_s;
+ glVertex2f (x + 1, y);
+ glVertex2f (x + 1 + (width / bands) - 1, y);
+ glVertex2f (x + 1 + (width / bands) - 1, y+1);
+ glVertex2f (x + 1, y+1);
+ }
+ glEnd();
+ gdk_gl_drawable_swap_buffers (d);
+
+ gdk_gl_drawable_gl_end (d);
+
+ return FALSE;
+}
+
+void
+w_spectrum_init (ddb_gtkui_widget_t *w) {
+ w_spectrum_t *s = (w_spectrum_t *)w;
+ gtkui_gl_init ();
+ if (s->drawtimer) {
+ g_source_remove (s->drawtimer);
+ s->drawtimer = 0;
+ }
+ if (!gtkui_gl_init ()) {
+ s->drawtimer = g_timeout_add (33, w_spectrum_draw_cb, w);
+ }
+}
+
+void
+spectrum_realize (GtkWidget *widget, gpointer data) {
+ w_spectrum_t *w = data;
+ w->glcontext = gtk_widget_create_gl_context (w->drawarea, NULL, TRUE, GDK_GL_RGBA_TYPE);
+}
+
+ddb_gtkui_widget_t *
+w_spectrum_create (void) {
+ w_spectrum_t *w = malloc (sizeof (w_spectrum_t));
+ memset (w, 0, sizeof (w_spectrum_t));
+
+ w->base.widget = gtk_event_box_new ();
+ w->base.init = w_spectrum_init;
+ w->base.destroy = w_spectrum_destroy;
+ w->drawarea = gtk_drawing_area_new ();
+ int attrlist[] = {GDK_GL_ATTRIB_LIST_NONE};
+ GdkGLConfig *conf = gdk_gl_config_new_by_mode ((GdkGLConfigMode)(GDK_GL_MODE_RGB |
+ GDK_GL_MODE_DOUBLE));
+ gboolean cap = gtk_widget_set_gl_capability (w->drawarea, conf, NULL, TRUE, GDK_GL_RGBA_TYPE);
+ gtk_widget_show (w->drawarea);
+ gtk_container_add (GTK_CONTAINER (w->base.widget), w->drawarea);
+#if !GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect_after ((gpointer) w->drawarea, "expose_event", G_CALLBACK (spectrum_expose_event), w);
+#else
+ g_signal_connect_after ((gpointer) w->drawarea, "draw", G_CALLBACK (spectrum_draw), w);
+#endif
+ g_signal_connect_after (G_OBJECT (w->drawarea), "realize", G_CALLBACK (spectrum_realize), w);
+ w_override_signals (w->base.widget, w);
+ return (ddb_gtkui_widget_t *)w;
+}
+
diff --git a/plugins/gtkui/widgets.h b/plugins/gtkui/widgets.h
new file mode 100644
index 00000000..56a3672d
--- /dev/null
+++ b/plugins/gtkui/widgets.h
@@ -0,0 +1,105 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __WIDGETS_H
+#define __WIDGETS_H
+
+#include "gtkui_api.h"
+
+void
+w_init (void);
+
+void
+w_free (void);
+
+void
+w_save (void);
+
+ddb_gtkui_widget_t *
+w_get_rootwidget (void);
+
+void
+w_set_design_mode (int active);
+
+void
+w_reg_widget (const char *type, const char *title, ddb_gtkui_widget_t *(*create_func) (void));
+
+void
+w_unreg_widget (const char *type);
+
+int
+w_is_registered (const char *type);
+
+ddb_gtkui_widget_t *
+w_create (const char *type);
+
+void
+w_set_name (ddb_gtkui_widget_t *w, const char *name);
+
+const char *
+w_create_from_string (const char *s, ddb_gtkui_widget_t **parent);
+
+void
+w_destroy (ddb_gtkui_widget_t *w);
+
+void
+w_append (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+
+void
+w_replace (ddb_gtkui_widget_t *w, ddb_gtkui_widget_t *from, ddb_gtkui_widget_t *to);
+
+void
+w_remove (ddb_gtkui_widget_t *cont, ddb_gtkui_widget_t *child);
+
+ddb_gtkui_widget_t *
+w_hsplitter_create (void);
+
+ddb_gtkui_widget_t *
+w_vsplitter_create (void);
+
+ddb_gtkui_widget_t *
+w_box_create (void);
+
+ddb_gtkui_widget_t *
+w_tabstrip_create (void);
+
+ddb_gtkui_widget_t *
+w_tabbed_playlist_create (void);
+
+ddb_gtkui_widget_t *
+w_playlist_create (void);
+
+ddb_gtkui_widget_t *
+w_placeholder_create (void);
+
+ddb_gtkui_widget_t *
+w_tabs_create (void);
+
+ddb_gtkui_widget_t *
+w_selproperties_create (void);
+
+ddb_gtkui_widget_t *
+w_coverart_create (void);
+
+ddb_gtkui_widget_t *
+w_scope_create (void);
+
+ddb_gtkui_widget_t *
+w_spectrum_create (void);
+
+#endif
diff --git a/plugins/medialib/Makefile.am b/plugins/medialib/Makefile.am
new file mode 100644
index 00000000..0406cac9
--- /dev/null
+++ b/plugins/medialib/Makefile.am
@@ -0,0 +1,8 @@
+if HAVE_MEDIALIB
+pkglib_LTLIBRARIES = medialib.la
+medialib_la_SOURCES = medialib.c
+medialib_la_LDFLAGS = -module
+
+medialib_la_LIBADD = $(LDADD)
+AM_CFLAGS = $(CFLAGS) -std=c99 -fPIC
+endif
diff --git a/plugins/medialib/medialib.c b/plugins/medialib/medialib.c
new file mode 100644
index 00000000..8a957156
--- /dev/null
+++ b/plugins/medialib/medialib.c
@@ -0,0 +1,256 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ This program 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#include <sys/time.h>
+#include <string.h>
+#include "../../deadbeef.h"
+
+DB_functions_t *deadbeef;
+
+typedef struct ml_string_s {
+ const char *text;
+ struct ml_string_s *next;
+} ml_string_t;
+
+typedef struct ml_entry_s {
+ const char *file;
+ const char *title;
+ int subtrack;
+ ml_string_t *artist;
+ ml_string_t *album;
+ ml_string_t *genre;
+ ml_string_t *folder;
+ struct ml_entry_s *next;
+} ml_entry_t;
+
+typedef struct {
+ ml_entry_t *tracks;
+
+ // index tables
+ ml_string_t *album;
+ ml_string_t *artist;
+ ml_string_t *genre;
+ ml_string_t *folder;
+} ml_db_t;
+
+#define REG_COL(col)\
+ml_string_t *\
+ml_reg_##col (ml_db_t *db, const char *col) {\
+ ml_string_t *s;\
+ int release = 0;\
+ if (!col) {\
+ col = deadbeef->metacache_add_string ("Unknown");\
+ release = 1;\
+ }\
+ for (s = db->col; s; s = s->next) {\
+ if (s->text == col) {\
+ if (release) {\
+ deadbeef->metacache_unref (col);\
+ }\
+ return s;\
+ }\
+ }\
+ if (!release) {\
+ deadbeef->metacache_ref (col);\
+ }\
+ s = malloc (sizeof (ml_string_t));\
+ memset (s, 0, sizeof (ml_string_t));\
+ s->text = col;\
+ s->next = db->col;\
+ db->col = s;\
+ return s;\
+}
+
+REG_COL(album);
+REG_COL(artist);
+REG_COL(genre);
+REG_COL(folder);
+
+DB_playItem_t *(*plt_insert_dir) (ddb_playlist_t *plt, DB_playItem_t *after, const char *dirname, int *pabort, int (*cb)(DB_playItem_t *it, void *data), void *user_data);
+
+uintptr_t tid;
+int scanner_terminate;
+
+static int
+add_file_info_cb (DB_playItem_t *it, void *data) {
+// fprintf (stderr, "added %s \r", deadbeef->pl_find_meta (it, ":URI"));
+ return 0;
+}
+
+static void
+scanner_thread (void *none) {
+ return;
+ // create invisible playlist
+ ddb_playlist_t *plt = deadbeef->plt_alloc ("scanner");
+
+ struct timeval tm1;
+ gettimeofday (&tm1, NULL);
+
+ plt_insert_dir (plt, NULL, "/backup/mus/en", &scanner_terminate, add_file_info_cb, NULL);
+
+ struct timeval tm2;
+ gettimeofday (&tm2, NULL);
+ int ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+ fprintf (stderr, "initial scan time: %f seconds (%d tracks)\n", ms / 1000.f, deadbeef->plt_get_item_count (plt, PL_MAIN));
+
+ fprintf (stderr, "building index...\n");
+ gettimeofday (&tm1, NULL);
+ ml_db_t db;
+ memset (&db, 0, sizeof (db));
+
+ ml_entry_t *tail = NULL;
+
+ DB_playItem_t *it = deadbeef->plt_get_first (plt, PL_MAIN);
+ while (it) {
+
+ ml_entry_t *en = malloc (sizeof (ml_entry_t));
+ memset (en, 0, sizeof (ml_entry_t));
+
+ const char *uri = deadbeef->pl_find_meta (it, ":URI");
+ const char *title = deadbeef->pl_find_meta (it, "title");
+ const char *artist = deadbeef->pl_find_meta (it, "artist");
+ const char *album = deadbeef->pl_find_meta (it, "album");
+ const char *genre = deadbeef->pl_find_meta (it, "genre");
+
+ ml_string_t *alb = ml_reg_album (&db, album);
+ ml_string_t *art = ml_reg_artist (&db, artist);
+ ml_string_t *gnr = ml_reg_genre (&db, genre);
+
+ char *fn = strrchr (uri, '/');
+ ml_string_t *fld = NULL;
+ if (fn) {
+ char folder[fn-uri+1];
+ memcpy (folder, uri, fn-uri);
+ folder[fn-uri] = 0;
+ const char *s = deadbeef->metacache_add_string (folder);
+ fld = ml_reg_folder (&db, s);
+ deadbeef->metacache_unref (s); // there should be at least 1 ref left, so it's safe
+ }
+
+ deadbeef->metacache_ref (uri);
+ en->file = uri;
+ deadbeef->metacache_ref (title);
+ if (deadbeef->pl_get_item_flags (it) & DDB_IS_SUBTRACK) {
+ en->subtrack = deadbeef->pl_find_meta_int (it, ":TRACKNUM", -1);
+ }
+ else {
+ en->subtrack = -1;
+ }
+ en->title = title;
+ en->artist = art;
+ en->album = alb;
+ en->genre = gnr;
+ en->folder = fld;
+
+ if (tail) {
+ tail->next = en;
+ tail = en;
+ }
+ else {
+ tail = db.tracks = en;
+ }
+
+ DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
+ deadbeef->pl_item_unref (it);
+ it = next;
+ }
+ ms = (tm2.tv_sec*1000+tm2.tv_usec/1000) - (tm1.tv_sec*1000+tm1.tv_usec/1000);
+
+ int nalb = 0;
+ int nart = 0;
+ int ngnr = 0;
+ int nfld = 0;
+ ml_string_t *s;
+ for (s = db.album; s; s = s->next, nalb++);
+ for (s = db.artist; s; s = s->next, nart++);
+ for (s = db.genre; s; s = s->next, ngnr++);
+ for (s = db.folder; s; s = s->next, nfld++);
+
+ fprintf (stderr, "index build time: %f seconds (%d albums, %d artists, %d genres, %d folders)\n", ms / 1000.f, nalb, nart, ngnr, nfld);
+
+ deadbeef->plt_free (plt);
+}
+
+static int
+ml_connect (void) {
+ tid = deadbeef->thread_start_low_priority (scanner_thread, NULL);
+ return 0;
+}
+
+static int
+ml_stop (void) {
+ if (tid) {
+ scanner_terminate = 1;
+ deadbeef->thread_join (tid);
+ tid = 0;
+ }
+
+ return 0;
+}
+
+static int
+ml_message (uint32_t id, uintptr_t ctx, uint32_t p1, uint32_t p2) {
+ return 0;
+}
+
+typedef struct {
+ DB_misc_t plugin;
+} ddb_medialib_plugin_t;
+
+// define plugin interface
+static ddb_medialib_plugin_t plugin = {
+ .plugin.plugin.api_vmajor = 1,
+ .plugin.plugin.api_vminor = 0,
+ .plugin.plugin.version_major = 0,
+ .plugin.plugin.version_minor = 1,
+ .plugin.plugin.type = DB_PLUGIN_MISC,
+ .plugin.plugin.id = "medialib",
+ .plugin.plugin.name = "Media Library",
+ .plugin.plugin.descr = "Scans disk for music files and manages them as database",
+ .plugin.plugin.copyright =
+ "Copyright (C) 2009-2011 Alexey Yakovenko <waker@users.sourceforge.net>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"
+ ,
+ .plugin.plugin.website = "http://deadbeef.sf.net",
+ .plugin.plugin.connect = ml_connect,
+ .plugin.plugin.stop = ml_stop,
+// .plugin.plugin.configdialog = settings_dlg,
+ .plugin.plugin.message = ml_message,
+};
+
+DB_plugin_t *
+medialib_load (DB_functions_t *api) {
+ deadbeef = api;
+
+ // hack: we need original function without overrides
+ plt_insert_dir = deadbeef->plt_insert_dir;
+ return DB_PLUGIN (&plugin);
+}
diff --git a/plugins/supereq/Makefile.am b/plugins/supereq/Makefile.am
index af5572c6..0096e4ab 100644
--- a/plugins/supereq/Makefile.am
+++ b/plugins/supereq/Makefile.am
@@ -3,47 +3,6 @@ supereqdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = supereq.la
supereq_la_SOURCES = supereq.c Equ.cpp Equ.h Fftsg_fl.c paramlist.hpp
-#nsfft-1.00/simd/SIMDBaseUndiff.c\
-#nsfft-1.00/simd/SIMDBase.c\
-#nsfft-1.00/dft/DFT.c\
-#nsfft-1.00/dft/DFTUndiff.c\
-#nsfft-1.00/simd/SIMDBase.h\
-#nsfft-1.00/simd/SIMDBaseUndiff.h\
-#nsfft-1.00/dft/DFTUndiff.h\
-#nsfft-1.00/dft/DFT.h\
-#shibatch_rdft.c
-
-#ffmpeg_fft/libavutil/mem.c\
-#ffmpeg_fft/libavutil/mathematics.c\
-#ffmpeg_fft/libavutil/rational.c\
-#ffmpeg_fft/libavutil/intfloat_readwrite.c\
-#ffmpeg_fft/libavcodec/dct.c\
-#ffmpeg_fft/libavcodec/avfft.c\
-#ffmpeg_fft/libavcodec/fft.c\
-#ffmpeg_fft/libavcodec/dct32.c\
-#ffmpeg_fft/libavcodec/rdft.c\
-#ffmpeg_fft/libavutil/intfloat_readwrite.h\
-#ffmpeg_fft/libavutil/avutil.h\
-#ffmpeg_fft/libavutil/common.h\
-#ffmpeg_fft/libavutil/attributes.h\
-#ffmpeg_fft/libavutil/mem.h\
-#ffmpeg_fft/libavutil/avconfig.h\
-#ffmpeg_fft/libavutil/mathematics.h\
-#ffmpeg_fft/libavutil/rational.h\
-#ffmpeg_fft/publik.h\
-#ffmpeg_fft/ffmpeg_fft.h\
-#ffmpeg_fft/libavcodec/dct32.h\
-#ffmpeg_fft/libavcodec/fft.h\
-#ffmpeg_fft/libavcodec/avfft.h\
-#ffmpeg_fft/config.h\
-#ff_rdft.c
-
-#AM_CFLAGS = $(CFLAGS) -I ffmpeg_fft -I ffmpeg_fft/libavcodec -I ffmpeg_fft/libavutil -std=c99
-#AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -I ffmpeg_fft -I ffmpeg_fft/libavcodec -I ffmpeg_fft/libavutil
-
-#AM_CFLAGS = $(CFLAGS) -I nsfft-1.00/dft -I nsfft-1.00/simd -std=c99 -msse -DENABLE_SSE_FLOAT -DUSE_SHIBATCH
-#AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -I nsfft-1.00/dft -I nsfft-1.00/simd -msse -DENABLE_SSE_FLOAT -DUSE_SHIBATCH
-
AM_CFLAGS = $(CFLAGS) -std=c99 -DUSE_OOURA
AM_CPPFLAGS = $(CXXFLAGS) -fno-exceptions -fno-rtti -nostdlib -fno-unwind-tables -DUSE_OOURA
diff --git a/scripts/quickinstall.sh b/scripts/quickinstall.sh
index ca09088b..41cc412e 100755
--- a/scripts/quickinstall.sh
+++ b/scripts/quickinstall.sh
@@ -45,5 +45,6 @@ cp ./plugins/converter/.libs/converter_gtk2.so /usr/local/lib/deadbeef/
cp ./plugins/converter/.libs/converter_gtk3.so /usr/local/lib/deadbeef/
cp ./plugins/soundtouch/ddb_soundtouch.so /usr/local/lib/deadbeef/
cp ./plugins/vfs_zip/.libs/vfs_zip.so /usr/local/lib/deadbeef/
+cp ./plugins/medialib/.libs/medialib.so /usr/local/lib/deadbeef/
cp ./plugins/mono2stereo/.libs/ddb_mono2stereo.so /usr/local/lib/deadbeef/
cp ./plugins/alac/.libs/alac.so /usr/local/lib/deadbeef/
diff --git a/streamer.c b/streamer.c
index f52ae450..9baac953 100644
--- a/streamer.c
+++ b/streamer.c
@@ -90,6 +90,7 @@ static char streambuffer[STREAM_BUFFER_SIZE];
static int bytes_until_next_song = 0;
static uintptr_t mutex;
static uintptr_t decodemutex;
+static uintptr_t audio_mem_mutex;
static int nextsong = -1;
static int nextsong_pstate = -1;
static int badsong = -1;
@@ -119,6 +120,10 @@ static int streamer_buffering;
// to allow interruption of stall file requests
static DB_FILE *streamer_file;
+// for vis plugins
+static float freq_data[DDB_AUDIO_MEMORY_FRAMES];
+static float audio_data[DDB_AUDIO_MEMORY_FRAMES];
+
#if DETECT_PL_LOCK_RC
volatile pthread_t streamer_lock_tid = 0;
#endif
@@ -1738,6 +1743,7 @@ streamer_init (void) {
#endif
mutex = mutex_create ();
decodemutex = mutex_create ();
+ audio_mem_mutex = mutex_create ();
ringbuf_init (&streamer_ringbuf, streambuffer, STREAM_BUFFER_SIZE);
@@ -1779,6 +1785,8 @@ streamer_free (void) {
decodemutex = 0;
mutex_free (mutex);
mutex = 0;
+ mutex_free (audio_mem_mutex);
+ audio_mem_mutex = 0;
streamer_dsp_chain_save();
@@ -1985,6 +1993,16 @@ streamer_read_async (char *bytes, int size) {
return bytesread;
}
+void rdft(int, int, float *, int *, float *);
+static void do_fft(int n,float *x)
+{
+ static int ipsize = 0,wsize=0;
+ static int ip[18];
+ static float w[256];
+
+ rdft(n,1,x,ip,w);
+}
+
int
streamer_read (char *bytes, int size) {
#if 0
@@ -2047,6 +2065,34 @@ streamer_read (char *bytes, int size) {
printf ("streamer_read took %d ms\n", ms);
#endif
+ mutex_lock (audio_mem_mutex);
+ int in_frame_size = (output->fmt.bps >> 3) * output->fmt.channels;
+ int in_frames = sz / in_frame_size;
+ ddb_waveformat_t out_fmt = {
+ .bps = 32,
+ .channels = 1,
+ .samplerate = output->fmt.samplerate,
+ .channelmask = DDB_SPEAKER_FRONT_LEFT,
+ .is_float = 1,
+ .is_bigendian = 0
+ };
+ if (in_frames < DDB_AUDIO_MEMORY_FRAMES) {
+ memmove (audio_data, audio_data + in_frames, (DDB_AUDIO_MEMORY_FRAMES-in_frames)*sizeof (float));
+ pcm_convert (&output->fmt, bytes, &out_fmt, (char *)(audio_data + DDB_AUDIO_MEMORY_FRAMES - in_frames), sz);
+ }
+ else {
+ pcm_convert (&output->fmt, bytes + sz - DDB_AUDIO_MEMORY_FRAMES * in_frame_size, &out_fmt, (char *)audio_data, DDB_AUDIO_MEMORY_FRAMES * in_frame_size);
+ }
+
+ memcpy (freq_data, audio_data, sizeof (audio_data));
+ int N = DDB_AUDIO_MEMORY_FRAMES;
+ do_fft(N, freq_data);
+ for (int n = 0; n < N / 2 - 1; n ++)
+ freq_data[n] = 2 * fabs (freq_data[1 + n]) / N;
+ freq_data[N / 2 - 1] = fabs(freq_data[N / 2]) / N;
+
+ mutex_unlock (audio_mem_mutex);
+
if (!output->has_volume) {
char *stream = bytes;
int bytesread = sz;
@@ -2299,3 +2345,13 @@ streamer_notify_order_changed (int prev_order, int new_order) {
streamer_unlock ();
}
}
+
+void
+audio_get_waveform_data (int type, float *data) {
+ if (!audio_mem_mutex) {
+ return;
+ }
+ mutex_lock (audio_mem_mutex);
+ memcpy (data, type == DDB_AUDIO_WAVEFORM ? audio_data : freq_data, sizeof (audio_data));
+ mutex_unlock (audio_mem_mutex);
+}
diff --git a/streamer.h b/streamer.h
index 6b77f382..d3818240 100644
--- a/streamer.h
+++ b/streamer.h
@@ -130,4 +130,7 @@ streamer_dsp_chain_save (void);
void
streamer_notify_order_changed (int prev_order, int new_order);
+void
+audio_get_waveform_data (int type, float *data);
+
#endif // __STREAMER_H
diff --git a/tools/pluginfo/pluginfo.c b/tools/pluginfo/pluginfo.c
index d1e4f4b9..d1a05d52 100644
--- a/tools/pluginfo/pluginfo.c
+++ b/tools/pluginfo/pluginfo.c
@@ -67,7 +67,18 @@ main (int argc, char *argv[]) {
printf ("version=\"%d.%d\"\n", plug->version_major, plug->version_minor);
printf ("id=\"%s\"\n", plug->id);
printf ("name=\"%s\"\n", plug->name);
- printf ("descr=\"%s\"\n", plug->descr);
+ printf ("descr=\"");
+ const char *c;
+ for (c = plug->descr; *c; c++) {
+ if (*c == '"') {
+ printf ("\\\"");
+ }
+ else {
+ printf ("%c", *c);
+ }
+ }
+
+ printf ("\"\n");
printf ("website=\"%s\"\n", plug->website);
dlclose (handle);