summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMateusz Łukasik <mati75@linuxmint.pl>2016-09-28 17:18:49 +0200
committerMateusz Łukasik <mati75@linuxmint.pl>2016-09-28 17:18:49 +0200
commitca923b7bbf94ef42095f76a43db89f5c779a7558 (patch)
treea77a26d5fc0e1b900e3117ab3be5df80b5d09672 /src
parent455e4bcbf950078d9e9215e7499a2e927f6ec9d5 (diff)
New upstream version 3.8
Diffstat (limited to 'src')
-rw-r--r--src/aac/Makefile (renamed from src/aac-raw/Makefile)4
-rw-r--r--src/aac/aac.cc (renamed from src/aac-raw/aac.cc)35
-rw-r--r--src/adplug/Makefile2
-rw-r--r--src/adplug/adplug-xmms.cc42
-rw-r--r--src/adplug/core/a2m.cc16
-rw-r--r--src/adplug/core/adl.cc4
-rw-r--r--src/adplug/core/adplug.cc6
-rw-r--r--src/adplug/core/adplug.h1
-rw-r--r--src/adplug/core/adtrack.cc2
-rw-r--r--src/adplug/core/bmf.cc2
-rw-r--r--src/adplug/core/debug.cc57
-rw-r--r--src/adplug/core/debug.h5
-rw-r--r--src/adplug/core/dfm.cc3
-rw-r--r--src/adplug/core/hsp.cc7
-rw-r--r--src/adplug/core/lds.cc2
-rw-r--r--src/adplug/core/mid.cc2
-rw-r--r--src/adplug/core/protrack.cc21
-rw-r--r--src/adplug/core/s3m.cc12
-rw-r--r--src/adplug/core/sa2.cc2
-rw-r--r--src/adplug/core/sng.cc2
-rw-r--r--src/alarm/alarm.cc15
-rw-r--r--src/alarm/interface.cc17
-rw-r--r--src/albumart-qt/albumart.cc6
-rw-r--r--src/albumart/albumart.cc6
-rw-r--r--src/alsa/alsa.cc49
-rw-r--r--src/alsa/alsa.h20
-rw-r--r--src/alsa/config.cc2
-rw-r--r--src/amidiplug/Makefile (renamed from src/amidi-plug/Makefile)0
-rw-r--r--src/amidiplug/amidi-plug.cc (renamed from src/amidi-plug/amidi-plug.cc)24
-rw-r--r--src/amidiplug/amidi-plug.midiicon.xpm (renamed from src/amidi-plug/amidi-plug.midiicon.xpm)0
-rw-r--r--src/amidiplug/backend-fluidsynth/b-fluidsynth.cc (renamed from src/amidi-plug/backend-fluidsynth/b-fluidsynth.cc)0
-rw-r--r--src/amidiplug/i_backend.h (renamed from src/amidi-plug/i_backend.h)0
-rw-r--r--src/amidiplug/i_configure-fluidsynth.cc (renamed from src/amidi-plug/i_configure-fluidsynth.cc)0
-rw-r--r--src/amidiplug/i_configure-fluidsynth.h (renamed from src/amidi-plug/i_configure-fluidsynth.h)0
-rw-r--r--src/amidiplug/i_configure.cc (renamed from src/amidi-plug/i_configure.cc)0
-rw-r--r--src/amidiplug/i_configure.h (renamed from src/amidi-plug/i_configure.h)0
-rw-r--r--src/amidiplug/i_fileinfo.cc (renamed from src/amidi-plug/i_fileinfo.cc)0
-rw-r--r--src/amidiplug/i_fileinfo.h (renamed from src/amidi-plug/i_fileinfo.h)0
-rw-r--r--src/amidiplug/i_midi.cc (renamed from src/amidi-plug/i_midi.cc)0
-rw-r--r--src/amidiplug/i_midi.h (renamed from src/amidi-plug/i_midi.h)0
-rw-r--r--src/amidiplug/i_midievent.h (renamed from src/amidi-plug/i_midievent.h)0
-rw-r--r--src/ampache/Makefile20
-rw-r--r--src/ampache/ampache.cc134
-rw-r--r--src/aosd/Makefile4
-rw-r--r--src/aosd/aosd.h4
-rw-r--r--src/aosd/aosd_osd.cc6
-rw-r--r--src/aosd/aosd_osd.h2
-rw-r--r--src/aosd/aosd_ui.cc28
-rw-r--r--src/aosd/ghosd.c6
-rw-r--r--src/aosd/ghosd.h2
-rw-r--r--src/audpl/audpl.cc64
-rw-r--r--src/blur_scope/blur_scope.cc4
-rw-r--r--src/cairo-spectrum/cairo-spectrum.cc11
-rw-r--r--src/cdaudio/Makefile (renamed from src/cdaudio-ng/Makefile)4
-rw-r--r--src/cdaudio/cdaudio-ng.cc (renamed from src/cdaudio-ng/cdaudio-ng.cc)158
-rw-r--r--src/console/Audacious_Driver.cc72
-rw-r--r--src/console/plugin.h8
-rw-r--r--src/coreaudio/coreaudio.cc5
-rw-r--r--src/cue/cue.cc45
-rw-r--r--src/delete-files/Makefile14
-rw-r--r--src/delete-files/delete-files.cc87
-rw-r--r--src/ffaudio/ffaudio-core.cc353
-rw-r--r--src/filewriter/Makefile4
-rw-r--r--src/filewriter/filewriter.cc212
-rw-r--r--src/filewriter/filewriter.h2
-rw-r--r--src/filewriter/mp3.cc805
-rw-r--r--src/filewriter/vorbis.cc43
-rw-r--r--src/flac/Makefile (renamed from src/flacng/Makefile)0
-rw-r--r--src/flac/flacng.h (renamed from src/flacng/flacng.h)9
-rw-r--r--src/flac/metadata.cc (renamed from src/flacng/metadata.cc)106
-rw-r--r--src/flac/plugin.cc (renamed from src/flacng/plugin.cc)0
-rw-r--r--src/flac/seekable_stream_callbacks.cc (renamed from src/flacng/seekable_stream_callbacks.cc)0
-rw-r--r--src/flac/tools.cc (renamed from src/flacng/tools.cc)0
-rw-r--r--src/gio/gio.cc82
-rw-r--r--src/glspectrum/Makefile (renamed from src/gl-spectrum/Makefile)0
-rw-r--r--src/glspectrum/gl-spectrum.cc (renamed from src/gl-spectrum/gl-spectrum.cc)5
-rw-r--r--src/gtkui/columns.cc18
-rw-r--r--src/gtkui/layout.cc14
-rw-r--r--src/gtkui/menus.cc112
-rw-r--r--src/gtkui/playlist_util.cc96
-rw-r--r--src/gtkui/playlist_util.h7
-rw-r--r--src/gtkui/ui_gtk.cc80
-rw-r--r--src/gtkui/ui_infoarea.cc2
-rw-r--r--src/gtkui/ui_playlist_widget.cc12
-rw-r--r--src/hotkey/plugin.cc4
-rw-r--r--src/jack/Makefile (renamed from src/jack-ng/Makefile)0
-rw-r--r--src/jack/jack-ng.cc (renamed from src/jack-ng/jack-ng.cc)18
-rw-r--r--src/lyricwiki-qt/lyricwiki.cc6
-rw-r--r--src/lyricwiki/lyricwiki.cc6
-rw-r--r--src/metronom/metronom.cc19
-rw-r--r--src/modplug/modplugbmp.cc22
-rw-r--r--src/modplug/modplugbmp.h8
-rw-r--r--src/mpg123/mpg123.cc54
-rw-r--r--src/neon/neon.cc37
-rw-r--r--src/notify/Makefile14
-rw-r--r--src/notify/event.cc69
-rw-r--r--src/notify/notify.cc6
-rw-r--r--src/oss4/oss.cc50
-rw-r--r--src/oss4/oss.h38
-rw-r--r--src/oss4/plugin.cc4
-rw-r--r--src/oss4/utils.cc4
-rw-r--r--src/playlist-manager-qt/playlist-manager-qt.cc6
-rw-r--r--src/playlist-manager/playlist-manager.cc6
-rw-r--r--src/psf/peops/reverb.cc3
-rw-r--r--src/psf/peops/spu.cc9
-rw-r--r--src/psf/peops2/reverb.cc6
-rw-r--r--src/psf/peops2/spu.cc10
-rw-r--r--src/psf/plugin.cc264
-rw-r--r--src/pulse/Makefile (renamed from src/pulse_audio/Makefile)0
-rw-r--r--src/pulse/pulse_audio.cc506
-rw-r--r--src/pulse_audio/pulse_audio.cc625
-rw-r--r--src/qtaudio/qtaudio.cc14
-rw-r--r--src/qtglspectrum/Makefile (renamed from src/gl-spectrum-qt/Makefile)0
-rw-r--r--src/qtglspectrum/gl-spectrum.cc (renamed from src/gl-spectrum-qt/gl-spectrum.cc)5
-rw-r--r--src/qtui/Makefile2
-rw-r--r--src/qtui/dialog_windows.cc5
-rw-r--r--src/qtui/dialog_windows.h4
-rw-r--r--src/qtui/info_bar.h1
-rw-r--r--src/qtui/main_window.cc37
-rw-r--r--src/qtui/main_window.h9
-rw-r--r--src/qtui/menus.cc (renamed from src/qtui/main_window_actions.cc)67
-rw-r--r--src/qtui/menus.h30
-rw-r--r--src/qtui/playlist.cc49
-rw-r--r--src/qtui/playlist.h19
-rw-r--r--src/qtui/playlist_model.cc2
-rw-r--r--src/qtui/playlist_model.h5
-rw-r--r--src/qtui/playlist_tabs.cc27
-rw-r--r--src/qtui/playlist_tabs.h7
-rw-r--r--src/qtui/qtui.cc12
-rw-r--r--src/qtui/status_bar.cc2
-rw-r--r--src/qtui/status_bar.h3
-rw-r--r--src/qtui/time_slider.cc4
-rw-r--r--src/qtui/time_slider.h6
-rw-r--r--src/scrobbler2/Makefile4
-rw-r--r--src/scrobbler2/config_window.cc193
-rw-r--r--src/scrobbler2/scrobbler.cc6
-rw-r--r--src/scrobbler2/scrobbler.h1
-rw-r--r--src/scrobbler2/scrobbler_communication.cc8
-rw-r--r--src/sdlout/sdlout.cc14
-rw-r--r--src/search-tool-qt/search-tool-qt.cc115
-rw-r--r--src/search-tool/search-tool.cc164
-rw-r--r--src/sid/xmms-sid.cc83
-rw-r--r--src/sid/xmms-sid.h4
-rw-r--r--src/sid/xs_sidplay2.cc57
-rw-r--r--src/sid/xs_sidplay2.h3
-rw-r--r--src/skins-qt/actions-playlist.h53
-rw-r--r--src/skins-qt/actions.cc192
-rw-r--r--src/skins-qt/main.cc13
-rw-r--r--src/skins-qt/menus.cc105
-rw-r--r--src/skins-qt/playlist-widget.cc4
-rw-r--r--src/skins-qt/playlist.cc2
-rw-r--r--src/skins-qt/plugin.cc7
-rw-r--r--src/skins-qt/skinselector.cc8
-rw-r--r--src/skins-qt/util.cc4
-rw-r--r--src/skins/actions-playlist.h51
-rw-r--r--src/skins/actions.cc181
-rw-r--r--src/skins/main.cc21
-rw-r--r--src/skins/menus.cc100
-rw-r--r--src/skins/playlist-widget.cc4
-rw-r--r--src/skins/playlist.cc2
-rw-r--r--src/skins/plugin-window.cc6
-rw-r--r--src/skins/plugin.cc10
-rw-r--r--src/skins/search-select.cc2
-rw-r--r--src/skins/skinselector.cc8
-rw-r--r--src/skins/util.cc13
-rw-r--r--src/sndfile/plugin.cc40
-rw-r--r--src/sndio/Makefile (renamed from src/sndio-ng/Makefile)2
-rw-r--r--src/sndio/sndio.cc (renamed from src/sndio-ng/sndio.cc)13
-rw-r--r--src/song-info-qt/song-info.cc8
-rw-r--r--src/songchange/Makefile (renamed from src/song_change/Makefile)0
-rw-r--r--src/songchange/formatter.cc (renamed from src/song_change/formatter.cc)0
-rw-r--r--src/songchange/formatter.h (renamed from src/song_change/formatter.h)0
-rw-r--r--src/songchange/song_change.cc (renamed from src/song_change/song_change.cc)0
-rw-r--r--src/soxr/Makefile (renamed from src/sox-resampler/Makefile)0
-rw-r--r--src/soxr/sox-resampler.cc (renamed from src/sox-resampler/sox-resampler.cc)19
-rw-r--r--src/speedpitch/Makefile (renamed from src/speed-pitch/Makefile)0
-rw-r--r--src/speedpitch/speed-pitch.cc (renamed from src/speed-pitch/speed-pitch.cc)25
-rw-r--r--src/statusicon-qt/statusicon.cc4
-rw-r--r--src/statusicon/statusicon.cc4
-rw-r--r--src/tonegen/tonegen.cc20
-rw-r--r--src/ui-common/menu-ops-gtk.cc133
-rw-r--r--src/ui-common/menu-ops-qt.cc107
-rw-r--r--src/ui-common/menu-ops.cc128
-rw-r--r--src/ui-common/menu-ops.h90
-rw-r--r--src/vorbis/vcedit.cc301
-rw-r--r--src/vorbis/vcedit.h59
-rw-r--r--src/vorbis/vcupdate.cc134
-rw-r--r--src/vorbis/vorbis.cc20
-rw-r--r--src/vorbis/vorbis.h8
-rw-r--r--src/vtx/vtx.cc42
-rw-r--r--src/waveout/Makefile13
-rw-r--r--src/waveout/waveout.cc339
-rw-r--r--src/wavpack/wavpack.cc28
-rw-r--r--src/xsf/desmume/NDSSystem.cc4
-rw-r--r--src/xsf/plugin.cc41
-rw-r--r--src/xspf/xspf.cc138
196 files changed, 3872 insertions, 4396 deletions
diff --git a/src/aac-raw/Makefile b/src/aac/Makefile
index c3c9ee2..64ed21a 100644
--- a/src/aac-raw/Makefile
+++ b/src/aac/Makefile
@@ -10,5 +10,5 @@ plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
-CPPFLAGS += ${PLUGIN_CPPFLAGS} ${FAAD_CFLAGS} -I../..
-LIBS += ${FAAD_LIBS} -lm -laudtag
+CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../..
+LIBS += -lfaad -lm -laudtag
diff --git a/src/aac-raw/aac.cc b/src/aac/aac.cc
index 1a6d251..b7727e9 100644
--- a/src/aac-raw/aac.cc
+++ b/src/aac/aac.cc
@@ -19,13 +19,11 @@ public:
PACKAGE
};
- static constexpr auto iinfo = InputInfo ()
- .with_exts (exts);
-
- constexpr AACDecoder () : InputPlugin (info, iinfo) {}
+ constexpr AACDecoder () : InputPlugin (info, InputInfo ()
+ .with_exts (exts)) {}
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
};
@@ -254,24 +252,24 @@ static void calc_aac_info (VFSFile & handle, int * length, int * bitrate,
NeAACDecClose (decoder);
}
-Tuple AACDecoder::read_tuple (const char * filename, VFSFile & handle)
+bool AACDecoder::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
- Tuple tuple;
int length, bitrate, samplerate, channels;
- tuple.set_filename (filename);
tuple.set_str (Tuple::Codec, "MPEG-2/4 AAC");
- calc_aac_info (handle, &length, &bitrate, &samplerate, &channels);
+ // TODO: error handling
+ calc_aac_info (file, &length, &bitrate, &samplerate, &channels);
if (length > 0)
tuple.set_int (Tuple::Length, length);
if (bitrate > 0)
tuple.set_int (Tuple::Bitrate, bitrate);
- tuple.fetch_stream_info (handle);
+ tuple.fetch_stream_info (file);
- return tuple;
+ return true;
}
static void aac_seek (VFSFile & file, NeAACDecHandle dec, int time, int len,
@@ -330,15 +328,9 @@ bool AACDecoder::play (const char * filename, VFSFile & file)
NeAACDecConfigurationPtr decoder_config;
unsigned long samplerate = 0;
unsigned char channels = 0;
- int bitrate = 0;
Tuple tuple = get_playback_tuple ();
-
- if (tuple)
- {
- bitrate = tuple.get_int (Tuple::Bitrate);
- bitrate = 1000 * aud::max (0, bitrate);
- }
+ int bitrate = 1000 * aud::max (0, tuple.get_int (Tuple::Bitrate));
if ((decoder = NeAACDecOpen ()) == nullptr)
{
@@ -400,7 +392,7 @@ bool AACDecoder::play (const char * filename, VFSFile & file)
/* == CHECK FOR METADATA == */
- if (tuple && tuple.fetch_stream_info (file))
+ if (tuple.fetch_stream_info (file))
set_playback_tuple (tuple.ref ());
set_stream_bitrate (bitrate);
@@ -419,8 +411,7 @@ bool AACDecoder::play (const char * filename, VFSFile & file)
if (seek_value >= 0)
{
- int length = tuple ? tuple.get_int (Tuple::Length) : 0;
-
+ int length = tuple.get_int (Tuple::Length);
if (length > 0)
aac_seek (file, decoder, seek_value, length, buf, sizeof buf, & buflen);
}
@@ -432,7 +423,7 @@ bool AACDecoder::play (const char * filename, VFSFile & file)
/* == CHECK FOR METADATA == */
- if (tuple && tuple.fetch_stream_info (file))
+ if (tuple.fetch_stream_info (file))
set_playback_tuple (tuple.ref ());
/* == DECODE A FRAME == */
diff --git a/src/adplug/Makefile b/src/adplug/Makefile
index 3239c1c..742c9e4 100644
--- a/src/adplug/Makefile
+++ b/src/adplug/Makefile
@@ -5,7 +5,6 @@ SRCS = adplug-xmms.cc \
binio/binio.cc \
binio/binstr.cc \
core/fmopl.cc \
- core/debug.cc \
core/adlibemu.cc \
core/adplug.cc \
core/emuopl.cc \
@@ -64,5 +63,6 @@ plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
+# FIXME: Turning off warnings for now; this code is awful
CXXFLAGS += ${PLUGIN_CFLAGS} -Wno-sign-compare
CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../.. -I./core -I./binio
diff --git a/src/adplug/adplug-xmms.cc b/src/adplug/adplug-xmms.cc
index 2cf0344..0a38719 100644
--- a/src/adplug/adplug-xmms.cc
+++ b/src/adplug/adplug-xmms.cc
@@ -43,16 +43,14 @@ public:
PACKAGE
};
- static constexpr auto iinfo = InputInfo ()
- .with_exts (exts);
-
- constexpr AdPlugXMMS () : InputPlugin (info, iinfo) {}
+ constexpr AdPlugXMMS () : InputPlugin (info, InputInfo ()
+ .with_exts (exts)) {}
bool init ();
void cleanup ();
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
};
@@ -123,33 +121,31 @@ dbg_printf (const char *fmt, ...)
/***** Main player (!! threaded !!) *****/
-Tuple AdPlugXMMS::read_tuple (const char * filename, VFSFile & fd)
+bool AdPlugXMMS::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
- Tuple tuple;
CSilentopl tmpopl;
- CFileProvider fp (fd);
+ CFileProvider fp (file);
CPlayer *p = CAdPlug::factory (filename, &tmpopl, fp);
- if (p)
- {
- tuple.set_filename (filename);
+ if (! p)
+ return false;
- if (! p->getauthor().empty())
- tuple.set_str (Tuple::Artist, p->getauthor().c_str());
+ if (! p->getauthor().empty())
+ tuple.set_str (Tuple::Artist, p->getauthor().c_str());
- if (! p->gettitle().empty())
- tuple.set_str (Tuple::Title, p->gettitle().c_str());
- else if (! p->getdesc().empty())
- tuple.set_str (Tuple::Title, p->getdesc().c_str());
+ if (! p->gettitle().empty())
+ tuple.set_str (Tuple::Title, p->gettitle().c_str());
+ else if (! p->getdesc().empty())
+ tuple.set_str (Tuple::Title, p->getdesc().c_str());
- tuple.set_str (Tuple::Codec, p->gettype().c_str());
- tuple.set_str (Tuple::Quality, _("sequenced"));
- tuple.set_int (Tuple::Length, p->songlength (plr.subsong));
- delete p;
- }
+ tuple.set_str (Tuple::Codec, p->gettype().c_str());
+ tuple.set_str (Tuple::Quality, _("sequenced"));
+ tuple.set_int (Tuple::Length, p->songlength (plr.subsong));
+ delete p;
- return tuple;
+ return true;
}
/* Main playback thread. Takes the filename to play as argument. */
diff --git a/src/adplug/core/a2m.cc b/src/adplug/core/a2m.cc
index 3ec924a..dd59a58 100644
--- a/src/adplug/core/a2m.cc
+++ b/src/adplug/core/a2m.cc
@@ -157,24 +157,24 @@ bool Ca2mLoader::load(const std::string &filename, const CFileProvider &fp)
orgptr += sixdepak(secptr,orgptr,len[1]); secptr += len[1] / 2;
if(version == 1) {
if(numpats > 16)
- orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; }
if(numpats > 32)
- orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; }
if(numpats > 48)
sixdepak(secptr,orgptr,len[4]);
} else {
if(numpats > 8)
- orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[2]); secptr += len[2] / 2; }
if(numpats > 16)
- orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[3]); secptr += len[3] / 2; }
if(numpats > 24)
- orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[4]); secptr += len[4] / 2; }
if(numpats > 32)
- orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[5]); secptr += len[5] / 2; }
if(numpats > 40)
- orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[6]); secptr += len[6] / 2; }
if(numpats > 48)
- orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2;
+ { orgptr += sixdepak(secptr,orgptr,len[7]); secptr += len[7] / 2; }
if(numpats > 56)
sixdepak(secptr,orgptr,len[8]);
}
diff --git a/src/adplug/core/adl.cc b/src/adplug/core/adl.cc
index 18b3ae8..b27d1bf 100644
--- a/src/adplug/core/adl.cc
+++ b/src/adplug/core/adl.cc
@@ -741,7 +741,9 @@ void AdlibDriver::executePrograms() {
}
Channel &channel = _channels[_curChannel];
- _curRegOffset = _regOffset[_curChannel];
+ if (_curChannel != 9) {
+ _curRegOffset = _regOffset[_curChannel];
+ }
if (channel.tempoReset) {
channel.tempo = _tempo;
diff --git a/src/adplug/core/adplug.cc b/src/adplug/core/adplug.cc
index 10a149b..a35cb10 100644
--- a/src/adplug/core/adplug.cc
+++ b/src/adplug/core/adplug.cc
@@ -182,9 +182,3 @@ std::string CAdPlug::get_version()
{
return std::string(VERSION);
}
-
-void CAdPlug::debug_output(const std::string &filename)
-{
- AdPlug_LogFile(filename.c_str());
- AdPlug_LogWrite("CAdPlug::debug_output(\"%s\"): Redirected.\n",filename.c_str());
-}
diff --git a/src/adplug/core/adplug.h b/src/adplug/core/adplug.h
index 6b247bf..01b56d2 100644
--- a/src/adplug/core/adplug.h
+++ b/src/adplug/core/adplug.h
@@ -43,7 +43,6 @@ public:
static void set_database(CAdPlugDatabase *db);
static std::string get_version();
- static void debug_output(const std::string &filename);
private:
static CAdPlugDatabase *database;
diff --git a/src/adplug/core/adtrack.cc b/src/adplug/core/adtrack.cc
index f8fc466..cc633c2 100644
--- a/src/adplug/core/adtrack.cc
+++ b/src/adplug/core/adtrack.cc
@@ -62,7 +62,7 @@ bool CadtrackLoader::load(const std::string &filename, const CFileProvider &fp)
AdPlug_LogWrite("CadtrackLoader::load(,\"%s\"): Checking for \"%s\"...\n",
filename.c_str(), instfilename.c_str());
instf = fp.open(instfilename);
- if(!instf || fp.filesize(instf) != 468) { fp.close(f); return false; }
+ if(!instf || fp.filesize(instf) != 468) { if(instf) { fp.close(instf); } fp.close(f); return false; }
// give CmodPlayer a hint on what we're up to
realloc_patterns(1,1000,9); realloc_instruments(9); realloc_order(1);
diff --git a/src/adplug/core/bmf.cc b/src/adplug/core/bmf.cc
index 01aeada..b3601de 100644
--- a/src/adplug/core/bmf.cc
+++ b/src/adplug/core/bmf.cc
@@ -111,11 +111,13 @@ bool CxadbmfPlayer::xadplayer_load()
ptr = 6;
strncpy(bmf.title,(char *)&tune[ptr],36);
+ bmf.title[35] = 0;
while (tune[ptr]) { ptr++; }
ptr++;
strncpy(bmf.author,(char *)&tune[ptr],36);
+ bmf.author[35] = 0;
while (tune[ptr]) { ptr++; }
ptr++;
diff --git a/src/adplug/core/debug.cc b/src/adplug/core/debug.cc
deleted file mode 100644
index 59d1f41..0000000
--- a/src/adplug/core/debug.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Adplug - Replayer for many OPL2/OPL3 audio file formats.
- * Copyright (C) 1999 - 2002 Simon Peter <dn.tlp@gmx.net>, et al.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * debug.h - AdPlug Debug Logger
- * Copyright (c) 2002 Riven the Mage <riven@ok.ru>
- * Copyright (c) 2002 Simon Peter <dn.tlp@gmx.net>
- */
-
-#ifdef DEBUG
-
-#include <stdio.h>
-#include <stdarg.h>
-
-static FILE *log = NULL;
-
-void AdPlug_LogFile(const char *filename)
-{
- if(log) fclose(log);
- log = fopen(filename,"wt");
-}
-
-void AdPlug_LogWrite(const char *fmt, ...)
-{
- va_list argptr;
-
- va_start(argptr, fmt);
-
- if(log) {
- vfprintf(log, fmt, argptr);
- fflush(log);
- } else
- vfprintf(stderr, fmt, argptr);
-
- va_end(argptr);
-}
-
-#else
-
-void AdPlug_LogFile(const char *filename) { }
-void AdPlug_LogWrite(const char *fmt, ...) { }
-
-#endif
diff --git a/src/adplug/core/debug.h b/src/adplug/core/debug.h
index 2f03efa..c8a72a7 100644
--- a/src/adplug/core/debug.h
+++ b/src/adplug/core/debug.h
@@ -32,7 +32,8 @@
#ifndef H_DEBUG
#define H_DEBUG
-void AdPlug_LogFile(const char *filename);
-void AdPlug_LogWrite(const char *fmt, ...);
+#include <libaudcore/runtime.h>
+
+#define AdPlug_LogWrite(...) AUDDBG(__VA_ARGS__)
#endif
diff --git a/src/adplug/core/dfm.cc b/src/adplug/core/dfm.cc
index d33f158..7a81f88 100644
--- a/src/adplug/core/dfm.cc
+++ b/src/adplug/core/dfm.cc
@@ -64,7 +64,8 @@ bool CdfmLoader::load(const std::string &filename, const CFileProvider &fp)
inst[i].data[0] = f->readInt(1);
}
for(i = 0; i < 128; i++) order[i] = f->readInt(1);
- for(i = 0; i < 128 && order[i] != 128; i++) continue; length = i;
+ for(i = 0; i < 128 && order[i] != 128; i++) continue;
+ length = i;
npats = f->readInt(1);
for(i = 0; i < npats; i++) {
n = f->readInt(1);
diff --git a/src/adplug/core/hsp.cc b/src/adplug/core/hsp.cc
index a4f610c..dcbda94 100644
--- a/src/adplug/core/hsp.cc
+++ b/src/adplug/core/hsp.cc
@@ -51,8 +51,15 @@ bool ChspLoader::load(const std::string &filename, const CFileProvider &fp)
if(j >= orgsize) break; // memory boundary check
memset(org + j, cmp[i + 1], j + cmp[i] < orgsize ? cmp[i] : orgsize - j - 1);
}
+ if (j < orgsize) {
+ orgsize = j;
+ }
delete [] cmp;
+ if (orgsize < 128 * 12 + 51) { // check decompressed size
+ delete [] org;
+ return false;
+ }
memcpy(instr, org, 128 * 12); // instruments
for(i = 0; i < 128; i++) { // correct instruments
instr[i][2] ^= (instr[i][2] & 0x40) << 1;
diff --git a/src/adplug/core/lds.cc b/src/adplug/core/lds.cc
index 7c87b28..1f89d23 100644
--- a/src/adplug/core/lds.cc
+++ b/src/adplug/core/lds.cc
@@ -273,7 +273,7 @@ bool CldsPlayer::update()
case 0xf0: // progch
// MIDI commands (unhandled)
AdPlug_LogWrite("CldsPlayer(): not handling MIDI command 0x%x, "
- "value = 0x%x\n", comhi);
+ "value = 0x%x\n", comhi, comlo);
break;
default:
if(comhi < 0xa0)
diff --git a/src/adplug/core/mid.cc b/src/adplug/core/mid.cc
index dc6c98d..9ff191f 100644
--- a/src/adplug/core/mid.cc
+++ b/src/adplug/core/mid.cc
@@ -871,7 +871,7 @@ void CmidPlayer::rewind(int subsong)
for (i=0; i<128; i++)
for (j=0; j<16; j++)
myinsbank[i][j]=midi_fm_instruments[i][j];
- for (i=0; i<16; i++)
+ for (i=0; i<16; i++)
{
ch[i].inum=0;
for (j=0; j<11; j++)
diff --git a/src/adplug/core/protrack.cc b/src/adplug/core/protrack.cc
index 1b038ae..b652e1f 100644
--- a/src/adplug/core/protrack.cc
+++ b/src/adplug/core/protrack.cc
@@ -138,20 +138,23 @@ bool CmodPlayer::update()
tone_portamento(chan,channel[chan].portainfo);
else
vibrato(chan,channel[chan].vibinfo1,channel[chan].vibinfo2);
- case 10: if(del % 4) // SA2 volume slide
- break;
+ case 10:
+ if(del % 4) // SA2 volume slide
+ break;
if(info1)
vol_up(chan,info1);
else
vol_down(chan,info2);
setvolume(chan);
break;
- case 14: if(info1 == 3) // retrig note
- if(!(del % (info2+1)))
- playnote(chan);
- break;
- case 16: if(del % 4) // AMD volume slide
+ case 14:
+ if(info1 == 3) // retrig note
+ if(!(del % (info2+1)))
+ playnote(chan);
break;
+ case 16:
+ if(del % 4) // AMD volume slide
+ break;
if(info1)
vol_up_alt(chan,info1);
else
@@ -193,8 +196,8 @@ bool CmodPlayer::update()
if(!resolve_order()) return !songend;
pattnr = order[ord];
- if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %d\n", pattnr, ord);
- AdPlug_LogWrite("CmodPlayer::update():%3d|", rw);
+ if(!rw) AdPlug_LogWrite("\nCmodPlayer::update(): Pattern: %d, Order: %lu\n", pattnr, ord);
+ AdPlug_LogWrite("CmodPlayer::update():%3lu|", rw);
// play row
pattern_delay = 0;
diff --git a/src/adplug/core/s3m.cc b/src/adplug/core/s3m.cc
index 1f626e2..f4ea7c6 100644
--- a/src/adplug/core/s3m.cc
+++ b/src/adplug/core/s3m.cc
@@ -352,13 +352,15 @@ bool Cs3mPlayer::update()
}
break;
case 7: // tone portamento
- case 8: if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands)
- channel[realchan].fx == 8) && pattern[pattnr][row][chan].info)
- channel[realchan].dualinfo = info;
+ case 8:
+ if((channel[realchan].fx == 7 || // vibrato (remember info for dual commands)
+ channel[realchan].fx == 8) && pattern[pattnr][row][chan].info)
+ channel[realchan].dualinfo = info;
break;
case 10: channel[realchan].trigger = 0; break; // arpeggio (set trigger)
- case 19: if(info == 0xb0) // set loop start
- loopstart = row;
+ case 19:
+ if(info == 0xb0) // set loop start
+ loopstart = row;
if(info > 0xb0 && info <= 0xbf) { // pattern loop
if(!loopcnt) {
loopcnt = info & 0x0f;
diff --git a/src/adplug/core/sa2.cc b/src/adplug/core/sa2.cc
index ee74f2b..d0f53c6 100644
--- a/src/adplug/core/sa2.cc
+++ b/src/adplug/core/sa2.cc
@@ -160,7 +160,7 @@ bool Csa2Loader::load(const std::string &filename, const CFileProvider &fp)
activechan = f->readInt(2) << 16; // active channels
AdPlug_LogWrite("Csa2Loader::load(\"%s\"): sat_type = %x, nop = %d, "
- "length = %d, restartpos = %d, activechan = %x, bpm = %d\n",
+ "length = %lu, restartpos = %lu, activechan = %lx, bpm = %d\n",
filename.c_str(), sat_type, nop, length, restartpos, activechan, bpm);
// track data
diff --git a/src/adplug/core/sng.cc b/src/adplug/core/sng.cc
index 89dbb3f..e34d65e 100644
--- a/src/adplug/core/sng.cc
+++ b/src/adplug/core/sng.cc
@@ -73,7 +73,7 @@ bool CsngPlayer::update()
if(!header.compressed)
opl->write(data[pos].reg, data[pos].val);
- if(data[pos].val) del = data[pos].val - 1; pos++;
+ if(data[pos].val) { del = data[pos].val - 1; pos++; }
if(pos >= header.length) { songend = true; pos = header.loop; }
return !songend;
}
diff --git a/src/alarm/alarm.cc b/src/alarm/alarm.cc
index 2eadfca..8a08822 100644
--- a/src/alarm/alarm.cc
+++ b/src/alarm/alarm.cc
@@ -28,7 +28,6 @@
#include <assert.h>
#include <math.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/interface.h>
@@ -56,7 +55,8 @@ public:
N_("Alarm"),
PACKAGE,
about,
- & prefs
+ & prefs,
+ PluginGLibOnly
};
constexpr AlarmPlugin () : GeneralPlugin (info, false) {}
@@ -149,7 +149,7 @@ static struct
GtkEntry *cmdstr;
GtkToggleButton *cmd_on;
- GtkEntry *playlist;
+ GtkWidget *playlist;
int default_hour;
int default_min;
@@ -251,9 +251,8 @@ static void alarm_save()
cmd_on = gtk_toggle_button_get_active (alarm_conf.cmd_on);
aud_set_bool ("alarm", "cmd_on", cmd_on);
- char * playlist = gtk_editable_get_chars ((GtkEditable *) alarm_conf.playlist, 0, -1);
- aud_set_str ("alarm", "playlist", playlist);
- g_free (playlist);
+ String playlist = audgui_file_entry_get_uri (alarm_conf.playlist);
+ aud_set_str ("alarm", "playlist", playlist ? playlist : "");
/* reminder */
char * reminder_msg = gtk_editable_get_chars ((GtkEditable *) alarm_conf.reminder, 0, -1);
@@ -418,8 +417,8 @@ static void *alarm_make_config_widget()
String playlist = aud_get_str ("alarm", "playlist");
w = lookup_widget(config_notebook, "playlist");
- alarm_conf.playlist = GTK_ENTRY(w);
- gtk_entry_set_text(alarm_conf.playlist, playlist);
+ alarm_conf.playlist = w;
+ audgui_file_entry_set_uri(alarm_conf.playlist, playlist);
String reminder_msg = aud_get_str ("alarm", "reminder_msg");
w = lookup_widget(config_notebook, "reminder_text");
diff --git a/src/alarm/interface.cc b/src/alarm/interface.cc
index 4b54ab5..1113b71 100644
--- a/src/alarm/interface.cc
+++ b/src/alarm/interface.cc
@@ -20,6 +20,7 @@
#include <gtk/gtk.h>
#include <libaudcore/i18n.h>
#include <libaudgui/libaudgui.h>
+#include <libaudgui/libaudgui-gtk.h>
#include "callbacks.h"
@@ -102,13 +103,6 @@ GtkWidget *create_reminder_dialog (const char *reminder_msg)
return reminder_dialog;
}
-static void file_set_cb (GtkFileChooserButton *button, void * entry)
-{
- char *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (button));
- gtk_entry_set_text (GTK_ENTRY (entry), uri);
- g_free (uri);
-}
-
GtkWidget *create_config_notebook ()
{
/* General */
@@ -150,8 +144,8 @@ GtkWidget *create_config_notebook ()
GtkWidget *fading_spin, *quiet_vol_scale, *vol_scale, *separator, *current_button;
/* Page 4 */
- GtkWidget *cmd_entry, *playlist_entry, *reminder_text;
- GtkWidget *cmd_checkb, *reminder_checkb, *file_chooser_button;
+ GtkWidget *cmd_entry, *playlist_entry, *reminder_text;
+ GtkWidget *cmd_checkb, *reminder_checkb;
/* Page 5 */
GtkWidget *view, *scrolled_window;
@@ -368,13 +362,10 @@ GtkWidget *create_config_notebook ()
hbox = gtk_hbox_new (false, 6);
gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
- playlist_entry = gtk_entry_new ();
+ playlist_entry = audgui_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, _("Select a playlist"));
g_object_set_data (G_OBJECT (notebook), "playlist", playlist_entry);
- file_chooser_button = gtk_file_chooser_button_new (_("Select a playlist"), GTK_FILE_CHOOSER_ACTION_OPEN);
- g_signal_connect (file_chooser_button, "file-set", G_CALLBACK (file_set_cb), playlist_entry);
gtk_box_pack_start (GTK_BOX (hbox), playlist_entry, true, true, 0);
- gtk_box_pack_start (GTK_BOX (hbox), file_chooser_button, true, true, 0);
gtk_container_add (GTK_CONTAINER (frame), hbox);
gtk_box_pack_start (GTK_BOX (vbox), frame, false, false, 0);
diff --git a/src/albumart-qt/albumart.cc b/src/albumart-qt/albumart.cc
index df7720c..438a02a 100644
--- a/src/albumart-qt/albumart.cc
+++ b/src/albumart-qt/albumart.cc
@@ -20,7 +20,6 @@
#include <QLabel>
#include <QPixmap>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -32,7 +31,10 @@ class AlbumArtQt : public GeneralPlugin {
public:
static constexpr PluginInfo info = {
N_("Album Art"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr AlbumArtQt () : GeneralPlugin (info, false) {}
diff --git a/src/albumart/albumart.cc b/src/albumart/albumart.cc
index 8711769..45fc0bb 100644
--- a/src/albumart/albumart.cc
+++ b/src/albumart/albumart.cc
@@ -17,7 +17,6 @@
* the use of this software.
*/
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -30,7 +29,10 @@ class AlbumArtPlugin : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("Album Art"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr AlbumArtPlugin () : GeneralPlugin (info, false) {}
diff --git a/src/alsa/alsa.cc b/src/alsa/alsa.cc
index 1d46f12..410f1ae 100644
--- a/src/alsa/alsa.cc
+++ b/src/alsa/alsa.cc
@@ -94,13 +94,13 @@ static bool poll_setup ()
{
if (pipe (poll_pipe))
{
- ERROR ("Failed to create pipe: %s.\n", strerror (errno));
+ AUDERR ("Failed to create pipe: %s.\n", strerror (errno));
return false;
}
if (fcntl (poll_pipe[0], F_SETFL, O_NONBLOCK))
{
- ERROR ("Failed to set O_NONBLOCK on pipe: %s.\n", strerror (errno));
+ AUDERR ("Failed to set O_NONBLOCK on pipe: %s.\n", strerror (errno));
close (poll_pipe[0]);
close (poll_pipe[1]);
return false;
@@ -120,7 +120,7 @@ static void poll_sleep ()
{
if (poll (poll_handles, poll_count, -1) < 0)
{
- ERROR ("Failed to poll: %s.\n", strerror (errno));
+ AUDERR ("Failed to poll: %s.\n", strerror (errno));
return;
}
@@ -136,7 +136,7 @@ static void poll_wake ()
{
const char c = 0;
if (write (poll_pipe[1], & c, 1) < 0)
- ERROR ("Failed to write to pipe: %s.\n", strerror (errno));
+ AUDERR ("Failed to write to pipe: %s.\n", strerror (errno));
}
static void poll_cleanup ()
@@ -307,7 +307,7 @@ static snd_pcm_format_t convert_aud_format (int aud_format)
return SND_PCM_FORMAT_UNKNOWN;
}
-bool ALSAPlugin::open_audio (int aud_format, int rate, int channels)
+bool ALSAPlugin::open_audio (int aud_format, int rate, int channels, String & error)
{
int total_buffer, hard_buffer, soft_buffer, buffer_frames;
unsigned useconds;
@@ -319,19 +319,26 @@ bool ALSAPlugin::open_audio (int aud_format, int rate, int channels)
String pcm = aud_get_str ("alsa", "pcm");
snd_pcm_format_t format = convert_aud_format (aud_format);
+
+ if (format == SND_PCM_FORMAT_UNKNOWN)
+ {
+ error = String ("Unsupported audio format");
+ goto FAILED;
+ }
+
AUDDBG ("Opening PCM device %s for %s, %d channels, %d Hz.\n",
(const char *) pcm, snd_pcm_format_name (format), channels, rate);
- CHECK_NOISY (snd_pcm_open, & alsa_handle, pcm, SND_PCM_STREAM_PLAYBACK, 0);
+ CHECK_STR (error, snd_pcm_open, & alsa_handle, pcm, SND_PCM_STREAM_PLAYBACK, 0);
snd_pcm_hw_params_t * params;
snd_pcm_hw_params_alloca (& params);
- CHECK_NOISY (snd_pcm_hw_params_any, alsa_handle, params);
- CHECK_NOISY (snd_pcm_hw_params_set_access, alsa_handle, params,
+ CHECK_STR (error, snd_pcm_hw_params_any, alsa_handle, params);
+ CHECK_STR (error, snd_pcm_hw_params_set_access, alsa_handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
- CHECK_NOISY (snd_pcm_hw_params_set_format, alsa_handle, params, format);
- CHECK_NOISY (snd_pcm_hw_params_set_channels, alsa_handle, params, channels);
- CHECK_NOISY (snd_pcm_hw_params_set_rate, alsa_handle, params, rate, 0);
+ CHECK_STR (error, snd_pcm_hw_params_set_format, alsa_handle, params, format);
+ CHECK_STR (error, snd_pcm_hw_params_set_channels, alsa_handle, params, channels);
+ CHECK_STR (error, snd_pcm_hw_params_set_rate, alsa_handle, params, rate, 0);
alsa_format = format;
alsa_channels = channels;
@@ -340,17 +347,17 @@ bool ALSAPlugin::open_audio (int aud_format, int rate, int channels)
total_buffer = aud_get_int (nullptr, "output_buffer_size");
useconds = 1000 * aud::min (1000, total_buffer / 2);
direction = 0;
- CHECK_NOISY (snd_pcm_hw_params_set_buffer_time_near, alsa_handle, params,
- & useconds, & direction);
+ CHECK_STR (error, snd_pcm_hw_params_set_buffer_time_near, alsa_handle,
+ params, & useconds, & direction);
hard_buffer = useconds / 1000;
useconds = 1000 * (hard_buffer / 4);
direction = 0;
- CHECK_NOISY (snd_pcm_hw_params_set_period_time_near, alsa_handle, params,
- & useconds, & direction);
+ CHECK_STR (error, snd_pcm_hw_params_set_period_time_near, alsa_handle,
+ params, & useconds, & direction);
alsa_period = useconds / 1000;
- CHECK_NOISY (snd_pcm_hw_params, alsa_handle, params);
+ CHECK_STR (error, snd_pcm_hw_params, alsa_handle, params);
soft_buffer = aud::max (total_buffer / 2, total_buffer - hard_buffer);
AUDDBG ("Buffer: hardware %d ms, software %d ms, period %d ms.\n",
@@ -543,10 +550,10 @@ void ALSAPlugin::open_mixer ()
goto FAILED;
AUDDBG ("Opening mixer card %s.\n", (const char *) mixer);
- CHECK_NOISY (snd_mixer_open, & alsa_mixer, 0);
- CHECK_NOISY (snd_mixer_attach, alsa_mixer, mixer);
- CHECK_NOISY (snd_mixer_selem_register, alsa_mixer, nullptr, nullptr);
- CHECK_NOISY (snd_mixer_load, alsa_mixer);
+ CHECK (snd_mixer_open, & alsa_mixer, 0);
+ CHECK (snd_mixer_attach, alsa_mixer, mixer);
+ CHECK (snd_mixer_selem_register, alsa_mixer, nullptr, nullptr);
+ CHECK (snd_mixer_load, alsa_mixer);
snd_mixer_selem_id_t * selem_id;
snd_mixer_selem_id_alloca (& selem_id);
@@ -555,7 +562,7 @@ void ALSAPlugin::open_mixer ()
if (! alsa_mixer_element)
{
- ERROR_NOISY ("snd_mixer_find_selem failed.\n");
+ AUDERR ("snd_mixer_find_selem failed.\n");
goto FAILED;
}
diff --git a/src/alsa/alsa.h b/src/alsa/alsa.h
index f59c24c..02b53bf 100644
--- a/src/alsa/alsa.h
+++ b/src/alsa/alsa.h
@@ -22,21 +22,14 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
-#include <libaudcore/interface.h>
#include <libaudcore/plugin.h>
#include <libaudcore/runtime.h>
-#define ERROR AUDERR
-
-#define ERROR_NOISY(...) do { \
- aud_ui_show_error (str_printf ("ALSA error: " __VA_ARGS__)); \
-} while (0)
-
#define CHECK_VAL(value, function, ...) \
do { \
(value) = function (__VA_ARGS__); \
if ((value) < 0) { \
- ERROR ("%s failed: %s.\n", #function, snd_strerror (value)); \
+ AUDERR ("%s failed: %s.\n", #function, snd_strerror (value)); \
goto FAILED; \
} \
} while (0)
@@ -47,11 +40,12 @@ do { \
CHECK_VAL (CHECK_error, function, __VA_ARGS__); \
} while (0)
-#define CHECK_NOISY(function, ...) \
+#define CHECK_STR(str, function, ...) \
do { \
- int CHECK_NOISY_error = function (__VA_ARGS__); \
- if (CHECK_NOISY_error < 0) { \
- ERROR_NOISY ("%s failed: %s.\n", #function, snd_strerror (CHECK_NOISY_error)); \
+ int CHECK_STR_error = function (__VA_ARGS__); \
+ if (CHECK_STR_error < 0) { \
+ str = String (str_printf ("ALSA error: %s failed: %s.\n", #function, \
+ snd_strerror (CHECK_STR_error))); \
goto FAILED; \
} \
} while (0)
@@ -81,7 +75,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume v);
- bool open_audio (int aud_format, int rate, int chans);
+ bool open_audio (int aud_format, int rate, int chans, String & error);
void close_audio ();
void period_wait ();
diff --git a/src/alsa/config.cc b/src/alsa/config.cc
index ffe9576..3eaaf5c 100644
--- a/src/alsa/config.cc
+++ b/src/alsa/config.cc
@@ -235,7 +235,7 @@ static void guess_element ()
}
}
- ERROR_NOISY ("No suitable mixer element found.\n");
+ AUDERR ("No suitable mixer element found.\n");
}
const char * const ALSAPlugin::defaults[] = {
diff --git a/src/amidi-plug/Makefile b/src/amidiplug/Makefile
index 6657a67..6657a67 100644
--- a/src/amidi-plug/Makefile
+++ b/src/amidiplug/Makefile
diff --git a/src/amidi-plug/amidi-plug.cc b/src/amidiplug/amidi-plug.cc
index edb6d54..c6de04a 100644
--- a/src/amidi-plug/amidi-plug.cc
+++ b/src/amidiplug/amidi-plug.cc
@@ -44,16 +44,14 @@ public:
& amidiplug_prefs
};
- static constexpr auto iinfo = InputInfo ()
- .with_exts (exts);
-
- constexpr AMIDIPlug () : InputPlugin (info, iinfo) {}
+ constexpr AMIDIPlug () : InputPlugin (info, InputInfo ()
+ .with_exts (exts)) {}
bool init ();
void cleanup ();
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
#ifdef USE_GTK
@@ -140,19 +138,17 @@ bool AMIDIPlug::is_our_file (const char * filename, VFSFile & file)
return false;
}
-Tuple AMIDIPlug::read_tuple (const char * filename, VFSFile & file)
+bool AMIDIPlug::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
- /* song title, get it from the filename */
- Tuple tuple;
- tuple.set_filename (filename);
- tuple.set_str (Tuple::Codec, "MIDI");
-
midifile_t mf;
+ if (! mf.parse_from_file (filename, file))
+ return false;
- if (mf.parse_from_file (filename, file))
- tuple.set_int (Tuple::Length, mf.length / 1000);
+ tuple.set_str (Tuple::Codec, "MIDI");
+ tuple.set_int (Tuple::Length, mf.length / 1000);
- return tuple;
+ return true;
}
diff --git a/src/amidi-plug/amidi-plug.midiicon.xpm b/src/amidiplug/amidi-plug.midiicon.xpm
index bff0e97..bff0e97 100644
--- a/src/amidi-plug/amidi-plug.midiicon.xpm
+++ b/src/amidiplug/amidi-plug.midiicon.xpm
diff --git a/src/amidi-plug/backend-fluidsynth/b-fluidsynth.cc b/src/amidiplug/backend-fluidsynth/b-fluidsynth.cc
index 09d8c24..09d8c24 100644
--- a/src/amidi-plug/backend-fluidsynth/b-fluidsynth.cc
+++ b/src/amidiplug/backend-fluidsynth/b-fluidsynth.cc
diff --git a/src/amidi-plug/i_backend.h b/src/amidiplug/i_backend.h
index d4f9ce3..d4f9ce3 100644
--- a/src/amidi-plug/i_backend.h
+++ b/src/amidiplug/i_backend.h
diff --git a/src/amidi-plug/i_configure-fluidsynth.cc b/src/amidiplug/i_configure-fluidsynth.cc
index 0e460e2..0e460e2 100644
--- a/src/amidi-plug/i_configure-fluidsynth.cc
+++ b/src/amidiplug/i_configure-fluidsynth.cc
diff --git a/src/amidi-plug/i_configure-fluidsynth.h b/src/amidiplug/i_configure-fluidsynth.h
index f6af4d8..f6af4d8 100644
--- a/src/amidi-plug/i_configure-fluidsynth.h
+++ b/src/amidiplug/i_configure-fluidsynth.h
diff --git a/src/amidi-plug/i_configure.cc b/src/amidiplug/i_configure.cc
index 6d551e5..6d551e5 100644
--- a/src/amidi-plug/i_configure.cc
+++ b/src/amidiplug/i_configure.cc
diff --git a/src/amidi-plug/i_configure.h b/src/amidiplug/i_configure.h
index 4648b1c..4648b1c 100644
--- a/src/amidi-plug/i_configure.h
+++ b/src/amidiplug/i_configure.h
diff --git a/src/amidi-plug/i_fileinfo.cc b/src/amidiplug/i_fileinfo.cc
index 1a2ee7e..1a2ee7e 100644
--- a/src/amidi-plug/i_fileinfo.cc
+++ b/src/amidiplug/i_fileinfo.cc
diff --git a/src/amidi-plug/i_fileinfo.h b/src/amidiplug/i_fileinfo.h
index 15749e5..15749e5 100644
--- a/src/amidi-plug/i_fileinfo.h
+++ b/src/amidiplug/i_fileinfo.h
diff --git a/src/amidi-plug/i_midi.cc b/src/amidiplug/i_midi.cc
index 7308712..7308712 100644
--- a/src/amidi-plug/i_midi.cc
+++ b/src/amidiplug/i_midi.cc
diff --git a/src/amidi-plug/i_midi.h b/src/amidiplug/i_midi.h
index 6863be6..6863be6 100644
--- a/src/amidi-plug/i_midi.h
+++ b/src/amidiplug/i_midi.h
diff --git a/src/amidi-plug/i_midievent.h b/src/amidiplug/i_midievent.h
index b939e5d..b939e5d 100644
--- a/src/amidi-plug/i_midievent.h
+++ b/src/amidiplug/i_midievent.h
diff --git a/src/ampache/Makefile b/src/ampache/Makefile
new file mode 100644
index 0000000..4d6dacf
--- /dev/null
+++ b/src/ampache/Makefile
@@ -0,0 +1,20 @@
+# Makefile
+#
+# Project: Ampache Browser Audacious Plugin
+# License: GNU GPLv3
+#
+# Copyright (C) 2015 - 2016 Róbert Čerňanský
+
+PLUGIN = ampache${PLUGIN_SUFFIX}
+
+SRCS = ampache.cc
+
+include ../../buildsys.mk
+include ../../extra.mk
+
+plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
+
+LD = ${CXX}
+CPPFLAGS += -I../.. -I. ${QT_CFLAGS} ${AMPACHE_CFLAGS}
+CFLAGS += ${PLUGIN_CFLAGS}
+LIBS += ${QT_LIBS} ${AMPACHE_LIBS}
diff --git a/src/ampache/ampache.cc b/src/ampache/ampache.cc
new file mode 100644
index 0000000..a09f6b9
--- /dev/null
+++ b/src/ampache/ampache.cc
@@ -0,0 +1,134 @@
+// ampache.cc
+//
+// Project: Ampache Browser Audacious Plugin
+// License: GNU GPLv3
+//
+// Copyright (C) 2015-2016 Róbert Čerňanský and John Lindgren
+
+#include <libaudcore/audstrings.h>
+#include <libaudcore/drct.h>
+#include <libaudcore/i18n.h>
+#include <libaudcore/runtime.h>
+#include <libaudcore/plugin.h>
+#include <libaudcore/playlist.h>
+#include <libaudcore/vfs_async.h>
+
+#include <ampache_browser/settings.h>
+#include <ampache_browser/ampache_browser.h>
+#include <ampache_browser/application_qt.h>
+
+#define CFG_SECT "ampache_browser"
+
+using NetworkCb = ampache_browser::ApplicationQt::NetworkRequestCb;
+using UrlList = std::vector<std::string>;
+
+class AmpacheBrowserPlugin: public GeneralPlugin
+{
+public:
+ static const char about[];
+
+ static constexpr PluginInfo pluginInfo = {
+ N_("Ampache Browser"),
+ PACKAGE,
+ about,
+ nullptr,
+ PluginQtOnly
+ };
+
+ constexpr AmpacheBrowserPlugin(): GeneralPlugin(pluginInfo, false) {}
+
+ bool init() override;
+ void cleanup() override;
+ void* get_qt_widget() override;
+};
+
+const char AmpacheBrowserPlugin::about[] =
+ N_("Ampache Browser\n\n"
+ "Ampache client for Audacious.\n\n"
+ "License: GNU GPLv3\n"
+ "Copyright (C) Róbert Čerňanský and John Lindgren\n");
+
+static SmartPtr<ampache_browser::ApplicationQt> s_app;
+
+static void vfsAsyncCb(const char* url, const Index<char>& data, void* callback)
+{
+ if (s_app) // ignore callbacks after cleanup()
+ (*(NetworkCb*)callback)(url, data.begin(), data.len());
+}
+
+static Index<PlaylistAddItem> toAddItems(const UrlList& urls)
+{
+ Index<PlaylistAddItem> addItems;
+ for (auto& url: urls)
+ addItems.append(String(url.c_str()));
+
+ return addItems;
+}
+
+static void initSettings(ampache_browser::Settings &settings)
+{
+ static const std::string bool_settings[] = {
+ settings.USE_DEMO_SERVER
+ };
+
+ static const std::string str_settings[] = {
+ settings.SERVER_URL,
+ settings.USER_NAME,
+ settings.PASSWORD_HASH
+ };
+
+ auto verbosity = getenv("AMPACHE_BROWSER_PLUGIN_VERBOSITY");
+ settings.setInt(settings.LOGGING_VERBOSITY, verbosity ? str_to_int(verbosity) : 0);
+
+ for (auto& name: bool_settings)
+ settings.setBool(name, aud_get_bool(CFG_SECT, name.c_str()));
+ for (auto& name: str_settings)
+ settings.setString(name, (const char*)aud_get_str(CFG_SECT, name.c_str()));
+
+ settings.connectChanged([&settings]() {
+ for (auto& name: bool_settings)
+ aud_set_bool(CFG_SECT, name.c_str(), settings.getBool(name));
+ for (auto& name: str_settings)
+ aud_set_str(CFG_SECT, name.c_str(), settings.getString(name).c_str());
+ });
+}
+
+bool AmpacheBrowserPlugin::init()
+{
+ s_app.capture(new ampache_browser::ApplicationQt);
+
+ s_app->setNetworkRequestFunction([](const std::string& url, NetworkCb& networkCb) {
+ vfs_async_file_get_contents(url.c_str(), vfsAsyncCb, &networkCb);
+ });
+
+ auto& browser = s_app->getAmpacheBrowser();
+
+ browser.connectPlay([](const UrlList& urls) {
+ aud_drct_pl_open_list(toAddItems(urls));
+ });
+
+ browser.connectCreatePlaylist([](const UrlList& urls) {
+ aud_playlist_entry_insert_batch(aud_playlist_new(), -1, toAddItems(urls), true);
+ });
+
+ browser.connectAddToPlaylist([](const UrlList& urls) {
+ aud_playlist_entry_insert_batch(aud_playlist_get_active(), -1, toAddItems(urls), false);
+ });
+
+ initSettings(s_app->getSettings());
+
+ return true;
+}
+
+void AmpacheBrowserPlugin::cleanup()
+{
+ s_app.clear();
+}
+
+void* AmpacheBrowserPlugin::get_qt_widget()
+{
+ s_app->run();
+ return s_app->getMainWidget();
+}
+
+EXPORT AmpacheBrowserPlugin aud_plugin_instance;
diff --git a/src/aosd/Makefile b/src/aosd/Makefile
index 3a02e65..9b148ea 100644
--- a/src/aosd/Makefile
+++ b/src/aosd/Makefile
@@ -17,5 +17,5 @@ plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
-CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${XRENDER_CFLAGS} ${XCOMPOSITE_CFLAGS} -I../..
-LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${XRENDER_LIBS} ${XCOMPOSITE_LIBS} -lm
+CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${X11EXT_CFLAGS} -I../..
+LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${X11EXT_LIBS} -lm
diff --git a/src/aosd/aosd.h b/src/aosd/aosd.h
index 0d7cb8e..87814c7 100644
--- a/src/aosd/aosd.h
+++ b/src/aosd/aosd.h
@@ -21,7 +21,6 @@
#ifndef _I_AOSD_H
#define _I_AOSD_H 1
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/plugin.h>
struct PreferencesWidget;
@@ -38,7 +37,8 @@ public:
N_("AOSD (On-Screen Display)"),
PACKAGE,
about,
- & prefs
+ & prefs,
+ PluginGLibOnly
};
constexpr AOSD () : GeneralPlugin (info, false) {}
diff --git a/src/aosd/aosd_osd.cc b/src/aosd/aosd_osd.cc
index d76c561..404a683 100644
--- a/src/aosd/aosd_osd.cc
+++ b/src/aosd/aosd_osd.cc
@@ -416,7 +416,6 @@ aosd_osd_init ( int transparency_mode )
if ( transparency_mode == AOSD_MISC_TRANSPARENCY_FAKE )
osd = ghosd_new();
else
-#ifdef HAVE_XCOMPOSITE
{
/* check if the composite module is actually loaded */
if ( aosd_osd_check_composite_ext() )
@@ -427,9 +426,6 @@ aosd_osd_init ( int transparency_mode )
osd = ghosd_new(); /* fall back to fake transparency */
}
}
-#else
- osd = ghosd_new();
-#endif
if ( osd == nullptr )
g_warning( "Unable to load osd object; OSD will not work properly!\n" );
@@ -450,7 +446,6 @@ aosd_osd_cleanup ( void )
return;
}
-#ifdef HAVE_XCOMPOSITE
int
aosd_osd_check_composite_ext ( void )
{
@@ -506,4 +501,3 @@ aosd_osd_check_composite_mgr ( void )
return have_comp_mgr;
}
}
-#endif
diff --git a/src/aosd/aosd_osd.h b/src/aosd/aosd_osd.h
index bd0cfdf..2d5ed6e 100644
--- a/src/aosd/aosd_osd.h
+++ b/src/aosd/aosd_osd.h
@@ -28,9 +28,7 @@ void aosd_osd_shutdown ( void );
void aosd_osd_init ( int transparency_mode ); /* to be called before any OSD usage */
void aosd_osd_cleanup ( void ); /* to be called when done with OSD usage */
-#ifdef HAVE_XCOMPOSITE
int aosd_osd_check_composite_ext ( void );
int aosd_osd_check_composite_mgr ( void );
-#endif
#endif /* !_I_AOSD_OSD_H */
diff --git a/src/aosd/aosd_ui.cc b/src/aosd/aosd_ui.cc
index 3f3862e..23f6014 100644
--- a/src/aosd/aosd_ui.cc
+++ b/src/aosd/aosd_ui.cc
@@ -99,17 +99,16 @@ static void
aosd_cb_configure_position_placement_commit ( GtkWidget * grid , aosd_cfg_t * cfg )
{
GList *placbt_list = gtk_container_get_children( GTK_CONTAINER(grid) );
- GList *list_iter = placbt_list;
- while ( list_iter != nullptr )
+ for ( GList *iter = placbt_list; iter != nullptr; iter = iter->next )
{
- GtkWidget *placbt = (GtkWidget *) list_iter->data;
+ GtkWidget *placbt = (GtkWidget *) iter->data;
+
if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(placbt) ) == true )
{
cfg->position.placement = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(placbt),"value"));
break;
}
- list_iter = g_list_next( list_iter );
}
g_list_free( placbt_list );
@@ -641,7 +640,6 @@ aosd_ui_configure_trigger ( aosd_cfg_t * cfg )
}
-#ifdef HAVE_XCOMPOSITE
static void
aosd_cb_configure_misc_transp_real_clicked ( GtkToggleButton * real_rbt , void * status_hbox )
{
@@ -671,22 +669,23 @@ aosd_cb_configure_misc_transp_real_clicked ( GtkToggleButton * real_rbt , void *
gtk_widget_set_sensitive( GTK_WIDGET(status_hbox) , false );
}
}
-#endif
static void
aosd_cb_configure_misc_transp_commit ( GtkWidget * mis_transp_vbox , aosd_cfg_t * cfg )
{
GList *child_list = gtk_container_get_children( GTK_CONTAINER(mis_transp_vbox) );
- while (child_list != nullptr)
+
+ for ( GList *iter = child_list; iter != nullptr; iter = iter->next )
{
- if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(child_list->data) ) )
+ if ( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(iter->data) ) )
{
- cfg->misc.transparency_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(child_list->data),"val"));
+ cfg->misc.transparency_mode = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(iter->data), "val"));
break;
}
- child_list = g_list_next(child_list);
}
+
+ g_list_free( child_list );
}
@@ -735,7 +734,6 @@ aosd_ui_configure_misc ( aosd_cfg_t * cfg )
g_object_set_data( G_OBJECT(mis_transp_status_hbox) , "img" , mis_transp_status_img );
g_object_set_data( G_OBJECT(mis_transp_status_hbox) , "label" , mis_transp_status_label );
-#ifdef HAVE_XCOMPOSITE
g_signal_connect( G_OBJECT(mis_transp_real_rbt) , "toggled" ,
G_CALLBACK(aosd_cb_configure_misc_transp_real_clicked) , mis_transp_status_hbox );
@@ -756,14 +754,6 @@ aosd_ui_configure_misc ( aosd_cfg_t * cfg )
gtk_label_set_text( GTK_LABEL(mis_transp_status_label) , _("Composite extension not loaded") );
gtk_widget_set_sensitive( GTK_WIDGET(mis_transp_status_hbox) , false );
}
-#else
- gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(mis_transp_fake_rbt) , true );
- gtk_widget_set_sensitive( GTK_WIDGET(mis_transp_real_rbt) , false );
- gtk_image_set_from_icon_name( GTK_IMAGE(mis_transp_status_img) ,
- "dialog-error" , GTK_ICON_SIZE_MENU );
- gtk_label_set_text( GTK_LABEL(mis_transp_status_label) , _("Composite extension not available") );
- gtk_widget_set_sensitive( GTK_WIDGET(mis_transp_status_hbox) , false );
-#endif
aosd_cb_list.append( mis_transp_vbox , aosd_cb_configure_misc_transp_commit );
diff --git a/src/aosd/ghosd.c b/src/aosd/ghosd.c
index cfe3886..67461cd 100644
--- a/src/aosd/ghosd.c
+++ b/src/aosd/ghosd.c
@@ -14,16 +14,13 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
-#ifdef HAVE_XCOMPOSITE
#include <X11/extensions/Xcomposite.h>
-#endif
#include <glib.h>
#include "ghosd.h"
#include "ghosd-internal.h"
-#ifdef HAVE_XCOMPOSITE
static Bool
composite_find_manager(Display *dpy, int scr)
{
@@ -77,7 +74,6 @@ composite_find_argb_visual(Display *dpy, int scr)
return visual;
}
-#endif
static Pixmap
take_snapshot(Ghosd *ghosd) {
@@ -359,7 +355,6 @@ ghosd_new(void) {
return ghosd;
}
-#ifdef HAVE_XCOMPOSITE
Ghosd *
ghosd_new_with_argbvisual(void) {
Ghosd *ghosd;
@@ -443,7 +438,6 @@ ghosd_check_composite_mgr(void)
XCloseDisplay(dpy);
return have_composite_m;
}
-#endif
void
ghosd_destroy(Ghosd* ghosd) {
diff --git a/src/aosd/ghosd.h b/src/aosd/ghosd.h
index 70c36a7..a2dcea5 100644
--- a/src/aosd/ghosd.h
+++ b/src/aosd/ghosd.h
@@ -38,11 +38,9 @@ extern "C" {
Ghosd *ghosd_new(void);
void ghosd_destroy(Ghosd* ghosd);
-#ifdef HAVE_XCOMPOSITE
Ghosd *ghosd_new_with_argbvisual(void);
int ghosd_check_composite_ext(void);
int ghosd_check_composite_mgr(void);
-#endif
#define GHOSD_COORD_CENTER INT_MAX
void ghosd_set_transparent(Ghosd *ghosd, int transparent);
diff --git a/src/audpl/audpl.cc b/src/audpl/audpl.cc
index 0549a78..d75ff51 100644
--- a/src/audpl/audpl.cc
+++ b/src/audpl/audpl.cc
@@ -1,6 +1,6 @@
/*
* Audacious playlist format plugin
- * Copyright 2011 John Lindgren
+ * Copyright 2011-2016 John Lindgren
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -20,10 +20,10 @@
#include <stdlib.h>
#include <string.h>
-#include <libaudcore/i18n.h>
-#include <libaudcore/plugin.h>
#include <libaudcore/audstrings.h>
+#include <libaudcore/i18n.h>
#include <libaudcore/inifile.h>
+#include <libaudcore/plugin.h>
static const char * const audpl_exts[] = {"audpl"};
@@ -65,7 +65,12 @@ private:
Tuple tuple;
void finish_item ()
- { items.append (std::move (uri), std::move (tuple)); }
+ {
+ if (tuple.valid ())
+ tuple.set_filename (uri);
+
+ items.append (std::move (uri), std::move (tuple));
+ }
/* no headings */
void handle_heading (const char * heading) {}
@@ -83,21 +88,30 @@ private:
}
else if (uri)
{
- /* item field */
- if (! tuple)
- tuple.set_filename (uri);
-
- if (strcmp (key, "empty"))
+ if (! strcmp (key, "state"))
{
+ /* item state */
+ if (! strcmp (value, "good"))
+ tuple.set_state (Tuple::Valid);
+ else if (! strcmp (value, "failed"))
+ tuple.set_state (Tuple::Failed);
+ }
+ else
+ {
+ /* item field */
auto field = Tuple::field_by_name (key);
if (field == Tuple::Invalid)
return;
auto type = Tuple::field_get_type (field);
if (type == Tuple::String)
- tuple.set_str (field, str_decode_percent (value));
+ tuple.set_str (field, (field == Tuple::AudioFile) ? value :
+ str_decode_percent (value));
else if (type == Tuple::Int)
tuple.set_int (field, atoi (value));
+
+ /* state is implicitly Valid if any field is present */
+ tuple.set_state (Tuple::Valid);
}
}
else
@@ -127,12 +141,15 @@ bool AudPlaylistLoader::save (const char * path, VFSFile & file,
if (! inifile_write_entry (file, "uri", item.filename))
return false;
- const Tuple & tuple = item.tuple;
+ int keys = 0;
- if (tuple)
+ switch (item.tuple.state ())
{
- int keys = 0;
+ case Tuple::Initial:
+ /* state is implicitly Initial if no fields are present */
+ break;
+ case Tuple::Valid:
for (auto f : Tuple::all_fields ())
{
if (f == Tuple::Path || f == Tuple::Basename ||
@@ -140,19 +157,20 @@ bool AudPlaylistLoader::save (const char * path, VFSFile & file,
continue;
const char * key = Tuple::field_get_name (f);
- Tuple::ValueType type = tuple.get_value_type (f);
+ Tuple::ValueType type = item.tuple.get_value_type (f);
if (type == Tuple::String)
{
- String str = tuple.get_str (f);
- if (! inifile_write_entry (file, key, str_encode_percent (str)))
+ String str = item.tuple.get_str (f);
+ if (! inifile_write_entry (file, key,
+ (f == Tuple::AudioFile) ? str : str_encode_percent (str)))
return false;
keys ++;
}
else if (type == Tuple::Int)
{
- int val = tuple.get_int (f);
+ int val = item.tuple.get_int (f);
if (! inifile_write_entry (file, key, int_to_str (val)))
return false;
@@ -160,9 +178,17 @@ bool AudPlaylistLoader::save (const char * path, VFSFile & file,
}
}
- /* distinguish between an empty tuple and no tuple at all */
- if (! keys && ! inifile_write_entry (file, "empty", "1"))
+ /* for an actual empty tuple, record state explicity */
+ if (! keys && ! inifile_write_entry (file, "state", "good"))
return false;
+
+ break;
+
+ case Tuple::Failed:
+ if (! inifile_write_entry (file, "state", "failed"))
+ return false;
+
+ break;
}
}
diff --git a/src/blur_scope/blur_scope.cc b/src/blur_scope/blur_scope.cc
index c5c08df..2b2c507 100644
--- a/src/blur_scope/blur_scope.cc
+++ b/src/blur_scope/blur_scope.cc
@@ -28,7 +28,6 @@
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/i18n.h>
#include <libaudcore/runtime.h>
#include <libaudcore/plugin.h>
@@ -56,7 +55,8 @@ public:
N_("Blur Scope"),
PACKAGE,
nullptr,
- & bscope_prefs
+ & bscope_prefs,
+ PluginGLibOnly
};
constexpr BlurScope () : VisPlugin (info, Visualizer::MonoPCM) {}
diff --git a/src/cairo-spectrum/cairo-spectrum.cc b/src/cairo-spectrum/cairo-spectrum.cc
index 8709402..045f27c 100644
--- a/src/cairo-spectrum/cairo-spectrum.cc
+++ b/src/cairo-spectrum/cairo-spectrum.cc
@@ -23,7 +23,6 @@
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
#include <libaudcore/interface.h>
@@ -40,7 +39,10 @@ class CairoSpectrum : public VisPlugin
public:
static constexpr PluginInfo info = {
N_("Spectrum Analyzer"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr CairoSpectrum () : VisPlugin (info, Visualizer::Freq) {}
@@ -192,10 +194,7 @@ static void get_color (GtkWidget * widget, int i, float * r, float * g, float *
rgb_to_hsv (c->red / 65535.0, c->green / 65535.0, c->blue / 65535.0, & h, & s, & v);
if (s < 0.1) /* monochrome theme? use blue instead */
- {
- h = 5;
- s = 0.75;
- }
+ h = 4.6;
s = 1 - 0.9 * i / (bands - 1);
v = 0.75 + 0.25 * i / (bands - 1);
diff --git a/src/cdaudio-ng/Makefile b/src/cdaudio/Makefile
index 59f125a..ba34c85 100644
--- a/src/cdaudio-ng/Makefile
+++ b/src/cdaudio/Makefile
@@ -10,5 +10,5 @@ plugindir := ${plugindir}/${INPUT_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
-CPPFLAGS += ${PLUGIN_CPPFLAGS} ${CDIO_CFLAGS} ${CDDB_CFLAGS} -I../..
-LIBS += ${CDIO_LIBS} ${CDDB_LIBS}
+CPPFLAGS += ${PLUGIN_CPPFLAGS} ${CDIO_CFLAGS} -I../..
+LIBS += ${CDIO_LIBS}
diff --git a/src/cdaudio-ng/cdaudio-ng.cc b/src/cdaudio/cdaudio-ng.cc
index 643484c..188b72a 100644
--- a/src/cdaudio-ng/cdaudio-ng.cc
+++ b/src/cdaudio/cdaudio-ng.cc
@@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses>.
*/
-#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
@@ -46,6 +45,7 @@
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
#include <libaudcore/interface.h>
+#include <libaudcore/mainloop.h>
#include <libaudcore/playlist.h>
#include <libaudcore/plugin.h>
#include <libaudcore/preferences.h>
@@ -74,16 +74,14 @@ public:
& prefs
};
- static constexpr auto iinfo = InputInfo (FlagSubtunes)
- .with_schemes (cdaudio_schemes);
-
- constexpr CDAudio () : InputPlugin (info, iinfo) {}
+ constexpr CDAudio () : InputPlugin (info, InputInfo (FlagSubtunes)
+ .with_schemes (cdaudio_schemes)) {}
bool init ();
void cleanup ();
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
};
@@ -108,9 +106,10 @@ static int lasttrackno = -1;
static int n_audio_tracks;
static cdrom_drive_t *pcdrom_drive = nullptr;
static Index<trackinfo_t> trackinfo;
+static QueuedFunc purge_func;
static bool scan_cd ();
-static void refresh_trackinfo (bool warning);
+static bool refresh_trackinfo (bool warning);
static void reset_trackinfo ();
static int calculate_track_length (int startlsn, int endlsn);
static int find_trackno_from_filename (const char * filename);
@@ -191,7 +190,7 @@ static void purge_playlist (int playlist)
}
/* main thread only */
-static void purge_all_playlists ()
+static void purge_all_playlists (void * = nullptr)
{
int playlists = aud_playlist_count ();
int count;
@@ -206,31 +205,10 @@ static void monitor (void *)
pthread_mutex_lock (& mutex);
/* make sure not to close drive handle while playing */
- if (playing)
- {
- pthread_mutex_unlock (& mutex);
- return;
- }
-
- if (trackinfo.len ())
+ if (! playing)
refresh_trackinfo (false);
- if (trackinfo.len ())
- {
- pthread_mutex_unlock (& mutex);
- return;
- }
-
- timer_remove (TimerRate::Hz1, monitor);
pthread_mutex_unlock (& mutex);
-
- purge_all_playlists ();
-}
-
-/* mutex must be locked */
-static void trigger_monitor ()
-{
- timer_add (TimerRate::Hz1, monitor);
}
/* main thread only */
@@ -260,15 +238,10 @@ bool CDAudio::play (const char * name, VFSFile & file)
{
pthread_mutex_lock (& mutex);
- if (! trackinfo.len ())
+ if (! trackinfo.len () && ! refresh_trackinfo (true))
{
- refresh_trackinfo (true);
-
- if (! trackinfo.len ())
- {
- pthread_mutex_unlock (& mutex);
- return false;
- }
+ pthread_mutex_unlock (& mutex);
+ return false;
}
bool okay = false;
@@ -371,16 +344,19 @@ void CDAudio::cleanup ()
pthread_mutex_lock (& mutex);
reset_trackinfo ();
+ purge_func.stop ();
+
libcddb_shutdown ();
pthread_mutex_unlock (& mutex);
}
/* thread safe */
-Tuple CDAudio::read_tuple (const char * filename, VFSFile & file)
+bool CDAudio::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
bool whole_disk = ! strcmp (filename, "cdda://");
- Tuple tuple;
+ bool valid = false;
pthread_mutex_lock (& mutex);
@@ -388,16 +364,12 @@ Tuple CDAudio::read_tuple (const char * filename, VFSFile & file)
if (whole_disk && ! playing)
reset_trackinfo ();
- if (! trackinfo.len ())
- refresh_trackinfo (true);
- if (! trackinfo.len ())
+ if (! trackinfo.len () && ! refresh_trackinfo (true))
goto DONE;
if (whole_disk)
{
- tuple.set_filename (filename);
-
- Index<int> subtunes;
+ Index<short> subtunes;
/* only add the audio tracks to the playlist */
for (int trackno = firsttrackno; trackno <= lasttrackno; trackno++)
@@ -405,6 +377,8 @@ Tuple CDAudio::read_tuple (const char * filename, VFSFile & file)
subtunes.append (trackno);
tuple.set_subtunes (subtunes.len (), subtunes.begin ());
+
+ valid = true;
}
else
{
@@ -422,7 +396,6 @@ Tuple CDAudio::read_tuple (const char * filename, VFSFile & file)
goto DONE;
}
- tuple.set_filename (filename);
tuple.set_format (_("Audio CD"), 2, 44100, 1411);
tuple.set_int (Tuple::Track, trackno);
tuple.set_int (Tuple::Length, calculate_track_length
@@ -438,19 +411,22 @@ Tuple CDAudio::read_tuple (const char * filename, VFSFile & file)
tuple.set_str (Tuple::AlbumArtist, trackinfo[0].performer);
if (trackinfo[trackno].genre)
tuple.set_str (Tuple::Genre, trackinfo[trackno].genre);
+
+ valid = true;
}
DONE:
pthread_mutex_unlock (& mutex);
- return tuple;
+ return valid;
}
/* mutex must be locked */
-static void open_cd ()
+static bool open_cd ()
{
- AUDDBG ("Opening CD drive.\n");
- assert (pcdrom_drive == nullptr);
+ if (pcdrom_drive)
+ return true;
+ AUDDBG ("Opening CD drive.\n");
String device = aud_get_str ("CDDA", "device");
if (device[0])
@@ -473,16 +449,40 @@ static void open_cd ()
if (ppcd_drives)
cdio_free_device_list (ppcd_drives);
}
+
+ return (bool) pcdrom_drive;
+}
+
+/* mutex must be locked */
+static bool check_disc_mode (bool warning)
+{
+ int mode = cdio_get_discmode (pcdrom_drive->p_cdio);
+
+#ifdef _WIN32 /* cdio_get_discmode reports the wrong disk type sometimes */
+ if (mode == CDIO_DISC_MODE_NO_INFO || mode == CDIO_DISC_MODE_ERROR)
+#else
+ if (mode != CDIO_DISC_MODE_CD_DA && mode != CDIO_DISC_MODE_CD_MIXED)
+#endif
+ {
+ if (warning)
+ {
+ if (mode == CDIO_DISC_MODE_NO_INFO)
+ cdaudio_error (_("Drive is empty."));
+ else
+ cdaudio_error (_("Unsupported disk type."));
+ }
+
+ return false;
+ }
+
+ return true;
}
/* mutex must be locked */
static bool scan_cd ()
{
AUDDBG ("Scanning CD drive.\n");
- assert (pcdrom_drive);
- assert (! trackinfo.len ());
-
- int trackno;
+ trackinfo.clear ();
/* general track initialization */
@@ -519,7 +519,7 @@ static bool scan_cd ()
n_audio_tracks = 0;
- for (trackno = firsttrackno; trackno <= lasttrackno; trackno++)
+ for (int trackno = firsttrackno; trackno <= lasttrackno; trackno++)
{
trackinfo[trackno].startlsn = cdda_track_firstsector (pcdrom_drive, trackno);
trackinfo[trackno].endlsn = cdda_track_lastsector (pcdrom_drive, trackno);
@@ -567,7 +567,7 @@ static bool scan_cd ()
/* get track information from cdtext */
bool cdtext_was_available = false;
- for (trackno = firsttrackno; trackno <= lasttrackno; trackno++)
+ for (int trackno = firsttrackno; trackno <= lasttrackno; trackno++)
{
#if LIBCDIO_VERSION_NUM < 90
if (aud_get_bool ("CDDA", "use_cdtext"))
@@ -656,7 +656,7 @@ static bool scan_cd ()
CDIO_CDROM_LEADOUT_TRACK);
cddb_disc_set_length (pcddb_disc, FRAMES_TO_SECONDS (lba));
- for (trackno = firsttrackno; trackno <= lasttrackno; trackno++)
+ for (int trackno = firsttrackno; trackno <= lasttrackno; trackno++)
{
pcddb_track = cddb_track_new ();
cddb_track_set_frame_offset (pcddb_track,
@@ -742,43 +742,25 @@ static bool scan_cd ()
}
/* mutex must be locked */
-static void refresh_trackinfo (bool warning)
+static bool refresh_trackinfo (bool warning)
{
- if (pcdrom_drive == nullptr)
- {
- open_cd ();
- if (pcdrom_drive == nullptr)
- return;
- }
+ if (! open_cd () || ! check_disc_mode (warning))
+ goto fail;
- int mode = cdio_get_discmode (pcdrom_drive->p_cdio);
-#ifdef _WIN32 /* cdio_get_discmode reports the wrong disk type sometimes */
- if (mode == CDIO_DISC_MODE_NO_INFO || mode == CDIO_DISC_MODE_ERROR)
-#else
- if (mode != CDIO_DISC_MODE_CD_DA && mode != CDIO_DISC_MODE_CD_MIXED)
-#endif
+ if (! trackinfo.len () || cdio_get_media_changed (pcdrom_drive->p_cdio))
{
- if (warning)
- {
- if (mode == CDIO_DISC_MODE_NO_INFO)
- cdaudio_error (_("Drive is empty."));
- else
- cdaudio_error (_("Unsupported disk type."));
- }
+ if (! scan_cd ())
+ goto fail;
- reset_trackinfo ();
- return;
+ timer_add (TimerRate::Hz1, monitor);
}
- if (! trackinfo.len () || cdio_get_media_changed (pcdrom_drive->p_cdio))
- {
- trackinfo.clear ();
+ return true;
- if (scan_cd ())
- trigger_monitor ();
- else
- reset_trackinfo ();
- }
+fail:
+ reset_trackinfo ();
+ purge_func.queue (purge_all_playlists, nullptr);
+ return false;
}
/* mutex must be locked */
diff --git a/src/console/Audacious_Driver.cc b/src/console/Audacious_Driver.cc
index 4d90bc7..2ed01a2 100644
--- a/src/console/Audacious_Driver.cc
+++ b/src/console/Audacious_Driver.cc
@@ -144,54 +144,56 @@ int ConsoleFileHandler::load(int sample_rate)
return 0;
}
-static Tuple get_track_ti(const char *path, const track_info_t *info, const int track)
+static int get_track_length(const track_info_t &info)
{
- Tuple tuple;
- tuple.set_filename (path);
-
- tuple.set_str (Tuple::Artist, info->author);
- tuple.set_str (Tuple::Album, info->game);
- tuple.set_str (Tuple::Title, info->song);
- tuple.set_str (Tuple::Copyright, info->copyright);
- tuple.set_str (Tuple::Codec, info->system);
- tuple.set_str (Tuple::Comment, info->comment);
-
- if (track >= 0)
- {
- tuple.set_int (Tuple::Track, track + 1);
- tuple.set_int (Tuple::Subtune, track + 1);
- tuple.set_int (Tuple::NumSubtunes, info->track_count);
- }
- else
- tuple.set_subtunes (info->track_count, nullptr);
-
- int length = info->length;
+ int length = info.length;
if (length <= 0)
- length = info->intro_length + 2 * info->loop_length;
+ length = info.intro_length + 2 * info.loop_length;
+
if (length <= 0)
length = audcfg.loop_length * 1000;
else if (length >= fade_threshold)
length += fade_length;
- tuple.set_int (Tuple::Length, length);
- return tuple;
+ return length;
}
-Tuple ConsolePlugin::read_tuple(const char *filename, VFSFile &file)
+bool ConsolePlugin::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
ConsoleFileHandler fh(filename, file);
if (!fh.m_type)
- return Tuple ();
+ return false;
+
+ if (fh.load(gme_info_only))
+ return false;
- if (!fh.load(gme_info_only))
+ track_info_t info;
+ if (log_err(fh.m_emu->track_info(&info, fh.m_track < 0 ? 0 : fh.m_track)))
+ return false;
+
+ auto set_str = [&tuple](Tuple::Field f, const char *s)
+ { if (s[0]) tuple.set_str(f, s); };
+
+ set_str(Tuple::Artist, info.author);
+ set_str(Tuple::Album, info.game);
+ set_str(Tuple::Title, info.song);
+ set_str(Tuple::Copyright, info.copyright);
+ set_str(Tuple::Codec, info.system);
+ set_str(Tuple::Comment, info.comment);
+
+ if (fh.m_track >= 0)
{
- track_info_t info;
- if (!log_err(fh.m_emu->track_info(&info, fh.m_track < 0 ? 0 : fh.m_track)))
- return get_track_ti(fh.m_path, &info, fh.m_track);
+ tuple.set_int(Tuple::Track, fh.m_track + 1);
+ tuple.set_int(Tuple::Subtune, fh.m_track + 1);
+ tuple.set_int(Tuple::NumSubtunes, info.track_count);
}
+ else
+ tuple.set_subtunes(info.track_count, nullptr);
+
+ tuple.set_int (Tuple::Length, get_track_length (info));
- return Tuple ();
+ return true;
}
bool ConsolePlugin::play(const char *filename, VFSFile &file)
@@ -246,12 +248,8 @@ bool ConsolePlugin::play(const char *filename, VFSFile &file)
if (fh.m_type == gme_spc_type && audcfg.ignore_spc_length)
info.length = -1;
- Tuple tuple = get_track_ti(fh.m_path, &info, fh.m_track);
- if (tuple)
- {
- length = tuple.get_int (Tuple::Length);
- set_stream_bitrate(fh.m_emu->voice_count() * 1000);
- }
+ length = get_track_length(info);
+ set_stream_bitrate(fh.m_emu->voice_count() * 1000);
}
// start track
diff --git a/src/console/plugin.h b/src/console/plugin.h
index 1c24eef..714b52f 100644
--- a/src/console/plugin.h
+++ b/src/console/plugin.h
@@ -29,10 +29,8 @@ public:
& prefs
};
- static constexpr auto iinfo = InputInfo (FlagSubtunes)
- .with_exts (exts);
-
- constexpr ConsolePlugin () : InputPlugin (info, iinfo) {}
+ constexpr ConsolePlugin () : InputPlugin (info, InputInfo (FlagSubtunes)
+ .with_exts (exts)) {}
bool init ();
void cleanup ();
@@ -40,7 +38,7 @@ public:
bool is_our_file (const char * filename, VFSFile & file)
{ return false; }
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
};
diff --git a/src/coreaudio/coreaudio.cc b/src/coreaudio/coreaudio.cc
index 6211db4..a98a2a0 100644
--- a/src/coreaudio/coreaudio.cc
+++ b/src/coreaudio/coreaudio.cc
@@ -61,7 +61,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume vol);
- bool open_audio (int format, int rate_, int chan_);
+ bool open_audio (int format, int rate_, int chan_, String & err);
void close_audio ();
void period_wait ();
@@ -245,7 +245,8 @@ OSStatus CoreAudioPlugin::callback (void *inRefCon, AudioUnitRenderActionFlags *
return 0;
}
-bool CoreAudioPlugin::open_audio (int format, int rate_, int chan_)
+// TODO: return error message to core instead of calling aud_ui_show_error
+bool CoreAudioPlugin::open_audio (int format, int rate_, int chan_, String & err)
{
struct AudioUnitFormatDescriptionMap * m = nullptr;
diff --git a/src/cue/cue.cc b/src/cue/cue.cc
index aa9e389..d198d0b 100644
--- a/src/cue/cue.cc
+++ b/src/cue/cue.cc
@@ -18,10 +18,15 @@
*/
#include <string.h>
+#include <pthread.h>
+#ifdef HAVE_LIBCUE2
+#include <libcue.h>
+#else
extern "C" {
#include <libcue/libcue.h>
}
+#endif
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
@@ -45,15 +50,20 @@ EXPORT CueLoader aud_plugin_instance;
bool CueLoader::load (const char * cue_filename, VFSFile & file, String & title,
Index<PlaylistAddItem> & items)
{
+ // XXX: cue_parse_string crashes if called concurrently
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
Index<char> buffer = file.read_all ();
if (! buffer.len ())
return false;
buffer.append (0); /* null-terminate */
+ pthread_mutex_lock (& mutex);
Cd * cd = cue_parse_string (buffer.begin ());
- int tracks = cd ? cd_get_ntrack (cd) : 0;
+ pthread_mutex_unlock (& mutex);
+ int tracks = cd ? cd_get_ntrack (cd) : 0;
if (tracks < 1)
return false;
@@ -63,20 +73,22 @@ bool CueLoader::load (const char * cue_filename, VFSFile & file, String & title,
if (! cur_name)
return false;
- bool new_file = true;
+ bool same_file = false;
String filename;
PluginHandle * decoder = nullptr;
Tuple base_tuple;
for (int track = 1; track <= tracks; track ++)
{
- if (new_file)
+ if (! same_file)
{
filename = String (uri_construct (cur_name, cue_filename));
- decoder = filename ? aud_file_find_decoder (filename, false) : nullptr;
- base_tuple = decoder ? aud_file_read_tuple (filename, decoder) : Tuple ();
+ decoder = nullptr;
+ base_tuple = Tuple ();
- if (base_tuple)
+ VFSFile file;
+ if ((decoder = aud_file_find_decoder (filename, false, file)) &&
+ aud_file_read_tag (filename, decoder, file, base_tuple))
{
Cdtext * cdtext = cd_get_cdtext (cd);
@@ -105,29 +117,30 @@ bool CueLoader::load (const char * cue_filename, VFSFile & file, String & title,
Track * next = (track + 1 <= tracks) ? cd_get_track (cd, track + 1) : nullptr;
const char * next_name = next ? track_get_filename (next) : nullptr;
- new_file = (! next_name || strcmp (next_name, cur_name));
+ same_file = (next_name && ! strcmp (next_name, cur_name));
- if (base_tuple)
+ if (base_tuple.valid ())
{
- StringBuf tfilename = str_printf ("%s?%d", (const char *) filename, track);
+ StringBuf tfilename = str_printf ("%s?%d", (const char *) cue_filename, track);
Tuple tuple = base_tuple.ref ();
tuple.set_filename (tfilename);
tuple.set_int (Tuple::Track, track);
+ tuple.set_str (Tuple::AudioFile, filename);
int begin = (int64_t) track_get_start (cur) * 1000 / 75;
tuple.set_int (Tuple::StartTime, begin);
- if (new_file)
+ if (same_file)
{
- int length = base_tuple.get_int (Tuple::Length);
- if (length > 0)
- tuple.set_int (Tuple::Length, length - begin);
+ int end = (int64_t) track_get_start (next) * 1000 / 75;
+ tuple.set_int (Tuple::EndTime, end);
+ tuple.set_int (Tuple::Length, end - begin);
}
else
{
- int length = (int64_t) track_get_length (cur) * 1000 / 75;
- tuple.set_int (Tuple::Length, length);
- tuple.set_int (Tuple::EndTime, begin + length);
+ int length = base_tuple.get_int (Tuple::Length);
+ if (length > 0)
+ tuple.set_int (Tuple::Length, length - begin);
}
Cdtext * cdtext = track_get_cdtext (cur);
diff --git a/src/delete-files/Makefile b/src/delete-files/Makefile
index 416a7ae..a019fea 100644
--- a/src/delete-files/Makefile
+++ b/src/delete-files/Makefile
@@ -9,6 +9,16 @@ plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
LD = ${CXX}
-CPPFLAGS += -I../.. ${GIO_CFLAGS} ${GTK_CFLAGS}
+CPPFLAGS += -I../.. ${GIO_CFLAGS}
CFLAGS += ${PLUGIN_CFLAGS}
-LIBS += ${GIO_LIBS} ${GTK_LIBS} -laudgui
+LIBS += ${GIO_LIBS}
+
+ifeq ($(USE_GTK),yes)
+CPPFLAGS += ${GTK_CFLAGS}
+LIBS += ${GTK_LIBS} -laudgui
+endif
+
+ifeq ($(USE_QT),yes)
+CPPFLAGS += ${QT_CFLAGS}
+LIBS += ${QT_LIBS}
+endif
diff --git a/src/delete-files/delete-files.cc b/src/delete-files/delete-files.cc
index 7b9994e..d3d408c 100644
--- a/src/delete-files/delete-files.cc
+++ b/src/delete-files/delete-files.cc
@@ -24,9 +24,7 @@
#include <gio/gio.h>
#include <glib/gstdio.h>
-#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
#include <libaudcore/interface.h>
@@ -34,7 +32,14 @@
#include <libaudcore/plugin.h>
#include <libaudcore/preferences.h>
#include <libaudcore/runtime.h>
+
+#ifdef USE_GTK
#include <libaudgui/libaudgui-gtk.h>
+#endif
+#ifdef USE_QT
+#include <QMessageBox>
+#include <QPushButton>
+#endif
class DeleteFiles : public GeneralPlugin
{
@@ -64,7 +69,12 @@ static constexpr AudMenuID menus[] = {
AudMenuID::PlaylistRemove
};
+#ifdef USE_GTK
static GtkWidget * dialog = nullptr;
+#endif
+#ifdef USE_QT
+static QMessageBox * qdialog = nullptr;
+#endif
static void move_to_trash (const char * filename)
{
@@ -121,34 +131,68 @@ static void confirm_delete ()
static void start_delete ()
{
- if (dialog)
- {
- gtk_window_present ((GtkWindow *) dialog);
- return;
- }
-
- const char * message;
- GtkWidget * button1, * button2;
+ const char * message, * action, * icon;
if (aud_get_bool ("delete_files", "use_trash"))
{
message = _("Do you want to move the selected files to the trash?");
- button1 = audgui_button_new (_("Move to Trash"), "user-trash",
- (AudguiCallback) confirm_delete, nullptr);
+ action = _("Move to Trash");
+ icon = "user-trash";
}
else
{
message = _("Do you want to permanently delete the selected files?");
- button1 = audgui_button_new (_("Delete"), "edit-delete",
- (AudguiCallback) confirm_delete, nullptr);
+ action = _("Delete");
+ icon = "edit-delete";
}
- button2 = audgui_button_new (_("Cancel"), "process-stop", nullptr, nullptr);
- dialog = audgui_dialog_new (GTK_MESSAGE_QUESTION, _("Delete Files"),
- message, button1, button2);
+#ifdef USE_GTK
+ if (aud_get_mainloop_type () == MainloopType::GLib)
+ {
+ if (dialog)
+ {
+ gtk_window_present ((GtkWindow *) dialog);
+ return;
+ }
+
+ auto button1 = audgui_button_new (action, icon, (AudguiCallback) confirm_delete, nullptr);
+ auto button2 = audgui_button_new (_("Cancel"), "process-stop", nullptr, nullptr);
+
+ dialog = audgui_dialog_new (GTK_MESSAGE_QUESTION, _("Delete Files"), message, button1, button2);
- g_signal_connect (dialog, "destroy", (GCallback) gtk_widget_destroyed, & dialog);
- gtk_widget_show_all (dialog);
+ g_signal_connect (dialog, "destroy", (GCallback) gtk_widget_destroyed, & dialog);
+ gtk_widget_show_all (dialog);
+ }
+#endif
+#ifdef USE_QT
+ if (aud_get_mainloop_type () == MainloopType::Qt)
+ {
+ if (qdialog)
+ return;
+
+ qdialog = new QMessageBox;
+ qdialog->setAttribute (Qt::WA_DeleteOnClose);
+ qdialog->setIcon (QMessageBox::Question);
+ qdialog->setWindowTitle (_("Delete Files"));
+ qdialog->setText (message);
+
+ auto remove = new QPushButton (action, qdialog);
+ auto cancel = new QPushButton (_("Cancel"), qdialog);
+
+ remove->setIcon (QIcon::fromTheme (icon));
+ cancel->setIcon (QIcon::fromTheme ("process-stop"));
+
+ qdialog->addButton (remove, QMessageBox::AcceptRole);
+ qdialog->addButton (cancel, QMessageBox::RejectRole);
+
+ QObject::connect (remove, & QPushButton::clicked, confirm_delete);
+ QObject::connect (qdialog, & QObject::destroyed, [] () {
+ qdialog = nullptr;
+ });
+
+ qdialog->show ();
+ }
+#endif
}
const char * const DeleteFiles::defaults[] = {
@@ -171,8 +215,13 @@ bool DeleteFiles::init ()
void DeleteFiles::cleanup ()
{
+#ifdef USE_GTK
if (dialog)
gtk_widget_destroy (dialog);
+#endif
+#ifdef USE_QT
+ delete qdialog;
+#endif
for (AudMenuID menu : menus)
aud_plugin_menu_remove (menu, start_delete);
diff --git a/src/ffaudio/ffaudio-core.cc b/src/ffaudio/ffaudio-core.cc
index ab954d9..3a56bf7 100644
--- a/src/ffaudio/ffaudio-core.cc
+++ b/src/ffaudio/ffaudio-core.cc
@@ -2,7 +2,7 @@
* Audacious FFaudio Plugin
* Copyright © 2009 William Pitcock <nenolod@dereferenced.org>
* Matti Hämäläinen <ccr@tnsp.org>
- * Copyright © 2011 John Lindgren <john.lindgren@tds.net>
+ * Copyright © 2011-2016 John Lindgren <john.lindgren@aol.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -18,19 +18,27 @@
* implied. In no event shall the authors be liable for any damages arising from
*/
-#include <pthread.h>
-
#undef FFAUDIO_DOUBLECHECK /* Doublecheck probing result for debugging purposes */
#undef FFAUDIO_NO_BLACKLIST /* Don't blacklist any recognized codecs/formats */
#include "ffaudio-stdinc.h"
+#include <pthread.h>
+
#include <audacious/audtag.h>
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
#include <libaudcore/multihash.h>
#include <libaudcore/runtime.h>
+#if CHECK_LIBAVFORMAT_VERSION (57, 33, 100, 57, 5, 0)
+#define ALLOC_CONTEXT 1
+#endif
+
+#if CHECK_LIBAVCODEC_VERSION (57, 37, 100, 57, 16, 0)
+#define SEND_PACKET 1
+#endif
+
class FFaudio : public InputPlugin
{
public:
@@ -43,19 +51,16 @@ public:
about
};
- static constexpr auto iinfo = InputInfo (FlagWritesTag)
+ constexpr FFaudio () : InputPlugin (info, InputInfo (FlagWritesTag)
.with_priority (10) /* lowest priority fallback */
.with_exts (exts)
- .with_mimes (mimes);
-
- constexpr FFaudio () : InputPlugin (info, iinfo) {}
+ .with_mimes (mimes)) {}
bool init ();
void cleanup ();
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
- Index<char> read_image (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
bool play (const char * filename, VFSFile & file);
};
@@ -66,11 +71,62 @@ typedef struct
{
int stream_idx;
AVStream * stream;
- AVCodecContext * context;
AVCodec * codec;
}
CodecInfo;
+struct ScopedContext
+{
+ AVCodecContext * ptr;
+ AVCodecContext * operator-> () { return ptr; }
+
+ ScopedContext (const CodecInfo & cinfo)
+ {
+#ifdef ALLOC_CONTEXT
+ ptr = avcodec_alloc_context3 (cinfo.codec);
+ avcodec_parameters_to_context (ptr, cinfo.stream->codecpar);
+#else
+ ptr = cinfo.stream->codec;
+#endif
+ }
+
+#ifdef ALLOC_CONTEXT
+ ~ScopedContext () { avcodec_free_context (& ptr); }
+#else
+ ~ScopedContext () { avcodec_close (ptr); }
+#endif
+};
+
+struct ScopedPacket : public AVPacket
+{
+ ScopedPacket () { av_init_packet (this); }
+
+#if CHECK_LIBAVCODEC_VERSION (55, 25, 100, 55, 16, 0)
+ ~ScopedPacket () { av_packet_unref (this); }
+#else
+ ~ScopedPacket () { av_free_packet (this); }
+#endif
+};
+
+struct ScopedFrame
+{
+#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
+ AVFrame * ptr = av_frame_alloc ();
+#else
+ AVFrame * ptr = avcodec_alloc_frame ();
+#endif
+
+ AVFrame * operator-> () { return ptr; }
+
+#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
+ ~ScopedFrame () { av_frame_free (& ptr); }
+#elif CHECK_LIBAVCODEC_VERSION (54, 59, 100, 54, 28, 0)
+ ~ScopedFrame () { avcodec_free_frame (& ptr); }
+#else
+ ~ScopedFrame () { av_free (ptr); }
+#endif
+};
+
static SimpleHash<String, AVInputFormat *> extension_dict;
static void create_extension_dict ();
@@ -149,12 +205,22 @@ void FFaudio::cleanup ()
av_lockmgr_register (nullptr);
}
-static const char * ffaudio_strerror (int error)
+static int log_result (const char * func, int ret)
{
- static char buf[256];
- return (! av_strerror (error, buf, sizeof buf)) ? buf : "unknown error";
+ if (ret < 0 && ret != (int) AVERROR_EOF && ret != AVERROR (EAGAIN))
+ {
+ static char buf[256];
+ if (! av_strerror (ret, buf, sizeof buf))
+ AUDERR ("%s failed: %s\n", func, buf);
+ else
+ AUDERR ("%s failed\n", func);
+ }
+
+ return ret;
}
+#define LOG(function, ...) log_result (#function, function (__VA_ARGS__))
+
static void create_extension_dict ()
{
AVInputFormat * f;
@@ -252,11 +318,8 @@ static AVFormatContext * open_input_file (const char * name, VFSFile & file)
AVIOContext * io = io_context_new (file);
c->pb = io;
- int ret = avformat_open_input (& c, name, f, nullptr);
-
- if (ret < 0)
+ if (LOG (avformat_open_input, & c, name, f, nullptr) < 0)
{
- AUDERR ("avformat_open_input failed for %s: %s.\n", name, ffaudio_strerror (ret));
io_context_free (io);
return nullptr;
}
@@ -268,12 +331,7 @@ static void close_input_file (AVFormatContext * c)
{
AVIOContext * io = c->pb;
-#if CHECK_LIBAVFORMAT_VERSION (53, 25, 0, 53, 17, 0)
avformat_close_input (&c);
-#else
- av_close_input_file (c);
-#endif
-
io_context_free (io);
}
@@ -285,20 +343,23 @@ static bool find_codec (AVFormatContext * c, CodecInfo * cinfo)
{
AVStream * stream = c->streams[i];
- if (stream && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+#ifndef ALLOC_CONTEXT
+#define codecpar codec
+#endif
+ if (stream && stream->codecpar && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
- AVCodec * codec = avcodec_find_decoder (stream->codec->codec_id);
+ AVCodec * codec = avcodec_find_decoder (stream->codecpar->codec_id);
if (codec)
{
cinfo->stream_idx = i;
cinfo->stream = stream;
- cinfo->context = stream->codec;
cinfo->codec = codec;
return true;
}
}
+#undef codecpar
}
return false;
@@ -345,191 +406,182 @@ static void read_metadata_dict (Tuple & tuple, AVDictionary * dict)
}
}
-Tuple FFaudio::read_tuple (const char * filename, VFSFile & file)
+bool FFaudio::read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image)
{
- Tuple tuple;
- AVFormatContext * ic = open_input_file (filename, file);
+ SmartPtr<AVFormatContext, close_input_file>
+ ic (open_input_file (filename, file));
- if (ic)
- {
- CodecInfo cinfo;
+ if (! ic)
+ return false;
- if (find_codec (ic, & cinfo))
- {
- tuple.set_filename (filename);
+ CodecInfo cinfo;
+ if (! find_codec (ic.get (), & cinfo))
+ return false;
- tuple.set_int (Tuple::Length, ic->duration / 1000);
- tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
+ tuple.set_int (Tuple::Length, ic->duration / 1000);
+ tuple.set_int (Tuple::Bitrate, ic->bit_rate / 1000);
- if (cinfo.codec->long_name)
- tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
+ if (cinfo.codec->long_name)
+ tuple.set_str (Tuple::Codec, cinfo.codec->long_name);
- if (ic->metadata)
- read_metadata_dict (tuple, ic->metadata);
- if (cinfo.stream->metadata)
- read_metadata_dict (tuple, cinfo.stream->metadata);
- }
+ if (ic->metadata)
+ read_metadata_dict (tuple, ic->metadata);
+ if (cinfo.stream->metadata)
+ read_metadata_dict (tuple, cinfo.stream->metadata);
- close_input_file (ic);
- }
+ if (! file.fseek (0, VFS_SEEK_SET))
+ audtag::read_tag (file, tuple, image);
- if (tuple && ! file.fseek (0, VFS_SEEK_SET))
- audtag::read_tag (file, & tuple, nullptr);
+ if (image && (str_has_suffix_nocase (filename, ".m4a") ||
+ str_has_suffix_nocase (filename, ".mp4")))
+ {
+ if (! file.fseek (0, VFS_SEEK_SET))
+ * image = read_itunes_cover (filename, file);
+ }
- return tuple;
+ return true;
}
bool FFaudio::write_tuple (const char * filename, VFSFile & file, const Tuple & tuple)
{
if (str_has_suffix_nocase (filename, ".ape"))
- return audtag::tuple_write (tuple, file, audtag::TagType::APE);
+ return audtag::write_tuple (file, tuple, audtag::TagType::APE);
- return audtag::tuple_write (tuple, file, audtag::TagType::None);
+ return audtag::write_tuple (file, tuple, audtag::TagType::None);
}
-Index<char> FFaudio::read_image (const char * filename, VFSFile & file)
+static bool convert_format (int ff_fmt, int & aud_fmt, bool & planar)
{
- if (str_has_suffix_nocase (filename, ".m4a") || str_has_suffix_nocase (filename, ".mp4"))
- return read_itunes_cover (filename, file);
+ switch (ff_fmt)
+ {
+ case AV_SAMPLE_FMT_U8: aud_fmt = FMT_U8; planar = false; break;
+ case AV_SAMPLE_FMT_S16: aud_fmt = FMT_S16_NE; planar = false; break;
+ case AV_SAMPLE_FMT_S32: aud_fmt = FMT_S32_NE; planar = false; break;
+ case AV_SAMPLE_FMT_FLT: aud_fmt = FMT_FLOAT; planar = false; break;
- return Index<char> ();
+ case AV_SAMPLE_FMT_U8P: aud_fmt = FMT_U8; planar = true; break;
+ case AV_SAMPLE_FMT_S16P: aud_fmt = FMT_S16_NE; planar = true; break;
+ case AV_SAMPLE_FMT_S32P: aud_fmt = FMT_S32_NE; planar = true; break;
+ case AV_SAMPLE_FMT_FLTP: aud_fmt = FMT_FLOAT; planar = true; break;
+
+ default:
+ AUDERR ("Unsupported audio format %d\n", (int) ff_fmt);
+ return false;
+ }
+
+ return true;
}
bool FFaudio::play (const char * filename, VFSFile & file)
{
- AUDDBG ("Playing %s.\n", filename);
+ SmartPtr<AVFormatContext, close_input_file>
+ ic (open_input_file (filename, file));
- AVPacket pkt = AVPacket();
- int errcount;
- bool codec_opened = false;
- int out_fmt;
- bool planar;
- bool error = false;
-
- Index<char> buf;
-
- AVFormatContext * ic = open_input_file (filename, file);
if (! ic)
return false;
CodecInfo cinfo;
-
- if (! find_codec (ic, & cinfo))
+ if (! find_codec (ic.get (), & cinfo))
{
AUDERR ("No codec found for %s.\n", filename);
- goto error_exit;
+ return false;
}
AUDDBG("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx);
- if (avcodec_open2 (cinfo.context, cinfo.codec, nullptr) < 0)
- goto error_exit;
-
- codec_opened = true;
-
- switch (cinfo.context->sample_fmt)
- {
- case AV_SAMPLE_FMT_U8: out_fmt = FMT_U8; planar = false; break;
- case AV_SAMPLE_FMT_S16: out_fmt = FMT_S16_NE; planar = false; break;
- case AV_SAMPLE_FMT_S32: out_fmt = FMT_S32_NE; planar = false; break;
- case AV_SAMPLE_FMT_FLT: out_fmt = FMT_FLOAT; planar = false; break;
-
- case AV_SAMPLE_FMT_U8P: out_fmt = FMT_U8; planar = true; break;
- case AV_SAMPLE_FMT_S16P: out_fmt = FMT_S16_NE; planar = true; break;
- case AV_SAMPLE_FMT_S32P: out_fmt = FMT_S32_NE; planar = true; break;
- case AV_SAMPLE_FMT_FLTP: out_fmt = FMT_FLOAT; planar = true; break;
+ ScopedContext context (cinfo);
+ if (LOG (avcodec_open2, context.ptr, cinfo.codec, nullptr) < 0)
+ return false;
- default:
- AUDERR ("Unsupported audio format %d\n", (int) cinfo.context->sample_fmt);
- goto error_exit;
- }
+ int out_fmt; bool planar;
+ if (! convert_format (context->sample_fmt, out_fmt, planar))
+ return false;
/* Open audio output */
- AUDDBG("opening audio output\n");
-
set_stream_bitrate(ic->bit_rate);
- open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels);
+ open_audio(out_fmt, context->sample_rate, context->channels);
+
+ int errcount = 0;
+ bool eof = false;
- errcount = 0;
+ Index<char> buf;
- while (! check_stop ())
+ while (! eof && ! check_stop ())
{
int seek_value = check_seek ();
if (seek_value >= 0)
{
- if (av_seek_frame (ic, -1, (int64_t) seek_value * AV_TIME_BASE /
- 1000, AVSEEK_FLAG_ANY) < 0)
- {
- AUDERR ("error while seeking\n");
- } else
+ if (LOG (av_seek_frame, ic.get (), -1, (int64_t) seek_value *
+ AV_TIME_BASE / 1000, AVSEEK_FLAG_ANY) >= 0)
errcount = 0;
seek_value = -1;
}
- AVPacket tmp;
- int ret;
-
/* Read next frame (or more) of data */
- if ((ret = av_read_frame(ic, &pkt)) < 0)
+ ScopedPacket pkt;
+ int ret = LOG (av_read_frame, ic.get (), & pkt);
+
+ if (ret < 0)
{
if (ret == (int) AVERROR_EOF)
- {
- AUDDBG("eof reached\n");
- break;
- }
+ eof = true;
+ else if (++ errcount > 4)
+ return false;
else
- {
- if (++errcount > 4)
- {
- AUDERR ("av_read_frame error %d, giving up.\n", ret);
- break;
- } else
- continue;
- }
- } else
+ continue;
+ }
+ else
+ {
errcount = 0;
- /* Ignore any other substreams */
- if (pkt.stream_index != cinfo.stream_idx)
- {
- av_free_packet(&pkt);
- continue;
+ /* Ignore any other substreams */
+ if (pkt.stream_index != cinfo.stream_idx)
+ continue;
}
/* Decode and play packet/frame */
- memcpy(&tmp, &pkt, sizeof(tmp));
- while (tmp.size > 0 && ! check_stop ())
- {
- /* Check for seek request and bail out if we have one */
- if (seek_value < 0)
- seek_value = check_seek ();
+ /* On EOF, send an empty packet to "flush" the decoder */
+ /* Otherwise, make a mutable (shallow) copy of the real packet */
+ AVPacket tmp;
+ if (eof)
+ av_init_packet (& tmp);
+ else
+ tmp = pkt;
- if (seek_value >= 0)
- break;
+#ifdef SEND_PACKET
+ if ((ret = LOG (avcodec_send_packet, context.ptr, & tmp)) < 0)
+ return false; /* defensive, errors not expected here */
+#endif
-#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
- AVFrame * frame = av_frame_alloc ();
+ while (! check_stop ())
+ {
+ ScopedFrame frame;
+
+#ifdef SEND_PACKET
+ if ((ret = LOG (avcodec_receive_frame, context.ptr, frame.ptr)) < 0)
+ break; /* read next packet (continue past errors) */
#else
- AVFrame * frame = avcodec_alloc_frame ();
-#endif
int decoded = 0;
- int len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp);
+ int len = LOG (avcodec_decode_audio4, context.ptr, frame.ptr, & decoded, & tmp);
if (len < 0)
- {
- AUDERR ("decode_audio() failed, code %d\n", len);
- break;
- }
+ break; /* read next packet (continue past errors) */
tmp.size -= len;
tmp.data += len;
if (! decoded)
- continue;
+ {
+ if (tmp.size > 0)
+ continue; /* process more of current packet */
- int size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples;
+ break; /* read next packet */
+ }
+#endif
+
+ int size = FMT_SIZEOF (out_fmt) * context->channels * frame->nb_samples;
if (planar)
{
@@ -537,34 +589,15 @@ bool FFaudio::play (const char * filename, VFSFile & file)
buf.resize (size);
audio_interlace ((const void * *) frame->data, out_fmt,
- cinfo.context->channels, buf.begin (), frame->nb_samples);
+ context->channels, buf.begin (), frame->nb_samples);
write_audio (buf.begin (), size);
}
else
write_audio (frame->data[0], size);
-
-#if CHECK_LIBAVCODEC_VERSION (55, 45, 101, 55, 28, 1)
- av_frame_free (& frame);
-#elif CHECK_LIBAVCODEC_VERSION (54, 59, 100, 54, 28, 0)
- avcodec_free_frame (& frame);
-#else
- av_free (frame);
-#endif
}
-
- if (pkt.data)
- av_free_packet(&pkt);
}
-error_exit:
- if (pkt.data)
- av_free_packet(&pkt);
- if (codec_opened)
- avcodec_close(cinfo.context);
- if (ic != nullptr)
- close_input_file(ic);
-
- return ! error;
+ return true;
}
const char FFaudio::about[] =
diff --git a/src/filewriter/Makefile b/src/filewriter/Makefile
index 347baba..04b08e4 100644
--- a/src/filewriter/Makefile
+++ b/src/filewriter/Makefile
@@ -15,5 +15,5 @@ plugindir := ${plugindir}/${OUTPUT_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
-CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GLIB_CFLAGS} ${GTK_CFLAGS} ${FILEWRITER_CFLAGS} -I../..
-LIBS += ${GTK_LIBS} ${FILEWRITER_LIBS}
+CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GLIB_CFLAGS} ${FILEWRITER_CFLAGS} -I../..
+LIBS += ${GLIB_LIBS} ${FILEWRITER_LIBS}
diff --git a/src/filewriter/filewriter.cc b/src/filewriter/filewriter.cc
index 7853e04..9540d12 100644
--- a/src/filewriter/filewriter.cc
+++ b/src/filewriter/filewriter.cc
@@ -20,8 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <glib.h>
#include <string.h>
-#include <gtk/gtk.h>
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
@@ -29,6 +29,10 @@
#include <libaudcore/preferences.h>
#include <libaudcore/runtime.h>
+#ifdef FILEWRITER_MP3
+#include <lame/lame.h>
+#endif
+
#include "filewriter.h"
#include "convert.h"
@@ -55,7 +59,7 @@ public:
void set_volume (StereoVolume v) {}
void set_info (const char * filename, const Tuple & tuple);
- bool open_audio (int fmt, int rate, int nch);
+ bool open_audio (int fmt, int rate, int nch, String & error);
void close_audio ();
void period_wait () {}
@@ -84,11 +88,17 @@ static int save_original;
/* stored as two separate booleans in the config file */
static int filename_mode;
+#ifdef FILEWRITER_MP3
+/* stored as integers (0 or 1) in the config file */
+static bool mp3_enforce_iso, mp3_error_protect;
+static bool mp3_vbr_on, mp3_enforce_min, mp3_omit_xing;
+static bool mp3_frame_copyright, mp3_frame_original;
+static bool mp3_id3_force_v2, mp3_id3_only_v1, mp3_id3_only_v2;
+#endif
+
static String in_filename;
static Tuple in_tuple;
-static GtkWidget * path_dirbrowser;
-
enum fileext_t
{
WAV = 0,
@@ -165,6 +175,22 @@ bool FileWriter::init ()
p->init ();
}
+#ifdef FILEWRITER_MP3
+ mp3_enforce_iso = aud_get_int ("filewriter_mp3", "enforce_iso_val");
+ mp3_error_protect = aud_get_int ("filewriter_mp3", "error_protect_val");
+
+ mp3_vbr_on = aud_get_int ("filewriter_mp3", "vbr_on");
+ mp3_enforce_min = aud_get_int ("filewriter_mp3", "enforce_min_val");
+ mp3_omit_xing = ! aud_get_int ("filewriter_mp3", "toggle_xing_val");
+
+ mp3_frame_copyright = aud_get_int ("filewriter_mp3", "mark_copyright_val");
+ mp3_frame_original = aud_get_int ("filewriter_mp3", "mark_original_val");
+
+ mp3_id3_force_v2 = aud_get_int ("filewriter_mp3", "force_v2_val");
+ mp3_id3_only_v1 = aud_get_int ("filewriter_mp3", "only_v1_val");
+ mp3_id3_only_v2 = aud_get_int ("filewriter_mp3", "only_v2_val");
+#endif
+
return true;
}
@@ -266,7 +292,7 @@ static StringBuf format_filename (const char * suffix)
return filename;
}
-bool FileWriter::open_audio (int fmt, int rate, int nch)
+bool FileWriter::open_audio (int fmt, int rate, int nch, String & error)
{
int ext = aud_get_int ("filewriter", "fileext");
g_return_val_if_fail (ext >= 0 && ext < FILEEXT_MAX, false);
@@ -310,31 +336,9 @@ void FileWriter::close_audio ()
in_tuple = Tuple ();
}
-static void * create_dirbrowser ()
-{
- path_dirbrowser = gtk_file_chooser_button_new (_("Pick a folder"),
- GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
- gtk_file_chooser_set_uri ((GtkFileChooser *) path_dirbrowser, get_file_path ());
- gtk_widget_set_sensitive (path_dirbrowser, ! save_original);
-
- auto set_cb = [] ()
- {
- char * uri = gtk_file_chooser_get_uri ((GtkFileChooser *) path_dirbrowser);
- aud_set_str ("filewriter", "file_path", uri);
- g_free (uri);
- };
-
- // "file-set" is unreliable, so get the path on "destroy" as well
- g_signal_connect (path_dirbrowser, "file-set", set_cb, nullptr);
- g_signal_connect (path_dirbrowser, "destroy", set_cb, nullptr);
-
- return path_dirbrowser;
-}
-
static void save_original_cb ()
{
aud_set_bool ("filewriter", "save_original", save_original);
- gtk_widget_set_sensitive (path_dirbrowser, ! save_original);
}
static void filename_mode_cb ()
@@ -381,7 +385,10 @@ static const PreferencesWidget main_widgets[] = {
WidgetRadio (N_("Save into custom directory:"),
WidgetInt (save_original, save_original_cb),
{false}),
- WidgetCustomGTK (create_dirbrowser),
+ WidgetFileEntry (nullptr,
+ WidgetString ("filewriter", "file_path"),
+ {FileSelectMode::Folder},
+ WIDGET_CHILD),
WidgetSeparator ({true}),
WidgetLabel (N_("Generate file name from:")),
WidgetRadio (N_("Original file name"),
@@ -399,14 +406,159 @@ static const PreferencesWidget main_widgets[] = {
};
#ifdef FILEWRITER_MP3
+static const ComboItem mp3_sample_rates[] = {
+ ComboItem(N_("Auto"), 0),
+ ComboItem(N_("8000 Hz"), 8000),
+ ComboItem(N_("11025 Hz"), 11025),
+ ComboItem(N_("12000 Hz"), 12000),
+ ComboItem(N_("16000 Hz"), 16000),
+ ComboItem(N_("22050 Hz"), 22050),
+ ComboItem(N_("24000 Hz"), 24000),
+ ComboItem(N_("32000 Hz"), 32000),
+ ComboItem(N_("44100 Hz"), 44100),
+ ComboItem(N_("48000 Hz"), 48000)
+};
+
+static const ComboItem mp3_bitrates[] = {
+ ComboItem(N_("8 kbps"), 8),
+ ComboItem(N_("16 kbps"), 16),
+ ComboItem(N_("32 kbps"), 32),
+ ComboItem(N_("40 kbps"), 40),
+ ComboItem(N_("48 kbps"), 48),
+ ComboItem(N_("56 kbps"), 56),
+ ComboItem(N_("64 kbps"), 64),
+ ComboItem(N_("80 kbps"), 80),
+ ComboItem(N_("96 kbps"), 96),
+ ComboItem(N_("112 kbps"), 112),
+ ComboItem(N_("128 kbps"), 128),
+ ComboItem(N_("160 kbps"), 160),
+ ComboItem(N_("192 kbps"), 192),
+ ComboItem(N_("224 kbps"), 224),
+ ComboItem(N_("256 kbps"), 256),
+ ComboItem(N_("320 kbps"), 320)
+};
+
+static const ComboItem mp3_modes[] = {
+ ComboItem(N_("Auto"), NOT_SET),
+ ComboItem(N_("Joint Stereo"), JOINT_STEREO),
+ ComboItem(N_("Stereo"), STEREO),
+ ComboItem(N_("Mono"), MONO)
+};
+
+static const ComboItem mp3_vbr_modes[] = {
+ ComboItem(N_("VBR"), 0),
+ ComboItem(N_("ABR"), 1)
+};
+
+static void mp3_bools_changed ()
+{
+ aud_set_int ("filewriter_mp3", "enforce_iso_val", mp3_enforce_iso);
+ aud_set_int ("filewriter_mp3", "error_protect_val", mp3_error_protect);
+
+ aud_set_int ("filewriter_mp3", "vbr_on", mp3_vbr_on);
+ aud_set_int ("filewriter_mp3", "enforce_min_val", mp3_enforce_min);
+ aud_set_int ("filewriter_mp3", "toggle_xing_val", ! mp3_omit_xing);
+
+ aud_set_int ("filewriter_mp3", "mark_copyright_val", mp3_frame_copyright);
+ aud_set_int ("filewriter_mp3", "mark_original_val", mp3_frame_original);
+
+ aud_set_int ("filewriter_mp3", "force_v2_val", mp3_id3_force_v2);
+ aud_set_int ("filewriter_mp3", "only_v1_val", mp3_id3_only_v1);
+ aud_set_int ("filewriter_mp3", "only_v2_val", mp3_id3_only_v2);
+}
+
+static const PreferencesWidget mp3_quality_widgets[] = {
+ WidgetSpin(N_("Algorithm quality:"),
+ WidgetInt("filewriter_mp3", "algo_quality_val"),
+ {0, 9, 1}),
+ WidgetCombo(N_("Sample rate:"),
+ WidgetInt("filewriter_mp3", "out_samplerate_val"),
+ {{mp3_sample_rates}}),
+ WidgetRadio(N_("Bitrate:"),
+ WidgetInt("filewriter_mp3", "enc_toggle_val"),
+ {0}),
+ WidgetCombo(nullptr,
+ WidgetInt("filewriter_mp3", "bitrate_val"),
+ {{mp3_bitrates}},
+ WIDGET_CHILD),
+ WidgetRadio(N_("Compression ratio:"),
+ WidgetInt("filewriter_mp3", "enc_toggle_val"),
+ {1}),
+ WidgetSpin(nullptr,
+ WidgetFloat("filewriter_mp3", "compression_val"),
+ {0, 100, 1},
+ WIDGET_CHILD),
+ WidgetCombo(N_("Audio mode:"),
+ WidgetInt("filewriter_mp3", "audio_mode_val"),
+ {{mp3_modes}}),
+ WidgetCheck(N_("Enforce strict ISO compliance"),
+ WidgetBool(mp3_enforce_iso, mp3_bools_changed)),
+ WidgetCheck(N_("Error protection"),
+ WidgetBool(mp3_error_protect, mp3_bools_changed)),
+};
+
+static const PreferencesWidget mp3_vbr_abr_widgets[] = {
+ WidgetCheck(N_("Enable VBR/ABR"),
+ WidgetBool(mp3_vbr_on, mp3_bools_changed)),
+ WidgetCombo(N_("Type:"),
+ WidgetInt("filewriter_mp3", "vbr_type"),
+ {{mp3_vbr_modes}},
+ WIDGET_CHILD),
+ WidgetCombo(N_("Minimum bitrate:"),
+ WidgetInt("filewriter_mp3", "vbr_min_val"),
+ {{mp3_bitrates}},
+ WIDGET_CHILD),
+ WidgetCombo(N_("Maximum bitrate:"),
+ WidgetInt("filewriter_mp3", "vbr_max_val"),
+ {{mp3_bitrates}},
+ WIDGET_CHILD),
+ WidgetCombo(N_("Average bitrate:"),
+ WidgetInt("filewriter_mp3", "abr_val"),
+ {{mp3_bitrates}},
+ WIDGET_CHILD),
+ WidgetSpin(N_("VBR quality level:"),
+ WidgetInt("filewriter_mp3", "vbr_quality_val"),
+ {0, 9, 1},
+ WIDGET_CHILD),
+ WidgetCheck(N_("Strictly enforce minimum bitrate"),
+ WidgetBool(mp3_enforce_min, mp3_bools_changed),
+ WIDGET_CHILD),
+ WidgetCheck(N_("Omit Xing VBR header"),
+ WidgetBool(mp3_omit_xing, mp3_bools_changed),
+ WIDGET_CHILD)
+};
+
+static const PreferencesWidget mp3_tag_widgets[] = {
+ WidgetLabel(N_("<b>Frame Headers</b>")),
+ WidgetCheck(N_("Mark as copyright"),
+ WidgetBool(mp3_frame_copyright, mp3_bools_changed)),
+ WidgetCheck(N_("Mark as original"),
+ WidgetBool(mp3_frame_original, mp3_bools_changed)),
+ WidgetLabel(N_("<b>ID3 Tags</b>")),
+ WidgetCheck(N_("Force addition of version 2 tag"),
+ WidgetBool(mp3_id3_force_v2, mp3_bools_changed)),
+ WidgetCheck(N_("Only add v1 tag"),
+ WidgetBool(mp3_id3_only_v1, mp3_bools_changed)),
+ WidgetCheck(N_("Only add v2 tag"),
+ WidgetBool(mp3_id3_only_v2, mp3_bools_changed)),
+};
+
+static const NotebookTab mp3_tabs[] = {
+ {N_("Quality"), {mp3_quality_widgets}},
+ {N_("VBR/ABR"), {mp3_vbr_abr_widgets}},
+ {N_("Tags"), {mp3_tag_widgets}}
+};
+
static const PreferencesWidget mp3_widgets[] = {
- WidgetCustomGTK (mp3_configure)
+ WidgetNotebook ({{mp3_tabs}})
};
#endif
#ifdef FILEWRITER_VORBIS
static const PreferencesWidget vorbis_widgets[] = {
- WidgetCustomGTK (vorbis_configure)
+ WidgetSpin(N_("Quality (0-1):"),
+ WidgetFloat("filewriter_vorbis", "base_quality"),
+ {0, 1, 0.01})
};
#endif
diff --git a/src/filewriter/filewriter.h b/src/filewriter/filewriter.h
index e3ff449..44b6acc 100644
--- a/src/filewriter/filewriter.h
+++ b/src/filewriter/filewriter.h
@@ -47,12 +47,10 @@ extern FileWriterImpl wav_plugin;
#ifdef FILEWRITER_MP3
extern FileWriterImpl mp3_plugin;
-void * mp3_configure ();
#endif
#ifdef FILEWRITER_VORBIS
extern FileWriterImpl vorbis_plugin;
-void * vorbis_configure ();
#endif
#ifdef FILEWRITER_FLAC
diff --git a/src/filewriter/mp3.cc b/src/filewriter/mp3.cc
index 3c50153..f03a63c 100644
--- a/src/filewriter/mp3.cc
+++ b/src/filewriter/mp3.cc
@@ -26,73 +26,17 @@
#ifdef FILEWRITER_MP3
-#include <string.h>
#include <lame/lame.h>
-#include <gtk/gtk.h>
#include <libaudcore/audstrings.h>
-#include <libaudcore/i18n.h>
#include <libaudcore/runtime.h>
-#define MODES 4
-static const int modes[MODES] = {NOT_SET, JOINT_STEREO, STEREO, MONO};
-static const char * const mode_names[MODES] = {N_("Auto"), N_("Joint Stereo"),
- N_("Stereo"), N_("Mono")};
-
-static GtkWidget *alg_quality_spin;
-static GtkWidget *alg_quality_hbox;
-static GtkAdjustment * alg_quality_adj;
-static GtkWidget *notebook;
-static GtkWidget *quality_vbox, *quality_hbox1, *alg_quality_frame;
-static GtkWidget *enc_quality_frame, *enc_quality_label1, *enc_quality_label2;
-static GtkWidget * enc_radio1, * enc_radio2;
-static GtkWidget *compression_spin;
-static GtkAdjustment * compression_adj;
-static GtkWidget * mode_hbox, * mode_frame;
-static GtkWidget * samplerate_hbox, * samplerate_label, * samplerate_frame;
-static GtkWidget *misc_frame, *misc_vbox, *enforce_iso_toggle,
- *error_protection_toggle;
-static GtkWidget *vbr_vbox, *vbr_toggle, *vbr_options_vbox, *vbr_type_frame,
- *vbr_type_hbox, *vbr_type_radio1, *vbr_type_radio2;
-static GtkWidget * abr_frame, * abr_hbox, * abr_label;
-static GtkWidget *vbr_frame, *vbr_options_vbox2;
-static GtkWidget * vbr_options_hbox1, * vbr_min_label;
-static GtkWidget * vbr_options_hbox2, * vbr_max_label, * enforce_min_toggle;
-static GtkWidget *vbr_options_hbox3, *vbr_quality_spin, *vbr_quality_label;
-static GtkAdjustment * vbr_quality_adj;
-static GtkWidget *xing_header_toggle;
-static GtkWidget *tags_vbox, *tags_frames_frame, *tags_frames_hbox,
- *tags_copyright_toggle, *tags_original_toggle;
-static GtkWidget *tags_id3_frame, *tags_id3_vbox, *tags_id3_hbox,
- *tags_force_id3v2_toggle, *tags_only_v1_toggle, *tags_only_v2_toggle;
-
-static GtkWidget *enc_quality_vbox, *hbox1, *hbox2;
-
-static unsigned long numsamples = 0;
-static int inside;
-
-static int available_samplerates[] =
-{ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 } ;
-
-static int available_bitrates[] =
-{ 8, 16, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } ;
-
-struct lameid3_t {
- String track_name;
- String album_name;
- String performer;
- String genre;
- String year;
- String track_number;
-};
-
-static lameid3_t lameid3;
-
static lame_global_flags *gfp;
static unsigned char encbuffer[LAME_MAXMP3BUFFER];
static int id3v2_size;
static int channels;
+static unsigned long numsamples;
static Index<unsigned char> write_buffer;
static void lame_debugf(const char *format, va_list ap)
@@ -125,9 +69,7 @@ static const char * const mp3_defaults[] = {
nullptr};
#define GET_INT(n) aud_get_int("filewriter_mp3", n)
-#define SET_INT(n, v) aud_set_int("filewriter_mp3", n, v)
#define GET_DOUBLE(n) aud_get_double("filewriter_mp3", n)
-#define SET_DOUBLE(n, v) aud_set_double("filewriter_mp3", n, v)
static void mp3_init ()
{
@@ -146,23 +88,12 @@ static bool mp3_open (VFSFile & file, const format_info & info, const Tuple & tu
id3tag_init(gfp);
/* XXX write UTF-8 even though libmp3lame does id3v2.3. --yaz */
- lameid3.track_name = tuple.get_str (Tuple::Title);
- id3tag_set_title(gfp, lameid3.track_name);
-
- lameid3.performer = tuple.get_str (Tuple::Artist);
- id3tag_set_artist(gfp, lameid3.performer);
-
- lameid3.album_name = tuple.get_str (Tuple::Album);
- id3tag_set_album(gfp, lameid3.album_name);
-
- lameid3.genre = tuple.get_str (Tuple::Genre);
- id3tag_set_genre(gfp, lameid3.genre);
-
- lameid3.year = String (int_to_str (tuple.get_int (Tuple::Year)));
- id3tag_set_year(gfp, lameid3.year);
-
- lameid3.track_number = String (int_to_str (tuple.get_int (Tuple::Track)));
- id3tag_set_track(gfp, lameid3.track_number);
+ id3tag_set_title(gfp, tuple.get_str (Tuple::Title));
+ id3tag_set_artist(gfp, tuple.get_str (Tuple::Artist));
+ id3tag_set_album(gfp, tuple.get_str (Tuple::Album));
+ id3tag_set_genre(gfp, tuple.get_str (Tuple::Genre));
+ id3tag_set_year(gfp, int_to_str (tuple.get_int (Tuple::Year)));
+ id3tag_set_track(gfp, int_to_str (tuple.get_int (Tuple::Track)));
if (GET_INT("force_v2_val"))
id3tag_add_v2(gfp);
@@ -193,10 +124,12 @@ static bool mp3_open (VFSFile & file, const format_info & info, const Tuple & tu
lame_set_msgf(gfp, lame_debugf);
const int vbr_on = GET_INT("vbr_on");
- if (GET_INT("enc_toggle_val") == 0 && vbr_on == 0)
- lame_set_brate(gfp, GET_INT("bitrate_val"));
- else if (vbr_on == 0)
- lame_set_compression_ratio(gfp, GET_DOUBLE("compression_val"));
+ if (vbr_on == 0) {
+ if (GET_INT("enc_toggle_val") == 0)
+ lame_set_brate(gfp, GET_INT("bitrate_val"));
+ else
+ lame_set_compression_ratio(gfp, GET_DOUBLE("compression_val"));
+ }
/* frame params */
@@ -240,6 +173,7 @@ static bool mp3_open (VFSFile & file, const format_info & info, const Tuple & tu
}
channels = info.channels;
+ numsamples = 0;
return true;
}
@@ -314,717 +248,6 @@ static void mp3_close (VFSFile & file)
lame_close(gfp);
AUDDBG("lame_close() done\n");
-
- lameid3 = lameid3_t ();
- numsamples = 0;
-}
-
-/*****************/
-/* Configuration */
-/*****************/
-
-/* Various Signal-Fuctions */
-
-static void algo_qual(GtkAdjustment * adjustment, void * user_data)
-{
- SET_INT("algo_quality_val",
- gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(alg_quality_spin)));
-
-}
-
-static void samplerate_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo) - 1;
-
- if (i >= 0 && i < aud::n_elems (available_samplerates))
- SET_INT("out_samplerate_val", available_samplerates[i]);
- else
- SET_INT("out_samplerate_val", 0);
-}
-
-static void bitrate_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo);
-
- if (i >= 0 && i < aud::n_elems (available_bitrates))
- SET_INT("bitrate_val", available_bitrates[i]);
- else
- SET_INT("bitrate_val", 128);
-}
-
-static void compression_change(GtkAdjustment * adjustment,
- void * user_data)
-{
- SET_DOUBLE("compression_val",
- gtk_spin_button_get_value(GTK_SPIN_BUTTON(compression_spin)));
-}
-
-static void encoding_toggle(GtkToggleButton * togglebutton,
- void * user_data)
-{
- SET_INT("enc_toggle_val", GPOINTER_TO_INT(user_data));
-}
-
-static void mode_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo);
-
- if (i >= 0 && i < MODES)
- SET_INT("audio_mode_val", modes[i]);
- else
- SET_INT("audio_mode_val", NOT_SET);
-}
-
-static void toggle_enforce_iso(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(enforce_iso_toggle)))
- SET_INT("enforce_iso_val", 1);
- else
- SET_INT("enforce_iso_val", 0);
-}
-
-static void toggle_error_protect(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(error_protection_toggle)))
- SET_INT("error_protect_val", 1);
- else
- SET_INT("error_protect_val", 0);
-}
-
-static void toggle_vbr(GtkToggleButton * togglebutton, void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vbr_toggle)) ==
- true) {
- gtk_widget_set_sensitive(vbr_options_vbox, true);
- gtk_widget_set_sensitive(enc_quality_frame, false);
- SET_INT("vbr_on", 1);
-
- if (GET_INT("vbr_type") == 0) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (vbr_type_radio1), true);
- gtk_widget_set_sensitive(abr_frame, false);
- gtk_widget_set_sensitive(vbr_frame, true);
- }
- else {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (vbr_type_radio2), true);
- gtk_widget_set_sensitive(abr_frame, true);
- gtk_widget_set_sensitive(vbr_frame, false);
- }
-
- }
- else {
- gtk_widget_set_sensitive(vbr_options_vbox, false);
- gtk_widget_set_sensitive(enc_quality_frame, true);
- SET_INT("vbr_on", 0);
- }
-}
-
-static void vbr_abr_toggle(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (!strcmp((char *) user_data, "VBR")) {
- gtk_widget_set_sensitive(abr_frame, false);
- gtk_widget_set_sensitive(vbr_frame, true);
- SET_INT("vbr_type", 0);
- }
- else if (!strcmp((char *) user_data, "ABR")) {
- gtk_widget_set_sensitive(abr_frame, true);
- gtk_widget_set_sensitive(vbr_frame, false);
- SET_INT("vbr_type", 1);
- }
-}
-
-static void vbr_min_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo);
-
- if (i >= 0 && i < aud::n_elems (available_bitrates))
- SET_INT("vbr_min_val", available_bitrates[i]);
- else
- SET_INT("vbr_min_val", 32);
-}
-
-static void vbr_max_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo);
-
- if (i >= 0 && i < aud::n_elems (available_bitrates))
- SET_INT("vbr_max_val", available_bitrates[i]);
- else
- SET_INT("vbr_max_val", 320);
-}
-
-static void toggle_enforce_min(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(enforce_min_toggle)))
- SET_INT("enforce_min_val", 1);
- else
- SET_INT("enforce_min_val", 0);
-}
-
-static void vbr_qual(GtkAdjustment * adjustment, void * user_data)
-{
- SET_INT("vbr_quality_val",
- gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vbr_quality_spin)));
-}
-
-static void abr_changed (GtkComboBox * combo)
-{
- int i = gtk_combo_box_get_active (combo);
-
- if (i >= 0 && i < aud::n_elems (available_bitrates))
- SET_INT("abr_val", available_bitrates[i]);
- else
- SET_INT("abr_val", 128);
-}
-
-static void toggle_xing(GtkToggleButton * togglebutton, void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xing_header_toggle)))
- SET_INT("toggle_xing_val", 0);
- else
- SET_INT("toggle_xing_val", 1);
-}
-
-static void toggle_original(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_original_toggle)))
- SET_INT("mark_original_val", 1);
- else
- SET_INT("mark_original_val", 0);
-}
-
-static void toggle_copyright(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_copyright_toggle)))
- SET_INT("mark_copyright_val", 1);
- else
- SET_INT("mark_copyright_val", 0);
-}
-
-static void force_v2_toggle(GtkToggleButton * togglebutton,
- void * user_data)
-{
-
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_force_id3v2_toggle))) {
- SET_INT("force_v2_val", 1);
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_only_v1_toggle))) {
- inside = 1;
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tags_only_v1_toggle), false);
- SET_INT("only_v1_val", 0);
- inside = 0;
- }
- }
- else
- SET_INT("force_v2_val", 0);
-
-}
-
-static void id3_only_version(GtkToggleButton * togglebutton,
- void * user_data)
-{
- if (!strcmp((char *) user_data, "v1") && inside != 1) {
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_only_v1_toggle)))
- {
- inside = 1;
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tags_only_v2_toggle), false);
- SET_INT("only_v1_val", 1);
- SET_INT("only_v2_val", 0);
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tags_force_id3v2_toggle), false);
- inside = 0;
- }
- }
- else if (!strcmp((char *) user_data, "v2") && inside != 1) {
- if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tags_only_v2_toggle)))
- {
- inside = 1;
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tags_only_v1_toggle), false);
- SET_INT("only_v1_val", 0);
- SET_INT("only_v2_val", 1);
- inside = 0;
- }
- }
-
-}
-
-/************************/
-/* Configuration Widget */
-/************************/
-
-void * mp3_configure ()
-{
- notebook = gtk_notebook_new();
-
- /* Quality */
-
- quality_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(quality_vbox), 5);
-
- quality_hbox1 = gtk_hbox_new (false, 5);
- gtk_box_pack_start(GTK_BOX(quality_vbox), quality_hbox1, false, false, 0);
-
- /* Algorithm Quality */
-
- alg_quality_frame = gtk_frame_new(_("Algorithm Quality:"));
- gtk_box_pack_start(GTK_BOX(quality_hbox1), alg_quality_frame, true, true, 0);
-
- alg_quality_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(alg_quality_hbox), 5);
- gtk_container_add(GTK_CONTAINER(alg_quality_frame),
- alg_quality_hbox);
-
- alg_quality_adj = (GtkAdjustment *) gtk_adjustment_new (5, 0, 9, 1, 1, 0);
- alg_quality_spin =
- gtk_spin_button_new(GTK_ADJUSTMENT(alg_quality_adj), 8, 0);
- gtk_box_pack_start(GTK_BOX(alg_quality_hbox), alg_quality_spin, false, false, 0);
- g_signal_connect (alg_quality_adj, "value-changed", (GCallback)
- algo_qual, nullptr);
-
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(alg_quality_spin),
- GET_INT("algo_quality_val"));
-
- /* Output Samplerate */
-
- samplerate_frame = gtk_frame_new(_("Output Sample Rate:"));
- gtk_box_pack_start(GTK_BOX(quality_hbox1), samplerate_frame, true, true, 0);
-
- samplerate_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(samplerate_hbox), 5);
- gtk_container_add(GTK_CONTAINER(samplerate_frame),
- samplerate_hbox);
-
- GtkWidget * combo = gtk_combo_box_text_new ();
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo, _("Auto"));
-
- const int out_samplerate_val = GET_INT("out_samplerate_val");
- if (! out_samplerate_val)
- gtk_combo_box_set_active ((GtkComboBox *) combo, 0);
-
- for (int i = 0; i < aud::n_elems (available_samplerates); i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- int_to_str (available_samplerates[i]));
-
- if (out_samplerate_val == available_samplerates[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, 1 + i);
- }
-
- gtk_box_pack_start ((GtkBox *) samplerate_hbox, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) samplerate_changed, nullptr);
-
- samplerate_label = gtk_label_new(_("(Hz)"));
- gtk_misc_set_alignment(GTK_MISC(samplerate_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(samplerate_hbox), samplerate_label, false, false, 0);
-
- /* Encoder Quality */
-
- enc_quality_frame = gtk_frame_new(_("Bitrate / Compression Ratio:"));
- gtk_box_pack_start(GTK_BOX(quality_vbox), enc_quality_frame, false, false, 0);
-
- // vbox sorrounding hbox1 and hbox2
- enc_quality_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(enc_quality_vbox), 5);
-
- // pack vbox to frame
- gtk_container_add(GTK_CONTAINER(enc_quality_frame), enc_quality_vbox);
-
- // hbox1 for bitrate
- hbox1 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(enc_quality_vbox), hbox1);
-
- // radio 1
- enc_radio1 = gtk_radio_button_new(nullptr);
- gtk_box_pack_start(GTK_BOX(hbox1), enc_radio1, false, false, 0);
-
- // label 1
- enc_quality_label1 = gtk_label_new(_("Bitrate (kbps):"));
- gtk_box_pack_start(GTK_BOX(hbox1), enc_quality_label1, false, false, 0);
-
- // bitrate menu
-
- combo = gtk_combo_box_text_new ();
-
- const int bitrate_val = GET_INT("bitrate_val");
- for (int i = 0; i < aud::n_elems (available_bitrates); i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- int_to_str (available_bitrates[i]));
-
- if (bitrate_val == available_bitrates[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, i);
- }
-
- gtk_box_pack_start ((GtkBox *) hbox1, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) bitrate_changed, nullptr);
-
- // hbox2 for compression ratio
- hbox2 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(enc_quality_vbox), hbox2);
-
- // radio 2
- enc_radio2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(enc_radio1));
- gtk_box_pack_start(GTK_BOX(hbox2), enc_radio2, false, false, 0);
-
- // label
- enc_quality_label2 = gtk_label_new(_("Compression ratio:"));
- gtk_box_pack_start(GTK_BOX(hbox2), enc_quality_label2, false, false, 0);
-
- // comp-ratio spin
- compression_adj = (GtkAdjustment *) gtk_adjustment_new (11, 0, 100, 1, 1, 0);
- compression_spin =
- gtk_spin_button_new(GTK_ADJUSTMENT(compression_adj), 8, 0);
- gtk_box_pack_start(GTK_BOX(hbox2), compression_spin, false, false, 0);
-
- g_signal_connect (compression_adj, "value-changed", (GCallback)
- compression_change, nullptr);
-
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(compression_spin),
- GET_DOUBLE("compression_val"));
-
- if (GET_INT("enc_toggle_val") == 0)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enc_radio1), true);
- else
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enc_radio2), true);
-
- // radio button signale connect
- g_signal_connect (enc_radio1, "toggled", (GCallback) encoding_toggle,
- GINT_TO_POINTER (0));
- g_signal_connect (enc_radio2, "toggled", (GCallback) encoding_toggle,
- GINT_TO_POINTER (1));
-
- /* Audio Mode */
-
- mode_frame = gtk_frame_new(_("Audio Mode:"));
- gtk_box_pack_start(GTK_BOX(quality_vbox), mode_frame, false, false, 0);
-
- mode_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(mode_hbox), 5);
- gtk_container_add(GTK_CONTAINER(mode_frame), mode_hbox);
-
- combo = gtk_combo_box_text_new ();
-
- const int audio_mode_val = GET_INT("audio_mode_val");
- for (int i = 0; i < MODES; i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- _(mode_names[i]));
-
- if (audio_mode_val == modes[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, i);
- }
-
- gtk_box_pack_start ((GtkBox *) mode_hbox, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) mode_changed, nullptr);
-
- /* Misc */
-
- misc_frame = gtk_frame_new(_("Miscellaneous:"));
- gtk_box_pack_start(GTK_BOX(quality_vbox), misc_frame, false, false, 0);
-
- misc_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(misc_vbox), 5);
- gtk_container_add(GTK_CONTAINER(misc_frame), misc_vbox);
-
- enforce_iso_toggle =
- gtk_check_button_new_with_label
- (_("Enforce strict ISO compliance"));
- gtk_box_pack_start(GTK_BOX(misc_vbox), enforce_iso_toggle, true, true, 0);
- g_signal_connect (enforce_iso_toggle, "toggled", (GCallback)
- toggle_enforce_iso, nullptr);
-
- if (GET_INT("enforce_iso_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (enforce_iso_toggle), true);
-
- error_protection_toggle =
- gtk_check_button_new_with_label(_("Error protection"));
- gtk_box_pack_start(GTK_BOX(misc_vbox), error_protection_toggle, true, true, 0);
- g_signal_connect (error_protection_toggle, "toggled", (GCallback)
- toggle_error_protect, nullptr);
-
- if (GET_INT("error_protect_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (error_protection_toggle), true);
-
- /* Add the Notebook */
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), quality_vbox,
- gtk_label_new(_("Quality")));
-
- /* VBR/ABR */
-
- vbr_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(vbr_vbox), 5);
-
- /* Toggle VBR */
-
- vbr_toggle = gtk_check_button_new_with_label(_("Enable VBR/ABR"));
- gtk_box_pack_start(GTK_BOX(vbr_vbox), vbr_toggle, false, false, 0);
- g_signal_connect (vbr_toggle, "toggled", (GCallback) toggle_vbr, nullptr);
-
- vbr_options_vbox = gtk_vbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(vbr_vbox), vbr_options_vbox);
- gtk_widget_set_sensitive(vbr_options_vbox, false);
-
- /* Choose VBR/ABR */
-
- vbr_type_frame = gtk_frame_new(_("Type:"));
- gtk_box_pack_start(GTK_BOX(vbr_options_vbox), vbr_type_frame, false, false, 0);
-
- vbr_type_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(vbr_type_hbox), 5);
- gtk_container_add(GTK_CONTAINER(vbr_type_frame), vbr_type_hbox);
-
- vbr_type_radio1 = gtk_radio_button_new_with_label(nullptr, "VBR");
- gtk_box_pack_start(GTK_BOX(vbr_type_hbox), vbr_type_radio1, false, false, 0);
-
- vbr_type_radio2 =
- gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON
- (vbr_type_radio1),
- "ABR");
- gtk_box_pack_start(GTK_BOX(vbr_type_hbox), vbr_type_radio2, false, false, 0);
-
- if (GET_INT("vbr_type") == 0)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vbr_type_radio1), true);
- else
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vbr_type_radio2), true);
-
- g_signal_connect (vbr_type_radio1, "toggled", (GCallback)
- vbr_abr_toggle, (void *) "VBR");
- g_signal_connect (vbr_type_radio2, "toggled", (GCallback)
- vbr_abr_toggle, (void *) "ABR");
-
- /* VBR Options */
-
- vbr_frame = gtk_frame_new(_("VBR Options:"));
- gtk_box_pack_start(GTK_BOX(vbr_options_vbox), vbr_frame, false, false, 0);
-
- vbr_options_vbox2 = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(vbr_options_vbox2), 5);
- gtk_container_add(GTK_CONTAINER(vbr_frame), vbr_options_vbox2);
-
- vbr_options_hbox1 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(vbr_options_vbox2),
- vbr_options_hbox1);
-
- vbr_min_label = gtk_label_new(_("Minimum bitrate (kbps):"));
- gtk_misc_set_alignment(GTK_MISC(vbr_min_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(vbr_options_hbox1), vbr_min_label, false, false, 0);
-
- combo = gtk_combo_box_text_new ();
-
- const int vbr_min_val = GET_INT("vbr_min_val");
- for (int i = 0; i < aud::n_elems (available_bitrates); i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- int_to_str (available_bitrates[i]));
-
- if (vbr_min_val == available_bitrates[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, i);
- }
-
- gtk_box_pack_start ((GtkBox *) vbr_options_hbox1, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) vbr_min_changed, nullptr);
-
- vbr_options_hbox2 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(vbr_options_vbox2),
- vbr_options_hbox2);
-
- vbr_max_label = gtk_label_new(_("Maximum bitrate (kbps):"));
- gtk_misc_set_alignment(GTK_MISC(vbr_max_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(vbr_options_hbox2), vbr_max_label, false, false, 0);
-
- combo = gtk_combo_box_text_new ();
-
- const int vbr_max_val = GET_INT("vbr_max_val");
- for (int i = 0; i < aud::n_elems (available_bitrates); i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- int_to_str (available_bitrates[i]));
-
- if (vbr_max_val == available_bitrates[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, i);
- }
-
- gtk_box_pack_start ((GtkBox *) vbr_options_hbox2, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) vbr_max_changed, nullptr);
-
- enforce_min_toggle =
- gtk_check_button_new_with_label
- (_("Strictly enforce minimum bitrate"));
- gtk_box_pack_start(GTK_BOX(vbr_options_vbox2), enforce_min_toggle, false, false, 0);
- g_signal_connect (enforce_min_toggle, "toggled", (GCallback)
- toggle_enforce_min, nullptr);
-
- if (GET_INT("enforce_min_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (enforce_min_toggle), true);
-
- /* ABR Options */
-
- abr_frame = gtk_frame_new(_("ABR Options:"));
- gtk_box_pack_start(GTK_BOX(vbr_options_vbox), abr_frame, false, false, 0);
- gtk_widget_set_sensitive(abr_frame, false);
-
- abr_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(abr_hbox), 5);
- gtk_container_add(GTK_CONTAINER(abr_frame), abr_hbox);
-
- abr_label = gtk_label_new(_("Average bitrate (kbps):"));
- gtk_misc_set_alignment(GTK_MISC(abr_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(abr_hbox), abr_label, false, false, 0);
-
- combo = gtk_combo_box_text_new ();
-
- const int abr_val = GET_INT("abr_val");
- for (int i = 0; i < aud::n_elems (available_bitrates); i ++)
- {
- gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
- int_to_str (available_bitrates[i]));
-
- if (abr_val == available_bitrates[i])
- gtk_combo_box_set_active ((GtkComboBox *) combo, i);
- }
-
- gtk_box_pack_start ((GtkBox *) abr_hbox, combo, false, false, 0);
- g_signal_connect (combo, "changed", (GCallback) abr_changed, nullptr);
-
- /* Quality Level */
-
- vbr_options_hbox3 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(vbr_options_vbox),
- vbr_options_hbox3);
-
- vbr_quality_label = gtk_label_new(_("VBR quality level:"));
- gtk_misc_set_alignment(GTK_MISC(vbr_quality_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(vbr_options_hbox3), vbr_quality_label, false, false, 0);
-
- vbr_quality_adj = (GtkAdjustment *) gtk_adjustment_new (4, 0, 9, 1, 1, 0);
- vbr_quality_spin =
- gtk_spin_button_new(GTK_ADJUSTMENT(vbr_quality_adj), 8, 0);
- gtk_box_pack_start(GTK_BOX(vbr_options_hbox3), vbr_quality_spin, false, false, 0);
- g_signal_connect (vbr_quality_adj, "value-changed", (GCallback)
- vbr_qual, nullptr);
-
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(vbr_quality_spin),
- GET_INT("vbr_quality_val"));
-
- /* Xing Header */
-
- xing_header_toggle =
- gtk_check_button_new_with_label(_("Omit Xing VBR header"));
- gtk_box_pack_start(GTK_BOX(vbr_options_vbox), xing_header_toggle, false, false, 0);
- g_signal_connect (xing_header_toggle, "toggled", (GCallback)
- toggle_xing, nullptr);
-
- if (GET_INT("toggle_xing_val") == 0)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (xing_header_toggle), true);
-
- /* Add the Notebook */
-
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbr_vbox,
- gtk_label_new(_("VBR/ABR")));
-
- /* Tags */
-
- tags_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(tags_vbox), 5);
-
- /* Frame Params */
-
- tags_frames_frame = gtk_frame_new(_("Frame Parameters:"));
- gtk_box_pack_start(GTK_BOX(tags_vbox), tags_frames_frame, false, false, 0);
-
- tags_frames_hbox = gtk_hbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(tags_frames_hbox), 5);
- gtk_container_add(GTK_CONTAINER(tags_frames_frame),
- tags_frames_hbox);
-
- tags_copyright_toggle =
- gtk_check_button_new_with_label(_("Mark as copyright"));
- gtk_box_pack_start(GTK_BOX(tags_frames_hbox),
- tags_copyright_toggle, false, false, 0);
- g_signal_connect (tags_copyright_toggle, "toggled", (GCallback)
- toggle_copyright, nullptr);
-
- if (GET_INT("mark_copyright_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (tags_copyright_toggle), true);
-
- tags_original_toggle =
- gtk_check_button_new_with_label(_("Mark as original"));
- gtk_box_pack_start(GTK_BOX(tags_frames_hbox), tags_original_toggle, false, false, 0);
- g_signal_connect (tags_original_toggle, "toggled", (GCallback)
- toggle_original, nullptr);
-
- if (GET_INT("mark_original_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (tags_original_toggle), true);
-
- /* ID3 Params */
-
- tags_id3_frame = gtk_frame_new(_("ID3 Parameters:"));
- gtk_box_pack_start(GTK_BOX(tags_vbox), tags_id3_frame, false, false, 0);
-
- tags_id3_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(tags_id3_vbox), 5);
- gtk_container_add(GTK_CONTAINER(tags_id3_frame), tags_id3_vbox);
-
- tags_force_id3v2_toggle =
- gtk_check_button_new_with_label
- (_("Force addition of version 2 tag"));
- gtk_box_pack_start(GTK_BOX(tags_id3_vbox), tags_force_id3v2_toggle, false, false, 0);
- g_signal_connect (tags_force_id3v2_toggle, "toggled", (GCallback)
- force_v2_toggle, nullptr);
-
- tags_id3_hbox = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(tags_id3_vbox), tags_id3_hbox);
-
- tags_only_v1_toggle =
- gtk_check_button_new_with_label(_("Only add v1 tag"));
- gtk_box_pack_start(GTK_BOX(tags_id3_hbox), tags_only_v1_toggle, false, false, 0);
- g_signal_connect (tags_only_v1_toggle, "toggled", (GCallback)
- id3_only_version, (void *) "v1");
-
- tags_only_v2_toggle =
- gtk_check_button_new_with_label(_("Only add v2 tag"));
- gtk_box_pack_start(GTK_BOX(tags_id3_hbox), tags_only_v2_toggle, false, false, 0);
- g_signal_connect (tags_only_v2_toggle, "toggled", (GCallback)
- id3_only_version, (void *) "v2");
-
- if (GET_INT("force_v2_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (tags_force_id3v2_toggle), true);
-
- if (GET_INT("only_v1_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (tags_only_v1_toggle), true);
-
- if (GET_INT("only_v2_val") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
- (tags_only_v2_toggle), true);
-
- /* Add the Notebook */
-
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tags_vbox,
- gtk_label_new(_("Tags")));
-
- /* Set States */
-
- if (GET_INT("vbr_on") == 1)
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vbr_toggle),
- true);
- else
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vbr_toggle),
- false);
-
- return notebook;
}
static int mp3_format_required (int fmt)
diff --git a/src/filewriter/vorbis.cc b/src/filewriter/vorbis.cc
index e8d2107..bc086fb 100644
--- a/src/filewriter/vorbis.cc
+++ b/src/filewriter/vorbis.cc
@@ -25,7 +25,6 @@
#include <stdlib.h>
#include <vorbis/vorbisenc.h>
-#include <gtk/gtk.h>
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
@@ -44,8 +43,7 @@ static const char * const vorbis_defaults[] = {
"base_quality", "0.5",
nullptr};
-#define GET_DOUBLE(n) aud_get_double("filewriter_vorbis", n)
-#define SET_DOUBLE(n, v) aud_set_double("filewriter_vorbis", n, v)
+#define GET_DOUBLE(n) aud_get_double("filewriter_vorbis", n)
static int channels;
@@ -177,45 +175,6 @@ static void vorbis_close (VFSFile & file)
vorbis_info_clear(&vi);
}
-/* configuration stuff */
-static GtkWidget *quality_frame, *quality_vbox, *quality_hbox1, *quality_spin, *quality_label;
-static GtkAdjustment * quality_adj;
-
-static void quality_change(GtkAdjustment *adjustment, void * user_data)
-{
- SET_DOUBLE ("base_quality", gtk_spin_button_get_value ((GtkSpinButton *) quality_spin) / 10);
-}
-
-void * vorbis_configure ()
-{
- GtkWidget * vbox = gtk_vbox_new (false, 5);
-
- /* quality options */
- quality_frame = gtk_frame_new(_("Quality"));
- gtk_box_pack_start(GTK_BOX(vbox), quality_frame, false, false, 0);
-
- quality_vbox = gtk_vbox_new (false, 5);
- gtk_container_set_border_width(GTK_CONTAINER(quality_vbox), 5);
- gtk_container_add(GTK_CONTAINER(quality_frame), quality_vbox);
-
- /* quality option: vbr level */
- quality_hbox1 = gtk_hbox_new (false, 5);
- gtk_container_add(GTK_CONTAINER(quality_vbox), quality_hbox1);
-
- quality_label = gtk_label_new(_("Quality level (0 - 10):"));
- gtk_misc_set_alignment(GTK_MISC(quality_label), 0, 0.5);
- gtk_box_pack_start(GTK_BOX(quality_hbox1), quality_label, false, false, 0);
-
- quality_adj = (GtkAdjustment *) gtk_adjustment_new (5, 0, 10, 0.1, 1, 0);
- quality_spin = gtk_spin_button_new(GTK_ADJUSTMENT(quality_adj), 1, 2);
- gtk_box_pack_start(GTK_BOX(quality_hbox1), quality_spin, false, false, 0);
- g_signal_connect(G_OBJECT(quality_adj), "value-changed", G_CALLBACK(quality_change), nullptr);
-
- gtk_spin_button_set_value(GTK_SPIN_BUTTON(quality_spin), GET_DOUBLE("base_quality") * 10);
-
- return vbox;
-}
-
static int vorbis_format_required (int fmt)
{
return FMT_FLOAT;
diff --git a/src/flacng/Makefile b/src/flac/Makefile
index fb53a2b..fb53a2b 100644
--- a/src/flacng/Makefile
+++ b/src/flac/Makefile
diff --git a/src/flacng/flacng.h b/src/flac/flacng.h
index 1f1d9aa..5a755d8 100644
--- a/src/flacng/flacng.h
+++ b/src/flac/flacng.h
@@ -37,18 +37,15 @@ public:
about
};
- static constexpr auto iinfo = InputInfo(FlagWritesTag)
+ constexpr FLACng() : InputPlugin(info, InputInfo(FlagWritesTag)
.with_priority(1)
- .with_exts(exts);
-
- constexpr FLACng() : InputPlugin(info, iinfo) {}
+ .with_exts(exts)) {}
bool init();
void cleanup();
bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
- Index<char> read_image(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool write_tuple(const char *filename, VFSFile &file, const Tuple &tuple);
bool play(const char *filename, VFSFile &file);
};
diff --git a/src/flacng/metadata.cc b/src/flac/metadata.cc
index cb413bf..ee30d0d 100644
--- a/src/flacng/metadata.cc
+++ b/src/flac/metadata.cc
@@ -162,6 +162,7 @@ bool FLACng::write_tuple(const char *filename, VFSFile &file, const Tuple &tuple
insert_str_tuple_to_vc(vc_block, tuple, Tuple::Title, "TITLE");
insert_str_tuple_to_vc(vc_block, tuple, Tuple::Artist, "ARTIST");
insert_str_tuple_to_vc(vc_block, tuple, Tuple::Album, "ALBUM");
+ insert_str_tuple_to_vc(vc_block, tuple, Tuple::AlbumArtist, "ALBUMARTIST");
insert_str_tuple_to_vc(vc_block, tuple, Tuple::Genre, "GENRE");
insert_str_tuple_to_vc(vc_block, tuple, Tuple::Comment, "COMMENT");
@@ -187,55 +188,6 @@ ERR:
return false;
}
-Index<char> FLACng::read_image(const char *filename, VFSFile &file)
-{
- AUDDBG("Probe for song image.\n");
-
- FLAC__Metadata_Iterator *iter;
- FLAC__Metadata_Chain *chain;
- FLAC__StreamMetadata *metadata = nullptr;
- FLAC__Metadata_ChainStatus status;
-
- Index<char> data;
-
- chain = FLAC__metadata_chain_new();
-
- if (!FLAC__metadata_chain_read_with_callbacks(chain, &file, io_callbacks))
- goto ERR;
-
- iter = FLAC__metadata_iterator_new();
-
- FLAC__metadata_iterator_init(iter, chain);
-
- while (FLAC__metadata_iterator_next(iter))
- if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_PICTURE)
- break;
-
- if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_PICTURE)
- {
- metadata = FLAC__metadata_iterator_get_block(iter);
-
- if (metadata->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
- {
- AUDDBG("FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER found.");
- data.insert ((const char *) metadata->data.picture.data, 0,
- metadata->data.picture.data_length);
- }
- }
-
- FLAC__metadata_iterator_delete(iter);
- FLAC__metadata_chain_delete(chain);
-
- return data;
-
-ERR:
- status = FLAC__metadata_chain_status(chain);
- FLAC__metadata_chain_delete(chain);
-
- AUDERR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
- return data;
-}
-
static void add_text (Tuple & tuple, Tuple::Field field, const char * value)
{
String cur = tuple.get_str (field);
@@ -255,6 +207,7 @@ static void parse_comment (Tuple & tuple, const char * key, const char * value)
} tfields[] = {
{"ARTIST", Tuple::Artist},
{"ALBUM", Tuple::Album},
+ {"ALBUMARTIST", Tuple::AlbumArtist},
{"TITLE", Tuple::Title},
{"COMMENT", Tuple::Comment},
{"GENRE", Tuple::Genre}
@@ -283,11 +236,10 @@ static void parse_comment (Tuple & tuple, const char * key, const char * value)
tuple.set_gain(Tuple::AlbumPeak, Tuple::PeakDivisor, value);
}
-Tuple FLACng::read_tuple(const char *filename, VFSFile &file)
+bool FLACng::read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image)
{
AUDDBG("Probe for tuple.\n");
- Tuple tuple;
FLAC__Metadata_Iterator *iter;
FLAC__Metadata_Chain *chain;
FLAC__StreamMetadata *metadata = nullptr;
@@ -296,8 +248,6 @@ Tuple FLACng::read_tuple(const char *filename, VFSFile &file)
char *key;
char *value;
- tuple.set_filename (filename);
-
tuple.set_str (Tuple::Codec, "Free Lossless Audio Codec (FLAC)");
tuple.set_str (Tuple::Quality, _("lossless"));
@@ -315,29 +265,27 @@ Tuple FLACng::read_tuple(const char *filename, VFSFile &file)
switch (FLAC__metadata_iterator_get_block_type(iter))
{
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ {
+ metadata = FLAC__metadata_iterator_get_block(iter);
- if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT)
- {
- metadata = FLAC__metadata_iterator_get_block(iter);
-
- AUDDBG("Vorbis comment contains %d fields\n", metadata->data.vorbis_comment.num_comments);
- AUDDBG("Vendor string: %s\n", metadata->data.vorbis_comment.vendor_string.entry);
+ AUDDBG("Vorbis comment contains %d fields\n", metadata->data.vorbis_comment.num_comments);
+ AUDDBG("Vendor string: %s\n", metadata->data.vorbis_comment.vendor_string.entry);
- entry = metadata->data.vorbis_comment.comments;
+ entry = metadata->data.vorbis_comment.comments;
- for (unsigned i = 0; i < metadata->data.vorbis_comment.num_comments; i++, entry++)
+ for (unsigned i = 0; i < metadata->data.vorbis_comment.num_comments; i++, entry++)
+ {
+ if (FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value) == false)
+ AUDDBG("Could not parse comment\n");
+ else
{
- if (FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value) == false)
- AUDDBG("Could not parse comment\n");
- else
- {
- parse_comment(tuple, key, value);
- free(key);
- free(value);
- }
+ parse_comment(tuple, key, value);
+ free(key);
+ free(value);
}
}
break;
+ }
case FLAC__METADATA_TYPE_STREAMINFO:
{
@@ -370,6 +318,22 @@ Tuple FLACng::read_tuple(const char *filename, VFSFile &file)
break;
}
+ case FLAC__METADATA_TYPE_PICTURE:
+ {
+ if (image && !image->len())
+ {
+ metadata = FLAC__metadata_iterator_get_block(iter);
+
+ if (metadata->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+ {
+ AUDDBG("FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER found.");
+ image->insert((const char *) metadata->data.picture.data, 0,
+ metadata->data.picture.data_length);
+ }
+ }
+ break;
+ }
+
default:
;
}
@@ -378,12 +342,12 @@ Tuple FLACng::read_tuple(const char *filename, VFSFile &file)
FLAC__metadata_iterator_delete(iter);
FLAC__metadata_chain_delete(chain);
- return tuple;
+ return true;
ERR:
status = FLAC__metadata_chain_status(chain);
FLAC__metadata_chain_delete(chain);
AUDERR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]);
- return tuple;
+ return false;
}
diff --git a/src/flacng/plugin.cc b/src/flac/plugin.cc
index 444e2b4..444e2b4 100644
--- a/src/flacng/plugin.cc
+++ b/src/flac/plugin.cc
diff --git a/src/flacng/seekable_stream_callbacks.cc b/src/flac/seekable_stream_callbacks.cc
index 8b3e7aa..8b3e7aa 100644
--- a/src/flacng/seekable_stream_callbacks.cc
+++ b/src/flac/seekable_stream_callbacks.cc
diff --git a/src/flacng/tools.cc b/src/flac/tools.cc
index e5c1a23..e5c1a23 100644
--- a/src/flacng/tools.cc
+++ b/src/flac/tools.cc
diff --git a/src/gio/gio.cc b/src/gio/gio.cc
index 73f020e..c782663 100644
--- a/src/gio/gio.cc
+++ b/src/gio/gio.cc
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <gio/gio.h>
@@ -33,7 +34,7 @@ static const char gio_about[] =
N_("GIO Plugin for Audacious\n"
"Copyright 2009-2012 John Lindgren");
-static const char * const gio_schemes[] = {"ftp", "sftp", "smb"};
+static const char * const gio_schemes[] = {"ftp", "sftp", "smb", "mtp"};
class GIOTransport : public TransportPlugin
{
@@ -43,6 +44,8 @@ public:
constexpr GIOTransport () : TransportPlugin (info, gio_schemes) {}
VFSImpl * fopen (const char * path, const char * mode, String & error);
+ VFSFileTest test_file (const char * filename, VFSFileTest test, String & error);
+ Index<String> read_folder (const char * filename, String & error);
};
EXPORT GIOTransport aud_plugin_instance;
@@ -368,3 +371,80 @@ int GIOFile::fflush ()
FAILED:
return -1;
}
+
+VFSFileTest GIOTransport::test_file (const char * filename, VFSFileTest test, String & error)
+{
+ GFile * file = g_file_new_for_uri (filename);
+ Index<String> attrs;
+ int passed = 0;
+
+ if (test & (VFS_IS_REGULAR | VFS_IS_DIR))
+ attrs.append (G_FILE_ATTRIBUTE_STANDARD_TYPE);
+ if (test & VFS_IS_SYMLINK)
+ attrs.append (G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
+ if (test & VFS_IS_EXECUTABLE)
+ attrs.append (G_FILE_ATTRIBUTE_UNIX_MODE);
+
+ GError * gerr = nullptr;
+ GFileInfo * info = g_file_query_info (file, index_to_str_list (attrs, ","),
+ G_FILE_QUERY_INFO_NONE, nullptr, & gerr);
+
+ if (! info)
+ {
+ passed |= VFS_NO_ACCESS;
+ error = String (gerr->message);
+ g_error_free (gerr);
+ }
+ else
+ {
+ passed |= VFS_EXISTS;
+
+ switch (g_file_info_get_file_type (info))
+ {
+ case G_FILE_TYPE_REGULAR: passed |= VFS_IS_REGULAR; break;
+ case G_FILE_TYPE_DIRECTORY: passed |= VFS_IS_DIR; break;
+ default: break;
+ };
+
+ if (g_file_info_get_is_symlink (info))
+ passed |= VFS_IS_SYMLINK;
+ if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & S_IXUSR)
+ passed |= VFS_IS_EXECUTABLE;
+
+ g_object_unref (info);
+ }
+
+ g_object_unref (file);
+ return VFSFileTest (test & passed);
+}
+
+Index<String> GIOTransport::read_folder (const char * filename, String & error)
+{
+ GFile * file = g_file_new_for_uri (filename);
+ Index<String> files;
+
+ GError * gerr = nullptr;
+ GFileEnumerator * dir = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NONE, nullptr, & gerr);
+
+ if (! dir)
+ {
+ error = String (gerr->message);
+ g_error_free (gerr);
+ }
+ else
+ {
+ GFileInfo * info;
+ while ((info = g_file_enumerator_next_file (dir, nullptr, nullptr)))
+ {
+ StringBuf enc = str_encode_percent (g_file_info_get_name (info));
+ files.append (String (str_concat ({filename, "/", enc})));
+ g_object_unref (info);
+ }
+
+ g_object_unref (dir);
+ }
+
+ g_object_unref (file);
+ return files;
+}
diff --git a/src/gl-spectrum/Makefile b/src/glspectrum/Makefile
index 423054d..423054d 100644
--- a/src/gl-spectrum/Makefile
+++ b/src/glspectrum/Makefile
diff --git a/src/gl-spectrum/gl-spectrum.cc b/src/glspectrum/gl-spectrum.cc
index 2deb4af..a91f241 100644
--- a/src/gl-spectrum/gl-spectrum.cc
+++ b/src/glspectrum/gl-spectrum.cc
@@ -24,7 +24,6 @@
#include <math.h>
#include <string.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -62,7 +61,9 @@ public:
static constexpr PluginInfo info = {
N_("OpenGL Spectrum Analyzer"),
PACKAGE,
- gl_about
+ gl_about,
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr GLSpectrum () : VisPlugin (info, Visualizer::Freq) {}
diff --git a/src/gtkui/columns.cc b/src/gtkui/columns.cc
index 2e53c51..daf5eda 100644
--- a/src/gtkui/columns.cc
+++ b/src/gtkui/columns.cc
@@ -113,12 +113,12 @@ void pw_col_init ()
String widths = aud_get_str ("gtkui", "column_widths");
- if (! str_to_int_array (widths, pw_col_widths, PW_COLS))
- {
- int dpi = audgui_get_dpi ();
- for (int i = 0; i < PW_COLS; i ++)
- pw_col_widths[i] = pw_default_widths[i] * dpi / 96;
- }
+ int iwidths[PW_COLS];
+ bool valid = str_to_int_array (widths, iwidths, PW_COLS);
+ auto source = valid ? iwidths : pw_default_widths;
+
+ for (int i = 0; i < PW_COLS; i ++)
+ pw_col_widths[i] = audgui_to_native_dpi (source[i]);
}
struct Column {
@@ -350,6 +350,10 @@ void pw_col_save ()
for (int i = 0; i < pw_num_cols; i ++)
index.append (String (pw_col_keys[pw_cols[i]]));
+ int widths[PW_COLS];
+ for (int i = 0; i < PW_COLS; i ++)
+ widths[i] = audgui_to_portable_dpi (pw_col_widths[i]);
+
aud_set_str ("gtkui", "playlist_columns", index_to_str_list (index, " "));
- aud_set_str ("gtkui", "column_widths", int_array_to_str (pw_col_widths, PW_COLS));
+ aud_set_str ("gtkui", "column_widths", int_array_to_str (widths, PW_COLS));
}
diff --git a/src/gtkui/layout.cc b/src/gtkui/layout.cc
index 08220c6..40b60b9 100644
--- a/src/gtkui/layout.cc
+++ b/src/gtkui/layout.cc
@@ -568,9 +568,12 @@ void layout_save ()
snprintf (key, sizeof key, "item%d_name", i);
aud_set_str ("gtkui-layout", key, item->name);
+ int temp_w = audgui_to_portable_dpi (item->w);
+ int temp_h = audgui_to_portable_dpi (item->h);
+
snprintf (key, sizeof key, "item%d_pos", i);
snprintf (value, sizeof value, "%d,%d,%d,%d,%d", item->dock, item->x,
- item->y, item->w, item->h);
+ item->y, temp_w, temp_h);
aud_set_str ("gtkui-layout", key, value);
i ++;
@@ -593,9 +596,16 @@ void layout_load ()
String name = aud_get_str ("gtkui-layout", key);
Item * item = item_new (name);
+ int temp_w = 0, temp_h = 0;
+
snprintf (key, sizeof key, "item%d_pos", i);
String pos = aud_get_str ("gtkui-layout", key);
- sscanf (pos, "%d,%d,%d,%d,%d", & item->dock, & item->x, & item->y, & item->w, & item->h);
+ sscanf (pos, "%d,%d,%d,%d,%d", & item->dock, & item->x, & item->y, & temp_w, & temp_h);
+
+ if (temp_w)
+ item->w = audgui_to_native_dpi (temp_w);
+ if (temp_h)
+ item->h = audgui_to_native_dpi (temp_h);
}
}
diff --git a/src/gtkui/menus.cc b/src/gtkui/menus.cc
index 90d41fb..58e7414 100644
--- a/src/gtkui/menus.cc
+++ b/src/gtkui/menus.cc
@@ -36,6 +36,8 @@
#include "ui_playlist_notebook.h"
#include "ui_playlist_widget.h"
+#include "../ui-common/menu-ops.h"
+
#define SHIFT GDK_SHIFT_MASK
#define CTRL GDK_CONTROL_MASK
#define ALT GDK_MOD1_MASK
@@ -54,42 +56,8 @@ static void configure_effects () { audgui_show_prefs_for_plugin_type (PluginType
static void configure_output () { audgui_show_prefs_for_plugin_type (PluginType::Output); }
static void configure_visualizations () { audgui_show_prefs_for_plugin_type (PluginType::Vis); }
-static void pl_sort_track () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Track); }
-static void pl_sort_title () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void pl_sort_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Artist); }
-static void pl_sort_album () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Album); }
-static void pl_sort_album_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::AlbumArtist); }
-static void pl_sort_date () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Date); }
-static void pl_sort_genre () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Genre); }
-static void pl_sort_length () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Length); }
-static void pl_sort_path () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Path); }
-static void pl_sort_custom () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::FormattedTitle); }
-static void pl_reverse () { aud_playlist_reverse (aud_playlist_get_active ()); }
-static void pl_random () { aud_playlist_randomize (aud_playlist_get_active ()); }
-
-static void pl_sort_selected_track () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Track); }
-static void pl_sort_selected_title () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void pl_sort_selected_artist () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Artist); }
-static void pl_sort_selected_album () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Album); }
-static void pl_sort_selected_album_artist () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::AlbumArtist); }
-static void pl_sort_selected_date () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Date); }
-static void pl_sort_selected_genre () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Genre); }
-static void pl_sort_selected_length () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Length); }
-static void pl_sort_selected_path () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::Path); }
-static void pl_sort_selected_custom () { aud_playlist_sort_selected_by_scheme (aud_playlist_get_active (), Playlist::FormattedTitle); }
-static void pl_reverse_selected () { aud_playlist_reverse_selected (aud_playlist_get_active ()); }
-static void pl_random_selected () { aud_playlist_randomize_selected (aud_playlist_get_active ()); }
-
-static void pl_play () { aud_playlist_play (aud_playlist_get_active ()); }
-static void pl_refresh () { aud_playlist_rescan (aud_playlist_get_active ()); }
-static void pl_remove_failed () { aud_playlist_remove_failed (aud_playlist_get_active ()); }
-static void pl_remove_dupes_by_title () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void pl_remove_dupes_by_filename () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Filename); }
-static void pl_remove_dupes_by_path () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Path); }
static void pl_rename () { start_rename_playlist (aud_playlist_get_active ()); }
static void pl_close () { audgui_confirm_playlist_delete (aud_playlist_get_active ()); }
-static void pl_refresh_sel () { aud_playlist_rescan_selected (aud_playlist_get_active ()); }
-static void pl_select_all () { aud_playlist_select_all (aud_playlist_get_active (), true); }
static void pl_tab_play ()
{
@@ -115,9 +83,6 @@ static void pl_tab_close ()
static GtkWidget * get_services_main () { return audgui_get_plugin_menu (AudMenuID::Main); }
static GtkWidget * get_services_pl () { return audgui_get_plugin_menu (AudMenuID::Playlist); }
-static void volume_up () { aud_drct_set_volume_main (aud_drct_get_volume_main () + 5); }
-static void volume_down () { aud_drct_set_volume_main (aud_drct_get_volume_main () - 5); }
-
static void toggle_record ()
{
if (! aud_drct_enable_record (aud_get_bool ("gtkui", "record")))
@@ -163,41 +128,41 @@ static const AudguiMenuItem playback_items[] = {
};
static const AudguiMenuItem dupe_items[] = {
- MenuCommand (N_("By _Title"), nullptr, NONE, pl_remove_dupes_by_title),
- MenuCommand (N_("By _File Name"), nullptr, NONE, pl_remove_dupes_by_filename),
- MenuCommand (N_("By File _Path"), nullptr, NONE, pl_remove_dupes_by_path)
+ MenuCommand (N_("By _Title"), nullptr, NONE, rm_dupes_title),
+ MenuCommand (N_("By _File Name"), nullptr, NONE, rm_dupes_filename),
+ MenuCommand (N_("By File _Path"), nullptr, NONE, rm_dupes_path)
};
static const AudguiMenuItem sort_items[] = {
- MenuCommand (N_("By Track _Number"), nullptr, NONE, pl_sort_track),
- MenuCommand (N_("By _Title"), nullptr, NONE, pl_sort_title),
- MenuCommand (N_("By _Artist"), nullptr, NONE, pl_sort_artist),
- MenuCommand (N_("By Al_bum"), nullptr, NONE, pl_sort_album),
- MenuCommand (N_("By Albu_m Artist"), nullptr, NONE, pl_sort_album_artist),
- MenuCommand (N_("By Release _Date"), nullptr, NONE, pl_sort_date),
- MenuCommand (N_("By _Genre"), nullptr, NONE, pl_sort_genre),
- MenuCommand (N_("By _Length"), nullptr, NONE, pl_sort_length),
- MenuCommand (N_("By _File Path"), nullptr, NONE, pl_sort_path),
- MenuCommand (N_("By _Custom Title"), nullptr, NONE, pl_sort_custom),
+ MenuCommand (N_("By Track _Number"), nullptr, NONE, sort_track),
+ MenuCommand (N_("By _Title"), nullptr, NONE, sort_title),
+ MenuCommand (N_("By _Artist"), nullptr, NONE, sort_artist),
+ MenuCommand (N_("By Al_bum"), nullptr, NONE, sort_album),
+ MenuCommand (N_("By Albu_m Artist"), nullptr, NONE, sort_album_artist),
+ MenuCommand (N_("By Release _Date"), nullptr, NONE, sort_date),
+ MenuCommand (N_("By _Genre"), nullptr, NONE, sort_genre),
+ MenuCommand (N_("By _Length"), nullptr, NONE, sort_length),
+ MenuCommand (N_("By _File Path"), nullptr, NONE, sort_path),
+ MenuCommand (N_("By _Custom Title"), nullptr, NONE, sort_custom_title),
MenuSep (),
- MenuCommand (N_("R_everse Order"), "view-sort-descending", NONE, pl_reverse),
- MenuCommand (N_("_Random Order"), nullptr, NONE, pl_random)
+ MenuCommand (N_("R_everse Order"), "view-sort-descending", NONE, sort_reverse),
+ MenuCommand (N_("_Random Order"), nullptr, NONE, sort_random)
};
-static const AudguiMenuItem sort_selected_items[] = {
- MenuCommand (N_("By Track _Number"), nullptr, NONE, pl_sort_selected_track),
- MenuCommand (N_("By _Title"), nullptr, NONE, pl_sort_selected_title),
- MenuCommand (N_("By _Artist"), nullptr, NONE, pl_sort_selected_artist),
- MenuCommand (N_("By Al_bum"), nullptr, NONE, pl_sort_selected_album),
- MenuCommand (N_("By Albu_m Artist"), nullptr, NONE, pl_sort_selected_album_artist),
- MenuCommand (N_("By Release _Date"), nullptr, NONE, pl_sort_selected_date),
- MenuCommand (N_("By _Genre"), nullptr, NONE, pl_sort_selected_genre),
- MenuCommand (N_("By _Length"), nullptr, NONE, pl_sort_selected_length),
- MenuCommand (N_("By _File Path"), nullptr, NONE, pl_sort_selected_path),
- MenuCommand (N_("By _Custom Title"), nullptr, NONE, pl_sort_selected_custom),
+static const AudguiMenuItem sort_sel_items[] = {
+ MenuCommand (N_("By Track _Number"), nullptr, NONE, sort_sel_track),
+ MenuCommand (N_("By _Title"), nullptr, NONE, sort_sel_title),
+ MenuCommand (N_("By _Artist"), nullptr, NONE, sort_sel_artist),
+ MenuCommand (N_("By Al_bum"), nullptr, NONE, sort_sel_album),
+ MenuCommand (N_("By Albu_m Artist"), nullptr, NONE, sort_sel_album_artist),
+ MenuCommand (N_("By Release _Date"), nullptr, NONE, sort_sel_date),
+ MenuCommand (N_("By _Genre"), nullptr, NONE, sort_sel_genre),
+ MenuCommand (N_("By _Length"), nullptr, NONE, sort_sel_length),
+ MenuCommand (N_("By _File Path"), nullptr, NONE, sort_sel_path),
+ MenuCommand (N_("By _Custom Title"), nullptr, NONE, sort_sel_custom_title),
MenuSep (),
- MenuCommand (N_("R_everse Order"), "view-sort-descending", NONE, pl_reverse_selected),
- MenuCommand (N_("_Random Order"), nullptr, NONE, pl_random_selected)
+ MenuCommand (N_("R_everse Order"), "view-sort-descending", NONE, sort_sel_reverse),
+ MenuCommand (N_("_Random Order"), nullptr, NONE, sort_sel_random)
};
static const AudguiMenuItem playlist_items[] = {
@@ -205,7 +170,7 @@ static const AudguiMenuItem playlist_items[] = {
MenuCommand (N_("_Refresh"), "view-refresh", GDK_KEY_F5, (GdkModifierType) 0, pl_refresh),
MenuSep (),
MenuSub (N_("_Sort"), "view-sort-ascending", {sort_items}),
- MenuSub (N_("Sort Se_lected"), "view-sort-ascending", {sort_selected_items}),
+ MenuSub (N_("Sort Se_lected"), "view-sort-ascending", {sort_sel_items}),
MenuSub (N_("Remove _Duplicates"), "edit-copy", {dupe_items}),
MenuCommand (N_("Remove _Unavailable Files"), "dialog-warning", NONE, pl_remove_failed),
MenuSep (),
@@ -252,15 +217,16 @@ static const AudguiMenuItem main_items[] = {
};
static const AudguiMenuItem rclick_items[] = {
- MenuCommand (N_("Song _Info ..."), "dialog-information", 'i', ALT, playlist_song_info),
- MenuCommand (N_("_Queue/Unqueue"), nullptr, 'q', ALT, playlist_queue_toggle),
+ MenuCommand (N_("Song _Info ..."), "dialog-information", 'i', ALT, pl_song_info),
+ MenuCommand (N_("_Queue/Unqueue"), nullptr, 'q', ALT, pl_queue_toggle),
MenuSep (),
- MenuCommand (N_("_Open Containing Folder"), "folder", NONE, playlist_open_folder),
- MenuCommand (N_("_Refresh"), "view-refresh", GDK_KEY_F6, (GdkModifierType) 0, pl_refresh_sel),
+ MenuCommand (N_("_Open Containing Folder"), "folder", NONE, pl_open_folder),
+ MenuCommand (N_("_Refresh Selected"), "view-refresh", GDK_KEY_F6, (GdkModifierType) 0, pl_refresh_sel),
MenuSep (),
- MenuCommand (N_("Cu_t"), "edit-cut", NONE, playlist_cut),
- MenuCommand (N_("_Copy"), "edit-copy", NONE, playlist_copy),
- MenuCommand (N_("_Paste"), "edit-paste", NONE, playlist_paste),
+ MenuCommand (N_("Cu_t"), "edit-cut", NONE, pl_cut),
+ MenuCommand (N_("_Copy"), "edit-copy", NONE, pl_copy),
+ MenuCommand (N_("_Paste"), "edit-paste", NONE, pl_paste),
+ MenuCommand (N_("Paste at _End"), "edit-paste", 'v', SHIFT_CTRL, pl_paste_end),
MenuCommand (N_("Select _All"), "edit-select-all", NONE, pl_select_all),
MenuSep (),
MenuSub (N_("_Services"), nullptr, get_services_pl)
diff --git a/src/gtkui/playlist_util.cc b/src/gtkui/playlist_util.cc
index 42d1c6a..05f5587 100644
--- a/src/gtkui/playlist_util.cc
+++ b/src/gtkui/playlist_util.cc
@@ -29,6 +29,8 @@
#include "playlist_util.h"
#include "ui_playlist_notebook.h"
+#include "../ui-common/menu-ops.h"
+
GtkWidget * playlist_get_treeview (int playlist)
{
GtkWidget * page = gtk_notebook_get_nth_page (UI_PLAYLIST_NOTEBOOK, playlist);
@@ -52,100 +54,6 @@ int playlist_count_selected_in_range (int list, int top, int length)
return selected;
}
-void playlist_song_info ()
-{
- int list = aud_playlist_get_active ();
- int focus = aud_playlist_get_focus (list);
-
- if (focus < 0)
- return;
-
- audgui_infowin_show (list, focus);
-}
-
-void playlist_open_folder ()
-{
- int list = aud_playlist_get_active ();
- int focus = aud_playlist_get_focus (list);
-
- String filename = aud_playlist_entry_get_filename (list, focus);
- if (! filename)
- return;
-
- const char * slash = strrchr (filename, '/');
- if (! slash)
- return;
-
- /* don't trim trailing slash, it may be important */
- StringBuf folder = str_copy (filename, slash + 1 - filename);
-
- GError * error = nullptr;
- gtk_show_uri (gdk_screen_get_default (), folder, GDK_CURRENT_TIME, & error);
-
- if (error)
- {
- aud_ui_show_error (error->message);
- g_error_free (error);
- }
-}
-
-void playlist_queue_toggle ()
-{
- int list = aud_playlist_get_active ();
- int focus = aud_playlist_get_focus (list);
-
- if (focus < 0)
- return;
-
- /* make sure focused row is selected */
- if (! aud_playlist_entry_get_selected (list, focus))
- {
- aud_playlist_select_all (list, false);
- aud_playlist_entry_set_selected (list, focus, true);
- }
-
- int at = aud_playlist_queue_find_entry (list, focus);
-
- if (at < 0)
- aud_playlist_queue_insert_selected (list, -1);
- else
- aud_playlist_queue_delete_selected (list);
-}
-
-void playlist_delete_selected ()
-{
- int list = aud_playlist_get_active ();
- aud_playlist_delete_selected (list);
- aud_playlist_entry_set_selected (list, aud_playlist_get_focus (list), true);
-}
-
-void playlist_copy ()
-{
- Index<char> text = audgui_urilist_create_from_selected (aud_playlist_get_active ());
- if (! text.len ())
- return;
-
- gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), text.begin (), text.len ());
-}
-
-void playlist_cut ()
-{
- playlist_copy ();
- playlist_delete_selected ();
-}
-
-void playlist_paste ()
-{
- char * text = gtk_clipboard_wait_for_text (gtk_clipboard_get
- (GDK_SELECTION_CLIPBOARD));
- if (! text)
- return;
-
- int list = aud_playlist_get_active ();
- audgui_urilist_insert (list, aud_playlist_get_focus (list), text);
- g_free (text);
-}
-
void playlist_shift (int offset)
{
int list = aud_playlist_get_active ();
diff --git a/src/gtkui/playlist_util.h b/src/gtkui/playlist_util.h
index b13b1f5..66ce5cb 100644
--- a/src/gtkui/playlist_util.h
+++ b/src/gtkui/playlist_util.h
@@ -23,13 +23,6 @@
GtkWidget * playlist_get_treeview (int playlist);
int playlist_count_selected_in_range (int list, int top, int length);
-void playlist_song_info ();
-void playlist_open_folder ();
-void playlist_queue_toggle ();
-void playlist_delete_selected ();
-void playlist_copy ();
-void playlist_cut ();
-void playlist_paste ();
void playlist_shift (int offset);
#endif
diff --git a/src/gtkui/ui_gtk.cc b/src/gtkui/ui_gtk.cc
index 7b3f8de..e823f91 100644
--- a/src/gtkui/ui_gtk.cc
+++ b/src/gtkui/ui_gtk.cc
@@ -22,7 +22,6 @@
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/drct.h>
#include <libaudcore/hook.h>
@@ -43,6 +42,9 @@
#include "ui_statusbar.h"
#include "playlist_util.h"
+#include "../ui-common/menu-ops.cc"
+#include "../ui-common/menu-ops-gtk.cc"
+
static const char * const gtkui_defaults[] = {
"infoarea_show_vis", "TRUE",
"infoarea_visible", "TRUE",
@@ -61,6 +63,8 @@ static const char * const gtkui_defaults[] = {
"player_x", "-1000",
"player_y", "-1000",
+ "player_width", "768",
+ "player_height", "480",
nullptr
};
@@ -72,7 +76,8 @@ public:
N_("GTK Interface"),
PACKAGE,
nullptr,
- & gtkui_prefs
+ & gtkui_prefs,
+ PluginGLibOnly
};
constexpr GtkUI () : IfacePlugin (info) {}
@@ -106,6 +111,9 @@ public:
{ audgui_plugin_menu_add (id, func, name, icon); }
void plugin_menu_remove (AudMenuID id, void func ())
{ audgui_plugin_menu_remove (id, func); }
+
+ void startup_notify (const char * id)
+ { gdk_notify_startup_complete_with_id (id); }
};
EXPORT GtkUI aud_plugin_instance;
@@ -137,22 +145,16 @@ static void save_window_size ()
aud_set_int ("gtkui", "player_x", x);
aud_set_int ("gtkui", "player_y", y);
- aud_set_int ("gtkui", "player_width", w);
- aud_set_int ("gtkui", "player_height", h);
+ aud_set_int ("gtkui", "player_width", audgui_to_portable_dpi (w));
+ aud_set_int ("gtkui", "player_height", audgui_to_portable_dpi (h));
}
static void restore_window_size ()
{
- int dpi = audgui_get_dpi ();
int x = aud_get_int ("gtkui", "player_x");
int y = aud_get_int ("gtkui", "player_y");
- int w = aud_get_int ("gtkui", "player_width");
- int h = aud_get_int ("gtkui", "player_height");
-
- if (w < 1)
- w = 8 * dpi;
- if (h < 1)
- h = 5 * dpi;
+ int w = audgui_to_native_dpi (aud_get_int ("gtkui", "player_width"));
+ int h = audgui_to_native_dpi (aud_get_int ("gtkui", "player_height"));
gtk_window_set_default_size ((GtkWindow *) window, w, h);
@@ -214,19 +216,23 @@ static void title_change (void * = nullptr)
{
delayed_title_change.stop ();
+ StringBuf title;
+
if (aud_drct_get_playing ())
{
if (aud_drct_get_ready ())
- {
- String title = aud_drct_get_title ();
- gtk_window_set_title ((GtkWindow *) window,
- str_printf (_("%s - Audacious"), (const char *) title));
- }
+ title.steal (str_printf (_("%s - Audacious"), (const char *) aud_drct_get_title ()));
else
- gtk_window_set_title ((GtkWindow *) window, _("Buffering ..."));
+ title.steal (str_copy (_("Buffering ...")));
}
else
- gtk_window_set_title ((GtkWindow *) window, _("Audacious"));
+ title.steal (str_copy (_("Audacious")));
+
+ int instance = aud_get_instance ();
+ if (instance != 1)
+ title.combine (str_printf (" (%d)", instance));
+
+ gtk_window_set_title ((GtkWindow *) window, title);
}
void GtkUI::show (bool show)
@@ -334,11 +340,20 @@ static gboolean ui_slider_change_value_cb (GtkRange * range,
return false;
}
+/* return an object property if it exists, otherwise false */
+static bool get_boolean_prop (void * obj, const char * prop)
+{
+ gboolean value = false;
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), prop))
+ g_object_get (obj, prop, & value, nullptr);
+
+ return value;
+}
+
static gboolean ui_slider_button_press_cb (GtkWidget * widget, GdkEventButton * event)
{
- gboolean primary_warps = false;
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-primary-button-warps-slider", & primary_warps, nullptr);
+ bool primary_warps = get_boolean_prop (gtk_widget_get_settings (widget),
+ "gtk-primary-button-warps-slider");
if (event->button == 1 && ! primary_warps)
event->button = 2;
@@ -349,9 +364,8 @@ static gboolean ui_slider_button_press_cb (GtkWidget * widget, GdkEventButton *
static gboolean ui_slider_button_release_cb (GtkWidget * widget, GdkEventButton * event)
{
- gboolean primary_warps = false;
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-primary-button-warps-slider", & primary_warps, nullptr);
+ bool primary_warps = get_boolean_prop (gtk_widget_get_settings (widget),
+ "gtk-primary-button-warps-slider");
if (event->button == 1 && ! primary_warps)
event->button = 2;
@@ -538,8 +552,7 @@ static gboolean window_keypress_cb (GtkWidget * widget, GdkEventKey * event)
{
case GDK_KEY_ISO_Left_Tab:
case GDK_KEY_Tab:
- aud_playlist_set_active ((aud_playlist_get_active () + 1) %
- aud_playlist_count ());
+ pl_next ();
break;
default:
@@ -551,8 +564,7 @@ static gboolean window_keypress_cb (GtkWidget * widget, GdkEventKey * event)
{
case GDK_KEY_ISO_Left_Tab:
case GDK_KEY_Tab:
- aud_playlist_set_active (aud_playlist_get_active () ?
- aud_playlist_get_active () - 1 : aud_playlist_count () - 1);
+ pl_prev ();
break;
default:
return false;
@@ -590,7 +602,7 @@ static gboolean playlist_keypress_cb (GtkWidget * widget, GdkEventKey * event)
ui_playlist_notebook_position (aud::to_ptr (aud_playlist_get_active ()), nullptr);
return true;
case GDK_KEY_Delete:
- playlist_delete_selected ();
+ pl_remove_selected ();
return true;
case GDK_KEY_Menu:
popup_menu_rclick (0, event->time);
@@ -602,16 +614,16 @@ static gboolean playlist_keypress_cb (GtkWidget * widget, GdkEventKey * event)
switch (event->keyval)
{
case 'x':
- playlist_cut ();
+ pl_cut ();
return true;
case 'c':
- playlist_copy ();
+ pl_copy ();
return true;
case 'v':
- playlist_paste ();
+ pl_paste ();
return true;
case 'a':
- aud_playlist_select_all (aud_playlist_get_active (), true);
+ pl_select_all ();
return true;
}
diff --git a/src/gtkui/ui_infoarea.cc b/src/gtkui/ui_infoarea.cc
index 012349f..3125091 100644
--- a/src/gtkui/ui_infoarea.cc
+++ b/src/gtkui/ui_infoarea.cc
@@ -248,7 +248,7 @@ static void get_color (GtkWidget * widget, int i, float * r, float * g, float *
rgb_to_hsv (c->red / 65535.0, c->green / 65535.0, c->blue / 65535.0, & h, & s, & v);
if (s < 0.1) /* monochrome theme? use blue instead */
- h = 5;
+ h = 4.6;
s = 1 - 0.9 * i / (VIS_BANDS - 1);
v = 0.75 + 0.25 * i / (VIS_BANDS - 1);
diff --git a/src/gtkui/ui_playlist_widget.cc b/src/gtkui/ui_playlist_widget.cc
index 6c58192..9307c6f 100644
--- a/src/gtkui/ui_playlist_widget.cc
+++ b/src/gtkui/ui_playlist_widget.cc
@@ -95,7 +95,7 @@ struct PlaylistWidgetData {
static void set_int_from_tuple (GValue * value, const Tuple & tuple, Tuple::Field field)
{
- int i = tuple ? tuple.get_int (field) : 0;
+ int i = tuple.get_int (field);
if (i > 0)
g_value_take_string (value, g_strdup_printf ("%d", i));
else
@@ -104,8 +104,7 @@ static void set_int_from_tuple (GValue * value, const Tuple & tuple, Tuple::Fiel
static void set_string_from_tuple (GValue * value, const Tuple & tuple, Tuple::Field field)
{
- String str = tuple ? tuple.get_str (field) : String ();
- g_value_set_string (value, str);
+ g_value_set_string (value, tuple.get_str (field));
}
static void set_queued (GValue * value, int list, int row)
@@ -150,7 +149,7 @@ static void get_value (void * user, int row, int column, GValue * value)
case PW_COL_PATH:
case PW_COL_CUSTOM:
case PW_COL_BITRATE:
- tuple = aud_playlist_entry_get_tuple (data->list, row, Playlist::Guess);
+ tuple = aud_playlist_entry_get_tuple (data->list, row, Playlist::NoWait);
break;
}
@@ -293,10 +292,11 @@ static Index<char> get_data (void * user)
return audgui_urilist_create_from_selected (playlist);
}
-static void receive_data (void * user, int row, const char * data, int length)
+// length is ignored; GtkSelectionData null-terminates the data for us
+static void receive_data (void * user, int row, const char * data, int /*length*/)
{
int playlist = ((PlaylistWidgetData *) user)->list;
- audgui_urilist_insert (playlist, row, str_copy (data, length));
+ audgui_urilist_insert (playlist, row, data);
}
static const AudguiListCallbacks callbacks = {
diff --git a/src/hotkey/plugin.cc b/src/hotkey/plugin.cc
index 1ea4a1a..b08975f 100644
--- a/src/hotkey/plugin.cc
+++ b/src/hotkey/plugin.cc
@@ -41,7 +41,6 @@
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
@@ -62,7 +61,8 @@ public:
N_("Global Hotkeys"),
PACKAGE,
about,
- & hotkey_prefs
+ & hotkey_prefs,
+ PluginGLibOnly
};
constexpr GlobalHotkeys () : GeneralPlugin (info, false) {}
diff --git a/src/jack-ng/Makefile b/src/jack/Makefile
index f2f5491..f2f5491 100644
--- a/src/jack-ng/Makefile
+++ b/src/jack/Makefile
diff --git a/src/jack-ng/jack-ng.cc b/src/jack/jack-ng.cc
index ed62cbb..242ab9e 100644
--- a/src/jack-ng/jack-ng.cc
+++ b/src/jack/jack-ng.cc
@@ -62,7 +62,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume v);
- bool open_audio (int format, int rate, int channels);
+ bool open_audio (int format, int rate, int channels, String & error);
void close_audio ();
void period_wait ();
@@ -75,7 +75,7 @@ public:
void flush ();
private:
- bool connect_ports (int channels);
+ bool connect_ports (int channels, String & error);
void generate (jack_nframes_t frames);
static void error_cb (const char * error)
@@ -135,7 +135,7 @@ StereoVolume JACKOutput::get_volume ()
return {aud_get_int ("jack", "volume_left"), aud_get_int ("jack", "volume_right")};
}
-bool JACKOutput::connect_ports (int channels)
+bool JACKOutput::connect_ports (int channels, String & error)
{
bool success = false;
const char * * ports = nullptr;
@@ -153,7 +153,7 @@ bool JACKOutput::connect_ports (int channels)
if (count < channels)
{
- aud_ui_show_error (str_printf (_("Only %d JACK output ports were "
+ error = String (str_printf (_("Only %d JACK output ports were "
"found but %d are required."), count, channels));
goto fail;
}
@@ -169,7 +169,7 @@ bool JACKOutput::connect_ports (int channels)
{
if (jack_connect (m_client, jack_port_name (m_ports[i % channels]), ports[i]) != 0)
{
- aud_ui_show_error (str_printf (_("Failed to connect to JACK port %s."), ports[i]));
+ error = String (str_printf (_("Failed to connect to JACK port %s."), ports[i]));
goto fail;
}
}
@@ -183,13 +183,13 @@ fail:
return success;
}
-bool JACKOutput::open_audio (int format, int rate, int channels)
+bool JACKOutput::open_audio (int format, int rate, int channels, String & error)
{
int buffer_time;
if (format != FMT_FLOAT)
{
- aud_ui_show_error (_("JACK supports only floating-point audio. You "
+ error = String (_("JACK supports only floating-point audio. You "
"must change the output bit depth to floating-point in Audacious "
"settings."));
return false;
@@ -202,7 +202,7 @@ bool JACKOutput::open_audio (int format, int rate, int channels)
if (! (m_client = jack_client_open ("audacious", JackNoStartServer, nullptr)))
{
- aud_ui_show_error (_("Failed to connect to the JACK server; is it running?"));
+ error = String (_("Failed to connect to the JACK server; is it running?"));
goto fail;
}
@@ -239,7 +239,7 @@ bool JACKOutput::open_audio (int format, int rate, int channels)
if (aud_get_bool ("jack", "auto_connect"))
{
- if (! connect_ports (channels))
+ if (! connect_ports (channels, error))
goto fail;
}
diff --git a/src/lyricwiki-qt/lyricwiki.cc b/src/lyricwiki-qt/lyricwiki.cc
index a87a100..cf140d2 100644
--- a/src/lyricwiki-qt/lyricwiki.cc
+++ b/src/lyricwiki-qt/lyricwiki.cc
@@ -33,7 +33,6 @@
#include <libxml/HTMLparser.h>
#include <libxml/xpath.h>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -67,7 +66,10 @@ class LyricWikiQt : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("LyricWiki Plugin"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr LyricWikiQt () : GeneralPlugin (info, false) {}
diff --git a/src/lyricwiki/lyricwiki.cc b/src/lyricwiki/lyricwiki.cc
index 3ef5dab..8fa8361 100644
--- a/src/lyricwiki/lyricwiki.cc
+++ b/src/lyricwiki/lyricwiki.cc
@@ -26,7 +26,6 @@
#include <libxml/HTMLparser.h>
#include <libxml/xpath.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -40,7 +39,10 @@ class LyricWiki : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("LyricWiki Plugin"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr LyricWiki () : GeneralPlugin (info, false) {}
diff --git a/src/metronom/metronom.cc b/src/metronom/metronom.cc
index 0effedd..458442f 100644
--- a/src/metronom/metronom.cc
+++ b/src/metronom/metronom.cc
@@ -46,13 +46,11 @@ public:
about
};
- static constexpr auto iinfo = InputInfo()
- .with_schemes(schemes);
-
- constexpr Metronome() : InputPlugin(info, iinfo) {}
+ constexpr Metronome() : InputPlugin(info, InputInfo()
+ .with_schemes(schemes)) {}
bool is_our_file(const char *filename, VFSFile &);
- Tuple read_tuple(const char *filename, VFSFile &);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool play(const char *filename, VFSFile &);
};
@@ -220,17 +218,16 @@ bool Metronome::play (const char * filename, VFSFile &)
return true;
}
-Tuple Metronome::read_tuple(const char *filename, VFSFile &)
+bool Metronome::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple tuple;
metronom_t metronom;
String desc;
- tuple.set_filename (filename);
- if (metronom_get_cp(filename, &metronom, desc))
- tuple.set_str (Tuple::Title, desc);
+ if (!metronom_get_cp(filename, &metronom, desc))
+ return false;
- return tuple;
+ tuple.set_str(Tuple::Title, desc);
+ return true;
}
const char Metronome::about[] =
diff --git a/src/modplug/modplugbmp.cc b/src/modplug/modplugbmp.cc
index 8fd269c..338f92a 100644
--- a/src/modplug/modplugbmp.cc
+++ b/src/modplug/modplugbmp.cc
@@ -273,10 +273,6 @@ bool ModplugXMMS::play (const char * filename, VFSFile & file)
mArchive->Size()
);
- Tuple ti = read_tuple (filename, file);
- if (ti)
- set_playback_tuple (std::move (ti));
-
set_stream_bitrate(mSoundFile->GetNumChannels() * 1000);
int fmt = (mModProps.mBits == 16) ? FMT_S16_NE : FMT_U8;
@@ -294,7 +290,8 @@ bool ModplugXMMS::play (const char * filename, VFSFile & file)
return true;
}
-Tuple ModplugXMMS::read_tuple (const char * filename, VFSFile & file)
+bool ModplugXMMS::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
CSoundFile* lSoundFile;
Archive* lArchive;
@@ -305,12 +302,9 @@ Tuple ModplugXMMS::read_tuple (const char * filename, VFSFile & file)
if(lArchive->Size() == 0)
{
delete lArchive;
- return Tuple ();
+ return false;
}
- Tuple ti;
- ti.set_filename (filename);
-
lSoundFile = new CSoundFile;
lSoundFile->Create((unsigned char*)lArchive->Map(), lArchive->Size());
@@ -339,22 +333,22 @@ Tuple ModplugXMMS::read_tuple (const char * filename, VFSFile & file)
case MOD_TYPE_PSM: tmps = "Protracker Studio Module"; break;
default: tmps = "ModPlug unknown"; break;
}
- ti.set_str (Tuple::Codec, tmps);
- ti.set_str (Tuple::Quality, _("sequenced"));
- ti.set_int (Tuple::Length, lSoundFile->GetSongTime() * 1000);
+ tuple.set_str (Tuple::Codec, tmps);
+ tuple.set_str (Tuple::Quality, _("sequenced"));
+ tuple.set_int (Tuple::Length, lSoundFile->GetSongTime() * 1000);
const char *tmps2 = lSoundFile->GetTitle();
// Chop any leading spaces off. They are annoying in the playlist.
while (tmps2[0] == ' ')
tmps2++;
if (tmps2[0])
- ti.set_str(Tuple::Title, tmps2);
+ tuple.set_str(Tuple::Title, tmps2);
//unload the file
lSoundFile->Destroy();
delete lSoundFile;
delete lArchive;
- return ti;
+ return true;
}
void ModplugXMMS::apply_settings ()
diff --git a/src/modplug/modplugbmp.h b/src/modplug/modplugbmp.h
index e2c4d3c..6ecfeb1 100644
--- a/src/modplug/modplugbmp.h
+++ b/src/modplug/modplugbmp.h
@@ -60,15 +60,13 @@ public:
& prefs
};
- static constexpr auto iinfo = InputInfo (FlagSubtunes)
- .with_exts (exts);
-
- constexpr ModplugXMMS () : InputPlugin (info, iinfo) {}
+ constexpr ModplugXMMS () : InputPlugin (info, InputInfo (FlagSubtunes)
+ .with_exts (exts)) {}
bool init ();
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
private:
diff --git a/src/mpg123/mpg123.cc b/src/mpg123/mpg123.cc
index 2855356..874574c 100644
--- a/src/mpg123/mpg123.cc
+++ b/src/mpg123/mpg123.cc
@@ -57,16 +57,14 @@ public:
& prefs
};
- static constexpr auto iinfo = InputInfo (FlagWritesTag)
- .with_exts (exts);
-
- constexpr MPG123Plugin() : InputPlugin (info, iinfo) {}
+ constexpr MPG123Plugin() : InputPlugin (info, InputInfo (FlagWritesTag)
+ .with_exts (exts)) {}
bool init ();
void cleanup ();
bool is_our_file (const char * filename, VFSFile & file);
- bool read_tag (const char * filename, VFSFile & file, Tuple * tuple, Index<char> * image);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
bool play (const char * filename, VFSFile & file);
};
@@ -88,6 +86,10 @@ const PluginPreferences MPG123Plugin::prefs = {{widgets}};
#define DECODE_OPTIONS (MPG123_QUIET | MPG123_GAPLESS | MPG123_SEEKBUFFER | MPG123_FUZZY)
+// this is a macro so that the printed line number is meaningful
+#define print_mpg123_error(filename, decoder) \
+ AUDERR ("mpg123 error in %s: %s\n", filename, mpg123_strerror (decoder))
+
static ssize_t replace_read (void * file, void * buffer, size_t length)
{
return ((VFSFile *) file)->fread (buffer, 1, length);
@@ -258,33 +260,26 @@ static bool read_mpg123_info (const char * filename, VFSFile & file, Tuple & tup
return true;
}
-bool MPG123Plugin::read_tag (const char * filename, VFSFile & file, Tuple * tuple, Index<char> * image)
+bool MPG123Plugin::read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image)
{
bool stream = (file.fsize () < 0);
- if (tuple)
- {
- if (! read_mpg123_info (filename, file, * tuple))
- return false;
-
- if (stream)
- tuple->fetch_stream_info (file);
+ if (! read_mpg123_info (filename, file, tuple))
+ return false;
- if (! stream && file.fseek (0, VFS_SEEK_SET) != 0)
+ if (stream)
+ tuple.fetch_stream_info (file);
+ else
+ {
+ if (file.fseek (0, VFS_SEEK_SET) != 0)
return false;
- }
- if (! stream)
audtag::read_tag (file, tuple, image);
+ }
return true;
}
-static void print_mpg123_error (const char * filename, mpg123_handle * decoder)
-{
- AUDERR ("mpg123 error in %s: %s\n", filename, mpg123_strerror (decoder));
-}
-
bool MPG123Plugin::play (const char * filename, VFSFile & file)
{
bool stream = (file.fsize () < 0);
@@ -293,7 +288,7 @@ bool MPG123Plugin::play (const char * filename, VFSFile & file)
if (stream)
{
tuple = get_playback_tuple ();
- if (detect_id3 (file) && audtag::read_tag (file, & tuple, nullptr))
+ if (detect_id3 (file) && audtag::read_tag (file, tuple, nullptr))
set_playback_tuple (tuple.ref ());
}
@@ -307,7 +302,7 @@ bool MPG123Plugin::play (const char * filename, VFSFile & file)
set_stream_bitrate (bitrate);
- if (tuple && tuple.fetch_stream_info (file))
+ if (stream && tuple.fetch_stream_info (file))
set_playback_tuple (tuple.ref ());
open_audio (FMT_FLOAT, s.rate, s.channels);
@@ -336,7 +331,7 @@ bool MPG123Plugin::play (const char * filename, VFSFile & file)
bitrate_count = 0;
}
- if (tuple && tuple.fetch_stream_info (file))
+ if (stream && tuple.fetch_stream_info (file))
set_playback_tuple (tuple.ref ());
if (! s.bytes_read)
@@ -348,10 +343,15 @@ bool MPG123Plugin::play (const char * filename, VFSFile & file)
if (ret < 0)
{
- print_mpg123_error (filename, s.dec);
+ // log only the first error
+ if (! error_count)
+ print_mpg123_error (filename, s.dec);
+ // generally unreported errors are bad, but due to the number of
+ // MP3s with junk data at the end, RESYNC_FAIL just becomes a
+ // nuisance, so silence it
if (++ error_count >= 10)
- return false;
+ return (mpg123_errcode (s.dec) == MPG123_RESYNC_FAIL);
}
}
@@ -372,7 +372,7 @@ bool MPG123Plugin::write_tuple (const char * filename, VFSFile & file, const Tup
if (file.fsize () < 0) // stream?
return false;
- return audtag::tuple_write (tuple, file, audtag::TagType::ID3v2);
+ return audtag::write_tuple (file, tuple, audtag::TagType::ID3v2);
}
const char * const MPG123Plugin::exts[] = { "mp3", "mp2", "mp1", "bmu", nullptr };
diff --git a/src/neon/neon.cc b/src/neon/neon.cc
index 092809e..6cddac0 100644
--- a/src/neon/neon.cc
+++ b/src/neon/neon.cc
@@ -130,7 +130,7 @@ public:
NeonFile (const char * url);
~NeonFile ();
- int open_handle (uint64_t startbyte, String * error = nullptr);
+ int open_handle (int64_t startbyte, String * error = nullptr);
protected:
int64_t fread (void * ptr, int64_t size, int64_t nmemb);
@@ -151,11 +151,14 @@ private:
ne_uri m_purl = ne_uri (); /* The URL, parsed into a structure */
unsigned char m_redircount = 0; /* Redirect count for the opened URL */
- long m_pos = 0; /* Current position in the stream (number of last byte delivered to the player) */
- unsigned long m_content_start = 0; /* Start position in the stream */
- long m_content_length = -1; /* Total content length, counting from content_start, if known. -1 if unknown */
+ int64_t m_pos = 0; /* Current position in the stream
+ (number of last byte delivered to the player) */
+ int64_t m_content_start = 0; /* Start position in the stream */
+ int64_t m_content_length = -1; /* Total content length, counting from
+ content_start, if known. -1 if unknown */
bool m_can_ranges = false; /* true if the webserver advertised accept-range: bytes */
- int64_t m_icy_metaint = 0; /* Interval in which the server will send metadata announcements. 0 if no announcments */
+ int64_t m_icy_metaint = 0; /* Interval in which the server will
+ send metadata announcements. 0 if no announcments */
int64_t m_icy_metaleft = 0; /* Bytes left until the next metadata block */
int m_icy_len = 0; /* Bytes in current metadata block */
@@ -174,7 +177,7 @@ private:
void kill_reader ();
int server_auth (const char * realm, int attempt, char * username, char * password);
void handle_headers ();
- int open_request (uint64_t startbyte, String * error);
+ int open_request (int64_t startbyte, String * error);
FillBufferResult fill_buffer ();
void reader ();
int64_t try_fread (void * ptr, int64_t size, int64_t nmemb, bool & data_read);
@@ -380,12 +383,12 @@ void NeonFile::handle_headers ()
{
/* The server sent us the content length. Parse and store. */
char * endptr;
- long len = strtol (value, & endptr, 10);
+ int64_t len = strtoll (value, & endptr, 10);
if (value[0] && ! endptr[0] && len >= 0)
{
/* Valid data. */
- AUDDBG ("Content length as advertised by server: %ld\n", len);
+ AUDDBG ("Content length as advertised by server: %" PRId64 "\n", len);
m_content_length = len;
}
else
@@ -401,12 +404,12 @@ void NeonFile::handle_headers ()
{
/* The server sent us a ICY metaint header. Parse and store. */
char * endptr;
- long len = strtol (value, & endptr, 10);
+ int64_t len = strtoll (value, & endptr, 10);
if (value[0] && ! endptr[0] && len > 0)
{
/* Valid data */
- AUDDBG ("ICY MetaInt as advertised by server: %ld\n", len);
+ AUDDBG ("ICY MetaInt as advertised by server: %" PRId64 "\n", len);
m_icy_metaint = len;
m_icy_metaleft = len;
}
@@ -440,7 +443,7 @@ static int neon_proxy_auth_cb (void * userdata, const char * realm, int attempt,
return attempt;
}
-int NeonFile::open_request (uint64_t startbyte, String * error)
+int NeonFile::open_request (int64_t startbyte, String * error)
{
int ret;
const ne_status * status;
@@ -546,7 +549,7 @@ int NeonFile::open_request (uint64_t startbyte, String * error)
return -1;
}
-int NeonFile::open_handle (uint64_t startbyte, String * error)
+int NeonFile::open_handle (int64_t startbyte, String * error)
{
int ret;
String proxy_host;
@@ -957,7 +960,7 @@ int64_t NeonFile::fwrite (const void * ptr, int64_t size, int64_t nmemb)
int64_t NeonFile::ftell ()
{
- AUDDBG ("<%p> Current file position: %ld\n", this, m_pos);
+ AUDDBG ("<%p> Current file position: %" PRId64 "\n", this, m_pos);
return m_pos;
}
@@ -983,7 +986,7 @@ int NeonFile::fflush ()
int NeonFile::fseek (int64_t offset, VFSSeekType whence)
{
- AUDDBG ("<%p> Seek requested: offset %ld, whence %d\n", this, offset, whence);
+ AUDDBG ("<%p> Seek requested: offset %" PRId64 ", whence %d\n", this, offset, whence);
/* To seek to a non-zero offset, two things must be satisfied:
* - the server must advertise a content-length
@@ -1023,7 +1026,7 @@ int NeonFile::fseek (int64_t offset, VFSSeekType whence)
return -1;
}
- AUDDBG ("<%p> Position to seek to: %ld, current: %ld\n", this, newpos, m_pos);
+ AUDDBG ("<%p> Position to seek to: %" PRId64 ", current: %" PRId64 "\n", this, newpos, m_pos);
if (newpos < 0)
{
@@ -1033,8 +1036,8 @@ int NeonFile::fseek (int64_t offset, VFSSeekType whence)
if (newpos && newpos >= content_length)
{
- AUDERR ("<%p> Can not seek beyond end of stream (%ld >= %ld)\n",
- this, (long) newpos, (long) content_length);
+ AUDERR ("<%p> Can not seek beyond end of stream (%" PRId64 " >= %"
+ PRId64 "\n", this, newpos, content_length);
return -1;
}
diff --git a/src/notify/Makefile b/src/notify/Makefile
index 82f1476..a7820e4 100644
--- a/src/notify/Makefile
+++ b/src/notify/Makefile
@@ -9,6 +9,16 @@ plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
LD = ${CXX}
-CPPFLAGS += -I../.. ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${NOTIFY_CFLAGS}
+CPPFLAGS += -I../.. ${PLUGIN_CPPFLAGS} ${NOTIFY_CFLAGS}
CFLAGS += ${PLUGIN_CFLAGS}
-LIBS += ${GTK_LIBS} ${NOTIFY_LIBS} -laudgui
+LIBS += ${NOTIFY_LIBS}
+
+ifeq ($(USE_GTK),yes)
+CPPFLAGS += ${GTK_CFLAGS}
+LIBS += ${GTK_LIBS} -laudgui
+endif
+
+ifeq ($(USE_QT),yes)
+CPPFLAGS += ${QT_CFLAGS}
+LIBS += ${QT_LIBS} -laudqt
+endif
diff --git a/src/notify/event.cc b/src/notify/event.cc
index f00f0d2..8f3a323 100644
--- a/src/notify/event.cc
+++ b/src/notify/event.cc
@@ -19,19 +19,29 @@
*/
#include "event.h"
+#include "osd.h"
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/runtime.h>
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
-#include <libaudgui/libaudgui-gtk.h>
-#include "osd.h"
+#ifdef USE_GTK
+#include <libaudgui/libaudgui.h>
+#include <libaudgui/libaudgui-gtk.h>
+#endif
+#ifdef USE_QT
+#include <libaudqt/libaudqt.h>
+#endif
static String last_title, last_message;
static GdkPixbuf * last_pixbuf = nullptr;
+#ifdef USE_QT
+static QImage qimage;
+#endif
+
static void clear_cache ()
{
last_title = String ();
@@ -43,20 +53,41 @@ static void clear_cache ()
last_pixbuf = nullptr;
}
+#ifdef USE_QT
+ qimage = QImage ();
+#endif
+
osd_hide ();
}
-static bool get_album_art ()
+static void get_album_art ()
{
if (last_pixbuf)
- return false;
-
- last_pixbuf = audgui_pixbuf_request_current ();
- if (! last_pixbuf)
- return false;
+ return;
- audgui_pixbuf_scale_within (& last_pixbuf, audgui_get_dpi ());
- return true;
+#ifdef USE_GTK
+ if (aud_get_mainloop_type () == MainloopType::GLib)
+ {
+ last_pixbuf = audgui_pixbuf_request_current ();
+ if (last_pixbuf)
+ audgui_pixbuf_scale_within (& last_pixbuf, audgui_get_dpi ());
+ }
+#endif
+#ifdef USE_QT
+ if (aud_get_mainloop_type () == MainloopType::Qt)
+ {
+ QImage image = audqt::art_request_current (96, 96, false).toImage ();
+ if (! image.isNull ())
+ qimage = image.convertToFormat (QImage::Format_RGBA8888);
+
+ // convert QImage to GdkPixbuf.
+ // note that the GdkPixbuf shares the same internal image data.
+ if (! qimage.isNull ())
+ last_pixbuf = gdk_pixbuf_new_from_data (qimage.bits (),
+ GDK_COLORSPACE_RGB, true, 8, qimage.width (), qimage.height (),
+ qimage.bytesPerLine (), nullptr, nullptr);
+ }
+#endif
}
static void show_stopped ()
@@ -124,6 +155,15 @@ static void force_show ()
void event_init ()
{
+#ifdef USE_GTK
+ if (aud_get_mainloop_type () == MainloopType::GLib)
+ audgui_init ();
+#endif
+#ifdef USE_QT
+ if (aud_get_mainloop_type () == MainloopType::Qt)
+ audqt::init ();
+#endif
+
if (aud_drct_get_ready ())
playback_update ();
else
@@ -151,4 +191,13 @@ void event_uninit ()
hook_dissociate ("aosd toggle", (HookFunction) force_show);
clear_cache ();
+
+#ifdef USE_GTK
+ if (aud_get_mainloop_type () == MainloopType::GLib)
+ audgui_cleanup ();
+#endif
+#ifdef USE_QT
+ if (aud_get_mainloop_type () == MainloopType::Qt)
+ audqt::cleanup ();
+#endif
}
diff --git a/src/notify/notify.cc b/src/notify/notify.cc
index 4a982d1..9ad10a6 100644
--- a/src/notify/notify.cc
+++ b/src/notify/notify.cc
@@ -18,16 +18,12 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <gtk/gtk.h>
-
#include <libnotify/notify.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/plugin.h>
#include <libaudcore/preferences.h>
#include <libaudcore/i18n.h>
#include <libaudcore/runtime.h>
-#include <libaudgui/libaudgui.h>
#include "event.h"
@@ -86,7 +82,6 @@ bool NotifyPlugin::init ()
if (! notify_init ("Audacious"))
return false;
- audgui_init ();
event_init ();
return true;
}
@@ -94,7 +89,6 @@ bool NotifyPlugin::init ()
void NotifyPlugin::cleanup ()
{
event_uninit ();
- audgui_cleanup ();
notify_uninit ();
}
diff --git a/src/oss4/oss.cc b/src/oss4/oss.cc
index 6c1a8dc..2c2bc33 100644
--- a/src/oss4/oss.cc
+++ b/src/oss4/oss.cc
@@ -54,7 +54,7 @@ bool OSSPlugin::init()
return oss_hardware_present();
}
-bool OSSPlugin::set_format(int format, int rate, int channels)
+bool OSSPlugin::set_format(int format, int rate, int channels, String &error)
{
int param;
@@ -69,17 +69,31 @@ bool OSSPlugin::set_format(int format, int rate, int channels)
#endif
param = format;
- CHECK_NOISY(ioctl, m_fd, SNDCTL_DSP_SETFMT, &param);
- CHECK_VAL(param == format, ERROR_NOISY, "Selected audio format is not supported by the device.\n");
+ CHECK_STR(error, ioctl, m_fd, SNDCTL_DSP_SETFMT, &param);
+
+ if (param != format)
+ {
+ error = String("Selected audio format is not supported by the device.");
+ goto FAILED;
+ }
param = rate;
- CHECK_NOISY(ioctl, m_fd, SNDCTL_DSP_SPEED, &param);
- CHECK_VAL(param >= rate * 9 / 10 && param <= rate * 11 / 10, ERROR_NOISY,
- "Selected sample rate is not supported by the device.\n");
+ CHECK_STR(error, ioctl, m_fd, SNDCTL_DSP_SPEED, &param);
+
+ if (param < rate * 9 / 10 || param > rate * 11 / 10)
+ {
+ error = String("Selected sample rate is not supported by the device.");
+ goto FAILED;
+ }
param = channels;
- CHECK_NOISY(ioctl, m_fd, SNDCTL_DSP_CHANNELS, &param);
- CHECK_VAL(param == channels, ERROR_NOISY, "Selected number of channels is not supported by the device.\n");
+ CHECK_STR(error, ioctl, m_fd, SNDCTL_DSP_CHANNELS, &param);
+
+ if (param != channels)
+ {
+ error = String("Selected number of channels is not supported by the device.");
+ goto FAILED;
+ }
m_format = format;
m_rate = rate;
@@ -102,7 +116,7 @@ static int log2(int x)
return y;
}
-bool OSSPlugin::set_buffer()
+bool OSSPlugin::set_buffer(String &error)
{
int milliseconds = aud_get_int(nullptr, "output_buffer_size");
int bytes = frames_to_bytes(aud::rescale(milliseconds, 1000, m_rate));
@@ -110,7 +124,7 @@ bool OSSPlugin::set_buffer()
int numfrags = aud::clamp(aud::rdiv(bytes, 1 << fragorder), 4, 32767);
int param = (numfrags << 16) | fragorder;
- CHECK_NOISY(ioctl, m_fd, SNDCTL_DSP_SETFRAGMENT, &param);
+ CHECK_STR(error, ioctl, m_fd, SNDCTL_DSP_SETFRAGMENT, &param);
return true;
@@ -200,7 +214,7 @@ static void poll_cleanup()
close(poll_pipe[1]);
}
-bool OSSPlugin::open_audio(int aud_format, int rate, int channels)
+bool OSSPlugin::open_audio(int aud_format, int rate, int channels, String &error)
{
AUDDBG("Opening audio.\n");
@@ -208,23 +222,27 @@ bool OSSPlugin::open_audio(int aud_format, int rate, int channels)
audio_buf_info buf_info;
bool poll_was_setup = false;
- CHECK_NOISY(m_fd = open_device);
+ CHECK_STR(error, m_fd = open_device);
if (poll_setup(m_fd))
poll_was_setup = true;
else
goto FAILED;
- format = oss_convert_aud_format(aud_format);
+ if ((format = oss_convert_aud_format(aud_format)) < 0)
+ {
+ error = String("Unsupported audio format");
+ goto FAILED;
+ }
- if (!set_format(format, rate, channels))
+ if (!set_format(format, rate, channels, error))
goto FAILED;
- if (!set_buffer())
+ if (!set_buffer(error))
goto FAILED;
memset(&buf_info, 0, sizeof buf_info);
- CHECK_NOISY(ioctl, m_fd, SNDCTL_DSP_GETOSPACE, &buf_info);
+ CHECK_STR(error, ioctl, m_fd, SNDCTL_DSP_GETOSPACE, &buf_info);
AUDINFO("Buffer information, fragstotal: %d, fragsize: %d, bytes: %d.\n",
buf_info.fragstotal,
diff --git a/src/oss4/oss.h b/src/oss4/oss.h
index aff7bb6..11de4af 100644
--- a/src/oss4/oss.h
+++ b/src/oss4/oss.h
@@ -34,43 +34,25 @@
#endif
#include <libaudcore/i18n.h>
-#include <libaudcore/interface.h>
#include <libaudcore/plugin.h>
#include <libaudcore/runtime.h>
-#define ERROR AUDERR
-
-#define ERROR_NOISY(...) \
-do { \
- aud_ui_show_error(str_printf("OSS4 error: " __VA_ARGS__)); \
- ERROR(__VA_ARGS__); \
-} while (0) \
-
-#define DESCRIBE_ERROR ERROR("%s\n", oss_describe_error())
-#define DESCRIBE_ERROR_NOISY ERROR_NOISY("%s\n", oss_describe_error())
+#define DESCRIBE_ERROR AUDERR("%s\n", oss_describe_error())
#define CHECK(function, ...) \
do { \
- int error = function(__VA_ARGS__); \
- if (error < 0) { \
+ int CHECK_error = function(__VA_ARGS__); \
+ if (CHECK_error < 0) { \
DESCRIBE_ERROR; \
goto FAILED; \
} \
} while (0)
-#define CHECK_NOISY(function, ...) \
-do { \
- int error = function(__VA_ARGS__); \
- if (error < 0) { \
- DESCRIBE_ERROR_NOISY; \
- goto FAILED; \
- } \
-} while (0)
-
-#define CHECK_VAL(value, function, ...) \
+#define CHECK_STR(str, function, ...) \
do { \
- if (!(value)) { \
- function(__VA_ARGS__); \
+ int CHECK_STR_error = function(__VA_ARGS__); \
+ if (CHECK_STR_error < 0) { \
+ str = String(str_printf("OSS error: %s\n", oss_describe_error())); \
goto FAILED; \
} \
} while (0)
@@ -112,7 +94,7 @@ public:
StereoVolume get_volume();
void set_volume(StereoVolume v);
- bool open_audio(int aud_format, int rate, int chans);
+ bool open_audio(int aud_format, int rate, int chans, String &error);
void close_audio();
void period_wait();
@@ -125,8 +107,8 @@ public:
void flush();
private:
- bool set_format(int format, int rate, int channels);
- bool set_buffer();
+ bool set_format(int format, int rate, int channels, String &error);
+ bool set_buffer(String &error);
int frames_to_bytes(int frames) const
{ return frames * (m_bytes_per_sample * m_channels); }
diff --git a/src/oss4/plugin.cc b/src/oss4/plugin.cc
index c710b43..6cbfa22 100644
--- a/src/oss4/plugin.cc
+++ b/src/oss4/plugin.cc
@@ -30,7 +30,7 @@ static void combo_init()
{
int mixerfd;
- CHECK_NOISY(mixerfd = open, DEFAULT_MIXER, O_RDWR);
+ CHECK(mixerfd = open, DEFAULT_MIXER, O_RDWR);
oss_elements.append(ComboItem(strdup(N_("Default device")), strdup(DEFAULT_DSP)));
@@ -38,7 +38,7 @@ static void combo_init()
oss_sysinfo sysinfo;
memset(&sysinfo, 0, sizeof sysinfo);
CHECK(ioctl, mixerfd, SNDCTL_SYSINFO, &sysinfo);
- CHECK_NOISY(oss_probe_for_adev, &sysinfo);
+ CHECK(oss_probe_for_adev, &sysinfo);
for (int i = 0; i < sysinfo.numaudios; i++)
{
diff --git a/src/oss4/utils.cc b/src/oss4/utils.cc
index 35f6e67..25db313 100644
--- a/src/oss4/utils.cc
+++ b/src/oss4/utils.cc
@@ -186,13 +186,13 @@ bool oss_hardware_present()
{
int mixerfd;
- CHECK_NOISY(mixerfd = open, DEFAULT_MIXER, O_RDWR, 0);
+ CHECK(mixerfd = open, DEFAULT_MIXER, O_RDWR, 0);
#ifdef SNDCTL_SYSINFO
oss_sysinfo sysinfo;
memset(&sysinfo, 0, sizeof sysinfo);
CHECK(ioctl, mixerfd, SNDCTL_SYSINFO, &sysinfo);
- CHECK_NOISY(oss_probe_for_adev, &sysinfo);
+ CHECK(oss_probe_for_adev, &sysinfo);
#endif
close(mixerfd);
diff --git a/src/playlist-manager-qt/playlist-manager-qt.cc b/src/playlist-manager-qt/playlist-manager-qt.cc
index 17907e6..cf779ca 100644
--- a/src/playlist-manager-qt/playlist-manager-qt.cc
+++ b/src/playlist-manager-qt/playlist-manager-qt.cc
@@ -27,7 +27,6 @@
#include <QTreeView>
#include <QVBoxLayout>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
#include <libaudcore/playlist.h>
@@ -39,7 +38,10 @@ class PlaylistManagerQt : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("Playlist Manager"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr PlaylistManagerQt () : GeneralPlugin (info, false) {}
diff --git a/src/playlist-manager/playlist-manager.cc b/src/playlist-manager/playlist-manager.cc
index 9c46a25..bb5f0d0 100644
--- a/src/playlist-manager/playlist-manager.cc
+++ b/src/playlist-manager/playlist-manager.cc
@@ -17,7 +17,6 @@
* the use of this software.
*/
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
@@ -36,7 +35,10 @@ class PlaylistManager : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("Playlist Manager"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr PlaylistManager () : GeneralPlugin (info, false) {}
diff --git a/src/psf/peops/reverb.cc b/src/psf/peops/reverb.cc
index 681d56c..1354444 100644
--- a/src/psf/peops/reverb.cc
+++ b/src/psf/peops/reverb.cc
@@ -81,7 +81,8 @@ static inline void s_buffer1(int iOff,int iVal) // set_buffer (+1
iOff=(iOff*4)+rvb.CurrAddr+1;
while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ if(iVal<-32768L) iVal=-32768L;
+ if(iVal>32767L) iVal=32767L;
*(p+iOff)=(s16)BFLIP16((s16)iVal);
}
diff --git a/src/psf/peops/spu.cc b/src/psf/peops/spu.cc
index 1e79cbc..1ebfce6 100644
--- a/src/psf/peops/spu.cc
+++ b/src/psf/peops/spu.cc
@@ -193,7 +193,7 @@ static u32 seektime;
int psf_seek(u32 t)
{
seektime=t*441/10;
- if(seektime>sampcount) return(1);
+ if(seektime>=sampcount) return(1);
return(0);
}
@@ -493,8 +493,10 @@ int SPUasync(u32 cycles, void (*update)(const void *, int))
// if(sr>32767 || sr < -32767) printf("Right: %d, %f\n",sl,asl);
//}
- if(sl>32767) sl=32767; if(sl<-32767) sl=-32767;
- if(sr>32767) sr=32767; if(sr<-32767) sr=-32767;
+ if(sl>32767) sl=32767;
+ if(sl<-32767) sl=-32767;
+ if(sr>32767) sr=32767;
+ if(sr<-32767) sr=-32767;
*pS++=sl;
*pS++=sr;
@@ -560,6 +562,7 @@ int SPUinit(void)
memset(spuMem,0,sizeof(spuMem));
InitADSR();
sampcount=ttemp=0;
+ seektime=0;
#ifdef TIMEO
begintime=gettime64();
#endif
diff --git a/src/psf/peops2/reverb.cc b/src/psf/peops2/reverb.cc
index 068dc95..cd20260 100644
--- a/src/psf/peops2/reverb.cc
+++ b/src/psf/peops2/reverb.cc
@@ -122,7 +122,8 @@ static inline void s_buffer(int iOff,int iVal,int core) // set_buffer con
iOff=(iOff)+rvb[core].CurrAddr;
while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ if(iVal<-32768L) iVal=-32768L;
+ if(iVal>32767L) iVal=32767L;
*(p+iOff)=(short)iVal;
}
@@ -134,7 +135,8 @@ static inline void s_buffer1(int iOff,int iVal,int core) // set_buffer (+1
iOff=(iOff)+rvb[core].CurrAddr+1;
while(iOff>rvb[core].EndAddr) iOff=rvb[core].StartAddr+(iOff-(rvb[core].EndAddr+1));
while(iOff<rvb[core].StartAddr) iOff=rvb[core].EndAddr-(rvb[core].StartAddr-iOff);
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;
+ if(iVal<-32768L) iVal=-32768L;
+ if(iVal>32767L) iVal=32767L;
*(p+iOff)=(short)iVal;
}
diff --git a/src/psf/peops2/spu.cc b/src/psf/peops2/spu.cc
index b5d0b3b..4585512 100644
--- a/src/psf/peops2/spu.cc
+++ b/src/psf/peops2/spu.cc
@@ -332,14 +332,13 @@ static u32 seektime;
int psf2_seek(u32 t)
{
seektime=t*441/10;
- if(seektime>sampcount) return(1);
+ if(seektime>=sampcount) return(1);
return(0);
}
// Counting to 65536 results in full volume offage.
void setlength2(s32 stop, s32 fade)
{
- seektime = 0;
if(stop==~0)
{
decaybegin=~0;
@@ -735,8 +734,10 @@ ENDX: ;
d=SSumL[0];SSumL[0]=0;
d2=SSumR[0];SSumR[0]=0;
- if(d<-32767) d=-32767;if(d>32767) d=32767;
- if(d2<-32767) d2=-32767;if(d2>32767) d2=32767;
+ if(d<-32767) d=-32767;
+ if(d>32767) d=32767;
+ if(d2<-32767) d2=-32767;
+ if(d2>32767) d2=32767;
if(sampcount>=decaybegin)
{
@@ -833,6 +834,7 @@ EXPORT_GCC long CALLBACK SPU2init(void)
memset(rvb,0,2*sizeof(REVERBInfo));
sampcount = 0;
+ seektime = 0;
InitADSR();
diff --git a/src/psf/plugin.cc b/src/psf/plugin.cc
index 1975d76..e512140 100644
--- a/src/psf/plugin.cc
+++ b/src/psf/plugin.cc
@@ -1,27 +1,27 @@
/*
- Audio Overload SDK - main driver. for demonstration only, not user friendly!
+ Audio Overload SDK - main driver. for demonstration only, not user friendly!
- Copyright (c) 2007-2008 R. Belmont and Richard Bannister.
+ Copyright (c) 2007-2008 R. Belmont and Richard Bannister.
- All rights reserved.
+ All rights reserved.
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the names of R. Belmont and Richard Bannister nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
@@ -39,48 +39,46 @@
class PSFPlugin : public InputPlugin
{
public:
- static const char *const exts[];
+ static const char *const exts[];
- static constexpr PluginInfo info = {
- N_("OpenPSF PSF1/PSF2 Decoder"),
- PACKAGE
- };
+ static constexpr PluginInfo info = {
+ N_("OpenPSF PSF1/PSF2 Decoder"),
+ PACKAGE
+ };
- static constexpr auto iinfo = InputInfo()
- .with_exts(exts);
+ constexpr PSFPlugin() : InputPlugin(info, InputInfo()
+ .with_exts(exts)) {}
- constexpr PSFPlugin() : InputPlugin(info, iinfo) {}
-
- bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
- bool play(const char *filename, VFSFile &file);
+ bool is_our_file(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
+ bool play(const char *filename, VFSFile &file);
protected:
- static void update(const void *data, int bytes);
+ static void update(const void *data, int bytes);
};
EXPORT PSFPlugin aud_plugin_instance;
typedef enum {
- ENG_NONE = 0,
- ENG_PSF1,
- ENG_PSF2,
- ENG_SPX,
- ENG_COUNT
+ ENG_NONE = 0,
+ ENG_PSF1,
+ ENG_PSF2,
+ ENG_SPX,
+ ENG_COUNT
} PSFEngine;
typedef struct {
- int32_t (*start)(uint8_t *buffer, uint32_t length);
- int32_t (*stop)(void);
- int32_t (*seek)(uint32_t);
- int32_t (*execute)(void (*update)(const void *, int));
+ int32_t (*start)(uint8_t *buffer, uint32_t length);
+ int32_t (*stop)(void);
+ int32_t (*seek)(uint32_t);
+ int32_t (*execute)(void (*update)(const void *, int));
} PSFEngineFunctors;
static PSFEngineFunctors psf_functor_map[ENG_COUNT] = {
- {nullptr, nullptr, nullptr, nullptr},
- {psf_start, psf_stop, psf_seek, psf_execute},
- {psf2_start, psf2_stop, psf2_seek, psf2_execute},
- {spx_start, spx_stop, psf_seek, spx_execute},
+ {nullptr, nullptr, nullptr, nullptr},
+ {psf_start, psf_stop, psf_seek, psf_execute},
+ {psf2_start, psf2_stop, psf2_seek, psf2_execute},
+ {spx_start, spx_stop, psf_seek, spx_execute},
};
static PSFEngineFunctors *f;
@@ -88,128 +86,148 @@ static String dirpath;
bool stop_flag = false;
+/* The emulation engine can only seek forward, not back. This variable is set
+ * a non-negative time (milliseconds) when the song is to be restarted in order
+ * to seek backward. */
+static int reverse_seek;
+
static PSFEngine psf_probe(const char *buf, int len)
{
- if (len < 4)
- return ENG_NONE;
+ if (len < 4)
+ return ENG_NONE;
- if (!memcmp(buf, "PSF\x01", 4))
- return ENG_PSF1;
+ if (!memcmp(buf, "PSF\x01", 4))
+ return ENG_PSF1;
- if (!memcmp(buf, "PSF\x02", 4))
- return ENG_PSF2;
+ if (!memcmp(buf, "PSF\x02", 4))
+ return ENG_PSF2;
- if (!memcmp(buf, "SPU", 3))
- return ENG_SPX;
+ if (!memcmp(buf, "SPU", 3))
+ return ENG_SPX;
- if (!memcmp(buf, "SPX", 3))
- return ENG_SPX;
+ if (!memcmp(buf, "SPX", 3))
+ return ENG_SPX;
- return ENG_NONE;
+ return ENG_NONE;
}
/* ao_get_lib: called to load secondary files */
Index<char> ao_get_lib(char *filename)
{
- VFSFile file(filename_build({dirpath, filename}), "r");
- return file ? file.read_all() : Index<char>();
+ VFSFile file(filename_build({dirpath, filename}), "r");
+ return file ? file.read_all() : Index<char>();
}
-Tuple PSFPlugin::read_tuple(const char *filename, VFSFile &file)
+bool PSFPlugin::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple t;
- corlett_t *c;
-
- Index<char> buf = file.read_all ();
+ Index<char> buf = file.read_all ();
+ if (!buf.len())
+ return false;
- if (!buf.len())
- return t;
+ corlett_t *c;
+ if (corlett_decode((uint8_t *)buf.begin(), buf.len(), nullptr, nullptr, &c) != AO_SUCCESS)
+ return false;
- if (corlett_decode((uint8_t *)buf.begin(), buf.len(), nullptr, nullptr, &c) != AO_SUCCESS)
- return t;
+ tuple.set_int(Tuple::Length, psfTimeToMS(c->inf_length) + psfTimeToMS(c->inf_fade));
+ tuple.set_str(Tuple::Artist, c->inf_artist);
+ tuple.set_str(Tuple::Album, c->inf_game);
+ tuple.set_str(Tuple::Title, c->inf_title);
+ tuple.set_str(Tuple::Copyright, c->inf_copy);
+ tuple.set_str(Tuple::Quality, _("sequenced"));
+ tuple.set_str(Tuple::Codec, "PlayStation 1/2 Audio");
- t.set_filename (filename);
+ free(c);
- t.set_int (Tuple::Length, psfTimeToMS(c->inf_length) + psfTimeToMS(c->inf_fade));
- t.set_str (Tuple::Artist, c->inf_artist);
- t.set_str (Tuple::Album, c->inf_game);
- t.set_str (Tuple::Title, c->inf_title);
- t.set_str (Tuple::Copyright, c->inf_copy);
- t.set_str (Tuple::Quality, _("sequenced"));
- t.set_str (Tuple::Codec, "PlayStation 1/2 Audio");
-
- free(c);
-
- return t;
+ return true;
}
bool PSFPlugin::play(const char *filename, VFSFile &file)
{
- bool error = false;
+ bool error = false;
+
+ const char * slash = strrchr (filename, '/');
+ if (! slash)
+ return false;
- const char * slash = strrchr (filename, '/');
- if (! slash)
- return false;
+ dirpath = String (str_copy (filename, slash + 1 - filename));
- dirpath = String (str_copy (filename, slash + 1 - filename));
+ Index<char> buf = file.read_all ();
- Index<char> buf = file.read_all ();
+ PSFEngine eng = psf_probe(buf.begin(), buf.len());
+ if (eng == ENG_NONE || eng == ENG_COUNT)
+ {
+ error = true;
+ goto cleanup;
+ }
- PSFEngine eng = psf_probe(buf.begin(), buf.len());
- if (eng == ENG_NONE || eng == ENG_COUNT)
- {
- error = true;
- goto cleanup;
- }
+ f = &psf_functor_map[eng];
- f = &psf_functor_map[eng];
- if (f->start((uint8_t *)buf.begin(), buf.len()) != AO_SUCCESS)
- {
- error = true;
- goto cleanup;
- }
+ set_stream_bitrate(44100*2*2*8);
+ open_audio(FMT_S16_NE, 44100, 2);
- set_stream_bitrate(44100*2*2*8);
- open_audio(FMT_S16_NE, 44100, 2);
+ reverse_seek = -1;
- stop_flag = false;
+ /* This loop will restart playback from the beginning when necessary to seek
+ * backwards in the file (reverse_seek >= 0). */
+ do
+ {
+ if (f->start((uint8_t *)buf.begin(), buf.len()) != AO_SUCCESS)
+ {
+ error = true;
+ goto cleanup;
+ }
- f->execute(update);
- f->stop();
+ if (reverse_seek >= 0)
+ {
+ f->seek(reverse_seek); /* should never fail here */
+ reverse_seek = -1;
+ }
+
+ stop_flag = false;
+
+ f->execute(update);
+ f->stop();
+ }
+ while (reverse_seek >= 0);
cleanup:
- f = nullptr;
- dirpath = String ();
+ f = nullptr;
+ dirpath = String ();
- return ! error;
+ return ! error;
}
void PSFPlugin::update(const void *data, int bytes)
{
- if (!data || check_stop())
- {
- stop_flag = true;
- return;
- }
-
- int seek = check_seek();
-
- if (seek >= 0)
- {
- f->seek(seek);
- return;
- }
-
- write_audio(data, bytes);
+ if (!data || check_stop())
+ {
+ stop_flag = true;
+ return;
+ }
+
+ int seek = check_seek();
+
+ if (seek >= 0)
+ {
+ if (!f->seek(seek))
+ {
+ reverse_seek = seek;
+ stop_flag = true;
+ }
+
+ return;
+ }
+
+ write_audio(data, bytes);
}
bool PSFPlugin::is_our_file(const char *filename, VFSFile &file)
{
- char magic[4];
- if (file.fread (magic, 1, 4) < 4)
- return false;
+ char magic[4];
+ if (file.fread (magic, 1, 4) < 4)
+ return false;
- return (psf_probe(magic, 4) != ENG_NONE);
+ return (psf_probe(magic, 4) != ENG_NONE);
}
const char *const PSFPlugin::exts[] = { "psf", "minipsf", "psf2", "minipsf2", "spu", "spx", nullptr };
diff --git a/src/pulse_audio/Makefile b/src/pulse/Makefile
index 831fc89..831fc89 100644
--- a/src/pulse_audio/Makefile
+++ b/src/pulse/Makefile
diff --git a/src/pulse/pulse_audio.cc b/src/pulse/pulse_audio.cc
new file mode 100644
index 0000000..b732f8d
--- /dev/null
+++ b/src/pulse/pulse_audio.cc
@@ -0,0 +1,506 @@
+/***
+ This file is part of xmms-pulse.
+
+ Updates for Audacious are:
+ Copyright 2016 John Lindgren
+
+ xmms-pulse 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.
+
+ xmms-pulse 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 xmms-pulse; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA.
+***/
+
+#include <condition_variable>
+#include <mutex>
+
+#include <pulse/pulseaudio.h>
+
+#include <libaudcore/runtime.h>
+#include <libaudcore/plugin.h>
+#include <libaudcore/i18n.h>
+
+using scoped_lock = std::unique_lock<std::mutex>;
+
+class PulseOutput : public OutputPlugin
+{
+public:
+ static const char about[];
+
+ static constexpr PluginInfo info = {
+ N_("PulseAudio Output"),
+ PACKAGE,
+ about
+ };
+
+ constexpr PulseOutput () : OutputPlugin (info, 8) {}
+
+ bool init ();
+
+ StereoVolume get_volume ();
+ void set_volume (StereoVolume v);
+
+ bool open_audio (int fmt, int rate, int nch, String & error);
+ void close_audio ();
+
+ void period_wait ();
+ int write_audio (const void * ptr, int length);
+ void drain ();
+
+ int get_delay ();
+
+ void pause (bool pause);
+ void flush ();
+};
+
+EXPORT PulseOutput aud_plugin_instance;
+
+static std::mutex pulse_mutex;
+static std::condition_variable pulse_cond;
+
+static pa_context * context = nullptr;
+static pa_stream * stream = nullptr;
+static pa_mainloop * mainloop = nullptr;
+
+static bool connected, flushed, polling;
+
+static pa_cvolume volume;
+
+/* Check whether the connection is still alive. */
+static bool alive ()
+{
+ return pa_context_get_state (context) == PA_CONTEXT_READY &&
+ pa_stream_get_state (stream) == PA_STREAM_READY;
+}
+
+/* Cooperative polling method. Only one thread calls the actual poll function,
+ * and dispatches the events received. Any other threads simply wait for the
+ * first thread to finish. */
+static void poll_events (scoped_lock & lock)
+{
+ if (polling)
+ pulse_cond.wait (lock);
+ else
+ {
+ pa_mainloop_prepare (mainloop, -1);
+
+ polling = true;
+ lock.unlock ();
+
+ pa_mainloop_poll (mainloop);
+
+ lock.lock ();
+ polling = false;
+
+ pa_mainloop_dispatch (mainloop);
+
+ pulse_cond.notify_all ();
+ }
+}
+
+/* Wait for an asynchronous operation to complete. Return immediately if the
+ * connection dies. */
+static bool finish (pa_operation * op, scoped_lock & lock)
+{
+ pa_operation_state_t state;
+ while ((state = pa_operation_get_state (op)) != PA_OPERATION_DONE && alive ())
+ poll_events (lock);
+
+ pa_operation_unref (op);
+ return (state == PA_OPERATION_DONE);
+}
+
+#define REPORT(function) do { \
+ AUDERR ("%s() failed: %s\n", function, pa_strerror (pa_context_errno (context))); \
+} while (0)
+
+#define CHECK(function, ...) do { \
+ auto op = function (__VA_ARGS__, & success); \
+ if (! op || ! finish (op, lock) || ! success) \
+ REPORT (#function); \
+} while (0)
+
+static void info_cb (pa_context *, const pa_sink_input_info * i, int, void * userdata)
+{
+ if (! i)
+ return;
+
+ volume = i->volume;
+
+ if (userdata)
+ * (int *) userdata = 1;
+}
+
+static void subscribe_cb (pa_context * c, pa_subscription_event_type t, uint32_t index, void *)
+{
+ pa_operation * o;
+
+ if (! stream || index != pa_stream_get_index (stream) ||
+ (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE) &&
+ t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_NEW)))
+ return;
+
+ if (! (o = pa_context_get_sink_input_info (c, index, info_cb, nullptr)))
+ {
+ REPORT ("pa_context_get_sink_input_info");
+ return;
+ }
+
+ pa_operation_unref (o);
+}
+
+static void stream_success_cb (pa_stream *, int success, void * userdata)
+{
+ if (userdata)
+ * (int * ) userdata = success;
+}
+
+static void context_success_cb (pa_context *, int success, void * userdata)
+{
+ if (userdata)
+ * (int * ) userdata = success;
+}
+
+StereoVolume PulseOutput::get_volume ()
+{
+ scoped_lock lock (pulse_mutex);
+
+ if (! connected)
+ return {0, 0};
+
+ if (! polling)
+ {
+ /* read any pending events to get the lastest volume */
+ while (pa_mainloop_iterate (mainloop, 0, nullptr) > 0)
+ continue;
+ }
+
+ StereoVolume v;
+ if (volume.channels == 2)
+ {
+ v.left = aud::rescale<int> (volume.values[0], PA_VOLUME_NORM, 100);
+ v.right = aud::rescale<int> (volume.values[1], PA_VOLUME_NORM, 100);
+ }
+ else
+ v.left = v.right = aud::rescale<int> (pa_cvolume_avg (& volume), PA_VOLUME_NORM, 100);
+
+ return v;
+}
+
+void PulseOutput::set_volume (StereoVolume v)
+{
+ scoped_lock lock (pulse_mutex);
+
+ if (! connected)
+ return;
+
+ if (volume.channels != 1)
+ {
+ volume.values[0] = aud::rescale<int> (v.left, 100, PA_VOLUME_NORM);
+ volume.values[1] = aud::rescale<int> (v.right, 100, PA_VOLUME_NORM);
+ volume.channels = 2;
+ }
+ else
+ {
+ volume.values[0] = aud::rescale<int> (aud::max (v.left, v.right), 100, PA_VOLUME_NORM);
+ volume.channels = 1;
+ }
+
+ int success = 0;
+ CHECK (pa_context_set_sink_input_volume, context,
+ pa_stream_get_index (stream), & volume, context_success_cb);
+}
+
+void PulseOutput::pause (bool pause)
+{
+ scoped_lock lock (pulse_mutex);
+
+ int success = 0;
+ CHECK (pa_stream_cork, stream, pause, stream_success_cb);
+}
+
+int PulseOutput::get_delay ()
+{
+ scoped_lock lock (pulse_mutex);
+
+ pa_usec_t usec;
+ int neg;
+
+ if (pa_stream_get_latency (stream, & usec, & neg) == PA_OK)
+ return usec / 1000;
+ else
+ return 0;
+}
+
+void PulseOutput::drain ()
+{
+ scoped_lock lock (pulse_mutex);
+
+ int success = 0;
+ CHECK (pa_stream_drain, stream, stream_success_cb);
+}
+
+void PulseOutput::flush ()
+{
+ scoped_lock lock (pulse_mutex);
+
+ int success = 0;
+ CHECK (pa_stream_flush, stream, stream_success_cb);
+
+ /* wake up period_wait() */
+ flushed = true;
+ if (polling)
+ pa_mainloop_wakeup (mainloop);
+}
+
+void PulseOutput::period_wait ()
+{
+ scoped_lock lock (pulse_mutex);
+
+ int success = 0;
+ CHECK (pa_stream_trigger, stream, stream_success_cb);
+
+ /* if the connection dies, wait until flush() is called */
+ while ((! pa_stream_writable_size (stream) || ! alive ()) && ! flushed)
+ poll_events (lock);
+}
+
+int PulseOutput::write_audio (const void * ptr, int length)
+{
+ scoped_lock lock (pulse_mutex);
+ int ret = 0;
+
+ length = aud::min ((size_t) length, pa_stream_writable_size (stream));
+
+ if (pa_stream_write (stream, ptr, length, nullptr, 0, PA_SEEK_RELATIVE) < 0)
+ REPORT ("pa_stream_write");
+ else
+ ret = length;
+
+ flushed = false;
+ return ret;
+}
+
+static void close_audio_locked (scoped_lock & lock)
+{
+ /* wait for any parallel tasks (e.g. set_volume()) to complete */
+ while (polling)
+ pulse_cond.wait (lock);
+
+ connected = false;
+
+ if (stream)
+ {
+ pa_stream_disconnect (stream);
+ pa_stream_unref (stream);
+ stream = nullptr;
+ }
+
+ if (context)
+ {
+ pa_context_disconnect (context);
+ pa_context_unref (context);
+ context = nullptr;
+ }
+
+ if (mainloop)
+ {
+ pa_mainloop_free (mainloop);
+ mainloop = nullptr;
+ }
+}
+
+void PulseOutput::close_audio ()
+{
+ scoped_lock lock (pulse_mutex);
+ close_audio_locked (lock);
+}
+
+static pa_sample_format_t to_pulse_format (int aformat)
+{
+ switch (aformat)
+ {
+ case FMT_U8: return PA_SAMPLE_U8;
+ case FMT_S16_LE: return PA_SAMPLE_S16LE;
+ case FMT_S16_BE: return PA_SAMPLE_S16BE;
+#ifdef PA_SAMPLE_S24_32LE
+ case FMT_S24_LE: return PA_SAMPLE_S24_32LE;
+ case FMT_S24_BE: return PA_SAMPLE_S24_32BE;
+#endif
+#ifdef PA_SAMPLE_S32LE
+ case FMT_S32_LE: return PA_SAMPLE_S32LE;
+ case FMT_S32_BE: return PA_SAMPLE_S32BE;
+#endif
+ case FMT_FLOAT: return PA_SAMPLE_FLOAT32NE;
+ default: return PA_SAMPLE_INVALID;
+ }
+}
+
+static bool set_sample_spec (pa_sample_spec & ss, int fmt, int rate, int nch)
+{
+ ss.format = to_pulse_format (fmt);
+ if (ss.format == PA_SAMPLE_INVALID)
+ return false;
+
+ ss.rate = rate;
+ ss.channels = nch;
+
+ return pa_sample_spec_valid (& ss);
+}
+
+static void set_buffer_attr (pa_buffer_attr & buffer, const pa_sample_spec & ss)
+{
+ int buffer_ms = aud_get_int (nullptr, "output_buffer_size");
+ size_t buffer_size = pa_usec_to_bytes ((pa_usec_t) 1000 * buffer_ms, & ss);
+
+ buffer.maxlength = (uint32_t) -1;
+ buffer.tlength = buffer_size;
+ buffer.prebuf = (uint32_t) -1;
+ buffer.minreq = (uint32_t) -1;
+ buffer.fragsize = buffer_size;
+}
+
+static bool create_context (scoped_lock & lock)
+{
+ if (! (mainloop = pa_mainloop_new ()))
+ {
+ AUDERR ("Failed to allocate main loop\n");
+ return false;
+ }
+
+ if (! (context = pa_context_new (pa_mainloop_get_api (mainloop), "Audacious")))
+ {
+ AUDERR ("Failed to allocate context\n");
+ return false;
+ }
+
+ if (pa_context_connect (context, nullptr, (pa_context_flags_t) 0, nullptr) < 0)
+ {
+ REPORT ("pa_context_connect");
+ return false;
+ }
+
+ /* Wait until the context is ready */
+ pa_context_state_t cstate;
+ while ((cstate = pa_context_get_state (context)) != PA_CONTEXT_READY)
+ {
+ if (cstate == PA_CONTEXT_TERMINATED || cstate == PA_CONTEXT_FAILED)
+ {
+ REPORT ("pa_context_connect");
+ return false;
+ }
+
+ poll_events (lock);
+ }
+
+ return true;
+}
+
+static bool create_stream (scoped_lock & lock, const pa_sample_spec & ss)
+{
+ if (! (stream = pa_stream_new (context, "Audacious", & ss, nullptr)))
+ {
+ REPORT ("pa_stream_new");
+ return false;
+ }
+
+ /* Connect stream with sink and default volume */
+ pa_buffer_attr buffer;
+ set_buffer_attr (buffer, ss);
+
+ auto flags = pa_stream_flags_t (PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE);
+ if (pa_stream_connect_playback (stream, nullptr, & buffer, flags, nullptr, nullptr) < 0)
+ {
+ REPORT ("pa_stream_connect_playback");
+ return false;
+ }
+
+ /* Wait until the stream is ready */
+ pa_stream_state_t sstate;
+ while ((sstate = pa_stream_get_state (stream)) != PA_STREAM_READY)
+ {
+ if (sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED)
+ {
+ REPORT ("pa_stream_connect_playback");
+ return false;
+ }
+
+ poll_events (lock);
+ }
+
+ return true;
+}
+
+static bool subscribe_events (scoped_lock & lock)
+{
+ pa_context_set_subscribe_callback (context, subscribe_cb, nullptr);
+
+ /* Now subscribe to events */
+ int success = 0;
+ CHECK (pa_context_subscribe, context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb);
+ if (! success)
+ return false;
+
+ /* Now request the initial stream info */
+ success = 0;
+ CHECK (pa_context_get_sink_input_info, context, pa_stream_get_index (stream), info_cb);
+ if (! success)
+ return false;
+
+ return true;
+}
+
+bool PulseOutput::open_audio (int fmt, int rate, int nch, String & error)
+{
+ scoped_lock lock (pulse_mutex);
+
+ pa_sample_spec ss;
+ if (! set_sample_spec (ss, fmt, rate, nch))
+ return false;
+
+ if (! create_context (lock) ||
+ ! create_stream (lock, ss) ||
+ ! subscribe_events (lock))
+ {
+ close_audio_locked (lock);
+ return false;
+ }
+
+ connected = true;
+ flushed = true;
+ return true;
+}
+
+bool PulseOutput::init ()
+{
+ String error;
+ if (! open_audio (FMT_S16_NE, 44100, 2, error))
+ return false;
+
+ close_audio ();
+ return true;
+}
+
+const char PulseOutput::about[] =
+ N_("Audacious PulseAudio Output Plugin\n\n"
+ "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.\n\n"
+ "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.\n\n"
+ "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.");
diff --git a/src/pulse_audio/pulse_audio.cc b/src/pulse_audio/pulse_audio.cc
deleted file mode 100644
index 4e828e8..0000000
--- a/src/pulse_audio/pulse_audio.cc
+++ /dev/null
@@ -1,625 +0,0 @@
-/***
- This file is part of xmms-pulse.
-
- xmms-pulse 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.
-
- xmms-pulse 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 xmms-pulse; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- USA.
-***/
-
-#include <assert.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include <pulse/pulseaudio.h>
-
-#include <libaudcore/runtime.h>
-#include <libaudcore/plugin.h>
-#include <libaudcore/i18n.h>
-
-class PulseOutput : public OutputPlugin
-{
-public:
- static const char about[];
-
- static constexpr PluginInfo info = {
- N_("PulseAudio Output"),
- PACKAGE,
- about
- };
-
- constexpr PulseOutput () : OutputPlugin (info, 8) {}
-
- bool init ();
-
- StereoVolume get_volume ();
- void set_volume (StereoVolume v);
-
- bool open_audio (int fmt, int rate, int nch);
- void close_audio ();
-
- void period_wait ();
- int write_audio (const void * ptr, int length);
- void drain ();
-
- int get_delay ();
-
- void pause (bool pause);
- void flush ();
-};
-
-EXPORT PulseOutput aud_plugin_instance;
-
-static pa_context *context = nullptr;
-static pa_stream *stream = nullptr;
-static pa_threaded_mainloop *mainloop = nullptr;
-
-static pa_cvolume volume;
-static bool volume_valid = false;
-
-static bool connected = false;
-
-#define CHECK_DEAD_GOTO(label, warn) do { \
-if (!mainloop || \
- !context || pa_context_get_state(context) != PA_CONTEXT_READY || \
- !stream || pa_stream_get_state(stream) != PA_STREAM_READY) { \
- if (warn) \
- AUDDBG("Connection died: %s\n", context ? pa_strerror(pa_context_errno(context)) : "nullptr"); \
- goto label; \
- } \
-} while(0);
-
-#define CHECK_CONNECTED(retval) \
-do { \
- if (!connected) return retval; \
-} while (0);
-
-static void info_cb(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
- assert(c);
-
- if (!i)
- return;
-
- volume = i->volume;
- volume_valid = true;
-}
-
-static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) {
- pa_operation *o;
-
- assert(c);
-
- if (!stream ||
- index != pa_stream_get_index(stream) ||
- (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
- t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)))
- return;
-
- if (!(o = pa_context_get_sink_input_info(c, index, info_cb, nullptr))) {
- AUDDBG("pa_context_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(c)));
- return;
- }
-
- pa_operation_unref(o);
-}
-
-static void context_state_cb(pa_context *c, void *userdata) {
- assert(c);
-
- switch (pa_context_get_state(c)) {
- case PA_CONTEXT_READY:
- case PA_CONTEXT_TERMINATED:
- case PA_CONTEXT_FAILED:
- pa_threaded_mainloop_signal(mainloop, 0);
- break;
-
- case PA_CONTEXT_UNCONNECTED:
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- break;
- }
-}
-
-static void stream_state_cb(pa_stream *s, void * userdata) {
- assert(s);
-
- switch (pa_stream_get_state(s)) {
-
- case PA_STREAM_READY:
- case PA_STREAM_FAILED:
- case PA_STREAM_TERMINATED:
- pa_threaded_mainloop_signal(mainloop, 0);
- break;
-
- case PA_STREAM_UNCONNECTED:
- case PA_STREAM_CREATING:
- break;
- }
-}
-
-static void stream_success_cb(pa_stream *s, int success, void *userdata) {
- assert(s);
-
- if (userdata)
- *(int*) userdata = success;
-
- pa_threaded_mainloop_signal(mainloop, 0);
-}
-
-static void context_success_cb(pa_context *c, int success, void *userdata) {
- assert(c);
-
- if (userdata)
- *(int*) userdata = success;
-
- pa_threaded_mainloop_signal(mainloop, 0);
-}
-
-static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
- assert(s);
-
- pa_threaded_mainloop_signal(mainloop, 0);
-}
-
-static void stream_latency_update_cb(pa_stream *s, void *userdata) {
- assert(s);
-
- pa_threaded_mainloop_signal(mainloop, 0);
-}
-
-StereoVolume PulseOutput::get_volume ()
-{
- StereoVolume v = {0, 0};
-
- if (! connected || ! volume_valid)
- return v;
-
- pa_threaded_mainloop_lock (mainloop);
- CHECK_DEAD_GOTO (fail, 1);
-
- if (volume.channels == 2)
- {
- v.left = aud::rescale<int> (volume.values[0], PA_VOLUME_NORM, 100);
- v.right = aud::rescale<int> (volume.values[1], PA_VOLUME_NORM, 100);
- }
- else
- v.left = v.right = aud::rescale<int> (pa_cvolume_avg (& volume), PA_VOLUME_NORM, 100);
-
-fail:
- pa_threaded_mainloop_unlock (mainloop);
- return v;
-}
-
-void PulseOutput::set_volume (StereoVolume v)
-{
- pa_operation * o;
-
- if (! connected)
- return;
-
- pa_threaded_mainloop_lock (mainloop);
- CHECK_DEAD_GOTO (fail, 1);
-
- if (! volume_valid || volume.channels != 1)
- {
- volume.values[0] = aud::rescale<int> (v.left, 100, PA_VOLUME_NORM);
- volume.values[1] = aud::rescale<int> (v.right, 100, PA_VOLUME_NORM);
- volume.channels = 2;
- }
- else
- {
- volume.values[0] = aud::rescale<int> (aud::max (v.left, v.right), 100, PA_VOLUME_NORM);
- volume.channels = 1;
- }
-
- volume_valid = true;
-
- if (! (o = pa_context_set_sink_input_volume (context, pa_stream_get_index
- (stream), & volume, nullptr, nullptr)))
- AUDDBG ("pa_context_set_sink_input_volume() failed: %s\n", pa_strerror
- (pa_context_errno (context)));
- else
- pa_operation_unref(o);
-
-fail:
- pa_threaded_mainloop_unlock (mainloop);
-}
-
-void PulseOutput::pause (bool pause)
-{
- pa_operation *o = nullptr;
- int success = 0;
-
- CHECK_CONNECTED();
-
- pa_threaded_mainloop_lock(mainloop);
- CHECK_DEAD_GOTO(fail, 1);
-
- if (!(o = pa_stream_cork(stream, pause, stream_success_cb, &success))) {
- AUDDBG("pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto fail;
- }
-
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(fail, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
- if (!success)
- AUDDBG("pa_stream_cork() failed: %s\n", pa_strerror(pa_context_errno(context)));
-
-fail:
-
- if (o)
- pa_operation_unref(o);
-
- pa_threaded_mainloop_unlock(mainloop);
-}
-
-int PulseOutput::get_delay ()
-{
- int delay = 0;
-
- CHECK_CONNECTED(0);
-
- pa_threaded_mainloop_lock(mainloop);
-
- pa_usec_t usec;
- int neg;
- if (pa_stream_get_latency (stream, & usec, & neg) == PA_OK)
- delay = usec / 1000;
-
- pa_threaded_mainloop_unlock(mainloop);
-
- return delay;
-}
-
-void PulseOutput::drain ()
-{
- pa_operation *o = nullptr;
- int success = 0;
-
- CHECK_CONNECTED();
-
- pa_threaded_mainloop_lock(mainloop);
- CHECK_DEAD_GOTO(fail, 0);
-
- if (!(o = pa_stream_drain(stream, stream_success_cb, &success))) {
- AUDDBG("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto fail;
- }
-
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(fail, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
- if (!success)
- AUDDBG("pa_stream_drain() failed: %s\n", pa_strerror(pa_context_errno(context)));
-
-fail:
- if (o)
- pa_operation_unref(o);
-
- pa_threaded_mainloop_unlock(mainloop);
-}
-
-void PulseOutput::flush ()
-{
- pa_operation *o = nullptr;
- int success = 0;
-
- CHECK_CONNECTED();
-
- pa_threaded_mainloop_lock(mainloop);
- CHECK_DEAD_GOTO(fail, 1);
-
- if (!(o = pa_stream_flush(stream, stream_success_cb, &success))) {
- AUDDBG("pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto fail;
- }
-
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(fail, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
- if (!success)
- AUDDBG("pa_stream_flush() failed: %s\n", pa_strerror(pa_context_errno(context)));
-
-fail:
- if (o)
- pa_operation_unref(o);
-
- pa_threaded_mainloop_unlock(mainloop);
-}
-
-void PulseOutput::period_wait ()
-{
- pa_operation * o = nullptr;
- int success = 0;
-
- CHECK_CONNECTED ();
-
- pa_threaded_mainloop_lock (mainloop);
- CHECK_DEAD_GOTO (fail, 1);
-
- if (! (o = pa_stream_trigger (stream, stream_success_cb, & success)))
- {
- AUDDBG ("pa_stream_trigger() failed: %s\n", pa_strerror (pa_context_errno (context)));
- goto fail;
- }
-
- while (pa_operation_get_state (o) != PA_OPERATION_DONE)
- {
- CHECK_DEAD_GOTO (fail, 1);
- pa_threaded_mainloop_wait (mainloop);
- }
-
- if (! success)
- AUDDBG ("pa_stream_trigger() failed: %s\n", pa_strerror (pa_context_errno (context)));
-
- while (! pa_stream_writable_size (stream))
- {
- CHECK_DEAD_GOTO (fail, 1);
- pa_threaded_mainloop_wait (mainloop);
- }
-
-fail:
- if (o)
- pa_operation_unref(o);
-
- pa_threaded_mainloop_unlock (mainloop);
-}
-
-int PulseOutput::write_audio (const void * ptr, int length)
-{
- CHECK_CONNECTED(0);
-
- int ret = 0;
- pa_threaded_mainloop_lock(mainloop);
- CHECK_DEAD_GOTO(fail, 1);
-
- length = aud::min ((size_t) length, pa_stream_writable_size (stream));
-
- if (pa_stream_write (stream, ptr, length, nullptr, 0, PA_SEEK_RELATIVE) < 0)
- {
- AUDDBG ("pa_stream_write() failed: %s\n", pa_strerror (pa_context_errno (context)));
- goto fail;
- }
-
- ret = length;
-
-fail:
- pa_threaded_mainloop_unlock(mainloop);
- return ret;
-}
-
-void PulseOutput::close_audio ()
-{
- connected = false;
-
- if (mainloop)
- pa_threaded_mainloop_stop(mainloop);
-
- if (stream) {
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = nullptr;
- }
-
- if (context) {
- pa_context_disconnect(context);
- pa_context_unref(context);
- context = nullptr;
- }
-
- if (mainloop) {
- pa_threaded_mainloop_free(mainloop);
- mainloop = nullptr;
- }
-
- volume_valid = false;
-}
-
-static pa_sample_format_t to_pulse_format (int aformat)
-{
- switch (aformat)
- {
- case FMT_U8: return PA_SAMPLE_U8;
- case FMT_S16_LE: return PA_SAMPLE_S16LE;
- case FMT_S16_BE: return PA_SAMPLE_S16BE;
-#ifdef PA_SAMPLE_S24_32LE
- case FMT_S24_LE: return PA_SAMPLE_S24_32LE;
- case FMT_S24_BE: return PA_SAMPLE_S24_32BE;
-#endif
-#ifdef PA_SAMPLE_S32LE
- case FMT_S32_LE: return PA_SAMPLE_S32LE;
- case FMT_S32_BE: return PA_SAMPLE_S32BE;
-#endif
- case FMT_FLOAT: return PA_SAMPLE_FLOAT32NE;
- default: return PA_SAMPLE_INVALID;
- }
-}
-
-bool PulseOutput::open_audio (int fmt, int rate, int nch)
-{
- pa_sample_spec ss;
-
- assert(!mainloop);
- assert(!context);
- assert(!stream);
- assert(!connected);
-
- ss.format = to_pulse_format (fmt);
- if (ss.format == PA_SAMPLE_INVALID)
- return false;
-
- ss.rate = rate;
- ss.channels = nch;
-
- if (!pa_sample_spec_valid(&ss))
- return false;
-
- if (!(mainloop = pa_threaded_mainloop_new())) {
- AUDERR ("Failed to allocate main loop\n");
- return false;
- }
-
- pa_threaded_mainloop_lock(mainloop);
-
- if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Audacious"))) {
- AUDERR ("Failed to allocate context\n");
- goto FAIL1;
- }
-
- pa_context_set_state_callback(context, context_state_cb, nullptr);
- pa_context_set_subscribe_callback(context, subscribe_cb, nullptr);
-
- if (pa_context_connect(context, nullptr, (pa_context_flags_t) 0, nullptr) < 0) {
- AUDERR ("Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL1;
- }
-
- if (pa_threaded_mainloop_start(mainloop) < 0) {
- AUDERR ("Failed to start main loop\n");
- goto FAIL1;
- }
-
- /* Wait until the context is ready */
- pa_threaded_mainloop_wait(mainloop);
-
- if (pa_context_get_state(context) != PA_CONTEXT_READY) {
- AUDERR ("Failed to connect to server: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL1;
- }
-
- if (!(stream = pa_stream_new(context, "Audacious", &ss, nullptr))) {
- AUDERR ("Failed to create stream: %s\n", pa_strerror(pa_context_errno(context)));
-
-FAIL1:
- pa_threaded_mainloop_unlock (mainloop);
- close_audio ();
- return false;
- }
-
- pa_stream_set_state_callback(stream, stream_state_cb, nullptr);
- pa_stream_set_write_callback(stream, stream_request_cb, nullptr);
- pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, nullptr);
-
- /* Connect stream with sink and default volume */
- /* Buffer struct */
-
- int aud_buffer = aud_get_int(nullptr, "output_buffer_size");
- size_t buffer_size = pa_usec_to_bytes(aud_buffer, &ss) * 1000;
- pa_buffer_attr buffer = {(uint32_t) -1, (uint32_t) buffer_size,
- (uint32_t) -1, (uint32_t) -1, (uint32_t) buffer_size};
-
- pa_operation *o = nullptr;
- int success;
-
- if (pa_stream_connect_playback (stream, nullptr, & buffer, (pa_stream_flags_t)
- (PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE), nullptr, nullptr) < 0)
- {
- AUDERR ("Failed to connect stream: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
-
-
- /* Wait until the stream is ready */
- pa_threaded_mainloop_wait(mainloop);
-
- if (pa_stream_get_state(stream) != PA_STREAM_READY) {
- AUDERR ("Failed to connect stream: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
-
- /* Now subscribe to events */
- if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) {
- AUDERR ("pa_context_subscribe() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
-
- success = 0;
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(FAIL2, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
- if (!success) {
- AUDERR ("pa_context_subscribe() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
-
- pa_operation_unref(o);
-
- /* Now request the initial stream info */
- if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, nullptr))) {
- AUDERR ("pa_context_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
-
- while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
- CHECK_DEAD_GOTO(FAIL2, 1);
- pa_threaded_mainloop_wait(mainloop);
- }
-
- if (!volume_valid) {
- AUDERR ("pa_context_get_sink_input_info() failed: %s\n", pa_strerror(pa_context_errno(context)));
- goto FAIL2;
- }
- pa_operation_unref(o);
-
- connected = true;
-
- pa_threaded_mainloop_unlock(mainloop);
-
- return true;
-
-FAIL2:
- if (o)
- pa_operation_unref(o);
-
- pa_threaded_mainloop_unlock(mainloop);
- close_audio ();
- return false;
-}
-
-bool PulseOutput::init ()
-{
- if (! open_audio (FMT_S16_NE, 44100, 2))
- return false;
-
- close_audio ();
- return true;
-}
-
-const char PulseOutput::about[] =
- N_("Audacious PulseAudio Output Plugin\n\n"
- "This program is free software; you can redistribute it and/or modify\n"
- "it under the terms of the GNU General Public License as published by\n"
- "the Free Software Foundation; either version 2 of the License, or\n"
- "(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,\n"
- "USA.");
diff --git a/src/qtaudio/qtaudio.cc b/src/qtaudio/qtaudio.cc
index e994283..6bf48ea 100644
--- a/src/qtaudio/qtaudio.cc
+++ b/src/qtaudio/qtaudio.cc
@@ -27,7 +27,6 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
-#include <libaudcore/interface.h>
#include <libaudcore/plugin.h>
#include <libaudcore/runtime.h>
@@ -35,10 +34,6 @@
#define VOLUME_RANGE 40 /* decibels */
-#define error(...) do { \
- aud_ui_show_error (str_printf ("QtAudio error: " __VA_ARGS__)); \
-} while (0)
-
class QtAudio : public OutputPlugin
{
public:
@@ -58,7 +53,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume v);
- bool open_audio (int aud_format, int rate, int chan);
+ bool open_audio (int aud_format, int rate, int chan, String & error);
void close_audio ();
void period_wait ();
@@ -143,7 +138,7 @@ void QtAudio::set_volume (StereoVolume v)
}
}
-bool QtAudio::open_audio (int format, int rate, int chan)
+bool QtAudio::open_audio (int format, int rate, int chan, String & error)
{
const FormatDescriptionMap * m = nullptr;
@@ -158,7 +153,8 @@ bool QtAudio::open_audio (int format, int rate, int chan)
if (! m)
{
- error ("The requested audio format %d is unsupported.\n", format);
+ error = String (str_printf ("QtAudio error: The requested audio format "
+ "%d is unsupported.", format));
return false;
}
@@ -186,7 +182,7 @@ bool QtAudio::open_audio (int format, int rate, int chan)
QAudioDeviceInfo info (QAudioDeviceInfo::defaultOutputDevice ());
if (! info.isFormatSupported (fmt))
{
- error ("Format not supported by backend.\n");
+ error = String ("QtAudio error: Format not supported by backend.");
return false;
}
diff --git a/src/gl-spectrum-qt/Makefile b/src/qtglspectrum/Makefile
index c4abd2b..c4abd2b 100644
--- a/src/gl-spectrum-qt/Makefile
+++ b/src/qtglspectrum/Makefile
diff --git a/src/gl-spectrum-qt/gl-spectrum.cc b/src/qtglspectrum/gl-spectrum.cc
index ea85e39..1f2a38e 100644
--- a/src/gl-spectrum-qt/gl-spectrum.cc
+++ b/src/qtglspectrum/gl-spectrum.cc
@@ -25,7 +25,6 @@
#include <math.h>
#include <string.h>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
@@ -53,7 +52,9 @@ public:
static constexpr PluginInfo info = {
N_("OpenGL Spectrum Analyzer"),
PACKAGE,
- gl_about
+ gl_about,
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr GLSpectrumQt () : VisPlugin (info, Visualizer::Freq) {}
diff --git a/src/qtui/Makefile b/src/qtui/Makefile
index 5808c32..0a1823f 100644
--- a/src/qtui/Makefile
+++ b/src/qtui/Makefile
@@ -3,7 +3,7 @@ PLUGIN = qtui${PLUGIN_SUFFIX}
SRCS = qtui.cc \
dialog_windows.cc \
main_window.cc \
- main_window_actions.cc \
+ menus.cc \
playlist.cc \
playlist_model.cc \
playlist_tabs.cc \
diff --git a/src/qtui/dialog_windows.cc b/src/qtui/dialog_windows.cc
index 1a0b720..05c47d6 100644
--- a/src/qtui/dialog_windows.cc
+++ b/src/qtui/dialog_windows.cc
@@ -38,6 +38,11 @@ void DialogWindows::show_error (const char * message)
audqt::simple_message (_("Error"), message, QMessageBox::Critical);
}
+void DialogWindows::show_info (const char * message)
+{
+ audqt::simple_message (_("Information"), message, QMessageBox::Information);
+}
+
void DialogWindows::show_progress (const char * message)
{
create_progress ();
diff --git a/src/qtui/dialog_windows.h b/src/qtui/dialog_windows.h
index 8b5468d..f6a6778 100644
--- a/src/qtui/dialog_windows.h
+++ b/src/qtui/dialog_windows.h
@@ -37,6 +37,7 @@ private:
void create_progress ();
void show_error (const char * message);
+ void show_info (const char * message);
void show_progress (const char * message);
void show_progress_2 (const char * message);
void hide_progress ();
@@ -44,7 +45,8 @@ private:
const HookReceiver<DialogWindows, const char *>
show_hook1 {"ui show progress", this, & DialogWindows::show_progress},
show_hook2 {"ui show progress 2", this, & DialogWindows::show_progress_2},
- show_hook3 {"ui show error", this, & DialogWindows::show_error};
+ show_hook3 {"ui show error", this, & DialogWindows::show_error},
+ show_hook4 {"ui show info", this, & DialogWindows::show_info};
const HookReceiver<DialogWindows>
hide_hook {"ui hide progress", this, & DialogWindows::hide_progress};
};
diff --git a/src/qtui/info_bar.h b/src/qtui/info_bar.h
index 75b5a30..2404967 100644
--- a/src/qtui/info_bar.h
+++ b/src/qtui/info_bar.h
@@ -24,7 +24,6 @@
#include <QWidget>
#include <libaudcore/hook.h>
-#include <libaudcore/visualizer.h>
class InfoVis;
diff --git a/src/qtui/main_window.cc b/src/qtui/main_window.cc
index 6f0b56d..57e4791 100644
--- a/src/qtui/main_window.cc
+++ b/src/qtui/main_window.cc
@@ -25,19 +25,23 @@
#include <libaudcore/plugins.h>
#include <libaudqt/libaudqt.h>
-#include <libaudqt/volumebutton.h>
#include "filter_input.h"
+#include "info_bar.h"
+#include "menus.h"
#include "playlist.h"
-#include "time_slider.h"
-#include "status_bar.h"
#include "playlist_tabs.h"
+#include "status_bar.h"
+#include "time_slider.h"
#include "tool_bar.h"
-#include <QApplication>
-#include <QDockWidget>
#include <QAction>
+#include <QBoxLayout>
+#include <QCloseEvent>
+#include <QDockWidget>
+#include <QLabel>
#include <QSettings>
+#include <QToolButton>
class PluginWidget : public QDockWidget
{
@@ -79,6 +83,12 @@ MainWindow::MainWindow () :
QIcon::setThemeSearchPaths (paths);
#endif
+ int instance = aud_get_instance ();
+ if (instance == 1)
+ m_config_name = "audacious";
+ else
+ m_config_name = QString ("audacious-%1").arg (instance);
+
auto slider = new TimeSlider (this);
const ToolBarItem items[] = {
@@ -99,7 +109,7 @@ MainWindow::MainWindow () :
[] (bool on) { aud_set_bool (nullptr, "repeat", on); }, & toolButtonRepeat),
ToolBarAction ("media-playlist-shuffle", N_("Shuffle"), N_("Shuffle"),
[] (bool on) { aud_set_bool (nullptr, "shuffle", on); }, & toolButtonShuffle),
- ToolBarCustom (new audqt::VolumeButton (this)),
+ ToolBarCustom (audqt::volume_button_new (this)),
ToolBarCustom (filterInput),
};
@@ -120,7 +130,7 @@ MainWindow::MainWindow () :
connect (filterInput, & QLineEdit::textChanged, playlistTabs, & PlaylistTabs::filterTrigger);
- setupActions ();
+ setMenuBar (qtui_build_menubar (this));
add_dock_plugins ();
if (aud_drct_get_playing ())
@@ -137,7 +147,7 @@ MainWindow::MainWindow () :
MainWindow::~MainWindow ()
{
- QSettings settings ("audacious", "QtUi");
+ QSettings settings (m_config_name, "QtUi");
settings.setValue ("geometry", saveGeometry ());
settings.setValue ("windowState", saveState ());
@@ -158,7 +168,7 @@ void MainWindow::closeEvent (QCloseEvent * e)
void MainWindow::readSettings ()
{
- QSettings settings ("audacious", "QtUi");
+ QSettings settings (m_config_name, "QtUi");
if (! restoreGeometry (settings.value ("geometry").toByteArray ()))
resize (768, 480);
@@ -183,6 +193,15 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
QMainWindow::keyPressEvent (e);
}
+void MainWindow::setWindowTitle (const QString & title)
+{
+ int instance = aud_get_instance ();
+ if (instance == 1)
+ QMainWindow::setWindowTitle (title);
+ else
+ QMainWindow::setWindowTitle (QString ("%1 (%2)").arg (title).arg (instance));
+}
+
void MainWindow::updateToggles ()
{
toolButtonRepeat->setChecked (aud_get_bool (nullptr, "repeat"));
diff --git a/src/qtui/main_window.h b/src/qtui/main_window.h
index f24c0e5..654abdd 100644
--- a/src/qtui/main_window.h
+++ b/src/qtui/main_window.h
@@ -23,18 +23,17 @@
#include <libaudcore/hook.h>
#include <libaudcore/index.h>
#include <libaudcore/mainloop.h>
-#include <libaudcore/objects.h>
#include "dialog_windows.h"
-#include "info_bar.h"
#include <QMainWindow>
-#include <QVBoxLayout>
class FilterInput;
+class InfoBar;
class PlaylistTabs;
class PluginHandle;
class PluginWidget;
+class QVBoxLayout;
class MainWindow : public QMainWindow
{
@@ -43,6 +42,7 @@ public:
~MainWindow ();
private:
+ QString m_config_name;
DialogWindows m_dialogs;
FilterInput * filterInput;
PlaylistTabs * playlistTabs;
@@ -59,8 +59,9 @@ private:
void closeEvent (QCloseEvent * e);
void keyPressEvent (QKeyEvent * e);
+ void setWindowTitle (const QString & title);
+
void updateToggles ();
- void setupActions ();
void readSettings ();
void add_dock_plugins ();
diff --git a/src/qtui/main_window_actions.cc b/src/qtui/menus.cc
index d9f2bf8..d3ca365 100644
--- a/src/qtui/main_window_actions.cc
+++ b/src/qtui/menus.cc
@@ -1,5 +1,5 @@
/*
- * main_window_actions.cc
+ * menus.cc
* Copyright 2014 Michał Lipski and William Pitcock
*
* Redistribution and use in source and binary forms, with or without
@@ -17,7 +17,8 @@
* the use of this software.
*/
-#include "main_window.h"
+#include "menus.h"
+#include "../ui-common/menu-ops.h"
#include <QMenuBar>
@@ -34,6 +35,7 @@
#include <libaudqt/menu.h>
static QMenu * services_menu () { return audqt::menu_get_by_id (AudMenuID::Main); }
+static QMenu * services_menu_pl () { return audqt::menu_get_by_id (AudMenuID::Playlist); }
static void open_files () { audqt::fileopener_show (audqt::FileMode::Open); }
static void add_files () { audqt::fileopener_show (audqt::FileMode::Add); }
@@ -42,48 +44,12 @@ static void add_folder () { audqt::fileopener_show (audqt::FileMode::AddFolder);
static void open_url () { audqt::urlopener_show (true); }
static void add_url () { audqt::urlopener_show (false); }
-static void rm_dupes_title () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void rm_dupes_filename () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Filename); }
-static void rm_dupes_path () { aud_playlist_remove_duplicates_by_scheme (aud_playlist_get_active (), Playlist::Path); }
-
-static void sort_track () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Track); }
-static void sort_title () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void sort_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Artist); }
-static void sort_album () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Album); }
-static void sort_album_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::AlbumArtist); }
-static void sort_date () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Date); }
-static void sort_genre () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Genre); }
-static void sort_length () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Length); }
-static void sort_path () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Path); }
-static void sort_custom_title () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::FormattedTitle); }
-static void sort_reverse () { aud_playlist_reverse (aud_playlist_get_active ()); }
-static void sort_random () { aud_playlist_randomize (aud_playlist_get_active ()); }
-
-static void sort_sel_track () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Track); }
-static void sort_sel_title () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Title); }
-static void sort_sel_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Artist); }
-static void sort_sel_album () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Album); }
-static void sort_sel_album_artist () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::AlbumArtist); }
-static void sort_sel_date () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Date); }
-static void sort_sel_genre () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Genre); }
-static void sort_sel_length () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Length); }
-static void sort_sel_path () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::Path); }
-static void sort_sel_custom_title () { aud_playlist_sort_by_scheme (aud_playlist_get_active (), Playlist::FormattedTitle); }
-static void sort_sel_reverse () { aud_playlist_reverse (aud_playlist_get_active ()); }
-static void sort_sel_random () { aud_playlist_randomize (aud_playlist_get_active ()); }
-
-static void pl_play () { aud_playlist_play (aud_playlist_get_active ()); }
-static void pl_refresh () { aud_playlist_rescan (aud_playlist_get_active ()); }
-static void pl_remove_failed () { aud_playlist_remove_failed (aud_playlist_get_active ()); }
static void pl_rename () { hook_call ("qtui rename playlist", nullptr); }
static void pl_close () { audqt::playlist_confirm_delete (aud_playlist_get_active ()); }
-static void volume_up () { aud_drct_set_volume_main (aud_drct_get_volume_main () + 5); }
-static void volume_down () { aud_drct_set_volume_main (aud_drct_get_volume_main () - 5); }
-
static void configure_effects () { audqt::prefswin_show_plugin_page (PluginType::Effect); }
-void MainWindow::setupActions ()
+QMenuBar * qtui_build_menubar (QWidget * parent)
{
static const audqt::MenuItem file_items[] = {
audqt::MenuCommand ({N_("_Open Files ..."), "document-open", "Ctrl+O"}, open_files),
@@ -192,5 +158,26 @@ void MainWindow::setupActions ()
audqt::MenuSub ({N_("_Output")}, output_items),
};
- setMenuBar (audqt::menubar_build (main_items, this));
+ return audqt::menubar_build (main_items, parent);
+}
+
+QMenu * qtui_build_pl_menu (QWidget * parent)
+{
+ static const audqt::MenuItem pl_items[] = {
+ audqt::MenuCommand ({N_("Song _Info ..."), "dialog-information", "Alt+I"}, pl_song_info),
+ audqt::MenuCommand ({N_("_Queue/Unqueue"), nullptr, "Alt+Q"}, pl_queue_toggle),
+ audqt::MenuSep (),
+ audqt::MenuCommand ({N_("_Open Containing Folder"), "folder"}, pl_open_folder),
+ audqt::MenuCommand ({N_("_Refresh Selected"), "view-refresh", "F6"}, pl_refresh_sel),
+ audqt::MenuSep (),
+ audqt::MenuCommand ({N_("Cu_t"), "edit-cut", "Ctrl+X"}, pl_cut),
+ audqt::MenuCommand ({N_("_Copy"), "edit-copy", "Ctrl+C"}, pl_copy),
+ audqt::MenuCommand ({N_("_Paste"), "edit-paste", "Ctrl+V"}, pl_paste),
+ audqt::MenuCommand ({N_("Paste at _End"), "edit-paste", "Shift+Ctrl+V"}, pl_paste_end),
+ audqt::MenuCommand ({N_("Select _All"), "edit-select-all"}, pl_select_all),
+ audqt::MenuSep (),
+ audqt::MenuSub ({N_("_Services")}, services_menu_pl)
+ };
+
+ return audqt::menu_build (pl_items, parent);
}
diff --git a/src/qtui/menus.h b/src/qtui/menus.h
new file mode 100644
index 0000000..bc1c254
--- /dev/null
+++ b/src/qtui/menus.h
@@ -0,0 +1,30 @@
+/*
+ * menus.h
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#ifndef MENUS_H
+#define MENUS_H
+
+class QMenu;
+class QMenuBar;
+class QWidget;
+
+QMenuBar * qtui_build_menubar (QWidget * parent);
+QMenu * qtui_build_pl_menu (QWidget * parent);
+
+#endif // MENUS_H
diff --git a/src/qtui/playlist.cc b/src/qtui/playlist.cc
index 5a9a91e..001193f 100644
--- a/src/qtui/playlist.cc
+++ b/src/qtui/playlist.cc
@@ -18,6 +18,7 @@
*/
#include <QKeyEvent>
+#include <QMenu>
#include <QSortFilterProxyModel>
#include <libaudcore/audstrings.h>
@@ -29,7 +30,9 @@
#include "playlist.h"
#include "playlist_model.h"
-PlaylistWidget::PlaylistWidget (QTreeView * parent, int uniqueId) : QTreeView (parent)
+#include "../ui-common/menu-ops.h"
+
+PlaylistWidget::PlaylistWidget (QWidget * parent, int uniqueId) : QTreeView (parent)
{
model = new PlaylistModel (nullptr, uniqueId);
@@ -38,7 +41,11 @@ PlaylistWidget::PlaylistWidget (QTreeView * parent, int uniqueId) : QTreeView (p
proxyModel->setSourceModel (model);
proxyModel->setFilterKeyColumn (-1); /* filter by all columns */
+ inUpdate = true; /* prevents changing focused row */
setModel (proxyModel);
+ inUpdate = false;
+
+ setAllColumnsShowFocus (true);
setAlternatingRowColors (true);
setAttribute (Qt::WA_MacShowFocusRect, false);
setIndentation (0);
@@ -89,6 +96,12 @@ int PlaylistWidget::indexToRow (const QModelIndex & index)
return proxyModel->mapToSource (index).row ();
}
+void PlaylistWidget::contextMenuEvent (QContextMenuEvent * event)
+{
+ if (contextMenu)
+ contextMenu->popup (event->globalPos ());
+}
+
void PlaylistWidget::keyPressEvent (QKeyEvent * event)
{
switch (event->modifiers ())
@@ -113,7 +126,7 @@ void PlaylistWidget::keyPressEvent (QKeyEvent * event)
aud_drct_play_pause ();
break;
case Qt::Key_Delete:
- deleteCurrentSelection ();
+ pl_remove_selected ();
break;
case Qt::Key_Z:
aud_drct_pl_prev ();
@@ -130,30 +143,16 @@ void PlaylistWidget::keyPressEvent (QKeyEvent * event)
case Qt::Key_B:
aud_drct_pl_next ();
return;
- case Qt::Key_Q:
- toggleQueue ();
- return;
}
break;
}
- QTreeView::keyPressEvent (event);
-}
-
-void PlaylistWidget::mousePressEvent (QMouseEvent * event)
-{
- QModelIndex index = indexAt (event->pos ());
-
- if (! index.isValid ())
- return;
-
- QTreeView::mousePressEvent (event);
+ QTreeView::keyPressEvent (event);
}
void PlaylistWidget::mouseDoubleClickEvent (QMouseEvent * event)
{
QModelIndex index = indexAt (event->pos ());
-
if (! index.isValid ())
return;
@@ -329,22 +328,6 @@ void PlaylistWidget::playCurrentIndex ()
aud_playlist_play (playlist ());
}
-void PlaylistWidget::deleteCurrentSelection ()
-{
- aud_playlist_delete_selected (playlist ());
-}
-
-void PlaylistWidget::toggleQueue ()
-{
- int row = indexToRow (currentIndex ());
- int at = aud_playlist_queue_find_entry (playlist (), row);
-
- if (at < 0)
- aud_playlist_queue_insert (playlist (), -1, row);
- else
- aud_playlist_queue_delete (playlist (), at, 1);
-}
-
void PlaylistWidget::updateSettings ()
{
setHeaderHidden (! aud_get_bool ("qtui", "playlist_headers"));
diff --git a/src/qtui/playlist.h b/src/qtui/playlist.h
index e8523c0..be396d9 100644
--- a/src/qtui/playlist.h
+++ b/src/qtui/playlist.h
@@ -25,29 +25,34 @@
#include <libaudcore/hook.h>
#include <libaudcore/playlist.h>
-#include "playlist_model.h"
-#include "filter_input.h"
-
+class PlaylistModel;
+class QContextMenuEvent;
+class QMenu;
class QSortFilterProxyModel;
class PlaylistWidget : public QTreeView
{
public:
- PlaylistWidget (QTreeView * parent = nullptr, int uniqueId = -1);
+ PlaylistWidget (QWidget * parent = nullptr, int uniqueId = -1);
~PlaylistWidget ();
+
void scrollToCurrent ();
void updatePlaybackIndicator ();
void update (const Playlist::Update & update);
void playCurrentIndex ();
- void deleteCurrentSelection ();
void setFilter (const QString & text);
- void toggleQueue ();
+
int playlist () const;
int uniqueId () const;
+ void setContextMenu (QMenu * menu)
+ { contextMenu = menu; }
+
private:
PlaylistModel * model;
QSortFilterProxyModel * proxyModel;
+ QMenu * contextMenu = nullptr;
+
int currentPos = -1;
bool inUpdate = false;
bool needIndicatorUpdate = false;
@@ -59,8 +64,8 @@ private:
void getSelectedRanges (const Playlist::Update & update,
QItemSelection & selected, QItemSelection & deselected);
+ void contextMenuEvent (QContextMenuEvent * event);
void keyPressEvent (QKeyEvent * event);
- void mousePressEvent (QMouseEvent * event);
void mouseDoubleClickEvent (QMouseEvent * event);
void currentChanged (const QModelIndex & current, const QModelIndex & previous);
void selectionChanged (const QItemSelection & selected, const QItemSelection & deselected);
diff --git a/src/qtui/playlist_model.cc b/src/qtui/playlist_model.cc
index 0d92cfd..7c15a98 100644
--- a/src/qtui/playlist_model.cc
+++ b/src/qtui/playlist_model.cc
@@ -69,7 +69,7 @@ QVariant PlaylistModel::data (const QModelIndex &index, int role) const
case PL_COL_ARTIST:
case PL_COL_ALBUM:
case PL_COL_LENGTH:
- tuple = aud_playlist_entry_get_tuple (playlist (), index.row (), Playlist::Guess);
+ tuple = aud_playlist_entry_get_tuple (playlist (), index.row (), Playlist::NoWait);
break;
}
diff --git a/src/qtui/playlist_model.h b/src/qtui/playlist_model.h
index 6c31f41..d2dad2e 100644
--- a/src/qtui/playlist_model.h
+++ b/src/qtui/playlist_model.h
@@ -37,16 +37,21 @@ class PlaylistModel : public QAbstractListModel
public:
PlaylistModel (QObject * parent = nullptr, int id = -1);
~PlaylistModel ();
+
int rowCount (const QModelIndex & parent = QModelIndex ()) const;
int columnCount (const QModelIndex & parent = QModelIndex ()) const;
QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
bool insertRows (int row, int count, const QModelIndex & parent = QModelIndex ());
bool removeRows (int row, int count, const QModelIndex & parent = QModelIndex ());
+
void updateRows (int row, int count);
+
QString getQueued (int row) const;
int playlist () const;
int uniqueId () const;
+
+private:
int m_uniqueId;
int m_rows;
};
diff --git a/src/qtui/playlist_tabs.cc b/src/qtui/playlist_tabs.cc
index 68632c5..cc8a875 100644
--- a/src/qtui/playlist_tabs.cc
+++ b/src/qtui/playlist_tabs.cc
@@ -19,6 +19,7 @@
#include "playlist.h"
#include "playlist_tabs.h"
+#include "menus.h"
#include <QKeyEvent>
#include <QLineEdit>
@@ -30,6 +31,7 @@
PlaylistTabs::PlaylistTabs (QWidget * parent) :
QTabWidget (parent),
+ m_pl_menu (qtui_build_pl_menu (this)),
m_leftbtn (nullptr),
m_tabbar (new PlaylistTabBar (this))
{
@@ -46,6 +48,14 @@ PlaylistTabs::PlaylistTabs (QWidget * parent) :
connect (this, & QTabWidget::currentChanged, this, & PlaylistTabs::currentChangedTrigger);
}
+PlaylistWidget * PlaylistTabs::createWidget (int list)
+{
+ int id = aud_playlist_get_unique_id (list);
+ auto widget = new PlaylistWidget (this, id);
+ widget->setContextMenu (m_pl_menu);
+ return widget;
+}
+
void PlaylistTabs::addRemovePlaylists ()
{
int tabs = count ();
@@ -83,8 +93,7 @@ void PlaylistTabs::addRemovePlaylists ()
if (! found)
{
- int id = aud_playlist_get_unique_id (i);
- insertTab (i, new PlaylistWidget (0, id), QString ());
+ insertTab (i, createWidget (i), QString ());
tabs ++;
}
}
@@ -92,8 +101,7 @@ void PlaylistTabs::addRemovePlaylists ()
while (tabs < playlists)
{
- int id = aud_playlist_get_unique_id (tabs);
- addTab (new PlaylistWidget (0, id), QString ());
+ addTab (createWidget (tabs), QString ());
tabs ++;
}
}
@@ -123,16 +131,13 @@ QLineEdit * PlaylistTabs::getTabEdit (int idx)
void PlaylistTabs::setTabTitle (int idx, const char * text)
{
- QString title = QString ();
+ // escape ampersands for setTabText ()
+ auto title = QString (text).replace ("&", "&&");
if (aud_get_bool ("qtui", "entry_count_visible"))
- {
- title.setNum (aud_playlist_entry_count (idx));
- title.prepend (" (").append (")");
- }
+ title += QString (" (%1)").arg (aud_playlist_entry_count (idx));
- // escape ampersands for setTabText ()
- setTabText (idx, title.prepend (QString (text).replace ("&", "&&")));
+ setTabText (idx, title);
}
void PlaylistTabs::setupTab (int idx, QWidget * button, const char * text, QWidget * * oldp)
diff --git a/src/qtui/playlist_tabs.h b/src/qtui/playlist_tabs.h
index 1aff1e0..d825068 100644
--- a/src/qtui/playlist_tabs.h
+++ b/src/qtui/playlist_tabs.h
@@ -20,17 +20,16 @@
#ifndef PLAYLIST_TABS_H
#define PLAYLIST_TABS_H
+#include <QTabBar>
#include <QTabWidget>
#include <libaudcore/hook.h>
#include <libaudcore/playlist.h>
-#include "playlist.h"
-#include "filter_input.h"
-
class PlaylistTabBar;
class PlaylistWidget;
class QLineEdit;
+class QMenu;
class PlaylistTabs : public QTabWidget
{
@@ -49,12 +48,14 @@ protected:
bool eventFilter (QObject * obj, QEvent * e);
private:
+ QMenu * m_pl_menu;
QWidget * m_leftbtn;
PlaylistTabBar * m_tabbar;
QLineEdit * getTabEdit (int idx);
void setTabTitle (int idx, const char * text);
void setupTab (int idx, QWidget * button, const char * text, QWidget * * oldp);
+ PlaylistWidget * createWidget (int list);
void addRemovePlaylists ();
void updateTitles ();
diff --git a/src/qtui/qtui.cc b/src/qtui/qtui.cc
index c410cdb..d786b30 100644
--- a/src/qtui/qtui.cc
+++ b/src/qtui/qtui.cc
@@ -19,7 +19,6 @@
#include <QApplication>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/i18n.h>
#include <libaudcore/plugin.h>
#include <libaudcore/runtime.h>
@@ -30,13 +29,22 @@
#include "main_window.h"
#include "settings.h"
+#include "../ui-common/menu-ops.cc"
+#include "../ui-common/menu-ops-qt.cc"
+
class QtUI : public audqt::QtIfacePlugin
{
private:
MainWindow * window = nullptr;
public:
- constexpr QtUI () : audqt::QtIfacePlugin ({N_("Qt Interface"), PACKAGE, nullptr, & qtui_prefs}) {}
+ constexpr QtUI () : audqt::QtIfacePlugin ({
+ N_("Qt Interface"),
+ PACKAGE,
+ nullptr,
+ & qtui_prefs,
+ PluginQtOnly
+ }) {}
bool init ()
{
diff --git a/src/qtui/status_bar.cc b/src/qtui/status_bar.cc
index 35f4632..4753fc3 100644
--- a/src/qtui/status_bar.cc
+++ b/src/qtui/status_bar.cc
@@ -24,6 +24,8 @@
#include <libaudcore/i18n.h>
#include <libaudcore/playlist.h>
+#include <QLabel>
+
StatusBar::StatusBar (QWidget * parent) :
QStatusBar (parent),
codec_label (new QLabel (this)),
diff --git a/src/qtui/status_bar.h b/src/qtui/status_bar.h
index 5e2c139..ebd1a63 100644
--- a/src/qtui/status_bar.h
+++ b/src/qtui/status_bar.h
@@ -20,11 +20,12 @@
#ifndef STATUS_BAR_H
#define STATUS_BAR_H
-#include <QLabel>
#include <QStatusBar>
#include <libaudcore/hook.h>
+class QLabel;
+
class StatusBar : public QStatusBar
{
public:
diff --git a/src/qtui/time_slider.cc b/src/qtui/time_slider.cc
index 8211991..68b850c 100644
--- a/src/qtui/time_slider.cc
+++ b/src/qtui/time_slider.cc
@@ -22,6 +22,10 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/drct.h>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QStyle>
+
TimeSlider::TimeSlider (QWidget * parent) :
QSlider (Qt::Horizontal, parent),
m_label (new QLabel (parent))
diff --git a/src/qtui/time_slider.h b/src/qtui/time_slider.h
index c6c90f8..d216026 100644
--- a/src/qtui/time_slider.h
+++ b/src/qtui/time_slider.h
@@ -20,13 +20,13 @@
#ifndef TIME_SLIDER_H
#define TIME_SLIDER_H
-#include <QLabel>
#include <QSlider>
-#include <QStyle>
-#include <QMouseEvent>
#include <libaudcore/hook.h>
+class QLabel;
+class QMouseEvent;
+
class TimeSlider : public QSlider
{
public:
diff --git a/src/scrobbler2/Makefile b/src/scrobbler2/Makefile
index 3bede4e..5180675 100644
--- a/src/scrobbler2/Makefile
+++ b/src/scrobbler2/Makefile
@@ -16,5 +16,5 @@ plugindir := ${plugindir}/${GENERAL_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS} -Wall
-CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${CURL_CFLAGS} ${XML_CFLAGS} -I../..
-LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${CURL_LIBS} ${XML_LIBS}
+CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GLIB_CFLAGS} ${CURL_CFLAGS} ${XML_CFLAGS} -I../..
+LIBS += ${GLIB_LIBS} ${CURL_LIBS} ${XML_LIBS}
diff --git a/src/scrobbler2/config_window.cc b/src/scrobbler2/config_window.cc
index 2b228f5..374c04b 100644
--- a/src/scrobbler2/config_window.cc
+++ b/src/scrobbler2/config_window.cc
@@ -1,6 +1,7 @@
+//audacious includes
+#include <libaudcore/audstrings.h>
+#include <libaudcore/hook.h>
-//external includes
-#include <gdk/gdk.h>
//plugin includes
#include "scrobbler.h"
@@ -12,103 +13,49 @@ enum permission perm_result = PERMISSION_UNKNOWN;
String username;
-//static (private) variables
-static GtkWidget *button;
-static GtkWidget *revoke_button;
-static GtkWidget *permission_status_icon;
-static GtkWidget *permission_status_label;
-
-static GtkWidget *details_label_first;
-static GtkWidget *url_button;
-static GtkWidget *details_label_second;
-
-static GtkWidget *additional_details_icon;
-static GtkWidget *additional_details_label;
-
-
-static gboolean permission_checker_thread (void * data) {
+static gboolean permission_checker_thread (void *) {
if (permission_check_requested == true) {
//the answer hasn't arrived yet
+ hook_call("ui show progress", (void *)N_("Checking Last.fm access ..."));
return true;
} else {
//the answer has arrived
+ hook_call("ui hide progress", nullptr);
g_assert(perm_result != PERMISSION_UNKNOWN);
- if (perm_result == PERMISSION_ALLOWED) {
- gtk_image_set_from_icon_name(GTK_IMAGE(permission_status_icon), "face-smile", GTK_ICON_SIZE_SMALL_TOOLBAR);
-
- char *markup = g_markup_printf_escaped(_("OK. Scrobbling for user: %s"),
- (const char *)username);
+ auto msg2 = _("Your scrobbles are being saved on your computer "
+ "temporarily. They will be submitted as soon as Audacious is "
+ "allowed access.");
- gtk_label_set_markup(GTK_LABEL(permission_status_label), markup);
- gtk_widget_set_sensitive(revoke_button, true);
- g_free(markup);
+ if (perm_result == PERMISSION_ALLOWED) {
+ hook_call("ui show info", (void *)(const char *)str_printf
+ (_("Permission granted. Scrobbling for user %s."),
+ (const char *)username));
} else if (perm_result == PERMISSION_DENIED) {
+ auto msg1 = _("Permission denied. Open the following "
+ "URL in a browser, allow Audacious access to your account, and "
+ "then click 'Check Permission' again:");
+ auto url = str_printf("http://www.last.fm/api/auth/?api_key=%s"
+ "&token=%s", SCROBBLER_API_KEY, (const char *)request_token);
- gtk_image_set_from_icon_name(GTK_IMAGE(permission_status_icon), "dialog-error", GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_image_set_from_icon_name(GTK_IMAGE(additional_details_icon), "dialog-information", GTK_ICON_SIZE_SMALL_TOOLBAR);
-
-
- gtk_label_set_label(GTK_LABEL(permission_status_label), _("Permission Denied"));
-
- gtk_label_set_markup(GTK_LABEL(details_label_first), _("Access the following link to allow Audacious to scrobble your plays:"));
-
- char *url = g_markup_printf_escaped("http://www.last.fm/api/auth/?api_key=%s&token=%s",
- SCROBBLER_API_KEY, (const char *)request_token);
-
- gtk_link_button_set_uri(GTK_LINK_BUTTON(url_button), url);
- gtk_button_set_label(GTK_BUTTON(url_button), url);
- gtk_widget_show(url_button);
- g_free(url);
-
- gtk_label_set_markup(GTK_LABEL(details_label_second), _("Keep this window open and click 'Check Permission' again.\n"));
-
- gtk_label_set_label(GTK_LABEL(additional_details_label),
- _("Don't worry. Your scrobbles are saved on your computer.\n"
- "They will be submitted as soon as Audacious is allowed to do so."));
+ hook_call("ui show error", (void *)(const char *)str_concat
+ ({msg1, "\n\n", url, "\n\n", msg2}));
} else if (perm_result == PERMISSION_NONET) {
- gtk_image_set_from_icon_name(GTK_IMAGE(permission_status_icon), "dialog-warning", GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_image_set_from_icon_name(GTK_IMAGE(additional_details_icon), "dialog-information", GTK_ICON_SIZE_SMALL_TOOLBAR);
+ auto msg1 = _("There was a problem contacting Last.fm.");
-
- gtk_label_set_label(GTK_LABEL(permission_status_label), _("Network Problem."));
- gtk_label_set_label(GTK_LABEL(details_label_first), _("There was a problem contacting Last.fm. Please try again later."));
- gtk_label_set_label(GTK_LABEL(additional_details_label),
- _("Don't worry. Your scrobbles are saved on your computer.\n"
- "They will be submitted as soon as Audacious is allowed to do so."));
+ hook_call("ui show error", (void *)(const char *)str_concat
+ ({msg1, "\n\n", msg2}));
}
perm_result = PERMISSION_UNKNOWN;
- gtk_widget_set_sensitive(button, true);
-
return false;
}
}
-
-static void cleanup_window() {
- gtk_widget_set_sensitive(button, false);
- gtk_widget_set_sensitive(revoke_button, false);
-
- gtk_image_clear(GTK_IMAGE(permission_status_icon));
- gtk_image_clear(GTK_IMAGE(additional_details_icon));
-
- gtk_label_set_label(GTK_LABEL(permission_status_label), (""));
- gtk_label_set_label(GTK_LABEL(details_label_first), "");
- gtk_widget_hide(url_button);
- gtk_label_set_label(GTK_LABEL(details_label_second), "");
- gtk_label_set_label(GTK_LABEL(additional_details_label), "");
-}
-
-static void permission_checker (GtkButton *button12, void * data) {
- cleanup_window();
-
- gtk_image_set_from_icon_name(GTK_IMAGE(permission_status_icon), "system-run", GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_label_set_label(GTK_LABEL(permission_status_label), _("Checking..."));
-
+static void permission_checker () {
//This will make the communication thread check the permission
//and set the current status on the perm_result enum
permission_check_requested = true;
@@ -123,102 +70,26 @@ static void permission_checker (GtkButton *button12, void * data) {
pthread_mutex_unlock(&communication_mutex);
//The button is clicked. Wait for the permission check to be done.
- gdk_threads_add_timeout_seconds(1, permission_checker_thread, data);
+ g_timeout_add(250, permission_checker_thread, nullptr);
}
-static void revoke_permissions (GtkButton *revoke_button2, void * data) {
- cleanup_window();
-
+static void revoke_permissions () {
pthread_mutex_lock(&communication_mutex);
invalidate_session_requested = true;
scrobbling_enabled = false;
pthread_cond_signal(&communication_signal);
pthread_mutex_unlock(&communication_mutex);
-
- gtk_widget_set_sensitive(button, true);
-}
-
-/*
- ,---config_box---------------------.
- | |
- |,-permission_box----------------. |
- || ,-buttons_box--. | |
- || |button | perm_status | |
- || |revoke_button | | |
- || `--------------' | |
- |`-------------------------------' |
- | |
- |,-details_box------------------. |
- ||details_label_first | |
- ||url_button | |
- ||details_label_second | |
- |`------------------------------' |
- | |
- |,-additional_details_box--------. |
- ||_______________________________| |
- |__________________________________|
-
- */
-static void *config_status_checker () {
- GtkWidget *config_box;
- GtkWidget *permission_box;
- GtkWidget *buttons_box;
- GtkWidget *details_box;
- GtkWidget *additional_details_box;
-
- config_box = gtk_vbox_new (false, 15);
- permission_box = gtk_hbox_new (false, 0);
- buttons_box = gtk_vbutton_box_new ();
- details_box = gtk_vbox_new (false, 0);
- additional_details_box = gtk_hbox_new (false, 7);
-
- button = gtk_button_new_with_mnemonic(_("C_heck Permission"));
- revoke_button = gtk_button_new_with_mnemonic(_("_Revoke Permission"));
- gtk_widget_set_sensitive(revoke_button, false);
-
- permission_status_icon = gtk_image_new();
- permission_status_label = gtk_label_new("");
-
- details_label_first = gtk_label_new ("");
- url_button = gtk_link_button_new("");
- details_label_second = gtk_label_new("");
-
- gtk_widget_hide(url_button);
- gtk_widget_set_no_show_all(url_button, true);
-
- additional_details_icon = gtk_image_new();
- additional_details_label = gtk_label_new("");
-
-
- g_signal_connect (button, "clicked", G_CALLBACK (permission_checker), nullptr);
- g_signal_connect (revoke_button, "clicked", G_CALLBACK (revoke_permissions), nullptr);
-
- gtk_box_pack_start(GTK_BOX(permission_box), buttons_box, false, false, 20);
- gtk_box_pack_start(GTK_BOX(permission_box), permission_status_icon, false, false, 0);
- gtk_box_pack_start(GTK_BOX(permission_box), permission_status_label, false, false, 5);
-
- gtk_box_pack_start(GTK_BOX(buttons_box), button, false, false, 0);
- gtk_box_pack_start(GTK_BOX(buttons_box), revoke_button, false, false, 0);
-
- gtk_box_pack_start(GTK_BOX(details_box), details_label_first, false, false, 0);
- gtk_box_pack_start(GTK_BOX(details_box), url_button, false, false, 0);
- gtk_box_pack_start(GTK_BOX(details_box), details_label_second, false, false, 0);
-
- gtk_box_pack_start(GTK_BOX(additional_details_box), additional_details_icon, false, false, 0);
- gtk_box_pack_start(GTK_BOX(additional_details_box), additional_details_label, false, false, 0);
-
- gtk_box_pack_start(GTK_BOX(config_box), permission_box, false, false, 0);
- gtk_box_pack_start(GTK_BOX(config_box), details_box, false, false, 0);
- gtk_box_pack_start(GTK_BOX(config_box), additional_details_box, false, false, 0);
-
- return config_box;
}
+static const PreferencesWidget buttons[] = {
+ WidgetButton (N_("Check Permission"), {permission_checker}),
+ WidgetButton (N_("Revoke Permission"), {revoke_permissions})
+};
static const PreferencesWidget config_contents[] = {
- WidgetLabel (N_("You need to allow Audacious to scrobble tracks to your Last.fm account.\n")),
- WidgetCustomGTK (config_status_checker)
+ WidgetLabel (N_("You need to allow Audacious to scrobble tracks to your Last.fm account.")),
+ WidgetBox ({{buttons}, true})
};
const PluginPreferences configuration = {{config_contents}};
diff --git a/src/scrobbler2/scrobbler.cc b/src/scrobbler2/scrobbler.cc
index c019595..9c44b94 100644
--- a/src/scrobbler2/scrobbler.cc
+++ b/src/scrobbler2/scrobbler.cc
@@ -139,7 +139,7 @@ static void ended (void *hook_data, void *user_data) {
//Called when when a track finishes playing.
//TODO: hic sunt race conditions
- if (playing_track && (g_get_monotonic_time() > (play_started_at + 30*G_USEC_PER_SEC)) ) {
+ if (playing_track.valid() && (g_get_monotonic_time() > (play_started_at + 30*G_USEC_PER_SEC)) ) {
//This is an odd situation when the track's real length doesn't correspond to the length reported by the player.
//If we are at the end of the track, it is longer than 30 seconds and it wasn't scrobbled, we scrobble it by then.
@@ -185,7 +185,7 @@ static void ready (void *hook_data, void *user_data) {
}
static void paused (void *hook_data, void *user_data) {
- if (! playing_track) {
+ if (! playing_track.valid()) {
//This happens when audacious is started in paused mode
return;
}
@@ -202,7 +202,7 @@ static void paused (void *hook_data, void *user_data) {
static void unpaused (void *hook_data, void *user_data) {
- if (! playing_track
+ if (! playing_track.valid()
|| pause_started_at == 0) { //TODO: audacious was started with a paused track.
return;
}
diff --git a/src/scrobbler2/scrobbler.h b/src/scrobbler2/scrobbler.h
index aa7db76..9236a31 100644
--- a/src/scrobbler2/scrobbler.h
+++ b/src/scrobbler2/scrobbler.h
@@ -15,7 +15,6 @@
#include <string.h>
#include <glib.h>
#include <libxml/xpath.h>
-#include <gtk/gtk.h>
//audacious includes
#include <libaudcore/i18n.h>
diff --git a/src/scrobbler2/scrobbler_communication.cc b/src/scrobbler2/scrobbler_communication.cc
index ecc9e64..e6bd579 100644
--- a/src/scrobbler2/scrobbler_communication.cc
+++ b/src/scrobbler2/scrobbler_communication.cc
@@ -48,14 +48,10 @@ static size_t result_callback (void *buffer, size_t size, size_t nmemb, void *us
return len;
}
-static int param_compare (const API_Parameter & a, const API_Parameter & b, void *)
-{
- return g_strcmp0 (a.paramName, b.paramName);
-}
-
static char * scrobbler_get_signature (Index<API_Parameter> & params)
{
- params.sort (param_compare, nullptr);
+ params.sort ([] (const API_Parameter & a, const API_Parameter & b)
+ { return g_strcmp0 (a.paramName, b.paramName); });
StringBuf buf (0);
diff --git a/src/sdlout/sdlout.cc b/src/sdlout/sdlout.cc
index cc3b379..4a94e24 100644
--- a/src/sdlout/sdlout.cc
+++ b/src/sdlout/sdlout.cc
@@ -27,17 +27,12 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
-#include <libaudcore/interface.h>
#include <libaudcore/plugin.h>
#include <libaudcore/ringbuf.h>
#include <libaudcore/runtime.h>
#define VOLUME_RANGE 40 /* decibels */
-#define sdlout_error(...) do { \
- aud_ui_show_error (str_printf ("SDL error: " __VA_ARGS__)); \
-} while (0)
-
class SDLOutput : public OutputPlugin
{
public:
@@ -58,7 +53,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume v);
- bool open_audio (int aud_format, int rate, int chans);
+ bool open_audio (int aud_format, int rate, int chans, String & error);
void close_audio ();
void period_wait ();
@@ -191,11 +186,11 @@ static void callback (void * user, unsigned char * buf, int len)
pthread_mutex_unlock (& sdlout_mutex);
}
-bool SDLOutput::open_audio (int format, int rate, int chan)
+bool SDLOutput::open_audio (int format, int rate, int chan, String & error)
{
if (format != FMT_S16_NE)
{
- sdlout_error ("Only signed 16-bit, native endian audio is supported.\n");
+ error = String ("SDL error: Only signed 16-bit, native endian audio is supported.");
return false;
}
@@ -220,7 +215,8 @@ bool SDLOutput::open_audio (int format, int rate, int chan)
if (SDL_OpenAudio (& spec, nullptr) < 0)
{
- sdlout_error ("Failed to open audio stream: %s.\n", SDL_GetError ());
+ error = String (str_printf
+ ("SDL error: Failed to open audio stream: %s.", SDL_GetError ()));
buffer.destroy ();
return false;
}
diff --git a/src/search-tool-qt/search-tool-qt.cc b/src/search-tool-qt/search-tool-qt.cc
index 7a1f51b..aab0cee 100644
--- a/src/search-tool-qt/search-tool-qt.cc
+++ b/src/search-tool-qt/search-tool-qt.cc
@@ -30,7 +30,6 @@
#include <QPushButton>
#include <QTreeView>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
@@ -50,7 +49,10 @@ class SearchToolQt : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("Search Tool"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr SearchToolQt () : GeneralPlugin (info, false) {}
@@ -225,17 +227,20 @@ static int get_playlist (bool require_added, bool require_scanned)
return list;
}
-static String get_path ()
+static String get_uri ()
{
+ auto to_uri = [] (const char * path)
+ { return String (filename_to_uri (path)); };
+
String path1 = aud_get_str ("search-tool", "path");
- if (g_file_test (path1, G_FILE_TEST_EXISTS))
- return path1;
+ if (path1[0])
+ return strstr (path1, "://") ? path1 : to_uri (path1);
StringBuf path2 = filename_build ({g_get_home_dir (), "Music"});
if (g_file_test (path2, G_FILE_TEST_EXISTS))
- return String (path2);
+ return to_uri (path2);
- return String (g_get_home_dir ());
+ return to_uri (g_get_home_dir ());
}
static void destroy_database ()
@@ -254,7 +259,7 @@ static void create_database (int list)
for (int e = 0; e < entries; e ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (list, e, Playlist::Nothing);
+ Tuple tuple = aud_playlist_entry_get_tuple (list, e, Playlist::NoWait);
aud::array<SearchField, String> fields;
fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
@@ -317,7 +322,7 @@ static void search_cb (const Key & key, Item & item, void * _state)
state->mask = oldmask;
}
-static int item_compare (const Item * const & a, const Item * const & b, void *)
+static int item_compare (const Item * const & a, const Item * const & b)
{
if (a->field < b->field)
return -1;
@@ -329,19 +334,19 @@ static int item_compare (const Item * const & a, const Item * const & b, void *)
return val;
if (a->parent)
- return b->parent ? item_compare (a->parent, b->parent, nullptr) : 1;
+ return b->parent ? item_compare (a->parent, b->parent) : 1;
else
return b->parent ? -1 : 0;
}
-static int item_compare_pass1 (const Item * const & a, const Item * const & b, void *)
+static int item_compare_pass1 (const Item * const & a, const Item * const & b)
{
if (a->matches.len () > b->matches.len ())
return -1;
if (a->matches.len () < b->matches.len ())
return 1;
- return item_compare (a, b, nullptr);
+ return item_compare (a, b);
}
static void do_search ()
@@ -362,7 +367,7 @@ static void do_search ()
items = std::move (state.items);
/* first sort by number of songs per item */
- items.sort (item_compare_pass1, nullptr);
+ items.sort (item_compare_pass1);
/* limit to items with most songs */
if (items.len () > MAX_RESULTS)
@@ -372,18 +377,29 @@ static void do_search ()
}
/* sort by item type, then item name */
- items.sort (item_compare, nullptr);
+ items.sort (item_compare);
}
static bool filter_cb (const char * filename, void * unused)
{
+ bool add = false;
tiny_lock (& adding_lock);
- bool add = adding && ! added_table.lookup (String (filename));
+
+ if (adding)
+ {
+ bool * added = added_table.lookup (String (filename));
+
+ if ((add = ! added))
+ added_table.add (String (filename), true);
+ else
+ (* added) = true;
+ }
+
tiny_unlock (& adding_lock);
return add;
}
-static void begin_add (const char * path)
+static void begin_add (const char * uri)
{
if (adding)
return;
@@ -393,13 +409,9 @@ static void begin_add (const char * path)
if (list < 0)
list = create_playlist ();
- aud_set_str ("search-tool", "path", path);
-
- StringBuf uri = filename_to_uri (path);
- g_return_if_fail (uri);
-
- if (! g_str_has_suffix (uri, "/"))
- uri.insert (-1, "/");
+ /* if possible, store local path for compatibility with older versions */
+ StringBuf path = uri_to_filename (uri);
+ aud_set_str ("search-tool", "path", path ? path : uri);
added_table.clear ();
@@ -409,17 +421,16 @@ static void begin_add (const char * path)
{
String filename = aud_playlist_entry_get_filename (list, entry);
- if (g_str_has_prefix (filename, uri) && ! added_table.lookup (filename))
+ if (! added_table.lookup (filename))
{
aud_playlist_entry_set_selected (list, entry, false);
- added_table.add (filename, true);
+ added_table.add (filename, false);
}
else
aud_playlist_entry_set_selected (list, entry, true);
}
aud_playlist_delete_selected (list);
- aud_playlist_remove_failed (list);
tiny_lock (& adding_lock);
adding = true;
@@ -518,7 +529,24 @@ static void add_complete_cb (void * unused, void * unused2)
adding = false;
tiny_unlock (& adding_lock);
+ int entries = aud_playlist_entry_count (list);
+
+ for (int entry = 0; entry < entries; entry ++)
+ {
+ String filename = aud_playlist_entry_get_filename (list, entry);
+ bool * added = added_table.lookup (filename);
+
+ aud_playlist_entry_set_selected (list, entry, ! added || ! (* added));
+ }
+
added_table.clear ();
+
+ /* don't clear the playlist if nothing was added */
+ if (aud_playlist_selected_count (list) < aud_playlist_entry_count (list))
+ aud_playlist_delete_selected (list);
+ else
+ aud_playlist_select_all (list, false);
+
aud_playlist_sort_by_scheme (list, Playlist::Path);
}
@@ -606,7 +634,8 @@ static void do_add (bool play, bool set_title)
{
add.append (
aud_playlist_entry_get_filename (list, entry),
- aud_playlist_entry_get_tuple (list, entry, Playlist::Nothing)
+ aud_playlist_entry_get_tuple (list, entry, Playlist::NoWait),
+ aud_playlist_entry_get_decoder (list, entry, Playlist::NoWait)
);
}
@@ -624,14 +653,7 @@ static void do_add (bool play, bool set_title)
static void action_play ()
{
- int list = aud_playlist_get_temporary ();
- aud_playlist_set_active (list);
-
- if (aud_get_bool (nullptr, "clear_playlist"))
- aud_playlist_entry_delete (list, 0, aud_playlist_entry_count (list));
- else
- aud_playlist_queue_delete (list, 0, aud_playlist_queue_count (list));
-
+ aud_playlist_set_active (aud_playlist_get_temporary ());
do_add (true, false);
}
@@ -734,9 +756,9 @@ void * SearchToolQt::get_qt_widget ()
button->setFlat (true);
hbox->addWidget (button);
- char * utf8 = g_filename_to_utf8 (get_path (), -1, nullptr, nullptr, nullptr);
- chooser->setText (utf8);
- g_free (utf8);
+ String uri = get_uri ();
+ StringBuf path = uri_to_filename (uri, false);
+ chooser->setText (path ? path : uri);
search_init ();
@@ -751,19 +773,20 @@ void * SearchToolQt::get_qt_widget ()
search_pending = true;
});
- QObject::connect (button, & QPushButton::clicked, [chooser] ()
- {
- char * path = g_filename_from_utf8 (chooser->text ().toUtf8 (), -1,
- nullptr, nullptr, nullptr);
+ QObject::connect (chooser, & QLineEdit::textEdited, [button] (const QString & text)
+ { button->setDisabled (text.isEmpty ()); });
- if (path && path[0])
+ auto refresh = [chooser] () {
+ QByteArray path = chooser->text ().toUtf8 ();
+ if (! path.isEmpty ())
{
- begin_add (path);
+ begin_add (strstr (path, "://") ? path : filename_to_uri (path));
update_database ();
}
+ };
- g_free (path);
- });
+ QObject::connect (chooser, & QLineEdit::returnPressed, refresh);
+ QObject::connect (button, & QPushButton::clicked, refresh);
return widget;
}
diff --git a/src/search-tool/search-tool.cc b/src/search-tool/search-tool.cc
index 4f8398e..4f1add1 100644
--- a/src/search-tool/search-tool.cc
+++ b/src/search-tool/search-tool.cc
@@ -20,7 +20,6 @@
#include <string.h>
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
@@ -41,7 +40,10 @@ class SearchTool : public GeneralPlugin
public:
static constexpr PluginInfo info = {
N_("Search Tool"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginGLibOnly
};
constexpr SearchTool () : GeneralPlugin (info, false) {}
@@ -158,17 +160,20 @@ static int get_playlist (bool require_added, bool require_scanned)
return list;
}
-static String get_path ()
+static String get_uri ()
{
+ auto to_uri = [] (const char * path)
+ { return String (filename_to_uri (path)); };
+
String path1 = aud_get_str ("search-tool", "path");
- if (g_file_test (path1, G_FILE_TEST_EXISTS))
- return path1;
+ if (path1[0])
+ return strstr (path1, "://") ? path1 : to_uri (path1);
StringBuf path2 = filename_build ({g_get_home_dir (), "Music"});
if (g_file_test (path2, G_FILE_TEST_EXISTS))
- return String (path2);
+ return to_uri (path2);
- return String (g_get_home_dir ());
+ return to_uri (g_get_home_dir ());
}
static void destroy_database ()
@@ -187,7 +192,7 @@ static void create_database (int list)
for (int e = 0; e < entries; e ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (list, e, Playlist::Nothing);
+ Tuple tuple = aud_playlist_entry_get_tuple (list, e, Playlist::NoWait);
aud::array<SearchField, String> fields;
fields[SearchField::Genre] = tuple.get_str (Tuple::Genre);
@@ -250,7 +255,7 @@ static void search_cb (const Key & key, Item & item, void * _state)
state->mask = oldmask;
}
-static int item_compare (const Item * const & a, const Item * const & b, void *)
+static int item_compare (const Item * const & a, const Item * const & b)
{
if (a->field < b->field)
return -1;
@@ -262,19 +267,19 @@ static int item_compare (const Item * const & a, const Item * const & b, void *)
return val;
if (a->parent)
- return b->parent ? item_compare (a->parent, b->parent, nullptr) : 1;
+ return b->parent ? item_compare (a->parent, b->parent) : 1;
else
return b->parent ? -1 : 0;
}
-static int item_compare_pass1 (const Item * const & a, const Item * const & b, void *)
+static int item_compare_pass1 (const Item * const & a, const Item * const & b)
{
if (a->matches.len () > b->matches.len ())
return -1;
if (a->matches.len () < b->matches.len ())
return 1;
- return item_compare (a, b, nullptr);
+ return item_compare (a, b);
}
static void do_search ()
@@ -295,7 +300,7 @@ static void do_search ()
items = std::move (state.items);
/* first sort by number of songs per item */
- items.sort (item_compare_pass1, nullptr);
+ items.sort (item_compare_pass1);
/* limit to items with most songs */
if (items.len () > MAX_RESULTS)
@@ -305,7 +310,7 @@ static void do_search ()
}
/* sort by item type, then item name */
- items.sort (item_compare, nullptr);
+ items.sort (item_compare);
selection.remove (0, -1);
selection.insert (0, items.len ());
@@ -315,13 +320,24 @@ static void do_search ()
static bool filter_cb (const char * filename, void * unused)
{
+ bool add = false;
tiny_lock (& adding_lock);
- bool add = adding && ! added_table.lookup (String (filename));
+
+ if (adding)
+ {
+ bool * added = added_table.lookup (String (filename));
+
+ if ((add = ! added))
+ added_table.add (String (filename), true);
+ else
+ (* added) = true;
+ }
+
tiny_unlock (& adding_lock);
return add;
}
-static void begin_add (const char * path)
+static void begin_add (const char * uri)
{
if (adding)
return;
@@ -331,13 +347,9 @@ static void begin_add (const char * path)
if (list < 0)
list = create_playlist ();
- aud_set_str ("search-tool", "path", path);
-
- StringBuf uri = filename_to_uri (path);
- g_return_if_fail (uri);
-
- if (! g_str_has_suffix (uri, "/"))
- uri.insert (-1, "/");
+ /* if possible, store local path for compatibility with older versions */
+ StringBuf path = uri_to_filename (uri);
+ aud_set_str ("search-tool", "path", path ? path : uri);
added_table.clear ();
@@ -347,17 +359,16 @@ static void begin_add (const char * path)
{
String filename = aud_playlist_entry_get_filename (list, entry);
- if (g_str_has_prefix (filename, uri) && ! added_table.lookup (filename))
+ if (! added_table.lookup (filename))
{
aud_playlist_entry_set_selected (list, entry, false);
- added_table.add (filename, true);
+ added_table.add (filename, false);
}
else
aud_playlist_entry_set_selected (list, entry, true);
}
aud_playlist_delete_selected (list);
- aud_playlist_remove_failed (list);
tiny_lock (& adding_lock);
adding = true;
@@ -451,7 +462,24 @@ static void add_complete_cb (void * unused, void * unused2)
adding = false;
tiny_unlock (& adding_lock);
+ int entries = aud_playlist_entry_count (list);
+
+ for (int entry = 0; entry < entries; entry ++)
+ {
+ String filename = aud_playlist_entry_get_filename (list, entry);
+ bool * added = added_table.lookup (filename);
+
+ aud_playlist_entry_set_selected (list, entry, ! added || ! (* added));
+ }
+
added_table.clear ();
+
+ /* don't clear the playlist if nothing was added */
+ if (aud_playlist_selected_count (list) < aud_playlist_entry_count (list))
+ aud_playlist_delete_selected (list);
+ else
+ aud_playlist_select_all (list, false);
+
aud_playlist_sort_by_scheme (list, Playlist::Path);
}
@@ -536,7 +564,8 @@ static void do_add (bool play, bool set_title)
{
add.append (
aud_playlist_entry_get_filename (list, entry),
- aud_playlist_entry_get_tuple (list, entry, Playlist::Nothing)
+ aud_playlist_entry_get_tuple (list, entry, Playlist::NoWait),
+ aud_playlist_entry_get_decoder (list, entry, Playlist::NoWait)
);
}
@@ -554,14 +583,7 @@ static void do_add (bool play, bool set_title)
static void action_play ()
{
- int list = aud_playlist_get_temporary ();
- aud_playlist_set_active (list);
-
- if (aud_get_bool (nullptr, "clear_playlist"))
- aud_playlist_entry_delete (list, 0, aud_playlist_entry_count (list));
- else
- aud_playlist_queue_delete (list, 0, aud_playlist_queue_count (list));
-
+ aud_playlist_set_active (aud_playlist_get_temporary ());
do_add (true, false);
}
@@ -647,13 +669,53 @@ static void list_right_click (void * user, GdkEventButton * event)
gtk_menu_popup ((GtkMenu *) menu, nullptr, nullptr, nullptr, nullptr, event->button, event->time);
}
+static Index<char> list_get_data (void * user)
+{
+ if (search_pending)
+ search_timeout ();
+
+ int list = aud_playlist_by_unique_id (playlist_id);
+ int n_items = items.len ();
+
+ Index<char> buf;
+
+ aud_playlist_select_all (playlist_id, false);
+
+ for (int i = 0; i < n_items; i ++)
+ {
+ if (! selection[i])
+ continue;
+
+ const Item * item = items[i];
+
+ for (int entry : item->matches)
+ {
+ if (buf.len ())
+ buf.append ('\n');
+
+ String filename = aud_playlist_entry_get_filename (list, entry);
+ buf.insert (filename, -1, strlen (filename));
+
+ aud_playlist_entry_set_selected (list, entry, true);
+ }
+ }
+
+ aud_playlist_cache_selected (list);
+
+ return buf;
+}
+
static const AudguiListCallbacks list_callbacks = {
list_get_value,
list_get_selected,
list_set_selected,
list_select_all,
list_activate_row,
- list_right_click
+ list_right_click,
+ nullptr, // shift_rows
+ "text/uri-list",
+ list_get_data,
+ nullptr // receive_data
};
static void entry_cb (GtkEntry * entry, void * unused)
@@ -664,13 +726,21 @@ static void entry_cb (GtkEntry * entry, void * unused)
search_pending = true;
}
-static void refresh_cb (GtkButton * button, GtkWidget * chooser)
+static void file_entry_cb (GtkEntry * entry, GtkWidget * button)
{
- char * path = gtk_file_chooser_get_filename ((GtkFileChooser *) chooser);
- begin_add (path);
- g_free (path);
+ const char * text = gtk_entry_get_text ((GtkEntry *) entry);
+ gtk_widget_set_sensitive (button, text[0] != 0);
+}
- update_database ();
+static void refresh_cb (GtkButton * button, GtkWidget * file_entry)
+{
+ String uri = audgui_file_entry_get_uri (file_entry);
+ if (uri)
+ {
+ audgui_file_entry_set_uri (file_entry, uri); // normalize path
+ begin_add (uri);
+ update_database ();
+ }
}
void * SearchTool::get_gtk_widget ()
@@ -719,11 +789,11 @@ void * SearchTool::get_gtk_widget ()
GtkWidget * hbox = gtk_hbox_new (false, 6);
gtk_box_pack_end ((GtkBox *) vbox, hbox, false, false, 0);
- GtkWidget * chooser = gtk_file_chooser_button_new (_("Choose Folder"),
- GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
- gtk_box_pack_start ((GtkBox *) hbox, chooser, true, true, 0);
+ GtkWidget * file_entry = audgui_file_entry_new
+ (GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, _("Choose Folder"));
+ gtk_box_pack_start ((GtkBox *) hbox, file_entry, true, true, 0);
- gtk_file_chooser_set_filename ((GtkFileChooser *) chooser, get_path ());
+ audgui_file_entry_set_uri (file_entry, get_uri ());
GtkWidget * button = gtk_button_new ();
gtk_container_add ((GtkContainer *) button, gtk_image_new_from_icon_name
@@ -736,7 +806,9 @@ void * SearchTool::get_gtk_widget ()
g_signal_connect (vbox, "destroy", (GCallback) search_cleanup, nullptr);
g_signal_connect (entry, "changed", (GCallback) entry_cb, nullptr);
g_signal_connect (entry, "activate", (GCallback) action_play, nullptr);
- g_signal_connect (button, "clicked", (GCallback) refresh_cb, chooser);
+ g_signal_connect (file_entry, "changed", (GCallback) file_entry_cb, button);
+ g_signal_connect (file_entry, "activate", (GCallback) refresh_cb, file_entry);
+ g_signal_connect (button, "clicked", (GCallback) refresh_cb, file_entry);
gtk_widget_show_all (vbox);
gtk_widget_show (results_list);
diff --git a/src/sid/xmms-sid.cc b/src/sid/xmms-sid.cc
index f1f59e9..e38f040 100644
--- a/src/sid/xmms-sid.cc
+++ b/src/sid/xmms-sid.cc
@@ -46,20 +46,25 @@ public:
& sid_prefs
};
- static constexpr auto iinfo = InputInfo(FlagSubtunes)
+ constexpr SIDPlugin() : InputPlugin(info, InputInfo(FlagSubtunes)
.with_priority(5) /* medium priority (slow to initialize) */
- .with_exts(exts);
+ .with_exts(exts)) {}
- constexpr SIDPlugin() : InputPlugin(info, iinfo) {}
+ bool init()
+ {
+ xs_init_configuration();
+ return true;
+ }
- bool delayed_init();
void cleanup();
bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool play(const char *filename, VFSFile &file);
private:
+ bool delayed_init();
+
pthread_mutex_t m_init_mutex = PTHREAD_MUTEX_INITIALIZER;
bool m_initialized = false;
bool m_init_failed = false;
@@ -78,9 +83,6 @@ bool SIDPlugin::delayed_init()
if (!m_initialized && !m_init_failed)
{
- /* Initialize and get configuration */
- xs_init_configuration();
-
/* Try to initialize emulator engine */
m_initialized = xs_sidplayfp_init();
if (!m_initialized)
@@ -136,7 +138,7 @@ bool SIDPlugin::play(const char *filename, VFSFile &file)
/* Get tune information */
xs_tuneinfo_t info;
- if (!xs_sidplayfp_getinfo(info, filename, buf.begin(), buf.len()))
+ if (!xs_sidplayfp_getinfo(info, buf.begin(), buf.len()))
return false;
/* Initialize the tune */
@@ -160,18 +162,10 @@ bool SIDPlugin::play(const char *filename, VFSFile &file)
/* Initialize song */
if (!xs_sidplayfp_initsong(subTune)) {
AUDERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
- (const char *) info.sidFilename, subTune);
+ filename, subTune);
return false;
}
- /* Set song information for current subtune */
- xs_sidplayfp_updateinfo(info, subTune);
-
- Tuple tmpTuple;
- tmpTuple.set_filename(info.sidFilename);
- xs_get_song_tuple_info(tmpTuple, info, subTune);
- set_playback_tuple(std::move(tmpTuple));
-
/* Open the audio output */
open_audio(FMT_S16_NE, xs_cfg.audioFrequency, xs_cfg.audioChannels);
@@ -230,16 +224,6 @@ static void xs_get_song_tuple_info(Tuple &tuple, const xs_tuneinfo_t &info, int
tuple.set_str (Tuple::Copyright, info.sidCopyright);
tuple.set_str (Tuple::Codec, info.sidFormat);
-#if 0
- switch (info.sidModel) {
- case XS_SIDMODEL_6581: tmpStr = "6581"; break;
- case XS_SIDMODEL_8580: tmpStr = "8580"; break;
- case XS_SIDMODEL_ANY: tmpStr = "ANY"; break;
- default: tmpStr = "?"; break;
- }
- tuple_set_str(tuple, -1, "sid-model", tmpStr);
-#endif
-
/* Get sub-tune information, if available */
if (subTune < 0 || info.startTune > info.nsubTunes)
subTune = info.startTune;
@@ -247,26 +231,6 @@ static void xs_get_song_tuple_info(Tuple &tuple, const xs_tuneinfo_t &info, int
if (subTune > 0 && subTune <= info.nsubTunes) {
int tmpInt = info.subTunes[subTune - 1].tuneLength;
tuple.set_int (Tuple::Length, (tmpInt < 0) ? -1 : tmpInt * 1000);
-
-#if 0
- tmpInt = info.subTunes[subTune - 1].tuneSpeed;
- if (tmpInt > 0) {
- switch (tmpInt) {
- case XS_CLOCK_PAL: tmpStr = "PAL"; break;
- case XS_CLOCK_NTSC: tmpStr = "NTSC"; break;
- case XS_CLOCK_ANY: tmpStr = "ANY"; break;
- case XS_CLOCK_VBI: tmpStr = "VBI"; break;
- case XS_CLOCK_CIA: tmpStr = "CIA"; break;
- default:
- snprintf(tmpStr2, sizeof(tmpStr2), "%dHz", tmpInt);
- tmpStr = tmpStr2;
- break;
- }
- } else
- tmpStr = "?";
-
- tuple_set_str(tuple, -1, "sid-speed", tmpStr);
-#endif
} else
subTune = 1;
@@ -278,7 +242,7 @@ static void xs_get_song_tuple_info(Tuple &tuple, const xs_tuneinfo_t &info, int
static void xs_fill_subtunes(Tuple &tuple, const xs_tuneinfo_t &info)
{
- Index<int> subtunes;
+ Index<short> subtunes;
for (int count = 0; count < info.nsubTunes; count++) {
if (count + 1 == info.startTune || !xs_cfg.subAutoMinOnly ||
@@ -290,34 +254,29 @@ static void xs_fill_subtunes(Tuple &tuple, const xs_tuneinfo_t &info)
tuple.set_subtunes (subtunes.len (), subtunes.begin ());
}
-Tuple SIDPlugin::read_tuple(const char *filename, VFSFile &file)
+bool SIDPlugin::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple tuple;
-
if (!delayed_init())
- return tuple;
-
- xs_tuneinfo_t info;
- int tune = -1;
+ return false;
Index<char> buf = file.read_all ();
if (!xs_sidplayfp_probe(buf.begin(), buf.len()))
- return tuple;
+ return false;
/* Get information from URL */
- tuple.set_filename (filename);
- tune = tuple.get_int (Tuple::Subtune);
+ int tune = tuple.get_int (Tuple::Subtune);
/* Get tune information from emulation engine */
- if (!xs_sidplayfp_getinfo(info, filename, buf.begin(), buf.len()))
- return tuple;
+ xs_tuneinfo_t info;
+ if (!xs_sidplayfp_getinfo(info, buf.begin(), buf.len()))
+ return false;
xs_get_song_tuple_info(tuple, info, tune);
if (xs_cfg.subAutoEnable && info.nsubTunes > 1 && tune < 0)
xs_fill_subtunes(tuple, info);
- return tuple;
+ return true;
}
/*
diff --git a/src/sid/xmms-sid.h b/src/sid/xmms-sid.h
index 13553ee..3018e64 100644
--- a/src/sid/xmms-sid.h
+++ b/src/sid/xmms-sid.h
@@ -37,13 +37,11 @@
/* Plugin-wide typedefs
*/
typedef struct {
- int tuneSpeed = -1;
int tuneLength = -1;
} xs_subtuneinfo_t;
typedef struct {
- String sidFilename, sidName, sidComposer, sidCopyright, sidFormat;
- int loadAddr, initAddr, playAddr, dataFileLen, sidModel;
+ String sidName, sidComposer, sidCopyright, sidFormat;
int nsubTunes, startTune;
Index<xs_subtuneinfo_t> subTunes;
} xs_tuneinfo_t;
diff --git a/src/sid/xs_sidplay2.cc b/src/sid/xs_sidplay2.cc
index 1564fe6..a30af8e 100644
--- a/src/sid/xs_sidplay2.cc
+++ b/src/sid/xs_sidplay2.cc
@@ -226,7 +226,7 @@ bool xs_sidplayfp_load(const void *buf, int64_t bufSize)
}
-bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const char *filename, const void *buf, int64_t bufSize)
+bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const void *buf, int64_t bufSize)
{
/* Check if the tune exists and is readable */
SidTune myTune((const uint8_t*)buf, bufSize);
@@ -238,8 +238,6 @@ bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const char *filename, const void *b
const SidTuneInfo *myInfo = myTune.getInfo();
/* Allocate tuneinfo structure and set information */
- ti.sidFilename = String (filename);
-
ti.sidName = String (myInfo->infoString(0));
ti.sidComposer = String (myInfo->infoString(1));
ti.sidCopyright = String (myInfo->infoString(2));
@@ -247,14 +245,8 @@ bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const char *filename, const void *b
ti.nsubTunes = myInfo->songs();
ti.startTune = myInfo->startSong();
- ti.loadAddr = myInfo->loadAddr();
- ti.initAddr = myInfo->initAddr();
- ti.playAddr = myInfo->playAddr();
- ti.dataFileLen = myInfo->dataFileLen();
ti.sidFormat = String (myInfo->formatString());
- ti.sidModel = myInfo->sidModel1();
-
/* Fill in subtune information */
ti.subTunes.insert(0, ti.nsubTunes);
@@ -273,50 +265,3 @@ bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const char *filename, const void *b
return true;
}
-
-bool xs_sidplayfp_updateinfo(xs_tuneinfo_t &ti, int subtune)
-{
- /* Get currently playing tune information */
- const SidTuneInfo *myInfo = state.currTune->getInfo();
-
- /* NOTICE! Here we assume that libSIDPlay[12] headers define
- * SIDTUNE_SIDMODEL_* similarly to our enums in xs_config.h ...
- */
- ti.sidModel = myInfo->sidModel1();
-
- if ((subtune > 0) && (subtune <= ti.nsubTunes)) {
- int tmpSpeed = -1;
-
- switch (myInfo->clockSpeed()) {
- case SidTuneInfo::CLOCK_PAL:
- tmpSpeed = XS_CLOCK_PAL;
- break;
- case SidTuneInfo::CLOCK_NTSC:
- tmpSpeed = XS_CLOCK_NTSC;
- break;
- case SidTuneInfo::CLOCK_ANY:
- tmpSpeed = XS_CLOCK_ANY;
- break;
- case SidTuneInfo::CLOCK_UNKNOWN:
- switch (myInfo->songSpeed()) {
- case SidTuneInfo::SPEED_VBI:
- tmpSpeed = XS_CLOCK_VBI;
- break;
- case SidTuneInfo::SPEED_CIA_1A:
- tmpSpeed = XS_CLOCK_CIA;
- break;
- default:
- tmpSpeed = myInfo->songSpeed();
- break;
- }
- break;
- default:
- tmpSpeed = myInfo->clockSpeed();
- break;
- }
-
- ti.subTunes[subtune - 1].tuneSpeed = tmpSpeed;
- }
-
- return true;
-}
diff --git a/src/sid/xs_sidplay2.h b/src/sid/xs_sidplay2.h
index 9e0dac8..1e42418 100644
--- a/src/sid/xs_sidplay2.h
+++ b/src/sid/xs_sidplay2.h
@@ -11,7 +11,6 @@ bool xs_sidplayfp_init();
bool xs_sidplayfp_initsong(int subtune);
unsigned xs_sidplayfp_fillbuffer(char *, unsigned);
bool xs_sidplayfp_load(const void *buf, int64_t bufSize);
-bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const char *filename, const void *buf, int64_t bufSize);
-bool xs_sidplayfp_updateinfo(xs_tuneinfo_t &ti, int subtune);
+bool xs_sidplayfp_getinfo(xs_tuneinfo_t &ti, const void *buf, int64_t bufSize);
#endif /* XS_SIDPLAYFP_H */
diff --git a/src/skins-qt/actions-playlist.h b/src/skins-qt/actions-playlist.h
index 8f530b4..0842482 100644
--- a/src/skins-qt/actions-playlist.h
+++ b/src/skins-qt/actions-playlist.h
@@ -20,64 +20,13 @@
#ifndef SKINS_ACTIONS_PLAYLIST_H
#define SKINS_ACTIONS_PLAYLIST_H
-void action_playlist_refresh_list ();
-
-void action_playlist_play ();
-void action_playlist_new ();
-void action_playlist_prev ();
-void action_playlist_next ();
void action_playlist_rename ();
void action_playlist_delete ();
-void action_playlist_invert_selection ();
-void action_playlist_select_all ();
-void action_playlist_select_none ();
-
-void action_playlist_clear_queue ();
-void action_playlist_remove_unavailable ();
-void action_playlist_remove_dupes_by_title ();
-void action_playlist_remove_dupes_by_filename ();
-void action_playlist_remove_dupes_by_full_path ();
-void action_playlist_remove_all ();
-void action_playlist_remove_selected ();
-void action_playlist_remove_unselected ();
-
-void action_playlist_copy ();
-void action_playlist_cut ();
-void action_playlist_paste ();
+void action_playlist_search_and_select ();
void action_playlist_add_url ();
void action_playlist_add_files ();
void action_playlist_add_folder ();
-void action_playlist_randomize_list ();
-void action_playlist_reverse_list ();
-
-void action_playlist_sort_by_title ();
-void action_playlist_sort_by_album ();
-void action_playlist_sort_by_artist ();
-void action_playlist_sort_by_album_artist ();
-void action_playlist_sort_by_length ();
-void action_playlist_sort_by_genre ();
-void action_playlist_sort_by_filename ();
-void action_playlist_sort_by_full_path ();
-void action_playlist_sort_by_date ();
-void action_playlist_sort_by_track_number ();
-void action_playlist_sort_by_custom_title ();
-
-void action_playlist_sort_selected_by_title ();
-void action_playlist_sort_selected_by_album ();
-void action_playlist_sort_selected_by_artist ();
-void action_playlist_sort_selected_by_album_artist ();
-void action_playlist_sort_selected_by_length ();
-void action_playlist_sort_selected_by_genre ();
-void action_playlist_sort_selected_by_filename ();
-void action_playlist_sort_selected_by_full_path ();
-void action_playlist_sort_selected_by_date ();
-void action_playlist_sort_selected_by_track_number ();
-void action_playlist_sort_selected_by_custom_title ();
-
-void action_playlist_track_info ();
-void action_queue_toggle ();
-
#endif /* SKINS_ACTIONS_PLAYLIST_H */
diff --git a/src/skins-qt/actions.cc b/src/skins-qt/actions.cc
index 3b2695d..a01db44 100644
--- a/src/skins-qt/actions.cc
+++ b/src/skins-qt/actions.cc
@@ -28,6 +28,8 @@
#include "main.h"
#include "plugin-window.h"
+#include "../ui-common/menu-ops.h"
+
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
#include <libaudcore/playlist.h>
@@ -92,204 +94,14 @@ void action_search_tool ()
}
}
-void action_playlist_refresh_list ()
- { aud_playlist_rescan (ACTIVE); }
-void action_playlist_play ()
- { aud_playlist_play (ACTIVE); }
-
-void action_playlist_new ()
-{
- int playlist = aud_playlist_get_active () + 1;
- aud_playlist_insert (playlist);
- aud_playlist_set_active (playlist);
-}
-
-void action_playlist_prev ()
-{
- int playlist = ACTIVE;
- if (playlist > 0)
- aud_playlist_set_active (playlist - 1);
- else
- {
- int count = aud_playlist_count ();
- if (count > 1)
- aud_playlist_set_active (count - 1);
- }
-}
-
-void action_playlist_next ()
-{
- int playlist = ACTIVE;
- int count = aud_playlist_count ();
- if (playlist + 1 < count)
- aud_playlist_set_active (playlist + 1);
- else if (count > 1)
- aud_playlist_set_active (0);
-}
-
void action_playlist_rename ()
{ audqt::playlist_show_rename (ACTIVE); }
void action_playlist_delete ()
{ audqt::playlist_confirm_delete (ACTIVE); }
-void action_playlist_invert_selection ()
-{
- int playlist = ACTIVE;
- int entries = aud_playlist_entry_count (playlist);
- for (int entry = 0; entry < entries; entry ++)
- aud_playlist_entry_set_selected (playlist, entry,
- ! aud_playlist_entry_get_selected (playlist, entry));
-}
-
-void action_playlist_select_all ()
- { aud_playlist_select_all (ACTIVE, true); }
-void action_playlist_select_none ()
- { aud_playlist_select_all (ACTIVE, false); }
-
-void action_playlist_clear_queue ()
-{
- int playlist = ACTIVE;
- aud_playlist_queue_delete (playlist, 0, aud_playlist_queue_count (playlist));
-}
-
-void action_playlist_remove_unavailable ()
- { aud_playlist_remove_failed (ACTIVE); }
-void action_playlist_remove_dupes_by_title ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_remove_dupes_by_filename ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_remove_dupes_by_full_path ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Path); }
-
-void action_playlist_remove_all ()
-{
- int playlist = ACTIVE;
- aud_playlist_entry_delete (playlist, 0, aud_playlist_entry_count (playlist));
-}
-
-void action_playlist_remove_selected ()
- { aud_playlist_delete_selected (ACTIVE); }
-
-void action_playlist_remove_unselected ()
-{
- action_playlist_invert_selection ();
- action_playlist_remove_selected ();
- action_playlist_select_all ();
-}
-
-void action_playlist_copy ()
-{
-#if 0
- GtkClipboard * clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- Index<char> list = audgui_urilist_create_from_selected (ACTIVE);
-
- if (list.len ())
- gtk_clipboard_set_text (clip, list.begin (), list.len ());
-#endif
-}
-
-void action_playlist_cut ()
-{
- action_playlist_copy ();
- action_playlist_remove_selected ();
-}
-
-void action_playlist_paste ()
-{
-#if 0
- GtkClipboard * clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- char * list = gtk_clipboard_wait_for_text (clip);
-
- if (list)
- {
- int playlist = ACTIVE;
- audgui_urilist_insert (playlist, aud_playlist_get_focus (playlist), list);
- g_free (list);
- }
-#endif
-}
-
void action_playlist_add_url ()
{ audqt::urlopener_show (false); }
void action_playlist_add_files ()
{ audqt::fileopener_show (audqt::FileMode::Add ); }
void action_playlist_add_folder ()
{ audqt::fileopener_show (audqt::FileMode::AddFolder ); }
-
-void action_playlist_randomize_list ()
- { aud_playlist_randomize (ACTIVE); }
-void action_playlist_reverse_list ()
- { aud_playlist_reverse (ACTIVE); }
-
-void action_playlist_sort_by_title ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_sort_by_album ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Album); }
-void action_playlist_sort_by_artist ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Artist); }
-void action_playlist_sort_by_album_artist ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::AlbumArtist); }
-void action_playlist_sort_by_length ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Length); }
-void action_playlist_sort_by_genre ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Genre); }
-void action_playlist_sort_by_filename ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_sort_by_full_path ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Path); }
-void action_playlist_sort_by_date ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Date); }
-void action_playlist_sort_by_track_number ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Track); }
-void action_playlist_sort_by_custom_title ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::FormattedTitle); }
-
-void action_playlist_sort_selected_by_title ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_sort_selected_by_album ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Album); }
-void action_playlist_sort_selected_by_artist ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Artist); }
-void action_playlist_sort_selected_by_album_artist ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::AlbumArtist); }
-void action_playlist_sort_selected_by_length ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Length); }
-void action_playlist_sort_selected_by_genre ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Genre); }
-void action_playlist_sort_selected_by_filename ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_sort_selected_by_full_path ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Path); }
-void action_playlist_sort_selected_by_date ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Date); }
-void action_playlist_sort_selected_by_track_number ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Track); }
-void action_playlist_sort_selected_by_custom_title ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::FormattedTitle); }
-
-void action_playlist_track_info ()
-{
- int playlist = ACTIVE;
- audqt::infowin_show (playlist, aud_playlist_get_focus (playlist));
-}
-
-void action_queue_toggle ()
-{
- int playlist = ACTIVE;
- int focus = aud_playlist_get_focus (playlist);
- if (focus == -1)
- return;
-
- /* make sure focused row is selected */
- if (! aud_playlist_entry_get_selected (playlist, focus))
- {
- aud_playlist_select_all (playlist, false);
- aud_playlist_entry_set_selected (playlist, focus, true);
- }
-
- int at = aud_playlist_queue_find_entry (playlist, focus);
- if (at == -1)
- aud_playlist_queue_insert_selected (playlist, -1);
- else
- aud_playlist_queue_delete_selected (playlist);
-}
diff --git a/src/skins-qt/main.cc b/src/skins-qt/main.cc
index 63eb7ee..f1db1a2 100644
--- a/src/skins-qt/main.cc
+++ b/src/skins-qt/main.cc
@@ -208,11 +208,18 @@ void mainwin_show_status_message (const char * message)
static void mainwin_set_song_title (const char * title)
{
+ StringBuf buf;
+
if (title)
- mainwin->setWindowTitle ((const char *) str_printf (_("%s - Audacious"), title));
+ buf.steal (str_printf (_("%s - Audacious"), title));
else
- mainwin->setWindowTitle (_("Audacious"));
+ buf.steal (str_copy (_("Audacious")));
+
+ int instance = aud_get_instance ();
+ if (instance != 1)
+ buf.combine (str_printf (" (%d)", instance));
+ mainwin->setWindowTitle ((const char *) buf);
mainwin_set_info_text (title ? title : "");
}
@@ -1056,7 +1063,6 @@ static void mainwin_create_window ()
bool shaded = aud_get_bool ("skins", "player_shaded");
mainwin = new MainWindow (shaded);
- mainwin->setWindowTitle (_("Audacious"));
#if 0
GtkWidget * w = mainwin->gtk ();
@@ -1111,6 +1117,7 @@ void mainwin_create ()
{
mainwin_create_window ();
mainwin_create_widgets ();
+ mainwin_set_song_title (nullptr);
}
static void mainwin_update_volume ()
diff --git a/src/skins-qt/menus.cc b/src/skins-qt/menus.cc
index f42019b..b302fd8 100644
--- a/src/skins-qt/menus.cc
+++ b/src/skins-qt/menus.cc
@@ -27,6 +27,7 @@
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
#include <libaudcore/interface.h>
+#include <libaudcore/playlist.h>
#include <libaudcore/plugins.h>
#include <libaudcore/runtime.h>
#include <libaudqt/menu.h>
@@ -36,6 +37,8 @@
#include "main.h"
#include "view.h"
+#include "../ui-common/menu-ops.h"
+
static QMenu * menus[UI_MENUS];
/* note: playback, playlist, and view menus must be created before main menu */
@@ -52,8 +55,8 @@ static void configure_effects () { audqt::prefswin_show_plugin_page (PluginType:
static void configure_output () { audqt::prefswin_show_plugin_page (PluginType::Output); }
static void configure_visualizations () { audqt::prefswin_show_plugin_page (PluginType::Vis); }
-static void volume_up () { mainwin_set_volume_diff (5); }
-static void volume_down () { mainwin_set_volume_diff (-5); }
+static void skins_volume_up () { mainwin_set_volume_diff (5); }
+static void skins_volume_down () { mainwin_set_volume_diff (-5); }
/* emulate a config item for the recording toggle */
static void toggle_record ()
@@ -80,8 +83,8 @@ static void record_toggled (void * = nullptr, void * = nullptr)
}
static const audqt::MenuItem output_items[] = {
- audqt::MenuCommand ({N_("Volume Up"), "audio-volume-high", "+"}, volume_up),
- audqt::MenuCommand ({N_("Volume Down"), "audio-volume-low", "-"}, volume_down),
+ audqt::MenuCommand ({N_("Volume Up"), "audio-volume-high", "+"}, skins_volume_up),
+ audqt::MenuCommand ({N_("Volume Down"), "audio-volume-low", "-"}, skins_volume_down),
audqt::MenuSep (),
audqt::MenuCommand ({N_("Effects ...")}, configure_effects),
audqt::MenuSep (),
@@ -132,14 +135,14 @@ static const audqt::MenuItem playback_items[] = {
};
static const audqt::MenuItem playlist_items[] = {
- audqt::MenuCommand ({N_("Play/Resume"), "media-playback-start", "Shift+Return"}, action_playlist_play),
+ audqt::MenuCommand ({N_("Play/Resume"), "media-playback-start", "Shift+Return"}, pl_play),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("New Playlist"), "document-new", "Shift+N"}, action_playlist_new),
+ audqt::MenuCommand ({N_("New Playlist"), "document-new", "Shift+N"}, (audqt::MenuFunc) aud_playlist_new),
audqt::MenuCommand ({N_("Rename Playlist ..."), "insert-text", "F2"}, action_playlist_rename),
audqt::MenuCommand ({N_("Remove Playlist"), "edit-delete", "Shift+D"}, action_playlist_delete),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("Previous Playlist"), "media-skip-backward", "Shift+Tab"}, action_playlist_prev),
- audqt::MenuCommand ({N_("Next Playlist"), "media-skip-forward", "Tab"}, action_playlist_next),
+ audqt::MenuCommand ({N_("Previous Playlist"), "media-skip-backward", "Shift+Tab"}, pl_prev),
+ audqt::MenuCommand ({N_("Next Playlist"), "media-skip-forward", "Tab"}, pl_next),
audqt::MenuSep (),
#if 0
audqt::MenuCommand ({N_("Import Playlist ..."), "document-open", "O"}, audgui_import_playlist),
@@ -149,7 +152,7 @@ static const audqt::MenuItem playlist_items[] = {
audqt::MenuCommand ({N_("Playlist Manager ..."), "audio-x-generic", "P"}, action_playlist_manager),
audqt::MenuCommand ({N_("Queue Manager ..."), nullptr, "Ctrl+U"}, audqt::queue_manager_show),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("Refresh Playlist"), "view-refresh", "F5"}, action_playlist_refresh_list)
+ audqt::MenuCommand ({N_("Refresh Playlist"), "view-refresh", "F5"}, pl_refresh)
};
static const audqt::MenuItem view_items[] = {
@@ -180,76 +183,76 @@ static const audqt::MenuItem playlist_add_items[] = {
};
static const audqt::MenuItem dupe_items[] = {
- audqt::MenuCommand ({N_("By Title")}, action_playlist_remove_dupes_by_title),
- audqt::MenuCommand ({N_("By File Name")}, action_playlist_remove_dupes_by_filename),
- audqt::MenuCommand ({N_("By File Path")}, action_playlist_remove_dupes_by_full_path)
+ audqt::MenuCommand ({N_("By Title")}, rm_dupes_title),
+ audqt::MenuCommand ({N_("By File Name")}, rm_dupes_filename),
+ audqt::MenuCommand ({N_("By File Path")}, rm_dupes_path)
};
static const audqt::MenuItem playlist_remove_items[] = {
audqt::MenuSub ({N_("Services")}, get_plugin_menu_playlist_remove),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("Remove All"), "edit-delete"}, action_playlist_remove_all),
- audqt::MenuCommand ({N_("Clear Queue"), "edit-clear", "Shift+Q"}, action_playlist_clear_queue),
+ audqt::MenuCommand ({N_("Remove All"), "edit-delete"}, pl_remove_all),
+ audqt::MenuCommand ({N_("Clear Queue"), "edit-clear", "Shift+Q"}, pl_queue_clear),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("Remove Unavailable Files"), "dialog-warning"}, action_playlist_remove_unavailable),
+ audqt::MenuCommand ({N_("Remove Unavailable Files"), "dialog-warning"}, pl_remove_failed),
audqt::MenuSub ({N_("Remove Duplicates"), "edit-copy"}, {dupe_items}),
audqt::MenuSep (),
- audqt::MenuCommand ({N_("Remove Unselected"), "list-remove"}, action_playlist_remove_unselected),
- audqt::MenuCommand ({N_("Remove Selected"), "list-remove", "Delete"}, action_playlist_remove_selected)
+ audqt::MenuCommand ({N_("Remove Unselected"), "list-remove"}, pl_remove_unselected),
+ audqt::MenuCommand ({N_("Remove Selected"), "list-remove", "Delete"}, pl_remove_selected)
};
static const audqt::MenuItem playlist_select_items[] = {
- audqt::MenuCommand ({N_("Invert Selection")}, action_playlist_invert_selection),
- audqt::MenuCommand ({N_("Select None"), nullptr, "Shift+Ctrl+A"}, action_playlist_select_none),
- audqt::MenuCommand ({N_("Select All"), "edit-select-all", "Ctrl+A"}, action_playlist_select_all),
+ audqt::MenuCommand ({N_("Invert Selection")}, pl_select_invert),
+ audqt::MenuCommand ({N_("Select None"), nullptr, "Shift+Ctrl+A"}, pl_select_none),
+ audqt::MenuCommand ({N_("Select All"), "edit-select-all", "Ctrl+A"}, pl_select_all),
};
static const audqt::MenuItem sort_items[] = {
- audqt::MenuCommand ({N_("By Track Number")}, action_playlist_sort_by_track_number),
- audqt::MenuCommand ({N_("By Title")}, action_playlist_sort_by_title),
- audqt::MenuCommand ({N_("By Artist")}, action_playlist_sort_by_artist),
- audqt::MenuCommand ({N_("By Album")}, action_playlist_sort_by_album),
- audqt::MenuCommand ({N_("By Album Artist")}, action_playlist_sort_by_album_artist),
- audqt::MenuCommand ({N_("By Release Date")}, action_playlist_sort_by_date),
- audqt::MenuCommand ({N_("By Genre")}, action_playlist_sort_by_genre),
- audqt::MenuCommand ({N_("By Length")}, action_playlist_sort_by_length),
- audqt::MenuCommand ({N_("By File Name")}, action_playlist_sort_by_filename),
- audqt::MenuCommand ({N_("By File Path")}, action_playlist_sort_by_full_path),
- audqt::MenuCommand ({N_("By Custom Title")}, action_playlist_sort_by_custom_title)
+ audqt::MenuCommand ({N_("By Track Number")}, sort_track),
+ audqt::MenuCommand ({N_("By Title")}, sort_title),
+ audqt::MenuCommand ({N_("By Artist")}, sort_artist),
+ audqt::MenuCommand ({N_("By Album")}, sort_album),
+ audqt::MenuCommand ({N_("By Album Artist")}, sort_album_artist),
+ audqt::MenuCommand ({N_("By Release Date")}, sort_date),
+ audqt::MenuCommand ({N_("By Genre")}, sort_genre),
+ audqt::MenuCommand ({N_("By Length")}, sort_length),
+ audqt::MenuCommand ({N_("By File Name")}, sort_filename),
+ audqt::MenuCommand ({N_("By File Path")}, sort_path),
+ audqt::MenuCommand ({N_("By Custom Title")}, sort_custom_title)
};
static const audqt::MenuItem sort_selected_items[] = {
- audqt::MenuCommand ({N_("By Track Number")}, action_playlist_sort_selected_by_track_number),
- audqt::MenuCommand ({N_("By Title")}, action_playlist_sort_selected_by_title),
- audqt::MenuCommand ({N_("By Artist")}, action_playlist_sort_selected_by_artist),
- audqt::MenuCommand ({N_("By Album")}, action_playlist_sort_selected_by_album),
- audqt::MenuCommand ({N_("By Album Artist")}, action_playlist_sort_selected_by_album_artist),
- audqt::MenuCommand ({N_("By Genre")}, action_playlist_sort_selected_by_genre),
- audqt::MenuCommand ({N_("By Release Date")}, action_playlist_sort_selected_by_date),
- audqt::MenuCommand ({N_("By Length")}, action_playlist_sort_selected_by_length),
- audqt::MenuCommand ({N_("By File Name")}, action_playlist_sort_selected_by_filename),
- audqt::MenuCommand ({N_("By File Path")}, action_playlist_sort_selected_by_full_path),
- audqt::MenuCommand ({N_("By Custom Title")}, action_playlist_sort_selected_by_custom_title)
+ audqt::MenuCommand ({N_("By Track Number")}, sort_sel_track),
+ audqt::MenuCommand ({N_("By Title")}, sort_sel_title),
+ audqt::MenuCommand ({N_("By Artist")}, sort_sel_artist),
+ audqt::MenuCommand ({N_("By Album")}, sort_sel_album),
+ audqt::MenuCommand ({N_("By Album Artist")}, sort_sel_album_artist),
+ audqt::MenuCommand ({N_("By Genre")}, sort_sel_genre),
+ audqt::MenuCommand ({N_("By Release Date")}, sort_sel_date),
+ audqt::MenuCommand ({N_("By Length")}, sort_sel_length),
+ audqt::MenuCommand ({N_("By File Name")}, sort_sel_filename),
+ audqt::MenuCommand ({N_("By File Path")}, sort_sel_path),
+ audqt::MenuCommand ({N_("By Custom Title")}, sort_sel_custom_title)
};
static const audqt::MenuItem playlist_sort_items[] = {
- audqt::MenuCommand ({N_("Randomize List"), nullptr, "Shift+Ctrl+R"}, action_playlist_randomize_list),
- audqt::MenuCommand ({N_("Reverse List"), "view-sort-descending"}, action_playlist_reverse_list),
+ audqt::MenuCommand ({N_("Randomize List"), nullptr, "Shift+Ctrl+R"}, sort_random),
+ audqt::MenuCommand ({N_("Reverse List"), "view-sort-descending"}, sort_reverse),
audqt::MenuSep (),
audqt::MenuSub ({N_("Sort Selected"), "view-sort-ascending"}, {sort_selected_items}),
audqt::MenuSub ({N_("Sort List"), "view-sort-ascending"}, {sort_items})
};
static const audqt::MenuItem playlist_context_items[] = {
- audqt::MenuCommand ({N_("Song Info ..."), "dialog-information", "Alt+I"}, action_playlist_track_info),
+ audqt::MenuCommand ({N_("Song Info ..."), "dialog-information", "Alt+I"}, pl_song_info),
+ audqt::MenuCommand ({N_("Open Containing Folder"), "folder"}, pl_open_folder),
audqt::MenuSep (),
-#if 0
- audqt::MenuCommand ({N_("Cut"), "edit-cut", "Ctrl+X"}, action_playlist_cut),
- audqt::MenuCommand ({N_("Copy"), "edit-copy", "Ctrl+C"}, action_playlist_copy),
- audqt::MenuCommand ({N_("Paste"), "edit-paste", "Ctrl+V"}, action_playlist_paste),
+ audqt::MenuCommand ({N_("Cut"), "edit-cut", "Ctrl+X"}, pl_cut),
+ audqt::MenuCommand ({N_("Copy"), "edit-copy", "Ctrl+C"}, pl_copy),
+ audqt::MenuCommand ({N_("Paste"), "edit-paste", "Ctrl+V"}, pl_paste),
+ audqt::MenuCommand ({N_("Paste at End"), "edit-paste", "Shift+Ctrl+V"}, pl_paste_end),
audqt::MenuSep (),
-#endif
- audqt::MenuCommand ({N_("Queue/Unqueue"), nullptr, "Q"}, action_queue_toggle),
+ audqt::MenuCommand ({N_("Queue/Unqueue"), nullptr, "Q"}, pl_queue_toggle),
audqt::MenuSep (),
audqt::MenuSub ({N_("Services")}, get_plugin_menu_playlist)
};
diff --git a/src/skins-qt/playlist-widget.cc b/src/skins-qt/playlist-widget.cc
index 07b8e30..af7606e 100644
--- a/src/skins-qt/playlist-widget.cc
+++ b/src/skins-qt/playlist-widget.cc
@@ -187,7 +187,7 @@ void PlaylistWidget::draw (QPainter & cr)
for (int i = m_first; i < m_first + m_rows && i < m_length; i ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::NoWait);
int len = tuple.get_int (Tuple::Length);
if (len < 0)
continue;
@@ -235,7 +235,7 @@ void PlaylistWidget::draw (QPainter & cr)
for (int i = m_first; i < m_first + m_rows && i < m_length; i ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::NoWait);
String title = tuple.get_str (Tuple::FormattedTitle);
cr.setPen (QColor (skin.colors[(i == active_entry) ?
diff --git a/src/skins-qt/playlist.cc b/src/skins-qt/playlist.cc
index 5cb7bac..3b63b34 100644
--- a/src/skins-qt/playlist.cc
+++ b/src/skins-qt/playlist.cc
@@ -104,7 +104,7 @@ static void update_rollup_text ()
{
int playlist = aud_playlist_get_active ();
int entry = aud_playlist_get_position (playlist);
- Tuple tuple = aud_playlist_entry_get_tuple (playlist, entry, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (playlist, entry, Playlist::NoWait);
char scratch[512];
scratch[0] = 0;
diff --git a/src/skins-qt/plugin.cc b/src/skins-qt/plugin.cc
index 9327345..d943164 100644
--- a/src/skins-qt/plugin.cc
+++ b/src/skins-qt/plugin.cc
@@ -22,7 +22,6 @@
#include <glib.h>
#include <QApplication>
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
@@ -45,6 +44,9 @@
#include "window.h"
#include "view.h"
+#include "../ui-common/menu-ops.cc"
+#include "../ui-common/menu-ops-qt.cc"
+
class QtSkins : public audqt::QtIfacePlugin
{
public:
@@ -52,7 +54,8 @@ public:
N_("Winamp Classic Interface"),
PACKAGE,
nullptr,
- & skins_prefs
+ & skins_prefs,
+ PluginQtOnly
};
constexpr QtSkins () : audqt::QtIfacePlugin (info) {}
diff --git a/src/skins-qt/skinselector.cc b/src/skins-qt/skinselector.cc
index f8de313..b6c97ea 100644
--- a/src/skins-qt/skinselector.cc
+++ b/src/skins-qt/skinselector.cc
@@ -102,11 +102,6 @@ static void scan_skindir_func (const char * path, const char * basename)
String (_("Unarchived Winamp 2.x skin")), String (path));
}
-static int skinlist_compare_func (const SkinNode & a, const SkinNode & b, void *)
-{
- return str_compare (a.name, b.name);
-}
-
void skinlist_update ()
{
skinlist.clear ();
@@ -125,5 +120,6 @@ void skinlist_update ()
dir_foreach (dir, scan_skindir_func);
}
- skinlist.sort (skinlist_compare_func, nullptr);
+ skinlist.sort ([] (const SkinNode & a, const SkinNode & b)
+ { return str_compare (a.name, b.name); });
}
diff --git a/src/skins-qt/util.cc b/src/skins-qt/util.cc
index 8c7badc..c5d6cf0 100644
--- a/src/skins-qt/util.cc
+++ b/src/skins-qt/util.cc
@@ -275,7 +275,7 @@ StringBuf archive_decompress (const char * filename)
StringBuf tmpdir = filename_build ({g_get_tmp_dir (), "audacious.XXXXXX"});
if (! g_mkdtemp (tmpdir))
{
- AUDWARN ("Error creating %s: %s\n", strerror (errno));
+ AUDWARN ("Error creating %s: %s\n", (const char *) tmpdir, strerror (errno));
return StringBuf ();
}
@@ -352,5 +352,5 @@ bool dir_foreach (const char * path, DirForeachFunc func)
void make_directory (const char * path)
{
if (g_mkdir_with_parents (path, DIRMODE) != 0)
- AUDWARN ("Error creating %s: %s\n", strerror (errno));
+ AUDWARN ("Error creating %s: %s\n", path, strerror (errno));
}
diff --git a/src/skins/actions-playlist.h b/src/skins/actions-playlist.h
index 97b04ea..7729241 100644
--- a/src/skins/actions-playlist.h
+++ b/src/skins/actions-playlist.h
@@ -20,63 +20,12 @@
#ifndef SKINS_ACTIONS_PLAYLIST_H
#define SKINS_ACTIONS_PLAYLIST_H
-void action_playlist_refresh_list ();
-
-void action_playlist_play ();
-void action_playlist_prev ();
-void action_playlist_next ();
void action_playlist_rename ();
void action_playlist_delete ();
void action_playlist_search_and_select ();
-void action_playlist_invert_selection ();
-void action_playlist_select_all ();
-void action_playlist_select_none ();
-
-void action_playlist_clear_queue ();
-void action_playlist_remove_unavailable ();
-void action_playlist_remove_dupes_by_title ();
-void action_playlist_remove_dupes_by_filename ();
-void action_playlist_remove_dupes_by_full_path ();
-void action_playlist_remove_all ();
-void action_playlist_remove_selected ();
-void action_playlist_remove_unselected ();
-
-void action_playlist_copy ();
-void action_playlist_cut ();
-void action_playlist_paste ();
void action_playlist_add_url ();
void action_playlist_add_files ();
-void action_playlist_randomize_list ();
-void action_playlist_reverse_list ();
-
-void action_playlist_sort_by_title ();
-void action_playlist_sort_by_album ();
-void action_playlist_sort_by_artist ();
-void action_playlist_sort_by_album_artist ();
-void action_playlist_sort_by_length ();
-void action_playlist_sort_by_genre ();
-void action_playlist_sort_by_filename ();
-void action_playlist_sort_by_full_path ();
-void action_playlist_sort_by_date ();
-void action_playlist_sort_by_track_number ();
-void action_playlist_sort_by_custom_title ();
-
-void action_playlist_sort_selected_by_title ();
-void action_playlist_sort_selected_by_album ();
-void action_playlist_sort_selected_by_artist ();
-void action_playlist_sort_selected_by_album_artist ();
-void action_playlist_sort_selected_by_length ();
-void action_playlist_sort_selected_by_genre ();
-void action_playlist_sort_selected_by_filename ();
-void action_playlist_sort_selected_by_full_path ();
-void action_playlist_sort_selected_by_date ();
-void action_playlist_sort_selected_by_track_number ();
-void action_playlist_sort_selected_by_custom_title ();
-
-void action_playlist_track_info ();
-void action_queue_toggle ();
-
#endif /* SKINS_ACTIONS_PLAYLIST_H */
diff --git a/src/skins/actions.cc b/src/skins/actions.cc
index 3d42dcb..6b2a60f 100644
--- a/src/skins/actions.cc
+++ b/src/skins/actions.cc
@@ -28,6 +28,8 @@
#include "main.h"
#include "plugin-window.h"
+#include "../ui-common/menu-ops.h"
+
#include <gtk/gtk.h>
#include <libaudcore/drct.h>
@@ -92,191 +94,12 @@ void action_search_tool ()
}
}
-void action_playlist_refresh_list ()
- { aud_playlist_rescan (ACTIVE); }
-void action_playlist_play ()
- { aud_playlist_play (ACTIVE); }
-
-void action_playlist_prev ()
-{
- int playlist = ACTIVE;
- if (playlist > 0)
- aud_playlist_set_active (playlist - 1);
- else
- {
- int count = aud_playlist_count ();
- if (count > 1)
- aud_playlist_set_active (count - 1);
- }
-}
-
-void action_playlist_next ()
-{
- int playlist = ACTIVE;
- int count = aud_playlist_count ();
- if (playlist + 1 < count)
- aud_playlist_set_active (playlist + 1);
- else if (count > 1)
- aud_playlist_set_active (0);
-}
-
void action_playlist_rename ()
{ audgui_show_playlist_rename (ACTIVE); }
void action_playlist_delete ()
{ audgui_confirm_playlist_delete (ACTIVE); }
-void action_playlist_invert_selection ()
-{
- int playlist = ACTIVE;
- int entries = aud_playlist_entry_count (playlist);
- for (int entry = 0; entry < entries; entry ++)
- aud_playlist_entry_set_selected (playlist, entry,
- ! aud_playlist_entry_get_selected (playlist, entry));
-}
-
-void action_playlist_select_all ()
- { aud_playlist_select_all (ACTIVE, true); }
-void action_playlist_select_none ()
- { aud_playlist_select_all (ACTIVE, false); }
-
-void action_playlist_clear_queue ()
-{
- int playlist = ACTIVE;
- aud_playlist_queue_delete (playlist, 0, aud_playlist_queue_count (playlist));
-}
-
-void action_playlist_remove_unavailable ()
- { aud_playlist_remove_failed (ACTIVE); }
-void action_playlist_remove_dupes_by_title ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_remove_dupes_by_filename ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_remove_dupes_by_full_path ()
- { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Path); }
-
-void action_playlist_remove_all ()
-{
- int playlist = ACTIVE;
- aud_playlist_entry_delete (playlist, 0, aud_playlist_entry_count (playlist));
-}
-
-void action_playlist_remove_selected ()
- { aud_playlist_delete_selected (ACTIVE); }
-
-void action_playlist_remove_unselected ()
-{
- action_playlist_invert_selection ();
- action_playlist_remove_selected ();
- action_playlist_select_all ();
-}
-
-void action_playlist_copy ()
-{
- GtkClipboard * clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- Index<char> list = audgui_urilist_create_from_selected (ACTIVE);
-
- if (list.len ())
- gtk_clipboard_set_text (clip, list.begin (), list.len ());
-}
-
-void action_playlist_cut ()
-{
- action_playlist_copy ();
- action_playlist_remove_selected ();
-}
-
-void action_playlist_paste ()
-{
- GtkClipboard * clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
- char * list = gtk_clipboard_wait_for_text (clip);
-
- if (list)
- {
- int playlist = ACTIVE;
- audgui_urilist_insert (playlist, aud_playlist_get_focus (playlist), list);
- g_free (list);
- }
-}
-
void action_playlist_add_url ()
{ audgui_show_add_url_window (false); }
void action_playlist_add_files ()
{ audgui_run_filebrowser (false); }
-
-void action_playlist_randomize_list ()
- { aud_playlist_randomize (ACTIVE); }
-void action_playlist_reverse_list ()
- { aud_playlist_reverse (ACTIVE); }
-
-void action_playlist_sort_by_title ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_sort_by_album ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Album); }
-void action_playlist_sort_by_artist ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Artist); }
-void action_playlist_sort_by_album_artist ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::AlbumArtist); }
-void action_playlist_sort_by_length ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Length); }
-void action_playlist_sort_by_genre ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Genre); }
-void action_playlist_sort_by_filename ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_sort_by_full_path ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Path); }
-void action_playlist_sort_by_date ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Date); }
-void action_playlist_sort_by_track_number ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Track); }
-void action_playlist_sort_by_custom_title ()
- { aud_playlist_sort_by_scheme (ACTIVE, Playlist::FormattedTitle); }
-
-void action_playlist_sort_selected_by_title ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Title); }
-void action_playlist_sort_selected_by_album ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Album); }
-void action_playlist_sort_selected_by_artist ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Artist); }
-void action_playlist_sort_selected_by_album_artist ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::AlbumArtist); }
-void action_playlist_sort_selected_by_length ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Length); }
-void action_playlist_sort_selected_by_genre ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Genre); }
-void action_playlist_sort_selected_by_filename ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Filename); }
-void action_playlist_sort_selected_by_full_path ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Path); }
-void action_playlist_sort_selected_by_date ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Date); }
-void action_playlist_sort_selected_by_track_number ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Track); }
-void action_playlist_sort_selected_by_custom_title ()
- { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::FormattedTitle); }
-
-void action_playlist_track_info ()
-{
- int playlist = ACTIVE;
- audgui_infowin_show (playlist, aud_playlist_get_focus (playlist));
-}
-
-void action_queue_toggle ()
-{
- int playlist = ACTIVE;
- int focus = aud_playlist_get_focus (playlist);
- if (focus == -1)
- return;
-
- /* make sure focused row is selected */
- if (! aud_playlist_entry_get_selected (playlist, focus))
- {
- aud_playlist_select_all (playlist, false);
- aud_playlist_entry_set_selected (playlist, focus, true);
- }
-
- int at = aud_playlist_queue_find_entry (playlist, focus);
- if (at == -1)
- aud_playlist_queue_insert_selected (playlist, -1);
- else
- aud_playlist_queue_delete_selected (playlist);
-}
diff --git a/src/skins/main.cc b/src/skins/main.cc
index b8fc696..704992a 100644
--- a/src/skins/main.cc
+++ b/src/skins/main.cc
@@ -63,6 +63,8 @@
#include "util.h"
#include "view.h"
+#include "../ui-common/menu-ops.h"
+
#define SEEK_THRESHOLD 200 /* milliseconds */
#define SEEK_SPEED 50 /* milliseconds per pixel */
@@ -211,11 +213,18 @@ void mainwin_show_status_message (const char * message)
static void mainwin_set_song_title (const char * title)
{
+ StringBuf buf;
+
if (title)
- mainwin->setWindowTitle ((const char *) str_printf (_("%s - Audacious"), title));
+ buf.steal (str_printf (_("%s - Audacious"), title));
else
- mainwin->setWindowTitle (_("Audacious"));
+ buf.steal (str_copy (_("Audacious")));
+ int instance = aud_get_instance ();
+ if (instance != 1)
+ buf.combine (str_printf (" (%d)", instance));
+
+ mainwin->setWindowTitle ((const char *) buf);
mainwin_set_info_text (title ? title : "");
}
@@ -531,13 +540,13 @@ bool Window::keypress (GdkEventKey * event)
break;
case GDK_KEY_Tab: /* GtkUIManager does not handle tab, apparently. */
if (event->state & GDK_SHIFT_MASK)
- action_playlist_prev ();
+ pl_prev ();
else
- action_playlist_next ();
+ pl_next ();
break;
case GDK_KEY_ISO_Left_Tab:
- action_playlist_prev ();
+ pl_prev ();
break;
default:
return false;
@@ -1100,7 +1109,6 @@ static void mainwin_create_window ()
bool shaded = aud_get_bool ("skins", "player_shaded");
mainwin = new MainWindow (shaded);
- mainwin->setWindowTitle (_("Audacious"));
GtkWidget * w = mainwin->gtk ();
drag_dest_set (w);
@@ -1153,6 +1161,7 @@ void mainwin_create ()
{
mainwin_create_window ();
mainwin_create_widgets ();
+ mainwin_set_song_title (nullptr);
}
static void mainwin_update_volume ()
diff --git a/src/skins/menus.cc b/src/skins/menus.cc
index 8c3a435..e50e0d3 100644
--- a/src/skins/menus.cc
+++ b/src/skins/menus.cc
@@ -39,6 +39,8 @@
#include "main.h"
#include "view.h"
+#include "../ui-common/menu-ops.h"
+
#define SHIFT GDK_SHIFT_MASK
#define CTRL GDK_CONTROL_MASK
#define ALT GDK_MOD1_MASK
@@ -66,8 +68,8 @@ static void configure_effects () { audgui_show_prefs_for_plugin_type (PluginType
static void configure_output () { audgui_show_prefs_for_plugin_type (PluginType::Output); }
static void configure_visualizations () { audgui_show_prefs_for_plugin_type (PluginType::Vis); }
-static void volume_up () { mainwin_set_volume_diff (5); }
-static void volume_down () { mainwin_set_volume_diff (-5); }
+static void skins_volume_up () { mainwin_set_volume_diff (5); }
+static void skins_volume_down () { mainwin_set_volume_diff (-5); }
/* emulate a config item for the recording toggle */
static void toggle_record ()
@@ -94,8 +96,8 @@ static void record_toggled (void * = nullptr, void * = nullptr)
}
static const AudguiMenuItem output_items[] = {
- MenuCommand (N_("Volume Up"), "audio-volume-high", '+', NO_MOD, volume_up),
- MenuCommand (N_("Volume Down"), "audio-volume-low", '-', NO_MOD, volume_down),
+ MenuCommand (N_("Volume Up"), "audio-volume-high", '+', NO_MOD, skins_volume_up),
+ MenuCommand (N_("Volume Down"), "audio-volume-low", '-', NO_MOD, skins_volume_down),
MenuSep (),
MenuCommand (N_("Effects ..."), nullptr, NO_KEY, configure_effects),
MenuSep (),
@@ -143,14 +145,14 @@ static const AudguiMenuItem playback_items[] = {
};
static const AudguiMenuItem playlist_items[] = {
- MenuCommand (N_("Play/Resume"), "media-playback-start", GDK_KEY_Return, SHIFT, action_playlist_play),
+ MenuCommand (N_("Play/Resume"), "media-playback-start", GDK_KEY_Return, SHIFT, pl_play),
MenuSep (),
MenuCommand (N_("New Playlist"), "document-new", 'n', SHIFT, (GCallback) aud_playlist_new),
MenuCommand (N_("Rename Playlist ..."), "insert-text", GDK_KEY_F2, NO_MOD, action_playlist_rename),
MenuCommand (N_("Remove Playlist"), "edit-delete", 'd', SHIFT, action_playlist_delete),
MenuSep (),
- MenuCommand (N_("Previous Playlist"), "media-skip-backward", GDK_KEY_Tab, SHIFT, action_playlist_prev),
- MenuCommand (N_("Next Playlist"), "media-skip-forward", GDK_KEY_Tab, NO_MOD, action_playlist_next),
+ MenuCommand (N_("Previous Playlist"), "media-skip-backward", GDK_KEY_Tab, SHIFT, pl_prev),
+ MenuCommand (N_("Next Playlist"), "media-skip-forward", GDK_KEY_Tab, NO_MOD, pl_next),
MenuSep (),
MenuCommand (N_("Import Playlist ..."), "document-open", 'o', NO_MOD, audgui_import_playlist),
MenuCommand (N_("Export Playlist ..."), "document-save", 's', SHIFT, audgui_export_playlist),
@@ -158,7 +160,7 @@ static const AudguiMenuItem playlist_items[] = {
MenuCommand (N_("Playlist Manager ..."), "audio-x-generic", 'p', NO_MOD, action_playlist_manager),
MenuCommand (N_("Queue Manager ..."), nullptr, 'u', CTRL, audgui_queue_manager_show),
MenuSep (),
- MenuCommand (N_("Refresh Playlist"), "view-refresh", GDK_KEY_F5, NO_MOD, action_playlist_refresh_list)
+ MenuCommand (N_("Refresh Playlist"), "view-refresh", GDK_KEY_F5, NO_MOD, pl_refresh)
};
static const AudguiMenuItem view_items[] = {
@@ -186,76 +188,78 @@ static const AudguiMenuItem playlist_add_items[] = {
};
static const AudguiMenuItem dupe_items[] = {
- MenuCommand (N_("By Title"), nullptr, NO_KEY, action_playlist_remove_dupes_by_title),
- MenuCommand (N_("By File Name"), nullptr, NO_KEY, action_playlist_remove_dupes_by_filename),
- MenuCommand (N_("By File Path"), nullptr, NO_KEY, action_playlist_remove_dupes_by_full_path)
+ MenuCommand (N_("By Title"), nullptr, NO_KEY, rm_dupes_title),
+ MenuCommand (N_("By File Name"), nullptr, NO_KEY, rm_dupes_filename),
+ MenuCommand (N_("By File Path"), nullptr, NO_KEY, rm_dupes_path)
};
static const AudguiMenuItem playlist_remove_items[] = {
MenuSub (N_("Services"), nullptr, get_plugin_menu_playlist_remove),
MenuSep (),
- MenuCommand (N_("Remove All"), "edit-delete", NO_KEY, action_playlist_remove_all),
- MenuCommand (N_("Clear Queue"), "edit-clear", 'q', SHIFT, action_playlist_clear_queue),
+ MenuCommand (N_("Remove All"), "edit-delete", NO_KEY, pl_remove_all),
+ MenuCommand (N_("Clear Queue"), "edit-clear", 'q', SHIFT, pl_queue_clear),
MenuSep (),
- MenuCommand (N_("Remove Unavailable Files"), "dialog-warning", NO_KEY, action_playlist_remove_unavailable),
+ MenuCommand (N_("Remove Unavailable Files"), "dialog-warning", NO_KEY, pl_remove_failed),
MenuSub (N_("Remove Duplicates"), "edit-copy", {dupe_items}),
MenuSep (),
- MenuCommand (N_("Remove Unselected"), "list-remove", NO_KEY, action_playlist_remove_unselected),
- MenuCommand (N_("Remove Selected"), "list-remove", GDK_KEY_Delete, NO_MOD, action_playlist_remove_selected)
+ MenuCommand (N_("Remove Unselected"), "list-remove", NO_KEY, pl_remove_unselected),
+ MenuCommand (N_("Remove Selected"), "list-remove", GDK_KEY_Delete, NO_MOD, pl_remove_selected)
};
static const AudguiMenuItem playlist_select_items[] = {
MenuCommand (N_("Search and Select"), "edit-find", 'f', CTRL, action_playlist_search_and_select),
MenuSep (),
- MenuCommand (N_("Invert Selection"), nullptr, NO_KEY, action_playlist_invert_selection),
- MenuCommand (N_("Select None"), nullptr, 'a', SHIFT_CTRL, action_playlist_select_none),
- MenuCommand (N_("Select All"), "edit-select-all", 'a', CTRL, action_playlist_select_all),
+ MenuCommand (N_("Invert Selection"), nullptr, NO_KEY, pl_select_invert),
+ MenuCommand (N_("Select None"), nullptr, 'a', SHIFT_CTRL, pl_select_none),
+ MenuCommand (N_("Select All"), "edit-select-all", 'a', CTRL, pl_select_all),
};
static const AudguiMenuItem sort_items[] = {
- MenuCommand (N_("By Track Number"), nullptr, NO_KEY, action_playlist_sort_by_track_number),
- MenuCommand (N_("By Title"), nullptr, NO_KEY, action_playlist_sort_by_title),
- MenuCommand (N_("By Artist"), nullptr, NO_KEY, action_playlist_sort_by_artist),
- MenuCommand (N_("By Album"), nullptr, NO_KEY, action_playlist_sort_by_album),
- MenuCommand (N_("By Album Artist"), nullptr, NO_KEY, action_playlist_sort_by_album_artist),
- MenuCommand (N_("By Release Date"), nullptr, NO_KEY, action_playlist_sort_by_date),
- MenuCommand (N_("By Genre"), nullptr, NO_KEY, action_playlist_sort_by_genre),
- MenuCommand (N_("By Length"), nullptr, NO_KEY, action_playlist_sort_by_length),
- MenuCommand (N_("By File Name"), nullptr, NO_KEY, action_playlist_sort_by_filename),
- MenuCommand (N_("By File Path"), nullptr, NO_KEY, action_playlist_sort_by_full_path),
- MenuCommand (N_("By Custom Title"), nullptr, NO_KEY, action_playlist_sort_by_custom_title)
+ MenuCommand (N_("By Track Number"), nullptr, NO_KEY, sort_track),
+ MenuCommand (N_("By Title"), nullptr, NO_KEY, sort_title),
+ MenuCommand (N_("By Artist"), nullptr, NO_KEY, sort_artist),
+ MenuCommand (N_("By Album"), nullptr, NO_KEY, sort_album),
+ MenuCommand (N_("By Album Artist"), nullptr, NO_KEY, sort_album_artist),
+ MenuCommand (N_("By Release Date"), nullptr, NO_KEY, sort_date),
+ MenuCommand (N_("By Genre"), nullptr, NO_KEY, sort_genre),
+ MenuCommand (N_("By Length"), nullptr, NO_KEY, sort_length),
+ MenuCommand (N_("By File Name"), nullptr, NO_KEY, sort_filename),
+ MenuCommand (N_("By File Path"), nullptr, NO_KEY, sort_path),
+ MenuCommand (N_("By Custom Title"), nullptr, NO_KEY, sort_custom_title)
};
static const AudguiMenuItem sort_selected_items[] = {
- MenuCommand (N_("By Track Number"), nullptr, NO_KEY, action_playlist_sort_selected_by_track_number),
- MenuCommand (N_("By Title"), nullptr, NO_KEY, action_playlist_sort_selected_by_title),
- MenuCommand (N_("By Artist"), nullptr, NO_KEY, action_playlist_sort_selected_by_artist),
- MenuCommand (N_("By Album"), nullptr, NO_KEY, action_playlist_sort_selected_by_album),
- MenuCommand (N_("By Album Artist"), nullptr, NO_KEY, action_playlist_sort_selected_by_album_artist),
- MenuCommand (N_("By Genre"), nullptr, NO_KEY, action_playlist_sort_selected_by_genre),
- MenuCommand (N_("By Release Date"), nullptr, NO_KEY, action_playlist_sort_selected_by_date),
- MenuCommand (N_("By Length"), nullptr, NO_KEY, action_playlist_sort_selected_by_length),
- MenuCommand (N_("By File Name"), nullptr, NO_KEY, action_playlist_sort_selected_by_filename),
- MenuCommand (N_("By File Path"), nullptr, NO_KEY, action_playlist_sort_selected_by_full_path),
- MenuCommand (N_("By Custom Title"), nullptr, NO_KEY, action_playlist_sort_selected_by_custom_title)
+ MenuCommand (N_("By Track Number"), nullptr, NO_KEY, sort_sel_track),
+ MenuCommand (N_("By Title"), nullptr, NO_KEY, sort_sel_title),
+ MenuCommand (N_("By Artist"), nullptr, NO_KEY, sort_sel_artist),
+ MenuCommand (N_("By Album"), nullptr, NO_KEY, sort_sel_album),
+ MenuCommand (N_("By Album Artist"), nullptr, NO_KEY, sort_sel_album_artist),
+ MenuCommand (N_("By Genre"), nullptr, NO_KEY, sort_sel_genre),
+ MenuCommand (N_("By Release Date"), nullptr, NO_KEY, sort_sel_date),
+ MenuCommand (N_("By Length"), nullptr, NO_KEY, sort_sel_length),
+ MenuCommand (N_("By File Name"), nullptr, NO_KEY, sort_sel_filename),
+ MenuCommand (N_("By File Path"), nullptr, NO_KEY, sort_sel_path),
+ MenuCommand (N_("By Custom Title"), nullptr, NO_KEY, sort_sel_custom_title)
};
static const AudguiMenuItem playlist_sort_items[] = {
- MenuCommand (N_("Randomize List"), nullptr, 'r', SHIFT_CTRL, action_playlist_randomize_list),
- MenuCommand (N_("Reverse List"), "view-sort-descending", NO_KEY, action_playlist_reverse_list),
+ MenuCommand (N_("Randomize List"), nullptr, 'r', SHIFT_CTRL, sort_random),
+ MenuCommand (N_("Reverse List"), "view-sort-descending", NO_KEY, sort_reverse),
MenuSep (),
MenuSub (N_("Sort Selected"), "view-sort-ascending", {sort_selected_items}),
MenuSub (N_("Sort List"), "view-sort-ascending", {sort_items})
};
static const AudguiMenuItem playlist_context_items[] = {
- MenuCommand (N_("Song Info ..."), "dialog-information", 'i', ALT, action_playlist_track_info),
+ MenuCommand (N_("Song Info ..."), "dialog-information", 'i', ALT, pl_song_info),
+ MenuCommand (N_("Open Containing Folder"), "folder", NO_KEY, pl_open_folder),
MenuSep (),
- MenuCommand (N_("Cut"), "edit-cut", 'x', CTRL, action_playlist_cut),
- MenuCommand (N_("Copy"), "edit-copy", 'c', CTRL, action_playlist_copy),
- MenuCommand (N_("Paste"), "edit-paste", 'v', CTRL, action_playlist_paste),
+ MenuCommand (N_("Cut"), "edit-cut", 'x', CTRL, pl_cut),
+ MenuCommand (N_("Copy"), "edit-copy", 'c', CTRL, pl_copy),
+ MenuCommand (N_("Paste"), "edit-paste", 'v', CTRL, pl_paste),
+ MenuCommand (N_("Paste at End"), "edit-paste", 'v', SHIFT_CTRL, pl_paste_end),
MenuSep (),
- MenuCommand (N_("Queue/Unqueue"), nullptr, 'q', NO_MOD, action_queue_toggle),
+ MenuCommand (N_("Queue/Unqueue"), nullptr, 'q', NO_MOD, pl_queue_toggle),
MenuSep (),
MenuSub (N_("Services"), nullptr, get_plugin_menu_playlist)
};
diff --git a/src/skins/playlist-widget.cc b/src/skins/playlist-widget.cc
index d493eb6..96edb82 100644
--- a/src/skins/playlist-widget.cc
+++ b/src/skins/playlist-widget.cc
@@ -204,7 +204,7 @@ void PlaylistWidget::draw (cairo_t * cr)
for (int i = m_first; i < m_first + m_rows && i < m_length; i ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::NoWait);
int len = tuple.get_int (Tuple::Length);
if (len < 0)
continue;
@@ -262,7 +262,7 @@ void PlaylistWidget::draw (cairo_t * cr)
for (int i = m_first; i < m_first + m_rows && i < m_length; i ++)
{
- Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (m_playlist, i, Playlist::NoWait);
String title = tuple.get_str (Tuple::FormattedTitle);
layout = gtk_widget_create_pango_layout (gtk_dr (), title);
diff --git a/src/skins/playlist.cc b/src/skins/playlist.cc
index 0ab4a42..af95724 100644
--- a/src/skins/playlist.cc
+++ b/src/skins/playlist.cc
@@ -108,7 +108,7 @@ static void update_rollup_text ()
{
int playlist = aud_playlist_get_active ();
int entry = aud_playlist_get_position (playlist);
- Tuple tuple = aud_playlist_entry_get_tuple (playlist, entry, Playlist::Guess);
+ Tuple tuple = aud_playlist_entry_get_tuple (playlist, entry, Playlist::NoWait);
char scratch[512];
scratch[0] = 0;
diff --git a/src/skins/plugin-window.cc b/src/skins/plugin-window.cc
index d438abf..485fcb9 100644
--- a/src/skins/plugin-window.cc
+++ b/src/skins/plugin-window.cc
@@ -78,6 +78,9 @@ static void add_dock_plugin (PluginHandle * plugin, void * unused)
if (pos_str && str_to_int_array (pos_str, pos, aud::n_elems (pos)))
{
+ pos[2] = audgui_to_native_dpi (pos[2]);
+ pos[3] = audgui_to_native_dpi (pos[3]);
+
gtk_window_set_default_size ((GtkWindow *) window, pos[2], pos[3]);
gtk_window_move ((GtkWindow *) window, pos[0], pos[1]);
}
@@ -103,6 +106,9 @@ static void save_window_size (GtkWidget * window)
gtk_window_get_position ((GtkWindow *) window, & pos[0], & pos[1]);
gtk_window_get_size ((GtkWindow *) window, & pos[2], & pos[3]);
+ pos[2] = audgui_to_portable_dpi (pos[2]);
+ pos[3] = audgui_to_portable_dpi (pos[3]);
+
const char * basename = aud_plugin_get_basename (plugin);
StringBuf pos_str = int_array_to_str (pos, aud::n_elems (pos));
aud_set_str ("skins-layout", basename, pos_str);
diff --git a/src/skins/plugin.cc b/src/skins/plugin.cc
index a027615..bab7ed6 100644
--- a/src/skins/plugin.cc
+++ b/src/skins/plugin.cc
@@ -20,7 +20,6 @@
#include <stdlib.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
@@ -43,6 +42,9 @@
#include "window.h"
#include "view.h"
+#include "../ui-common/menu-ops.cc"
+#include "../ui-common/menu-ops-gtk.cc"
+
class SkinnedUI : public IfacePlugin
{
public:
@@ -50,7 +52,8 @@ public:
N_("Winamp Classic Interface"),
PACKAGE,
nullptr,
- & skins_prefs
+ & skins_prefs,
+ PluginGLibOnly
};
constexpr SkinnedUI () : IfacePlugin (info) {}
@@ -86,6 +89,9 @@ public:
{ audgui_plugin_menu_add (id, func, name, icon); }
void plugin_menu_remove (AudMenuID id, void func ())
{ audgui_plugin_menu_remove (id, func); }
+
+ void startup_notify (const char * id)
+ { gdk_notify_startup_complete_with_id (id); }
};
EXPORT SkinnedUI aud_plugin_instance;
diff --git a/src/skins/search-select.cc b/src/skins/search-select.cc
index 47741c1..2267473 100644
--- a/src/skins/search-select.cc
+++ b/src/skins/search-select.cc
@@ -60,7 +60,7 @@ static void copy_selected_to_new (int playlist)
{
items.append
(aud_playlist_entry_get_filename (playlist, entry),
- aud_playlist_entry_get_tuple (playlist, entry, Playlist::Nothing));
+ aud_playlist_entry_get_tuple (playlist, entry, Playlist::NoWait));
}
}
diff --git a/src/skins/skinselector.cc b/src/skins/skinselector.cc
index fe8044c..7d090c3 100644
--- a/src/skins/skinselector.cc
+++ b/src/skins/skinselector.cc
@@ -115,11 +115,6 @@ static void scan_skindir_func (const char * path, const char * basename)
String (_("Unarchived Winamp 2.x skin")), String (path));
}
-static int skinlist_compare_func (const SkinNode & a, const SkinNode & b, void *)
-{
- return str_compare (a.name, b.name);
-}
-
static void skinlist_update ()
{
skinlist.clear ();
@@ -138,7 +133,8 @@ static void skinlist_update ()
dir_foreach (dir, scan_skindir_func);
}
- skinlist.sort (skinlist_compare_func, nullptr);
+ skinlist.sort ([] (const SkinNode & a, const SkinNode & b)
+ { return str_compare (a.name, b.name); });
}
void skin_view_update (GtkTreeView * treeview)
diff --git a/src/skins/util.cc b/src/skins/util.cc
index 8c7badc..793765c 100644
--- a/src/skins/util.cc
+++ b/src/skins/util.cc
@@ -80,14 +80,7 @@ StringBuf find_file_case_path (const char * folder, const char * basename)
VFSFile open_local_file_nocase (const char * folder, const char * basename)
{
StringBuf path = find_file_case_path (folder, basename);
- if (! path)
- return VFSFile ();
-
- StringBuf uri = filename_to_uri (path);
- if (! uri)
- return VFSFile ();
-
- return VFSFile (uri, "r");
+ return path ? VFSFile (filename_to_uri (path), "r") : VFSFile ();
}
StringBuf skin_pixmap_locate (const char * folder, const char * basename, const char * altname)
@@ -275,7 +268,7 @@ StringBuf archive_decompress (const char * filename)
StringBuf tmpdir = filename_build ({g_get_tmp_dir (), "audacious.XXXXXX"});
if (! g_mkdtemp (tmpdir))
{
- AUDWARN ("Error creating %s: %s\n", strerror (errno));
+ AUDWARN ("Error creating %s: %s\n", (const char *) tmpdir, strerror (errno));
return StringBuf ();
}
@@ -352,5 +345,5 @@ bool dir_foreach (const char * path, DirForeachFunc func)
void make_directory (const char * path)
{
if (g_mkdir_with_parents (path, DIRMODE) != 0)
- AUDWARN ("Error creating %s: %s\n", strerror (errno));
+ AUDWARN ("Error creating %s: %s\n", path, strerror (errno));
}
diff --git a/src/sndfile/plugin.cc b/src/sndfile/plugin.cc
index 588f024..51e9017 100644
--- a/src/sndfile/plugin.cc
+++ b/src/sndfile/plugin.cc
@@ -41,14 +41,12 @@ public:
about
};
- static constexpr auto iinfo = InputInfo ()
+ constexpr SndfilePlugin () : InputPlugin (info, InputInfo ()
.with_priority (9) /* low priority fallback (but before ffaudio) */
- .with_exts (exts);
-
- constexpr SndfilePlugin () : InputPlugin (info, iinfo) {}
+ .with_exts (exts)) {}
bool is_our_file (const char * filename, VFSFile & file);
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool play (const char * filename, VFSFile & file);
};
@@ -128,33 +126,31 @@ static void copy_int (SNDFILE * sf, int sf_id, Tuple & tup, Tuple::Field field)
tup.set_int (field, atoi (str));
}
-Tuple SndfilePlugin::read_tuple (const char * filename, VFSFile & file)
+bool SndfilePlugin::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
SF_INFO sfinfo {}; // must be zeroed before sf_open()
const char *format, *subformat;
- Tuple ti;
bool stream = (file.fsize () < 0);
SNDFILE * sndfile = sf_open_virtual (stream ? & sf_virtual_io_stream :
& sf_virtual_io, SFM_READ, & sfinfo, & file);
- if (sndfile == nullptr)
- return ti;
-
- ti.set_filename (filename);
+ if (! sndfile)
+ return false;
- copy_string (sndfile, SF_STR_TITLE, ti, Tuple::Title);
- copy_string (sndfile, SF_STR_ARTIST, ti, Tuple::Artist);
- copy_string (sndfile, SF_STR_ALBUM, ti, Tuple::Album);
- copy_string (sndfile, SF_STR_COMMENT, ti, Tuple::Comment);
- copy_string (sndfile, SF_STR_GENRE, ti, Tuple::Genre);
- copy_int (sndfile, SF_STR_DATE, ti, Tuple::Year);
- copy_int (sndfile, SF_STR_TRACKNUMBER, ti, Tuple::Track);
+ copy_string (sndfile, SF_STR_TITLE, tuple, Tuple::Title);
+ copy_string (sndfile, SF_STR_ARTIST, tuple, Tuple::Artist);
+ copy_string (sndfile, SF_STR_ALBUM, tuple, Tuple::Album);
+ copy_string (sndfile, SF_STR_COMMENT, tuple, Tuple::Comment);
+ copy_string (sndfile, SF_STR_GENRE, tuple, Tuple::Genre);
+ copy_int (sndfile, SF_STR_DATE, tuple, Tuple::Year);
+ copy_int (sndfile, SF_STR_TRACKNUMBER, tuple, Tuple::Track);
sf_close (sndfile);
if (sfinfo.samplerate > 0)
- ti.set_int (Tuple::Length, ceil (1000.0 * sfinfo.frames / sfinfo.samplerate));
+ tuple.set_int (Tuple::Length, ceil (1000.0 * sfinfo.frames / sfinfo.samplerate));
switch (sfinfo.format & SF_FORMAT_TYPEMASK)
{
@@ -296,12 +292,12 @@ Tuple SndfilePlugin::read_tuple (const char * filename, VFSFile & file)
}
if (subformat != nullptr)
- ti.set_format (str_printf ("%s (%s)", format, subformat),
+ tuple.set_format (str_printf ("%s (%s)", format, subformat),
sfinfo.channels, sfinfo.samplerate, 0);
else
- ti.set_format (format, sfinfo.channels, sfinfo.samplerate, 0);
+ tuple.set_format (format, sfinfo.channels, sfinfo.samplerate, 0);
- return ti;
+ return true;
}
bool SndfilePlugin::play (const char * filename, VFSFile & file)
diff --git a/src/sndio-ng/Makefile b/src/sndio/Makefile
index bc7bcd8..f1caae5 100644
--- a/src/sndio-ng/Makefile
+++ b/src/sndio/Makefile
@@ -10,4 +10,4 @@ plugindir := ${plugindir}/${OUTPUT_PLUGIN_DIR}
LD = ${CXX}
CFLAGS += ${PLUGIN_CFLAGS}
CPPFLAGS += ${PLUGIN_CPPFLAGS} -I../..
-LIBS += ${SNDIO_LIBS}
+LIBS += -lsndio
diff --git a/src/sndio-ng/sndio.cc b/src/sndio/sndio.cc
index 59301f5..b7b986c 100644
--- a/src/sndio-ng/sndio.cc
+++ b/src/sndio/sndio.cc
@@ -19,7 +19,6 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
-#include <libaudcore/interface.h>
#include <libaudcore/plugin.h>
#include <libaudcore/preferences.h>
#include <libaudcore/runtime.h>
@@ -54,7 +53,7 @@ public:
StereoVolume get_volume ();
void set_volume (StereoVolume v);
- bool open_audio (int format, int rate, int channels);
+ bool open_audio (int format, int rate, int channels, String & error);
void close_audio ();
void period_wait ();
@@ -167,7 +166,7 @@ static const FormatData format_table[] = {
{FMT_U32_BE, 32, 4, false, false},
};
-bool SndioPlugin::open_audio (int format, int rate, int channels)
+bool SndioPlugin::open_audio (int format, int rate, int channels, String & error)
{
const FormatData * fdata = nullptr;
@@ -179,7 +178,7 @@ bool SndioPlugin::open_audio (int format, int rate, int channels)
if (! fdata)
{
- aud_ui_show_error (str_printf (_("Sndio error: Unsupported audio format (%d)"), format));
+ error = String (str_printf (_("Sndio error: Unsupported audio format (%d)"), format));
return false;
}
@@ -190,7 +189,7 @@ bool SndioPlugin::open_audio (int format, int rate, int channels)
if (! m_handle)
{
- aud_ui_show_error (_("Sndio error: sio_open() failed"));
+ error = String (_("Sndio error: sio_open() failed"));
return false;
}
@@ -219,7 +218,7 @@ bool SndioPlugin::open_audio (int format, int rate, int channels)
if (! sio_setpar (m_handle, & par))
{
- aud_ui_show_error (_("Sndio error: sio_setpar() failed"));
+ error = String (_("Sndio error: sio_setpar() failed"));
goto fail;
}
@@ -231,7 +230,7 @@ bool SndioPlugin::open_audio (int format, int rate, int channels)
if (! sio_start (m_handle))
{
- aud_ui_show_error (_("Sndio error: sio_start() failed"));
+ error = String (_("Sndio error: sio_start() failed"));
goto fail;
}
diff --git a/src/song-info-qt/song-info.cc b/src/song-info-qt/song-info.cc
index 6f80108..8d012d6 100644
--- a/src/song-info-qt/song-info.cc
+++ b/src/song-info-qt/song-info.cc
@@ -17,7 +17,6 @@
* the use of this software.
*/
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/drct.h>
#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
@@ -32,7 +31,10 @@ class SongInfo : public GeneralPlugin {
public:
static constexpr PluginInfo info = {
N_("Song Info"),
- PACKAGE
+ PACKAGE,
+ nullptr, // about
+ nullptr, // prefs
+ PluginQtOnly
};
constexpr SongInfo () : GeneralPlugin (info, false) {}
@@ -70,7 +72,7 @@ void SongInfo::update (void * unused, audqt::InfoWidget * widget)
return;
Tuple tuple = aud_playlist_entry_get_tuple (playlist, position);
- if (tuple)
+ if (tuple.valid ())
widget->fillInfo (playlist, position, filename, tuple, decoder,
aud_file_can_write_tuple (filename, decoder));
}
diff --git a/src/song_change/Makefile b/src/songchange/Makefile
index 5ae5784..5ae5784 100644
--- a/src/song_change/Makefile
+++ b/src/songchange/Makefile
diff --git a/src/song_change/formatter.cc b/src/songchange/formatter.cc
index 3686cf0..3686cf0 100644
--- a/src/song_change/formatter.cc
+++ b/src/songchange/formatter.cc
diff --git a/src/song_change/formatter.h b/src/songchange/formatter.h
index 196fbc3..196fbc3 100644
--- a/src/song_change/formatter.h
+++ b/src/songchange/formatter.h
diff --git a/src/song_change/song_change.cc b/src/songchange/song_change.cc
index fdca5bc..fdca5bc 100644
--- a/src/song_change/song_change.cc
+++ b/src/songchange/song_change.cc
diff --git a/src/sox-resampler/Makefile b/src/soxr/Makefile
index bc3bcd9..bc3bcd9 100644
--- a/src/sox-resampler/Makefile
+++ b/src/soxr/Makefile
diff --git a/src/sox-resampler/sox-resampler.cc b/src/soxr/sox-resampler.cc
index 43cbe61..6e6bf91 100644
--- a/src/sox-resampler/sox-resampler.cc
+++ b/src/soxr/sox-resampler.cc
@@ -61,9 +61,10 @@ public:
EXPORT SoXResampler aud_plugin_instance;
const char * const SoXResampler::defaults[] = {
- "quality", aud::numeric_string<SOXR_HQ>::str,
- "rate", "44100",
- nullptr};
+ "quality", aud::numeric_string<SOXR_HQ>::str,
+ "rate", "44100",
+ nullptr
+};
static soxr_t soxr;
static soxr_error_t error;
@@ -95,13 +96,13 @@ void SoXResampler::start (int & channels, int & rate)
if (new_rate == rate)
return;
- soxr_quality_spec_t q = soxr_quality_spec(aud_get_int ("soxr", "quality"), 0);
+ soxr_quality_spec_t q = soxr_quality_spec (aud_get_int ("soxr", "quality"), 0);
- soxr = soxr_create(rate, new_rate, channels, & error, nullptr, & q, nullptr);
+ soxr = soxr_create (rate, new_rate, channels, & error, nullptr, & q, nullptr);
if (error)
{
- AUDERR (error);
+ AUDERR ("%s\n", error);
return;
}
@@ -123,7 +124,7 @@ Index<float> & SoXResampler::process (Index<float> & data)
if (error)
{
- AUDERR (error);
+ AUDERR ("%s\n", error);
return data;
}
@@ -134,8 +135,8 @@ Index<float> & SoXResampler::process (Index<float> & data)
bool SoXResampler::flush (bool force)
{
- if (soxr && (error = soxr_process(soxr, nullptr, 0, nullptr, nullptr, 0, nullptr)))
- AUDERR (error);
+ if (soxr && (error = soxr_process (soxr, nullptr, 0, nullptr, nullptr, 0, nullptr)))
+ AUDERR ("%s\n", error);
return true;
}
diff --git a/src/speed-pitch/Makefile b/src/speedpitch/Makefile
index 41a00d5..41a00d5 100644
--- a/src/speed-pitch/Makefile
+++ b/src/speedpitch/Makefile
diff --git a/src/speed-pitch/speed-pitch.cc b/src/speedpitch/speed-pitch.cc
index 17acca4..81a42fc 100644
--- a/src/speed-pitch/speed-pitch.cc
+++ b/src/speedpitch/speed-pitch.cc
@@ -20,6 +20,7 @@
#include <math.h>
#include <samplerate.h>
+#include <libaudcore/hook.h>
#include <libaudcore/i18n.h>
#include <libaudcore/runtime.h>
#include <libaudcore/plugin.h>
@@ -39,6 +40,8 @@
#define MAXSPEED 2.0
#define MINPITCH 0.5
#define MAXPITCH 2.0
+#define MINSEMITONES -12.0
+#define MAXSEMITONES 12.0
class SpeedPitch : public EffectPlugin
{
@@ -74,6 +77,7 @@ private:
EXPORT SpeedPitch aud_plugin_instance;
+static double semitones;
static int curchans, currate;
static SRC_STATE * srcstate;
static int outstep, width;
@@ -201,6 +205,18 @@ int SpeedPitch::adjust_delay (int delay)
return (delay + in_samples * samples_to_ms) * speed + out_samples * samples_to_ms;
}
+static void pitch_changed ()
+{
+ semitones = 12 * log (aud_get_double (CFGSECT, "pitch")) / log (2);
+ hook_call ("speed-pitch set semitones", nullptr);
+}
+
+static void semitones_changed ()
+{
+ aud_set_double (CFGSECT, "pitch", pow (2, semitones / 12));
+ hook_call ("speed-pitch set pitch", nullptr);
+}
+
const char * const SpeedPitch::defaults[] = {
"speed", "1",
"pitch", "1",
@@ -212,8 +228,12 @@ const PreferencesWidget SpeedPitch::widgets[] = {
WidgetFloat (CFGSECT, "speed"),
{MINSPEED, MAXSPEED, 0.05}),
WidgetSpin (N_("Pitch:"),
- WidgetFloat (CFGSECT, "pitch"),
- {MINPITCH, MAXPITCH, 0.05})
+ WidgetFloat (CFGSECT, "pitch", pitch_changed, "speed-pitch set pitch"),
+ {MINPITCH, MAXPITCH, 0.005}),
+ WidgetSpin (nullptr,
+ WidgetFloat (semitones, semitones_changed, "speed-pitch set semitones"),
+ {MINSEMITONES, MAXSEMITONES, 0.05, N_("semitones")},
+ WIDGET_CHILD)
};
const PluginPreferences SpeedPitch::prefs = {{widgets}};
@@ -221,6 +241,7 @@ const PluginPreferences SpeedPitch::prefs = {{widgets}};
bool SpeedPitch::init ()
{
aud_config_set_defaults (CFGSECT, defaults);
+ pitch_changed ();
return true;
}
diff --git a/src/statusicon-qt/statusicon.cc b/src/statusicon-qt/statusicon.cc
index d1218a9..f72b874 100644
--- a/src/statusicon-qt/statusicon.cc
+++ b/src/statusicon-qt/statusicon.cc
@@ -17,7 +17,6 @@
* the use of this software.
*/
-#define AUD_PLUGIN_QT_ONLY
#include <libaudcore/i18n.h>
#include <libaudcore/drct.h>
#include <libaudcore/hook.h>
@@ -44,7 +43,8 @@ public:
N_("Status Icon"),
PACKAGE,
about,
- & prefs
+ & prefs,
+ PluginQtOnly
};
constexpr StatusIcon () : GeneralPlugin (info, false) {}
diff --git a/src/statusicon/statusicon.cc b/src/statusicon/statusicon.cc
index 152111f..07b6661 100644
--- a/src/statusicon/statusicon.cc
+++ b/src/statusicon/statusicon.cc
@@ -22,7 +22,6 @@
#include <gdk/gdk.h>
#include <gtk/gtk.h>
-#define AUD_PLUGIN_GLIB_ONLY
#include <libaudcore/audstrings.h>
#include <libaudcore/drct.h>
#include <libaudcore/i18n.h>
@@ -48,7 +47,8 @@ public:
N_("Status Icon"),
PACKAGE,
about,
- & prefs
+ & prefs,
+ PluginGLibOnly
};
constexpr StatusIcon () : GeneralPlugin (info, false) {}
diff --git a/src/tonegen/tonegen.cc b/src/tonegen/tonegen.cc
index 9d9c9ef..b2a610d 100644
--- a/src/tonegen/tonegen.cc
+++ b/src/tonegen/tonegen.cc
@@ -47,13 +47,11 @@ public:
about
};
- static constexpr auto iinfo = InputInfo()
- .with_schemes(schemes);
-
- constexpr ToneGen() : InputPlugin(info, iinfo) {}
+ constexpr ToneGen() : InputPlugin(info, InputInfo()
+ .with_schemes(schemes)) {}
bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool play(const char *filename, VFSFile &file);
};
@@ -148,12 +146,14 @@ bool ToneGen::play(const char *filename, VFSFile &file)
return true;
}
-Tuple ToneGen::read_tuple(const char *filename, VFSFile &file)
+bool ToneGen::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple tuple;
- tuple.set_filename(filename);
- tuple.set_str(Tuple::Title, tone_title(filename));
- return tuple;
+ StringBuf title = tone_title(filename);
+ if (!title)
+ return false;
+
+ tuple.set_str(Tuple::Title, title);
+ return true;
}
const char ToneGen::about[] =
diff --git a/src/ui-common/menu-ops-gtk.cc b/src/ui-common/menu-ops-gtk.cc
new file mode 100644
index 0000000..2d85982
--- /dev/null
+++ b/src/ui-common/menu-ops-gtk.cc
@@ -0,0 +1,133 @@
+/*
+ * menu-ops-gtk.cc
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#include "menu-ops.h"
+
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include <libaudcore/audstrings.h>
+#include <libaudcore/interface.h>
+#include <libaudcore/playlist.h>
+#include <libaudgui/libaudgui.h>
+
+static void uri_get_func (GtkClipboard *, GtkSelectionData * sel, unsigned, void * data)
+ { gtk_selection_data_set_uris (sel, (char * *) data); }
+static void uri_clear_func (GtkClipboard *, void * data)
+ { g_strfreev ((char * *) data); }
+
+void pl_copy ()
+{
+ int list = aud_playlist_get_active ();
+ int entries = aud_playlist_entry_count (list);
+ int selected = aud_playlist_selected_count (list);
+ int fetched = 0;
+
+ if (! selected)
+ return;
+
+ aud_playlist_cache_selected (list);
+
+ char * * uris = g_new (char *, selected + 1);
+
+ for (int i = 0; i < entries && fetched < selected; i ++)
+ {
+ if (aud_playlist_entry_get_selected (list, i))
+ uris[fetched ++] = g_strdup (aud_playlist_entry_get_filename (list, i));
+ }
+
+ uris[fetched] = nullptr;
+
+ GtkTargetList * tlist = gtk_target_list_new (nullptr, 0);
+ gtk_target_list_add_uri_targets (tlist, 0);
+
+ GtkTargetEntry * targets; int n_targets;
+ targets = gtk_target_table_new_from_list (tlist, & n_targets);
+
+ gtk_clipboard_set_with_data (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
+ targets, n_targets, uri_get_func, uri_clear_func, uris);
+
+ gtk_target_table_free (targets, n_targets);
+ gtk_target_list_unref (tlist);
+}
+
+void pl_cut ()
+{
+ pl_copy ();
+ pl_remove_selected ();
+}
+
+static void paste_to (int list, int pos)
+{
+ char * * uris = gtk_clipboard_wait_for_uris (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
+ if (! uris)
+ return;
+
+ Index<PlaylistAddItem> items;
+ for (int i = 0; uris[i]; i ++)
+ items.append (String (uris[i]));
+
+ aud_playlist_entry_insert_batch (list, pos, std::move (items), false);
+ g_strfreev (uris);
+}
+
+void pl_paste ()
+{
+ int list = aud_playlist_get_active ();
+ paste_to (list, aud_playlist_get_focus (list));
+}
+
+void pl_paste_end ()
+{
+ paste_to (aud_playlist_get_active (), -1);
+}
+
+void pl_song_info ()
+{
+ int list = aud_playlist_get_active ();
+ int focus = aud_playlist_get_focus (list);
+ if (focus >= 0)
+ audgui_infowin_show (list, focus);
+}
+
+void pl_open_folder ()
+{
+ int list = aud_playlist_get_active ();
+ int focus = aud_playlist_get_focus (list);
+
+ String filename = aud_playlist_entry_get_filename (list, focus);
+ if (! filename)
+ return;
+
+ const char * slash = strrchr (filename, '/');
+ if (! slash)
+ return;
+
+ /* don't trim trailing slash, it may be important */
+ StringBuf folder = str_copy (filename, slash + 1 - filename);
+
+ GError * error = nullptr;
+ gtk_show_uri (gdk_screen_get_default (), folder, GDK_CURRENT_TIME, & error);
+
+ if (error)
+ {
+ aud_ui_show_error (error->message);
+ g_error_free (error);
+ }
+}
diff --git a/src/ui-common/menu-ops-qt.cc b/src/ui-common/menu-ops-qt.cc
new file mode 100644
index 0000000..f603e5a
--- /dev/null
+++ b/src/ui-common/menu-ops-qt.cc
@@ -0,0 +1,107 @@
+/*
+ * menu-ops-qt.cc
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#include "menu-ops.h"
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDesktopServices>
+#include <QMimeData>
+#include <QUrl>
+
+#include <libaudcore/audstrings.h>
+#include <libaudcore/playlist.h>
+#include <libaudqt/libaudqt.h>
+
+void pl_copy ()
+{
+ int list = aud_playlist_get_active ();
+ int entries = aud_playlist_entry_count (list);
+
+ if (! aud_playlist_selected_count (list))
+ return;
+
+ aud_playlist_cache_selected (list);
+
+ QList<QUrl> urls;
+ for (int i = 0; i < entries; i ++)
+ {
+ if (aud_playlist_entry_get_selected (list, i))
+ urls.append (QString (aud_playlist_entry_get_filename (list, i)));
+ }
+
+ auto data = new QMimeData;
+ data->setUrls (urls);
+ QApplication::clipboard ()->setMimeData (data);
+}
+
+void pl_cut ()
+{
+ pl_copy ();
+ pl_remove_selected ();
+}
+
+static void paste_to (int list, int pos)
+{
+ auto data = QApplication::clipboard ()->mimeData ();
+ if (! data->hasUrls ())
+ return;
+
+ Index<PlaylistAddItem> items;
+ for (auto & url : data->urls ())
+ items.append (String (url.toEncoded ()));
+
+ aud_playlist_entry_insert_batch (list, pos, std::move (items), false);
+}
+
+void pl_paste ()
+{
+ int list = aud_playlist_get_active ();
+ paste_to (list, aud_playlist_get_focus (list));
+}
+
+void pl_paste_end ()
+{
+ paste_to (aud_playlist_get_active (), -1);
+}
+
+void pl_song_info ()
+{
+ int list = aud_playlist_get_active ();
+ int focus = aud_playlist_get_focus (list);
+ if (focus >= 0)
+ audqt::infowin_show (list, focus);
+}
+
+void pl_open_folder ()
+{
+ int list = aud_playlist_get_active ();
+ int focus = aud_playlist_get_focus (list);
+
+ String filename = aud_playlist_entry_get_filename (list, focus);
+ if (! filename)
+ return;
+
+ const char * slash = strrchr (filename, '/');
+ if (! slash)
+ return;
+
+ /* don't trim trailing slash, it may be important */
+ QDesktopServices::openUrl (QString::fromUtf8 (filename, slash + 1 - filename));
+}
diff --git a/src/ui-common/menu-ops.cc b/src/ui-common/menu-ops.cc
new file mode 100644
index 0000000..cd2dc71
--- /dev/null
+++ b/src/ui-common/menu-ops.cc
@@ -0,0 +1,128 @@
+/*
+ * menu-ops.cc
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#include <libaudcore/drct.h>
+#include <libaudcore/playlist.h>
+
+#define ACTIVE aud_playlist_get_active ()
+
+void rm_dupes_title () { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Title); }
+void rm_dupes_filename () { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Filename); }
+void rm_dupes_path () { aud_playlist_remove_duplicates_by_scheme (ACTIVE, Playlist::Path); }
+
+void sort_track () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Track); }
+void sort_title () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Title); }
+void sort_artist () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Artist); }
+void sort_album () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Album); }
+void sort_album_artist () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::AlbumArtist); }
+void sort_date () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Date); }
+void sort_genre () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Genre); }
+void sort_length () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Length); }
+void sort_path () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Path); }
+void sort_filename () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::Filename); }
+void sort_custom_title () { aud_playlist_sort_by_scheme (ACTIVE, Playlist::FormattedTitle); }
+void sort_reverse () { aud_playlist_reverse (ACTIVE); }
+void sort_random () { aud_playlist_randomize (ACTIVE); }
+
+void sort_sel_track () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Track); }
+void sort_sel_title () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Title); }
+void sort_sel_artist () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Artist); }
+void sort_sel_album () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Album); }
+void sort_sel_album_artist () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::AlbumArtist); }
+void sort_sel_date () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Date); }
+void sort_sel_genre () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Genre); }
+void sort_sel_length () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Length); }
+void sort_sel_path () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Path); }
+void sort_sel_filename () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::Filename); }
+void sort_sel_custom_title () { aud_playlist_sort_selected_by_scheme (ACTIVE, Playlist::FormattedTitle); }
+void sort_sel_reverse () { aud_playlist_reverse_selected (ACTIVE); }
+void sort_sel_random () { aud_playlist_randomize_selected (ACTIVE); }
+
+void pl_prev ()
+{
+ int list = aud_playlist_get_active ();
+ aud_playlist_set_active (list > 0 ? list - 1 : aud_playlist_count () - 1);
+}
+
+void pl_next ()
+{
+ aud_playlist_set_active ((aud_playlist_get_active () + 1) % aud_playlist_count ());
+}
+
+void pl_play () { aud_playlist_play (ACTIVE); }
+
+void pl_select_all () { aud_playlist_select_all (ACTIVE, true); }
+void pl_select_none () { aud_playlist_select_all (ACTIVE, false); }
+void pl_refresh () { aud_playlist_rescan (ACTIVE); }
+void pl_refresh_sel () { aud_playlist_rescan_selected (ACTIVE); }
+void pl_remove_failed () { aud_playlist_remove_failed (ACTIVE); }
+void pl_remove_selected () { aud_playlist_delete_selected (ACTIVE); }
+
+void pl_queue_clear ()
+{
+ int list = aud_playlist_get_active ();
+ aud_playlist_queue_delete (list, 0, aud_playlist_queue_count (list));
+}
+
+void pl_queue_toggle ()
+{
+ int list = aud_playlist_get_active ();
+ int focus = aud_playlist_get_focus (list);
+ if (focus < 0)
+ return;
+
+ /* make sure focused row is selected */
+ if (! aud_playlist_entry_get_selected (list, focus))
+ {
+ aud_playlist_select_all (list, false);
+ aud_playlist_entry_set_selected (list, focus, true);
+ }
+
+ int at = aud_playlist_queue_find_entry (list, focus);
+ if (at < 0)
+ aud_playlist_queue_insert_selected (list, -1);
+ else
+ aud_playlist_queue_delete_selected (list);
+}
+
+void pl_select_invert ()
+{
+ int list = aud_playlist_get_active ();
+ int entries = aud_playlist_entry_count (list);
+
+ for (int entry = 0; entry < entries; entry ++)
+ aud_playlist_entry_set_selected (list, entry,
+ ! aud_playlist_entry_get_selected (list, entry));
+}
+
+void pl_remove_all ()
+{
+ int list = aud_playlist_get_active ();
+ aud_playlist_entry_delete (list, 0, aud_playlist_entry_count (list));
+}
+
+void pl_remove_unselected ()
+{
+ pl_select_invert ();
+ pl_remove_selected ();
+ pl_select_all ();
+}
+
+void volume_up () { aud_drct_set_volume_main (aud_drct_get_volume_main () + 5); }
+void volume_down () { aud_drct_set_volume_main (aud_drct_get_volume_main () - 5); }
diff --git a/src/ui-common/menu-ops.h b/src/ui-common/menu-ops.h
new file mode 100644
index 0000000..b7bcfc7
--- /dev/null
+++ b/src/ui-common/menu-ops.h
@@ -0,0 +1,90 @@
+/*
+ * menu-ops.h
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#ifndef UI_COMMON_MENU_OPS_H
+#define UI_COMMON_MENU_OPS_H
+
+// remove duplicate playlist entries
+void rm_dupes_title ();
+void rm_dupes_filename ();
+void rm_dupes_path ();
+
+// sort entire playlist
+void sort_track ();
+void sort_title ();
+void sort_artist ();
+void sort_album ();
+void sort_album_artist ();
+void sort_date ();
+void sort_genre ();
+void sort_length ();
+void sort_path ();
+void sort_filename ();
+void sort_custom_title ();
+void sort_reverse ();
+void sort_random ();
+
+// sort selected playlist entries
+void sort_sel_track ();
+void sort_sel_title ();
+void sort_sel_artist ();
+void sort_sel_album ();
+void sort_sel_album_artist ();
+void sort_sel_date ();
+void sort_sel_genre ();
+void sort_sel_length ();
+void sort_sel_path ();
+void sort_sel_filename ();
+void sort_sel_custom_title ();
+void sort_sel_reverse ();
+void sort_sel_random ();
+
+// playlist switching
+void pl_prev ();
+void pl_next ();
+void pl_play ();
+
+// playlist editing
+void pl_queue_clear ();
+void pl_queue_toggle ();
+void pl_select_all ();
+void pl_select_none ();
+void pl_select_invert ();
+void pl_refresh ();
+void pl_refresh_sel ();
+void pl_remove_all ();
+void pl_remove_failed ();
+void pl_remove_selected ();
+void pl_remove_unselected ();
+
+// clipboard
+void pl_copy ();
+void pl_cut ();
+void pl_paste ();
+void pl_paste_end ();
+
+// misc playlist
+void pl_song_info ();
+void pl_open_folder ();
+
+// volume control
+void volume_up ();
+void volume_down ();
+
+#endif // UI_COMMON_MENU_OPS_H
diff --git a/src/vorbis/vcedit.cc b/src/vorbis/vcedit.cc
index 188a4cb..5c6f465 100644
--- a/src/vorbis/vcedit.cc
+++ b/src/vorbis/vcedit.cc
@@ -3,11 +3,10 @@
*
* (c) 2000-2001 Michael Smith <msmith@labyrinth.net.au>
*
- *
* Comment editing backend, suitable for use by nice frontend interfaces.
*
+ * Somewhat cleaned up for C++ by John Lindgren, 2015.
*/
-#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <ogg/ogg.h>
@@ -17,70 +16,35 @@
#define CHUNKSIZE 4096
-vcedit_state *
-vcedit_new_state()
-{
- return g_new0(vcedit_state, 1);
-}
-
-const char *
-vcedit_error(vcedit_state * state)
-{
- return state->lasterror;
-}
-
-vorbis_comment *
-vcedit_comments(vcedit_state * state)
-{
- return state->vc;
-}
-
-static void
-vcedit_clear_internals(vcedit_state * state)
+VCEdit::VCEdit()
{
- if (state->vc) {
- vorbis_comment_clear(state->vc);
- g_free(state->vc);
- state->vc = nullptr;
- }
- if (state->os) {
- ogg_stream_clear(state->os);
- g_free(state->os);
- state->os = nullptr;
- }
- if (state->oy) {
- ogg_sync_clear(state->oy);
- g_free(state->oy);
- state->oy = nullptr;
- }
- if (state->vendor) {
- g_free(state->vendor);
- state->vendor = nullptr;
- }
+ ogg_sync_init(&oy);
+ ogg_stream_init(&os, 0);
+ vorbis_comment_init(&vc);
+ vorbis_info_init(&vi);
}
-void
-vcedit_clear(vcedit_state * state)
+VCEdit::~VCEdit()
{
- if (state) {
- vcedit_clear_internals(state);
- g_free(state);
- }
+ ogg_sync_clear(&oy);
+ ogg_stream_clear(&os);
+ vorbis_comment_clear(&vc);
+ vorbis_info_clear(&vi);
}
/* Next two functions pulled straight from libvorbis, apart from one change
* - we don't want to overwrite the vendor string.
*/
static void
-_v_writestring(oggpack_buffer * o, const char *s, int len)
+_v_writestring(oggpack_buffer *o, const char *s, int len)
{
while (len--) {
oggpack_write(o, *s++, 8);
}
}
-static int
-_commentheader_out(vorbis_comment * vc, char *vendor, ogg_packet * op)
+static void
+_commentheader_out(vorbis_comment *vc, const char *vendor, ogg_packet *op)
{
oggpack_buffer opb;
@@ -118,141 +82,113 @@ _commentheader_out(vorbis_comment * vc, char *vendor, ogg_packet * op)
op->b_o_s = 0;
op->e_o_s = 0;
op->granulepos = 0;
-
- return 0;
}
-static int
-_blocksize(vcedit_state * s, ogg_packet * p)
+int VCEdit::blocksize(ogg_packet *p)
{
- int size = vorbis_packet_blocksize(&s->vi, p);
- int ret = (size + s->prevW) / 4;
+ int size = vorbis_packet_blocksize(&vi, p);
+ int ret = (size + prevW) / 4;
- if (!s->prevW) {
- s->prevW = size;
+ if (!prevW) {
+ prevW = size;
return 0;
}
- s->prevW = size;
+ prevW = size;
return ret;
}
-static int
-_fetch_next_packet(vcedit_state * s, ogg_packet * p, ogg_page * page)
+bool VCEdit::fetch_next_packet(VFSFile &in, ogg_packet *p, ogg_page *page)
{
- int result;
- char *buffer;
- int64_t bytes;
-
- result = ogg_stream_packetout(s->os, p);
-
- if (result > 0)
- return 1;
+ if (ogg_stream_packetout(&os, p) > 0)
+ return true;
else {
- if (s->eosin)
- return 0;
- while (ogg_sync_pageout(s->oy, page) <= 0) {
- buffer = ogg_sync_buffer(s->oy, CHUNKSIZE);
- bytes = s->in->fread(buffer, 1, CHUNKSIZE);
- ogg_sync_wrote(s->oy, bytes);
+ if (eosin)
+ return false;
+ while (ogg_sync_pageout(&oy, page) <= 0) {
+ char *buffer = ogg_sync_buffer(&oy, CHUNKSIZE);
+ int64_t bytes = in.fread(buffer, 1, CHUNKSIZE);
+ ogg_sync_wrote(&oy, bytes);
if (bytes == 0)
- return 0;
+ return false;
}
if (ogg_page_eos(page))
- s->eosin = 1;
- else if (ogg_page_serialno(page) != s->serial) {
- s->eosin = 1;
- s->extrapage = 1;
- return 0;
+ eosin = true;
+ else if (ogg_page_serialno(page) != serial) {
+ eosin = true;
+ extrapage = true;
+ return false;
}
- ogg_stream_pagein(s->os, page);
- return _fetch_next_packet(s, p, page);
+ ogg_stream_pagein(&os, page);
+ return fetch_next_packet(in, p, page);
}
}
-
-int
-vcedit_open(vcedit_state * state, VFSFile & in)
+bool VCEdit::open(VFSFile &in)
{
- char *buffer;
- int64_t bytes, i;
- ogg_packet *header;
ogg_packet header_main;
ogg_packet header_comments;
ogg_packet header_codebooks;
ogg_page og;
- state->in = & in;
-
- state->oy = g_new(ogg_sync_state, 1);
- ogg_sync_init(state->oy);
-
- buffer = ogg_sync_buffer(state->oy, CHUNKSIZE);
+ char *buffer = ogg_sync_buffer(&oy, CHUNKSIZE);
- bytes = state->in->fread(buffer, 1, CHUNKSIZE);
+ int64_t bytes = in.fread(buffer, 1, CHUNKSIZE);
- ogg_sync_wrote(state->oy, bytes);
+ ogg_sync_wrote(&oy, bytes);
- if (ogg_sync_pageout(state->oy, &og) != 1) {
+ if (ogg_sync_pageout(&oy, &og) != 1) {
if (bytes < CHUNKSIZE)
- state->lasterror = "Input truncated or empty.";
+ lasterror = "Input truncated or empty.";
else
- state->lasterror = "Input is not an Ogg bitstream.";
- goto err;
+ lasterror = "Input is not an Ogg bitstream.";
+ return false;
}
- state->serial = ogg_page_serialno(&og);
+ serial = ogg_page_serialno(&og);
- state->os = g_new(ogg_stream_state, 1);
- ogg_stream_init(state->os, state->serial);
+ ogg_stream_reset_serialno(&os, serial);
- vorbis_info_init(&state->vi);
-
- state->vc = g_new(vorbis_comment, 1);
- vorbis_comment_init(state->vc);
-
- if (ogg_stream_pagein(state->os, &og) < 0) {
- state->lasterror = "Error reading first page of Ogg bitstream.";
- goto err;
+ if (ogg_stream_pagein(&os, &og) < 0) {
+ lasterror = "Error reading first page of Ogg bitstream.";
+ return false;
}
- if (ogg_stream_packetout(state->os, &header_main) != 1) {
- state->lasterror = "Error reading initial header packet.";
- goto err;
+ if (ogg_stream_packetout(&os, &header_main) != 1) {
+ lasterror = "Error reading initial header packet.";
+ return false;
}
- if (vorbis_synthesis_headerin(&state->vi, state->vc, &header_main) < 0) {
- state->lasterror = "Ogg bitstream does not contain vorbis data.";
- goto err;
+ if (vorbis_synthesis_headerin(&vi, &vc, &header_main) < 0) {
+ lasterror = "Ogg bitstream does not contain vorbis data.";
+ return false;
}
- state->mainlen = header_main.bytes;
- state->mainbuf = g_new (unsigned char, state->mainlen);
- memcpy(state->mainbuf, header_main.packet, header_main.bytes);
+ mainbuf.clear();
+ mainbuf.insert(header_main.packet, 0, header_main.bytes);
- i = 0;
- header = &header_comments;
+ int i = 0;
+ ogg_packet *header = &header_comments;
while (i < 2) {
while (i < 2) {
- int result = ogg_sync_pageout(state->oy, &og);
+ int result = ogg_sync_pageout(&oy, &og);
if (result == 0)
break; /* Too little data so far */
else if (result == 1) {
- ogg_stream_pagein(state->os, &og);
+ ogg_stream_pagein(&os, &og);
while (i < 2) {
- result = ogg_stream_packetout(state->os, header);
+ result = ogg_stream_packetout(&os, header);
if (result == 0)
break;
if (result == -1) {
- state->lasterror = "Corrupt secondary header.";
- goto err;
+ lasterror = "Corrupt secondary header.";
+ return false;
}
- vorbis_synthesis_headerin(&state->vi, state->vc, header);
+ vorbis_synthesis_headerin(&vi, &vc, header);
if (i == 1) {
- state->booklen = header->bytes;
- state->bookbuf = g_new (unsigned char, state->booklen);
- memcpy(state->bookbuf, header->packet, header->bytes);
+ bookbuf.clear();
+ bookbuf.insert(header->packet, 0, header->bytes);
}
i++;
header = &header_codebooks;
@@ -260,37 +196,24 @@ vcedit_open(vcedit_state * state, VFSFile & in)
}
}
- buffer = ogg_sync_buffer(state->oy, CHUNKSIZE);
- bytes = state->in->fread(buffer, 1, CHUNKSIZE);
+ buffer = ogg_sync_buffer(&oy, CHUNKSIZE);
+ bytes = in.fread(buffer, 1, CHUNKSIZE);
if (bytes == 0 && i < 2) {
- state->lasterror = "EOF before end of vorbis headers.";
- goto err;
+ lasterror = "EOF before end of vorbis headers.";
+ return false;
}
- ogg_sync_wrote(state->oy, bytes);
+ ogg_sync_wrote(&oy, bytes);
}
/* Copy the vendor tag */
- state->vendor = g_strdup (state->vc->vendor);
+ vendor = String(vc.vendor);
/* Headers are done! */
- return 0;
-
- err:
- vcedit_clear_internals(state);
- return -1;
+ return true;
}
-#if 0
-static void
-dump_state(vcedit_state * state)
+bool VCEdit::write(VFSFile &in, VFSFile &out)
{
-}
-#endif
-
-int
-vcedit_write(vcedit_state * state, VFSFile & out)
-{
-
ogg_stream_state streamout;
ogg_packet header_main;
ogg_packet header_comments;
@@ -299,45 +222,41 @@ vcedit_write(vcedit_state * state, VFSFile & out)
ogg_page ogout, ogin;
ogg_packet op;
ogg_int64_t granpos = 0;
- int result;
- char *buffer;
- int64_t bytes;
- int needflush = 0, needout = 0;
+ bool needflush = false;
+ bool needout = false;
- state->eosin = 0;
- state->extrapage = 0;
+ eosin = false;
+ extrapage = false;
- header_main.bytes = state->mainlen;
- header_main.packet = state->mainbuf;
+ header_main.bytes = mainbuf.len();
+ header_main.packet = mainbuf.begin();
header_main.b_o_s = 1;
header_main.e_o_s = 0;
header_main.granulepos = 0;
- header_codebooks.bytes = state->booklen;
- header_codebooks.packet = state->bookbuf;
+ header_codebooks.bytes = bookbuf.len();
+ header_codebooks.packet = bookbuf.begin();
header_codebooks.b_o_s = 0;
header_codebooks.e_o_s = 0;
header_codebooks.granulepos = 0;
- ogg_stream_init(&streamout, state->serial);
+ ogg_stream_init(&streamout, serial);
- _commentheader_out(state->vc, state->vendor, &header_comments);
+ _commentheader_out(&vc, vendor, &header_comments);
ogg_stream_packetin(&streamout, &header_main);
ogg_stream_packetin(&streamout, &header_comments);
ogg_stream_packetin(&streamout, &header_codebooks);
- while ((result = ogg_stream_flush(&streamout, &ogout))) {
+ while (ogg_stream_flush(&streamout, &ogout)) {
if (out.fwrite(ogout.header, 1, ogout.header_len) != ogout.header_len)
goto cleanup;
if (out.fwrite(ogout.body, 1, ogout.body_len) != ogout.body_len)
goto cleanup;
}
- while (_fetch_next_packet(state, &op, &ogin)) {
- int size;
- size = _blocksize(state, &op);
- granpos += size;
+ while (fetch_next_packet(in, &op, &ogin)) {
+ granpos += blocksize(&op);
if (needflush) {
if (ogg_stream_flush(&streamout, &ogout)) {
@@ -356,7 +275,8 @@ vcedit_write(vcedit_state * state, VFSFile & out)
}
}
- needflush = needout = 0;
+ needflush = false;
+ needout = false;
if (op.granulepos == -1) {
op.granulepos = granpos;
@@ -367,11 +287,11 @@ vcedit_write(vcedit_state * state, VFSFile & out)
if (granpos > op.granulepos) {
granpos = op.granulepos;
ogg_stream_packetin(&streamout, &op);
- needflush = 1;
+ needflush = true;
}
else {
ogg_stream_packetin(&streamout, &op);
- needout = 1;
+ needout = true;
}
}
}
@@ -384,27 +304,23 @@ vcedit_write(vcedit_state * state, VFSFile & out)
goto cleanup;
}
- /* FIXME: freeing this here probably leaks memory */
- /* Done with this, now */
- vorbis_info_clear(&state->vi);
-
- if (state->extrapage) {
+ if (extrapage) {
if (out.fwrite(ogin.header, 1, ogin.header_len) != ogin.header_len)
goto cleanup;
if (out.fwrite(ogin.body, 1, ogin.body_len) != ogin.body_len)
goto cleanup;
}
- state->eosin = 0; /* clear it, because not all paths to here do */
- while (!state->eosin) { /* We reached eos, not eof */
+ eosin = false; /* clear it, because not all paths to here do */
+ while (!eosin) { /* We reached eos, not eof */
/* We copy the rest of the stream (other logical streams)
* through, a page at a time. */
while (1) {
- result = ogg_sync_pageout(state->oy, &ogout);
+ int result = ogg_sync_pageout(&oy, &ogout);
if (result == 0)
break;
if (result < 0)
- state->lasterror = "Corrupt or missing data, continuing...";
+ lasterror = "Corrupt or missing data, continuing...";
else {
/* Don't bother going through the rest, we can just
* write the page out now */
@@ -414,30 +330,25 @@ vcedit_write(vcedit_state * state, VFSFile & out)
goto cleanup;
}
}
- buffer = ogg_sync_buffer(state->oy, CHUNKSIZE);
- bytes = state->in->fread(buffer, 1, CHUNKSIZE);
- ogg_sync_wrote(state->oy, bytes);
+ char *buffer = ogg_sync_buffer(&oy, CHUNKSIZE);
+ int64_t bytes = in.fread(buffer, 1, CHUNKSIZE);
+ ogg_sync_wrote(&oy, bytes);
if (bytes == 0) {
- state->eosin = 1;
+ eosin = true;
break;
}
}
-
cleanup:
ogg_stream_clear(&streamout);
ogg_packet_clear(&header_comments);
- g_free(state->mainbuf);
- g_free(state->bookbuf);
-
- vcedit_clear_internals(state);
- if (!state->eosin) {
- state->lasterror =
+ if (!eosin) {
+ lasterror =
"Error writing stream to output. "
"Output stream may be corrupted or truncated.";
- return -1;
+ return false;
}
- return 0;
+ return true;
}
diff --git a/src/vorbis/vcedit.h b/src/vorbis/vcedit.h
index 5473b84..ee3d37f 100644
--- a/src/vorbis/vcedit.h
+++ b/src/vorbis/vcedit.h
@@ -14,32 +14,39 @@
#include <vorbis/codec.h>
#include <libaudcore/vfs.h>
-typedef struct {
- ogg_sync_state *oy;
- ogg_stream_state *os;
-
- vorbis_comment *vc;
- vorbis_info vi;
-
- VFSFile *in;
- long serial;
- unsigned char *mainbuf;
- unsigned char *bookbuf;
- int mainlen;
- int booklen;
- const char *lasterror;
- char *vendor;
- int prevW;
- int extrapage;
- int eosin;
-} vcedit_state;
-
-extern vcedit_state *vcedit_new_state();
-extern void vcedit_clear(vcedit_state *state);
-extern vorbis_comment *vcedit_comments(vcedit_state *state);
-extern int vcedit_open(vcedit_state *state, VFSFile &in);
-extern int vcedit_write(vcedit_state *state, VFSFile &out);
-extern const char *vcedit_error(vcedit_state *state);
+class VCEdit
+{
+public:
+ vorbis_comment vc;
+ const char *lasterror = nullptr;
+
+ VCEdit();
+ ~VCEdit();
+
+ VCEdit(const VCEdit&) = delete;
+ VCEdit& operator=(const VCEdit&) = delete;
+
+ bool open(VFSFile &in);
+ bool write(VFSFile &in, VFSFile &out);
+
+private:
+ ogg_sync_state oy;
+ ogg_stream_state os;
+ vorbis_info vi;
+
+ long serial = 0;
+ int prevW = 0;
+ bool extrapage = false;
+ bool eosin = false;
+
+ String vendor;
+
+ Index<unsigned char> mainbuf;
+ Index<unsigned char> bookbuf;
+
+ int blocksize(ogg_packet *p);
+ bool fetch_next_packet(VFSFile &in, ogg_packet *p, ogg_page *page);
+};
#endif /* __VCEDIT_H */
diff --git a/src/vorbis/vcupdate.cc b/src/vorbis/vcupdate.cc
index bb4d62e..2be5b7e 100644
--- a/src/vorbis/vcupdate.cc
+++ b/src/vorbis/vcupdate.cc
@@ -27,9 +27,6 @@
#include <string.h>
#include <unistd.h>
-#include <glib.h>
-#include <glib/gstdio.h>
-
#include <libaudcore/audstrings.h>
#include <libaudcore/i18n.h>
#include <libaudcore/multihash.h>
@@ -38,8 +35,6 @@
#include "vorbis.h"
#include "vcedit.h"
-static bool write_and_pivot_files(vcedit_state * state);
-
typedef SimpleHash<String, String> Dictionary;
static Dictionary dictionary_from_vorbis_comment (vorbis_comment * vc)
@@ -48,19 +43,12 @@ static Dictionary dictionary_from_vorbis_comment (vorbis_comment * vc)
for (int i = 0; i < vc->comments; i ++)
{
- char **frags;
-
- AUDDBG("%s\n", vc->user_comments[i]);
- frags = g_strsplit(vc->user_comments[i], "=", 2);
+ const char * s = vc->user_comments[i];
+ AUDDBG("%s\n", s);
- if (frags[0] && frags[1])
- {
- char * key = g_ascii_strdown (frags[0], -1);
- dict.add (String (key), String (frags[1]));
- g_free (key);
- }
-
- g_strfreev(frags); /* Don't use g_free() for string lists! --eugene */
+ const char * eq = strchr (s, '=');
+ if (eq && eq > s && eq[1])
+ dict.add (String (str_tolower (str_copy (s, eq - s))), String (eq + 1));
}
return dict;
@@ -73,7 +61,7 @@ static void add_tag_cb (const String & key, String & field, void * vc)
static void dictionary_to_vorbis_comment (vorbis_comment * vc, Dictionary & dict)
{
- vorbis_comment_clear(vc);
+ vorbis_comment_clear (vc);
dict.iterate (add_tag_cb, vc);
}
@@ -101,109 +89,33 @@ static void insert_int_tuple_field_to_dictionary (const Tuple & tuple,
bool VorbisPlugin::write_tuple (const char * filename, VFSFile & file, const Tuple & tuple)
{
- vcedit_state *state;
- vorbis_comment *comment;
- bool ret;
-
- state = vcedit_new_state();
-
- if(vcedit_open(state, file) < 0) {
- vcedit_clear(state);
+ VCEdit edit;
+ if (! edit.open (file))
return false;
- }
-
- comment = vcedit_comments(state);
- Dictionary dict = dictionary_from_vorbis_comment (comment);
- insert_str_tuple_field_to_dictionary(tuple, Tuple::Title, dict, "title");
- insert_str_tuple_field_to_dictionary(tuple, Tuple::Artist, dict, "artist");
- insert_str_tuple_field_to_dictionary(tuple, Tuple::Album, dict, "album");
- insert_str_tuple_field_to_dictionary(tuple, Tuple::Comment, dict, "comment");
- insert_str_tuple_field_to_dictionary(tuple, Tuple::Genre, dict, "genre");
+ Dictionary dict = dictionary_from_vorbis_comment (& edit.vc);
- insert_int_tuple_field_to_dictionary(tuple, Tuple::Year, dict, "date");
- insert_int_tuple_field_to_dictionary(tuple, Tuple::Track, dict, "tracknumber");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::Title, dict, "title");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::Artist, dict, "artist");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::Album, dict, "album");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::AlbumArtist, dict, "albumartist");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::Comment, dict, "comment");
+ insert_str_tuple_field_to_dictionary (tuple, Tuple::Genre, dict, "genre");
- dictionary_to_vorbis_comment(comment, dict);
+ insert_int_tuple_field_to_dictionary (tuple, Tuple::Year, dict, "date");
+ insert_int_tuple_field_to_dictionary (tuple, Tuple::Track, dict, "tracknumber");
- ret = write_and_pivot_files(state);
+ dictionary_to_vorbis_comment (& edit.vc, dict);
- vcedit_clear(state);
-
- return ret;
-}
-
-#define COPY_BUF 65536
-
-bool copy_vfs (VFSFile & in, VFSFile & out)
-{
- if (in.fseek (0, VFS_SEEK_SET) < 0 || out.fseek (0, VFS_SEEK_SET) < 0)
+ auto temp_vfs = VFSFile::tmpfile ();
+ if (! temp_vfs)
return false;
- char * buffer = g_new (char, COPY_BUF);
- int64_t size = 0, readed;
-
- while ((readed = in.fread (buffer, 1, COPY_BUF)) > 0)
+ if (! edit.write (file, temp_vfs))
{
- if (out.fwrite (buffer, 1, readed) != readed)
- goto FAILED;
-
- size += readed;
- }
-
- if (out.ftruncate (size) < 0)
- goto FAILED;
-
- g_free (buffer);
- return true;
-
-FAILED:
- g_free (buffer);
- return false;
-}
-
-#undef COPY_BUF
-
-bool write_and_pivot_files (vcedit_state * state)
-{
- char * temp;
- GError * error = nullptr;
- int handle = g_file_open_tmp (nullptr, & temp, & error);
-
- if (handle < 0)
- {
- AUDERR ("Failed to create temp file: %s.\n", error->message);
- g_error_free (error);
- return false;
- }
-
- close (handle);
-
- StringBuf temp_uri = filename_to_uri (temp);
- g_return_val_if_fail (temp_uri, false);
- VFSFile temp_vfs (temp_uri, "r+");
- g_return_val_if_fail (temp_vfs, false);
-
- if (vcedit_write (state, temp_vfs) < 0)
- {
- AUDERR ("Tag update failed: %s.\n", state->lasterror);
- g_free (temp);
+ AUDERR ("Tag update failed: %s.\n", edit.lasterror);
return false;
}
- if (! copy_vfs (temp_vfs, * state->in))
- {
- AUDERR ("Failed to copy temp file. The temp file has not "
- "been deleted: %s.\n", temp);
- g_free (temp);
- return false;
- }
-
- temp_vfs = VFSFile ();
-
- if (g_unlink (temp) < 0)
- AUDERR ("Failed to delete temp file: %s.\n", temp);
-
- g_free (temp);
- return true;
+ return file.replace_with (temp_vfs);
}
diff --git a/src/vorbis/vorbis.cc b/src/vorbis/vorbis.cc
index 71c86bb..a03b303 100644
--- a/src/vorbis/vorbis.cc
+++ b/src/vorbis/vorbis.cc
@@ -138,6 +138,7 @@ static void read_comment (vorbis_comment * comment, Tuple & tuple)
set_tuple_str (tuple, Tuple::Title, comment, "title");
set_tuple_str (tuple, Tuple::Artist, comment, "artist");
set_tuple_str (tuple, Tuple::Album, comment, "album");
+ set_tuple_str (tuple, Tuple::AlbumArtist, comment, "albumartist");
set_tuple_str (tuple, Tuple::Genre, comment, "genre");
set_tuple_str (tuple, Tuple::Comment, comment, "comment");
@@ -314,7 +315,8 @@ play_cleanup:
return ! error;
}
-bool VorbisPlugin::read_tag (const char * filename, VFSFile & file, Tuple * tuple, Index<char> * image)
+bool VorbisPlugin::read_tag (const char * filename, VFSFile & file,
+ Tuple & tuple, Index<char> * image)
{
OggVorbis_File vfile;
@@ -329,20 +331,16 @@ bool VorbisPlugin::read_tag (const char * filename, VFSFile & file, Tuple * tupl
vorbis_callbacks_stream : vorbis_callbacks) < 0)
return false;
+ vorbis_info * info = ov_info (& vfile, -1);
vorbis_comment * comment = ov_comment (& vfile, -1);
- if (tuple)
- {
- vorbis_info * info = ov_info (& vfile, -1);
- tuple->set_format ("Ogg Vorbis", info->channels, info->rate, info->bitrate_nominal / 1000);
- tuple->set_str (Tuple::MIMEType, "application/ogg");
+ tuple.set_format ("Ogg Vorbis", info->channels, info->rate, info->bitrate_nominal / 1000);
- if (! stream)
- tuple->set_int (Tuple::Length, ov_time_total (& vfile, -1) * 1000);
+ if (! stream)
+ tuple.set_int (Tuple::Length, ov_time_total (& vfile, -1) * 1000);
- if (comment)
- read_comment (comment, * tuple);
- }
+ if (comment)
+ read_comment (comment, tuple);
if (image && comment)
* image = read_image_from_comment (filename, comment);
diff --git a/src/vorbis/vorbis.h b/src/vorbis/vorbis.h
index e5684f0..4a1dbb7 100644
--- a/src/vorbis/vorbis.h
+++ b/src/vorbis/vorbis.h
@@ -20,15 +20,13 @@ public:
about
};
- static constexpr auto iinfo = InputInfo (FlagWritesTag)
+ constexpr VorbisPlugin () : InputPlugin (info, InputInfo (FlagWritesTag)
.with_priority (2) /* medium-high priority (a little slow) */
.with_exts (exts)
- .with_mimes (mimes);
-
- constexpr VorbisPlugin () : InputPlugin (info, iinfo) {}
+ .with_mimes (mimes)) {}
bool is_our_file (const char * filename, VFSFile & file);
- bool read_tag (const char * filename, VFSFile & file, Tuple * tuple, Index<char> * image);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
bool play (const char * filename, VFSFile & file);
};
diff --git a/src/vtx/vtx.cc b/src/vtx/vtx.cc
index 038521b..9078b33 100644
--- a/src/vtx/vtx.cc
+++ b/src/vtx/vtx.cc
@@ -40,13 +40,11 @@ public:
about
};
- static constexpr auto iinfo = InputInfo()
- .with_exts(exts);
-
- constexpr VTXPlugin() : InputPlugin(info, iinfo) {}
+ constexpr VTXPlugin() : InputPlugin(info, InputInfo()
+ .with_exts(exts)) {}
bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool play(const char *filename, VFSFile &file);
#ifdef USE_GTK
@@ -73,35 +71,27 @@ bool VTXPlugin::is_our_file(const char *filename, VFSFile &file)
return (!strcmp_nocase(buf, "ay", 2) || !strcmp_nocase(buf, "ym", 2));
}
-Tuple vtx_get_song_tuple_from_vtx(const char * filename, ayemu_vtx_t * in)
+bool VTXPlugin::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple tuple;
- tuple.set_filename (filename);
+ ayemu_vtx_t tmp;
- tuple.set_str (Tuple::Artist, in->hdr.author);
- tuple.set_str (Tuple::Title, in->hdr.title);
+ if (!tmp.read_header(file))
+ return false;
- tuple.set_int (Tuple::Length, in->hdr.regdata_size / 14 * 1000 / 50);
+ tuple.set_str(Tuple::Artist, tmp.hdr.author);
+ tuple.set_str(Tuple::Title, tmp.hdr.title);
- tuple.set_str (Tuple::Genre, (in->hdr.chiptype == AYEMU_AY) ? "AY chiptunes" : "YM chiptunes");
- tuple.set_str (Tuple::Album, in->hdr.from);
+ tuple.set_int(Tuple::Length, tmp.hdr.regdata_size / 14 * 1000 / 50);
- tuple.set_str (Tuple::Quality, _("sequenced"));
- tuple.set_str (Tuple::Codec, in->hdr.tracker);
+ tuple.set_str(Tuple::Genre, (tmp.hdr.chiptype == AYEMU_AY) ? "AY chiptunes" : "YM chiptunes");
+ tuple.set_str(Tuple::Album, tmp.hdr.from);
- tuple.set_int (Tuple::Year, in->hdr.year);
+ tuple.set_str(Tuple::Quality, _("sequenced"));
+ tuple.set_str(Tuple::Codec, tmp.hdr.tracker);
- return tuple;
-}
+ tuple.set_int(Tuple::Year, tmp.hdr.year);
-Tuple VTXPlugin::read_tuple(const char *filename, VFSFile &file)
-{
- ayemu_vtx_t tmp;
-
- if (tmp.read_header(file))
- return vtx_get_song_tuple_from_vtx(filename, &tmp);
-
- return Tuple ();
+ return true;
}
bool VTXPlugin::play(const char *filename, VFSFile &file)
diff --git a/src/waveout/Makefile b/src/waveout/Makefile
new file mode 100644
index 0000000..ba15a74
--- /dev/null
+++ b/src/waveout/Makefile
@@ -0,0 +1,13 @@
+PLUGIN = waveout${PLUGIN_SUFFIX}
+
+SRCS = waveout.cc
+
+include ../../buildsys.mk
+include ../../extra.mk
+
+plugindir := ${plugindir}/${OUTPUT_PLUGIN_DIR}
+
+LD = ${CXX}
+CPPFLAGS += -I../..
+CXXFLAGS += ${PLUGIN_CFLAGS}
+LIBS += -lwinmm
diff --git a/src/waveout/waveout.cc b/src/waveout/waveout.cc
new file mode 100644
index 0000000..17c91be
--- /dev/null
+++ b/src/waveout/waveout.cc
@@ -0,0 +1,339 @@
+/*
+ * Win32 waveOut Plugin for Audacious
+ * Copyright 2016 John Lindgren
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions, and the following disclaimer in the documentation
+ * provided with the distribution.
+ *
+ * This software is provided "as is" and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising from
+ * the use of this software.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+
+#include <windows.h>
+
+// missing from MinGW header
+#ifndef WAVE_FORMAT_IEEE_FLOAT
+#define WAVE_FORMAT_IEEE_FLOAT 3
+#endif
+
+#include <libaudcore/audstrings.h>
+#include <libaudcore/i18n.h>
+#include <libaudcore/plugin.h>
+#include <libaudcore/runtime.h>
+
+#define NUM_BLOCKS 4
+
+class WaveOut : public OutputPlugin
+{
+public:
+ static const char about[];
+
+ static constexpr PluginInfo info = {
+ N_("Win32 waveOut"),
+ PACKAGE,
+ about
+ };
+
+ constexpr WaveOut () : OutputPlugin (info, 5) {}
+
+ StereoVolume get_volume ();
+ void set_volume (StereoVolume v);
+
+ bool open_audio (int aud_format, int rate, int chans, String & error);
+ void close_audio ();
+
+ void period_wait ();
+ int write_audio (const void * data, int size);
+ void drain ();
+
+ int get_delay ();
+
+ void pause (bool pause);
+ void flush ();
+};
+
+EXPORT WaveOut aud_plugin_instance;
+
+const char WaveOut::about[] =
+ N_("Win32 waveOut Plugin for Audacious\n"
+ "Copyright 2016 John Lindgren");
+
+// lock order is state, then buffer
+static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t buffer_cond = PTHREAD_COND_INITIALIZER;
+
+static int waveout_format;
+static int waveout_chan, waveout_rate;
+static int block_size;
+
+// guarded by state_mutex
+static HWAVEOUT device;
+static bool prebuffer_flag, paused_flag;
+static int64_t total_frames;
+
+// guarded by buffer_mutex
+static Index<WAVEHDR> headers;
+static Index<Index<char>> blocks;
+static int next_block, blocks_free;
+
+StereoVolume WaveOut::get_volume ()
+{
+ DWORD vol = 0;
+ waveOutGetVolume ((HWAVEOUT) WAVE_MAPPER, & vol);
+ return {aud::rescale (int (vol & 0xffff), 0xffff, 100),
+ aud::rescale (int (vol >> 16), 0xffff, 100)};
+}
+
+void WaveOut::set_volume (StereoVolume v)
+{
+ int left = aud::rescale (v.left, 100, 0xffff);
+ int right = aud::rescale (v.right, 100, 0xffff);
+ waveOutSetVolume ((HWAVEOUT) WAVE_MAPPER, left | (right << 16));
+}
+
+static void CALLBACK callback (HWAVEOUT, UINT uMsg, DWORD_PTR, DWORD_PTR, DWORD_PTR)
+{
+ if (uMsg != WOM_DONE)
+ return;
+
+ pthread_mutex_lock (& buffer_mutex);
+
+ assert (blocks_free < NUM_BLOCKS);
+ int old_block = (next_block + blocks_free) % NUM_BLOCKS;
+ blocks[old_block].resize (0);
+ blocks_free ++;
+
+ pthread_cond_broadcast (& buffer_cond);
+ pthread_mutex_unlock (& buffer_mutex);
+}
+
+bool WaveOut::open_audio (int format, int rate, int chan, String & error)
+{
+ if (format != FMT_S16_NE && format != FMT_S32_NE && format != FMT_FLOAT)
+ {
+ error = String ("waveOut error: Unsupported audio format. Supported "
+ "bit depths are 16, 32, and floating point.");
+ return false;
+ }
+
+ AUDDBG ("Opening audio for format %d, %d channels, %d Hz.\n", format, chan, rate);
+
+ waveout_format = format;
+ waveout_chan = chan;
+ waveout_rate = rate;
+
+ WAVEFORMATEX desc;
+ desc.wFormatTag = (format == FMT_FLOAT) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
+ desc.nChannels = chan;
+ desc.nSamplesPerSec = rate;
+ desc.nAvgBytesPerSec = FMT_SIZEOF (format) * chan * rate;
+ desc.nBlockAlign = FMT_SIZEOF (format) * chan;
+ desc.wBitsPerSample = 8 * FMT_SIZEOF (format);
+ desc.cbSize = 0;
+
+ MMRESULT res = waveOutOpen (& device, WAVE_MAPPER, & desc,
+ (DWORD_PTR) callback, 0, CALLBACK_FUNCTION);
+
+ if (res != MMSYSERR_NOERROR)
+ {
+ error = String (str_printf ("Error opening device (%d)!", (int) res));
+ return false;
+ }
+
+ int block_ms = aud_get_int (nullptr, "output_buffer_size") / NUM_BLOCKS;
+ block_size = FMT_SIZEOF (format) * chan * aud::rescale (block_ms, 1000, rate);
+
+ headers.insert (0, NUM_BLOCKS);
+ blocks.insert (0, NUM_BLOCKS);
+
+ next_block = 0;
+ blocks_free = NUM_BLOCKS;
+
+ waveOutPause (device);
+ prebuffer_flag = true;
+ paused_flag = false;
+ total_frames = 0;
+
+ return true;
+}
+
+void WaveOut::close_audio ()
+{
+ AUDDBG ("Closing audio.\n");
+ flush ();
+ waveOutClose (device);
+
+ headers.clear ();
+ blocks.clear ();
+}
+
+void WaveOut::period_wait ()
+{
+ pthread_mutex_lock (& buffer_mutex);
+
+ while (! blocks_free)
+ pthread_cond_wait (& buffer_cond, & buffer_mutex);
+
+ pthread_mutex_unlock (& buffer_mutex);
+}
+
+// assumes state_mutex + buffer_mutex locked
+static void write_next_block ()
+{
+ WAVEHDR & header = headers[next_block];
+ Index<char> & block = blocks[next_block];
+
+ header.lpData = block.begin ();
+ header.dwBufferLength = block.len ();
+
+ waveOutPrepareHeader (device, & header, sizeof header);
+ waveOutWrite (device, & header, sizeof header);
+
+ next_block = (next_block + 1) % NUM_BLOCKS;
+ blocks_free --;
+}
+
+// assumes state_mutex locked
+static void check_started ()
+{
+ if (prebuffer_flag)
+ {
+ AUDDBG ("Prebuffering complete.\n");
+ if (! paused_flag)
+ waveOutRestart (device);
+
+ prebuffer_flag = false;
+ }
+}
+
+int WaveOut::write_audio (const void * data, int len)
+{
+ int written = 0;
+ pthread_mutex_lock (& state_mutex);
+ pthread_mutex_lock (& buffer_mutex);
+
+ while (len > 0 && blocks_free > 0)
+ {
+ Index<char> & block = blocks[next_block];
+ int copy = aud::min (len, block_size - block.len ());
+ block.insert ((const char *) data, -1, copy);
+
+ if (block.len () == block_size)
+ write_next_block ();
+
+ written += copy;
+ data = (const char *) data + copy;
+ len -= copy;
+ }
+
+ bool filled = ! blocks_free;
+ pthread_mutex_unlock (& buffer_mutex);
+
+ if (filled)
+ check_started ();
+
+ total_frames += written / (FMT_SIZEOF (waveout_format) * waveout_chan);
+
+ pthread_mutex_unlock (& state_mutex);
+ return written;
+}
+
+void WaveOut::drain ()
+{
+ AUDDBG ("Draining.\n");
+ pthread_mutex_lock (& state_mutex);
+ pthread_mutex_lock (& buffer_mutex);
+
+ // write last partial block, if any
+ if (blocks_free > 0 && blocks[next_block].len () > 0)
+ write_next_block ();
+
+ pthread_mutex_unlock (& buffer_mutex);
+
+ check_started ();
+
+ pthread_mutex_unlock (& state_mutex);
+ pthread_mutex_lock (& buffer_mutex);
+
+ while (blocks_free < NUM_BLOCKS)
+ pthread_cond_wait (& buffer_cond, & buffer_mutex);
+
+ pthread_mutex_unlock (& buffer_mutex);
+}
+
+int WaveOut::get_delay ()
+{
+ int delay = 0;
+ pthread_mutex_lock (& state_mutex);
+
+ MMTIME t;
+ t.wType = TIME_SAMPLES;
+
+ if (waveOutGetPosition (device, & t, sizeof t) == MMSYSERR_NOERROR && t.wType == TIME_SAMPLES)
+ {
+ // frame_diff is intentionally truncated to a signed 32-bit word to
+ // account for overflow in the DWORD frame counter returned by Windows
+ int32_t frame_diff = total_frames - t.u.sample;
+ delay = aud::rescale ((int) frame_diff, waveout_rate, 1000);
+ }
+
+ pthread_mutex_unlock (& state_mutex);
+ return delay;
+}
+
+void WaveOut::pause (bool pause)
+{
+ AUDDBG (pause ? "Pausing.\n" : "Unpausing.\n");
+ pthread_mutex_lock (& state_mutex);
+
+ if (! prebuffer_flag)
+ {
+ if (pause)
+ waveOutPause (device);
+ else
+ waveOutRestart (device);
+ }
+
+ paused_flag = pause;
+
+ pthread_mutex_unlock (& state_mutex);
+}
+
+void WaveOut::flush ()
+{
+ AUDDBG ("Flushing buffers.\n");
+ pthread_mutex_lock (& state_mutex);
+
+ waveOutReset (device);
+
+ pthread_mutex_lock (& buffer_mutex);
+
+ for (auto & header : headers)
+ waveOutUnprepareHeader (device, & header, sizeof header);
+ for (auto & block : blocks)
+ block.resize (0);
+
+ next_block = 0;
+ blocks_free = NUM_BLOCKS;
+
+ pthread_cond_broadcast (& buffer_cond);
+ pthread_mutex_unlock (& buffer_mutex);
+
+ waveOutPause (device);
+ prebuffer_flag = true;
+ total_frames = 0;
+
+ pthread_mutex_unlock (& state_mutex);
+}
diff --git a/src/wavpack/wavpack.cc b/src/wavpack/wavpack.cc
index 10224a8..05768a2 100644
--- a/src/wavpack/wavpack.cc
+++ b/src/wavpack/wavpack.cc
@@ -26,15 +26,13 @@ public:
about
};
- static constexpr auto iinfo = InputInfo (FlagWritesTag)
- .with_exts (exts);
-
- constexpr WavpackPlugin() : InputPlugin (info, iinfo) {}
+ constexpr WavpackPlugin() : InputPlugin (info, InputInfo (FlagWritesTag)
+ .with_exts (exts)) {}
bool is_our_file (const char * filename, VFSFile & file)
{ return false; }
- Tuple read_tuple (const char * filename, VFSFile & file);
+ bool read_tag (const char * filename, VFSFile & file, Tuple & tuple, Index<char> * image);
bool write_tuple (const char * filename, VFSFile & file, const Tuple & tuple);
bool play (const char * filename, VFSFile & file);
};
@@ -218,21 +216,17 @@ wv_get_quality(WavpackContext *ctx)
(mode & MODE_DNS) ? " (dynamic noise shaped)" : ""});
}
-Tuple WavpackPlugin::read_tuple (const char * filename, VFSFile & file)
+bool WavpackPlugin::read_tag (const char * filename, VFSFile & file, Tuple & tuple,
+ Index<char> * image)
{
- WavpackContext *ctx;
- Tuple tuple;
char error[1024];
- ctx = WavpackOpenFileInputEx(&wv_readers, &file, nullptr, error, OPEN_TAGS, 0);
-
- if (ctx == nullptr)
- return tuple;
+ auto ctx = WavpackOpenFileInputEx(&wv_readers, &file, nullptr, error, OPEN_TAGS, 0);
+ if (! ctx)
+ return false;
AUDDBG("starting probe of %s\n", file.filename ());
- tuple.set_filename (filename);
-
tuple.set_int (Tuple::Length,
((uint64_t) WavpackGetNumSamples(ctx) * 1000) / (uint64_t) WavpackGetSampleRate(ctx));
tuple.set_str (Tuple::Codec, "WavPack");
@@ -242,15 +236,15 @@ Tuple WavpackPlugin::read_tuple (const char * filename, VFSFile & file)
WavpackCloseFile(ctx);
if (! file.fseek (0, VFS_SEEK_SET))
- audtag::read_tag (file, & tuple, nullptr);
+ audtag::read_tag (file, tuple, nullptr);
AUDDBG("returning tuple for file %s\n", file.filename ());
- return tuple;
+ return true;
}
bool WavpackPlugin::write_tuple (const char * filename, VFSFile & handle, const Tuple & tuple)
{
- return audtag::tuple_write(tuple, handle, audtag::TagType::APE);
+ return audtag::write_tuple (handle, tuple, audtag::TagType::APE);
}
const char WavpackPlugin::about[] =
diff --git a/src/xsf/desmume/NDSSystem.cc b/src/xsf/desmume/NDSSystem.cc
index ee02bc9..e55d14c 100644
--- a/src/xsf/desmume/NDSSystem.cc
+++ b/src/xsf/desmume/NDSSystem.cc
@@ -184,8 +184,8 @@ void NDS_DeInit(void) {
if(MMU.CART_ROM != MMU.UNUSED_RAM)
NDS_FreeROM();
- armcpu_deinit(&NDS_ARM7);
- armcpu_deinit(&NDS_ARM9);
+ armcpu_deinit(&NDS_ARM7);
+ armcpu_deinit(&NDS_ARM9);
nds.nextHBlank = 3168;
SPU_DeInit();
diff --git a/src/xsf/plugin.cc b/src/xsf/plugin.cc
index ae116b8..54b4da7 100644
--- a/src/xsf/plugin.cc
+++ b/src/xsf/plugin.cc
@@ -53,15 +53,13 @@ public:
& prefs
};
- static constexpr auto iinfo = InputInfo()
- .with_exts(exts);
-
- constexpr XSFPlugin() : InputPlugin(info, iinfo) {}
+ constexpr XSFPlugin() : InputPlugin(info, InputInfo()
+ .with_exts(exts)) {}
bool init();
bool is_our_file(const char *filename, VFSFile &file);
- Tuple read_tuple(const char *filename, VFSFile &file);
+ bool read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image);
bool play(const char *filename, VFSFile &file);
};
@@ -90,32 +88,27 @@ Index<char> xsf_get_lib(char *filename)
return file ? file.read_all() : Index<char>();
}
-Tuple XSFPlugin::read_tuple(const char *filename, VFSFile &fd)
+bool XSFPlugin::read_tag(const char *filename, VFSFile &file, Tuple &tuple, Index<char> *image)
{
- Tuple t;
- corlett_t *c;
-
- Index<char> buf = fd.read_all ();
-
+ Index<char> buf = file.read_all ();
if (!buf.len())
- return t;
+ return false;
+ corlett_t *c;
if (corlett_decode((uint8_t *)buf.begin(), buf.len(), nullptr, nullptr, &c) != AO_SUCCESS)
- return t;
-
- t.set_filename (filename);
+ return false;
- t.set_int (Tuple::Length, psfTimeToMS(c->inf_length) + psfTimeToMS(c->inf_fade));
- t.set_str (Tuple::Artist, c->inf_artist);
- t.set_str (Tuple::Album, c->inf_game);
- t.set_str (Tuple::Title, c->inf_title);
- t.set_str (Tuple::Copyright, c->inf_copy);
- t.set_str (Tuple::Quality, _("sequenced"));
- t.set_str (Tuple::Codec, "GBA/Nintendo DS Audio");
+ tuple.set_int(Tuple::Length, psfTimeToMS(c->inf_length) + psfTimeToMS(c->inf_fade));
+ tuple.set_str(Tuple::Artist, c->inf_artist);
+ tuple.set_str(Tuple::Album, c->inf_game);
+ tuple.set_str(Tuple::Title, c->inf_title);
+ tuple.set_str(Tuple::Copyright, c->inf_copy);
+ tuple.set_str(Tuple::Quality, _("sequenced"));
+ tuple.set_str(Tuple::Codec, "GBA/Nintendo DS Audio");
free(c);
- return t;
+ return true;
}
static int xsf_get_length(const Index<char> &buf)
@@ -204,7 +197,7 @@ bool XSFPlugin::play(const char *filename, VFSFile &file)
xsf_gen(samples, seglen);
pos += 16.666;
- write_audio(samples, seglen * 4);
+ write_audio(samples, seglen * 4);
bool ignore_length = aud_get_bool(CFG_ID, "ignore_length");
if (pos >= length && !ignore_length)
diff --git a/src/xspf/xspf.cc b/src/xspf/xspf.cc
index 5072774..dc89c9a 100644
--- a/src/xspf/xspf.cc
+++ b/src/xspf/xspf.cc
@@ -41,44 +41,45 @@
typedef struct {
Tuple::Field tupleField;
const char *xspfName;
- Tuple::ValueType type;
bool isMeta;
} xspf_entry_t;
static const xspf_entry_t xspf_entries[] = {
- {Tuple::Artist, "creator", Tuple::String, false},
- {Tuple::Title, "title", Tuple::String, false},
- {Tuple::Album, "album", Tuple::String, false},
- {Tuple::Comment, "annotation", Tuple::String, false},
- {Tuple::Genre, "genre", Tuple::String, true},
-
- {Tuple::Track, "trackNum", Tuple::Int, false},
- {Tuple::Length, "duration", Tuple::Int, false},
- {Tuple::Year, "year", Tuple::Int, true},
- {Tuple::Quality, "quality", Tuple::String, true},
-
- {Tuple::Codec, "codec", Tuple::String, true},
-
- {Tuple::AlbumArtist, "album-artist", Tuple::String, true},
- {Tuple::Composer, "composer", Tuple::String, true},
- {Tuple::Performer, "performer", Tuple::String, true},
- {Tuple::Copyright, "copyright", Tuple::String, true},
- {Tuple::Date, "date", Tuple::String, true},
-
- {Tuple::Subtune, "subsong-id", Tuple::Int, true},
- {Tuple::NumSubtunes, "subsong-num", Tuple::Int, true},
- {Tuple::MIMEType, "mime-type", Tuple::String, true},
- {Tuple::Bitrate, "bitrate", Tuple::Int, true},
- {Tuple::StartTime, "seg-start", Tuple::Int, true},
- {Tuple::EndTime, "seg-end", Tuple::Int, true},
-
- {Tuple::AlbumGain, "gain-album-gain", Tuple::Int, true},
- {Tuple::AlbumPeak, "gain-album-peak", Tuple::Int, true},
- {Tuple::TrackGain, "gain-track-gain", Tuple::Int, true},
- {Tuple::TrackPeak, "gain-track-peak", Tuple::Int, true},
- {Tuple::GainDivisor, "gain-gain-unit", Tuple::Int, true},
- {Tuple::PeakDivisor, "gain-peak-unit", Tuple::Int, true},
+ {Tuple::Title, "title", false},
+ {Tuple::Artist, "creator", false},
+ {Tuple::Album, "album", false},
+ {Tuple::AlbumArtist, "album-artist", true},
+ {Tuple::Comment, "annotation", false},
+ {Tuple::Genre, "genre", true},
+ {Tuple::Year, "year", true},
+
+ {Tuple::Composer, "composer", true},
+ {Tuple::Performer, "performer", true},
+ {Tuple::Copyright, "copyright", true},
+ {Tuple::Date, "date", true},
+
+ {Tuple::Track, "trackNum", false},
+ {Tuple::Length, "duration", false},
+
+ {Tuple::Bitrate, "bitrate", true},
+ {Tuple::Codec, "codec", true},
+ {Tuple::Quality, "quality", true},
+
+ {Tuple::AudioFile, "audio-file", true},
+
+ {Tuple::Subtune, "subsong-id", true},
+ {Tuple::NumSubtunes, "subsong-num", true},
+
+ {Tuple::StartTime, "seg-start", true},
+ {Tuple::EndTime, "seg-end", true},
+
+ {Tuple::AlbumGain, "gain-album-gain", true},
+ {Tuple::AlbumPeak, "gain-album-peak", true},
+ {Tuple::TrackGain, "gain-track-gain", true},
+ {Tuple::TrackPeak, "gain-track-peak", true},
+ {Tuple::GainDivisor, "gain-gain-unit", true},
+ {Tuple::PeakDivisor, "gain-peak-unit", true},
};
static const char * const xspf_exts[] = {"xspf"};
@@ -148,13 +149,15 @@ static void xspf_add_file (xmlNode * track, const char * filename,
if ((entry.isMeta == isMeta) &&
!xmlStrcmp(findName, (xmlChar *)entry.xspfName)) {
xmlChar *str = xmlNodeGetContent(nptr);
- switch (entry.type) {
+ switch (Tuple::field_get_type (entry.tupleField)) {
case Tuple::String:
tuple.set_str (entry.tupleField, (char *)str);
+ tuple.set_state (Tuple::Valid);
break;
case Tuple::Int:
tuple.set_int (entry.tupleField, atol((char *)str));
+ tuple.set_state (Tuple::Valid);
break;
default:
@@ -171,7 +174,7 @@ static void xspf_add_file (xmlNode * track, const char * filename,
if (location != nullptr)
{
- if (tuple)
+ if (tuple.valid ())
tuple.set_filename (location);
items.append (location, std::move (tuple));
@@ -313,11 +316,10 @@ static bool is_valid_string (const char * s, char * * subst)
}
-static void xspf_add_node(xmlNodePtr node, Tuple::ValueType type,
- bool isMeta, const char *xspfName, const char *strVal,
- const int intVal)
+static void xspf_add_node (xmlNodePtr node, bool isMeta, const char * xspfName, const char * strVal)
{
xmlNodePtr tmp;
+ char * subst;
if (isMeta) {
tmp = xmlNewNode(nullptr, (xmlChar *) "meta");
@@ -325,24 +327,12 @@ static void xspf_add_node(xmlNodePtr node, Tuple::ValueType type,
} else
tmp = xmlNewNode(nullptr, (xmlChar *) xspfName);
- switch (type) {
- case Tuple::String:
- char * subst;
- if (is_valid_string (strVal, & subst))
- xmlAddChild (tmp, xmlNewText ((xmlChar *) strVal));
- else
- {
- xmlAddChild (tmp, xmlNewText ((xmlChar *) subst));
- g_free (subst);
- }
- break;
-
- case Tuple::Int:
- xmlAddChild (tmp, xmlNewText ((xmlChar *) (char *) int_to_str (intVal)));
- break;
-
- default:
- break;
+ if (is_valid_string (strVal, & subst))
+ xmlAddChild (tmp, xmlNewText ((xmlChar *) strVal));
+ else
+ {
+ xmlAddChild (tmp, xmlNewText ((xmlChar *) subst));
+ g_free (subst);
}
xmlAddChild(node, tmp);
@@ -367,7 +357,7 @@ bool XSPFLoader::save (const char * filename, VFSFile & file,
xmlDocSetRootElement(doc, rootnode);
if (title)
- xspf_add_node (rootnode, Tuple::String, false, "title", title, 0);
+ xspf_add_node (rootnode, false, "title", title);
tracklist = xmlNewNode(nullptr, (xmlChar *)"trackList");
xmlAddChild(rootnode, tracklist);
@@ -377,8 +367,6 @@ bool XSPFLoader::save (const char * filename, VFSFile & file,
const char * filename = item.filename;
const Tuple & tuple = item.tuple;
xmlNodePtr track, location;
- String scratch;
- int scratchi = 0;
track = xmlNewNode(nullptr, (xmlChar *)"track");
location = xmlNewNode(nullptr, (xmlChar *)"location");
@@ -387,28 +375,20 @@ bool XSPFLoader::save (const char * filename, VFSFile & file,
xmlAddChild(track, location);
xmlAddChild(tracklist, track);
- if (tuple)
+ for (auto & entry : xspf_entries)
{
- for (const xspf_entry_t & entry : xspf_entries)
+ switch (tuple.get_value_type (entry.tupleField))
{
- bool isOK = (tuple.get_value_type (entry.tupleField) == entry.type);
-
- switch (entry.type) {
- case Tuple::String:
- scratch = tuple.get_str (entry.tupleField);
- if (! scratch)
- isOK = false;
- break;
- case Tuple::Int:
- scratchi = tuple.get_int (entry.tupleField);
- break;
- default:
- break;
- }
-
- if (isOK)
- xspf_add_node (track, entry.type, entry.isMeta,
- entry.xspfName, scratch, scratchi);
+ case Tuple::String:
+ xspf_add_node (track, entry.isMeta, entry.xspfName,
+ tuple.get_str (entry.tupleField));
+ break;
+ case Tuple::Int:
+ xspf_add_node (track, entry.isMeta, entry.xspfName,
+ int_to_str (tuple.get_int (entry.tupleField)));
+ break;
+ default:
+ break;
}
}
}